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