|
|
1.1 ! root 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: * [email protected] ! 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 */ ! 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, ! 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, ! 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.