aboutsummaryrefslogtreecommitdiff
path: root/inc/scsi.h
blob: a9d8b0558d59ca73f5da378437d7dce6cde9468d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#ifndef SCSICAM_H
#define SCSICAM_H

/** (from SCSICAM) converts a capacitity in sectors to CHS
 *  keeps cylinders <= 1024 and sectors <= 62,
 *  but may give very large head numbers, though. */
static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs)
{
	unsigned int rv = 0;
	unsigned long heads, sectors, cylinders, temp;

	cylinders = 1024L;	/* Set number of cylinders to max */
	sectors = 62L;		/* Maximize sectors per track */

	temp = cylinders * sectors;	/* Compute divisor for heads */
	heads = capacity / temp;	/* Compute value for number of heads */
	if (capacity % temp) {	/* If no remainder, done! */
		heads++;	/* Else, increment number of heads */
		temp = cylinders * heads;	/* Compute divisor for sectors */
		sectors = capacity / temp;	/* Compute value for sectors per
						   track */
		if (capacity % temp) {	/* If no remainder, done! */
			sectors++;	/* Else, increment number of sectors */
			temp = heads * sectors;		/* Compute divisor for cylinders */
			cylinders = capacity / temp;	/* Compute number of cylinders */
		}
	}
	if (cylinders == 0)
		rv = (unsigned) -1;	/* Give error if 0 cylinders */

	*cyls = (unsigned int) cylinders;	/* Stuff return values */
	*secs = (unsigned int) sectors;
	*hds = (unsigned int) heads;
	return (rv);
}

static void guess_geometry(uint32_t num_sectors, unsigned int *cyls, unsigned int *hds, unsigned int *secs)
{
	unsigned int cylinders, heads, sectors;
	// First try to use SCSI CAM approach
	if (setsize(num_sectors, &cylinders, &heads, &sectors) != 0
	        || cylinders > 1024 || heads  > 255 || sectors > 63) {
		// Didn't work. So now we just use max heads and sectors but a crazy number of cyls
		if (num_sectors <= 64 * 32 * 65534) {
			// This follows the same behavior as Linux,
			// which uses smaller values for heads/sects as long as cyls fits < 65535
			heads = 64;
			sectors = 32;
		} else {
			heads = 255;
			sectors = 63;
		}
		cylinders = num_sectors / (heads * sectors);
	}

	*cyls = cylinders;
	*hds = heads;
	*secs = sectors;
}

#endif // SCSICAM_H