OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [scsi/] [scsicam.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.