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

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