root/drivers/scsi/scsicam.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. scsicam_bios_param
  2. partsize
  3. setsize

   1 /*
   2  * scsicam.c - SCSI CAM support functions, use for HDIO_GETGEO, etc.
   3  *
   4  * Copyright 1993, 1994 Drew Eckhardt
   5  *      Visionary Computing 
   6  *      (Unix and Linux consulting and custom programming)
   7  *      drew@Colorado.EDU
   8  *      +1 (303) 786-7975
   9  *
  10  * For more information, please consult the SCSI-CAM draft.
  11  */
  12 
  13 #ifdef MODULE
  14 /*
  15  * Don't import our own symbols, as this would severely mess up our
  16  * symbol tables.
  17  */
  18 #define _SCSI_SYMS_VER_
  19 #include <linux/autoconf.h>
  20 #include <linux/module.h>
  21 #include <linux/version.h>
  22 #else
  23 #define MOD_INC_USE_COUNT
  24 #define MOD_DEC_USE_COUNT
  25 #endif
  26 
  27 #include <linux/fs.h>
  28 #include <linux/genhd.h>
  29 #include <linux/kernel.h>
  30 #include "../block/blk.h"
  31 #include "scsi.h"
  32 #include "hosts.h"
  33 #include "sd.h"
  34 
  35 static int partsize(struct buffer_head *bh, unsigned long capacity,
  36     unsigned int  *cyls, unsigned int *hds, unsigned int *secs);
  37 static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds,
  38     unsigned int *secs);
  39 
  40 /*
  41  * Function : int scsicam_bios_param (Disk *disk, int dev, int *ip)
  42  *
  43  * Purpose : to determine the BIOS mapping used for a drive in a 
  44  *      SCSI-CAM system, storing the results in ip as required
  45  *      by the HDIO_GETGEO ioctl().
  46  *
  47  * Returns : -1 on failure, 0 on success.
  48  *
  49  */
  50 
  51 int scsicam_bios_param (Disk *disk, /* SCSI disk */
     /* [previous][next][first][last][top][bottom][index][help] */
  52         kdev_t dev,             /* Device major, minor */
  53         int *ip                 /* Heads, sectors, cylinders in that order */) {
  54 
  55     struct buffer_head *bh;
  56     int ret_code;
  57     int size = disk->capacity;
  58 
  59     if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024)))
  60         return -1;
  61 
  62 #ifdef DEBUG
  63         printk ("scsicam_bios_param : trying existing mapping\n");
  64 #endif
  65     ret_code = partsize (bh, (unsigned long) size, (unsigned int *) ip + 2, 
  66         (unsigned int *) ip + 0, (unsigned int *) ip + 1);
  67     brelse (bh);
  68 
  69     if (ret_code == -1) {
  70 #ifdef DEBUG
  71         printk ("scsicam_bios_param : trying optimal mapping\n");
  72 #endif
  73         ret_code = setsize ((unsigned long) size, (unsigned int *) ip + 2, 
  74             (unsigned int *) ip + 0, (unsigned int *) ip + 1);
  75     }
  76 
  77     return ret_code;
  78 }
  79 
  80 /*
  81  * Function : static int partsize(struct buffer_head *bh, unsigned long 
  82  *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
  83  *
  84  * Purpose : to determine the BIOS mapping used to create the partition
  85  *      table, storing the results in *cyls, *hds, and *secs 
  86  *
  87  * Returns : -1 on failure, 0 on success.
  88  *
  89  */
  90 
  91 static int partsize(struct buffer_head *bh, unsigned long capacity,
     /* [previous][next][first][last][top][bottom][index][help] */
  92     unsigned int  *cyls, unsigned int *hds, unsigned int *secs) {
  93     struct partition *p, *largest = NULL;
  94     int i, largest_cyl;
  95     int cyl, end_head, end_cyl, end_sector;
  96     unsigned int logical_end, physical_end;
  97     
  98 
  99     if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
 100         for (largest_cyl = -1, p = (struct partition *) 
 101             (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) {
 102             if (!p->sys_ind)
 103                 continue;
 104 #ifdef DEBUG
 105         printk ("scsicam_bios_param : partition %d has system \n",
 106             i);
 107 #endif
 108             cyl = p->cyl + ((p->sector & 0xc0) << 2);
 109             if (cyl > largest_cyl) {
 110                 largest_cyl = cyl;
 111                 largest = p;
 112             }
 113         }
 114     }
 115 
 116     if (largest) {
 117         end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2);
 118         end_head = largest->end_head;
 119         end_sector = largest->end_sector & 0x3f;
 120 #ifdef DEBUG
 121         printk ("scsicam_bios_param : end at h = %d, c = %d, s = %d\n",
 122             end_head, end_cyl, end_sector);
 123 #endif
 124 
 125         physical_end =  end_cyl * (end_head + 1) * end_sector +
 126             end_head * end_sector + end_sector;
 127 
 128         /* This is the actual _sector_ number at the end */
 129         logical_end = largest->start_sect + largest->nr_sects;
 130 
 131         if (logical_end == physical_end) {
 132             *secs = end_sector;
 133             *hds = end_head + 1;
 134             *cyls = capacity / ((end_head + 1) * end_sector);
 135             return 0;
 136         }
 137 #ifdef DEBUG
 138         printk ("scsicam_bios_param : logical (%u) != physical (%u)\n",
 139             logical_end, physical_end);
 140 #endif
 141     }
 142     return -1;
 143 }
 144 
 145 /*
 146  * Function : static int setsize(unsigned long capacity,unsigned int *cyls,
 147  *      unsigned int *hds, unsigned int *secs);
 148  *
 149  * Purpose : to determine a near-optimal int 0x13 mapping for a
 150  *      SCSI disk in terms of lost space of size capacity, storing
 151  *      the results in *cyls, *hds, and *secs.
 152  *
 153  * Returns : -1 on failure, 0 on success.
 154  *
 155  * Extracted from
 156  *
 157  * WORKING                                                    X3T9.2
 158  * DRAFT                                                        792D
 159  *
 160  *
 161  *                                                        Revision 6
 162  *                                                         10-MAR-94
 163  * Information technology -
 164  * SCSI-2 Common access method
 165  * transport and SCSI interface module
 166  * 
 167  * ANNEX A :
 168  *
 169  * setsize() converts a read capacity value to int 13h
 170  * head-cylinder-sector requirements. It minimizes the value for
 171  * number of heads and maximizes the number of cylinders. This
 172  * will support rather large disks before the number of heads
 173  * will not fit in 4 bits (or 6 bits). This algorithm also
 174  * minimizes the number of sectors that will be unused at the end
 175  * of the disk while allowing for very large disks to be
 176  * accommodated. This algorithm does not use physical geometry. 
 177  */
 178 
 179 static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds,
     /* [previous][next][first][last][top][bottom][index][help] */
 180     unsigned int *secs) { 
 181     unsigned int rv = 0; 
 182     unsigned long heads, sectors, cylinders, temp; 
 183 
 184     cylinders = 1024L;                  /* Set number of cylinders to max */ 
 185     sectors = 62L;                      /* Maximize sectors per track */ 
 186 
 187     temp = cylinders * sectors;         /* Compute divisor for heads */ 
 188     heads = capacity / temp;            /* Compute value for number of heads */
 189     if (capacity % temp) {              /* If no remainder, done! */ 
 190         heads++;                        /* Else, increment number of heads */ 
 191         temp = cylinders * heads;       /* Compute divisor for sectors */ 
 192         sectors = capacity / temp;      /* Compute value for sectors per
 193                                                track */ 
 194         if (capacity % temp) {          /* If no remainder, done! */ 
 195             sectors++;                  /* Else, increment number of sectors */ 
 196             temp = heads * sectors;     /* Compute divisor for cylinders */
 197             cylinders = capacity / temp;/* Compute number of cylinders */ 
 198         } 
 199     } 
 200     if (cylinders == 0) rv=(unsigned)-1;/* Give error if 0 cylinders */ 
 201 
 202     *cyls = (unsigned int) cylinders;   /* Stuff return values */ 
 203     *secs = (unsigned int) sectors; 
 204     *hds  = (unsigned int) heads; 
 205     return(rv); 
 206 } 

/* [previous][next][first][last][top][bottom][index][help] */