|
|
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.