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

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