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