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

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