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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [scsi/] [scsicam.c] - Blame information for rev 1626

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
/*
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
/*
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
#include <scsi/scsicam.h>
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 */
58
    ret_code = scsi_partsize (bh, (unsigned long) size, (unsigned int *) ip + 2,
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
/*
87
 * Function : static int scsi_partsize(struct buffer_head *bh, unsigned long
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
 
97
int scsi_partsize(struct buffer_head *bh, unsigned long capacity,
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
}

powered by: WebSVN 2.1.0

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