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