1 |
199 |
simons |
/*
|
2 |
|
|
* Disk Array driver for Compaq SMART2 Controllers
|
3 |
|
|
* Copyright 1998 Compaq Computer Corporation
|
4 |
|
|
*
|
5 |
|
|
* This program is free software; you can redistribute it and/or modify
|
6 |
|
|
* it under the terms of the GNU General Public License as published by
|
7 |
|
|
* the Free Software Foundation; either version 2 of the License, or
|
8 |
|
|
* (at your option) any later version.
|
9 |
|
|
*
|
10 |
|
|
* This program is distributed in the hope that it will be useful,
|
11 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12 |
|
|
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
13 |
|
|
* NON INFRINGEMENT. See the GNU General Public License for more details.
|
14 |
|
|
*
|
15 |
|
|
* You should have received a copy of the GNU General Public License
|
16 |
|
|
* along with this program; if not, write to the Free Software
|
17 |
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
18 |
|
|
*
|
19 |
|
|
* Questions/Comments/Bugfixes to arrays@compaq.com
|
20 |
|
|
*
|
21 |
|
|
* If you want to make changes, improve or add functionality to this
|
22 |
|
|
* driver, you'll probably need the Compaq Array Controller Interface
|
23 |
|
|
* Specificiation (Document number ECG086/1198)
|
24 |
|
|
*/
|
25 |
|
|
#include <linux/config.h>
|
26 |
|
|
#include <linux/types.h>
|
27 |
|
|
#include <linux/bios32.h>
|
28 |
|
|
#include <linux/pci.h>
|
29 |
|
|
#include <linux/kernel.h>
|
30 |
|
|
#include <linux/malloc.h>
|
31 |
|
|
#include <linux/delay.h>
|
32 |
|
|
#include <linux/major.h>
|
33 |
|
|
#include <linux/fs.h>
|
34 |
|
|
#include <linux/timer.h>
|
35 |
|
|
#include <linux/proc_fs.h>
|
36 |
|
|
#include <linux/hdreg.h>
|
37 |
|
|
#include <asm/io.h>
|
38 |
|
|
#include <asm/bitops.h>
|
39 |
|
|
|
40 |
|
|
#ifdef MODULE
|
41 |
|
|
#include <linux/module.h>
|
42 |
|
|
#include <linux/version.h>
|
43 |
|
|
#else
|
44 |
|
|
#define MOD_INC_USE_COUNT
|
45 |
|
|
#define MOD_DEC_USE_COUNT
|
46 |
|
|
#endif
|
47 |
|
|
|
48 |
|
|
#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0)"
|
49 |
|
|
|
50 |
|
|
#define MAJOR_NR COMPAQ_SMART2_MAJOR
|
51 |
|
|
#include <linux/blk.h>
|
52 |
|
|
#include <linux/blkdev.h>
|
53 |
|
|
#include <linux/genhd.h>
|
54 |
|
|
|
55 |
|
|
#include "cpqarray.h"
|
56 |
|
|
#include "ida_cmd.h"
|
57 |
|
|
#include "ida_ioctl.h"
|
58 |
|
|
|
59 |
|
|
#define READ_AHEAD 128
|
60 |
|
|
#define NR_CMDS 128 /* This can probably go as high as ~400 */
|
61 |
|
|
|
62 |
|
|
#define MAX_CTLR 8
|
63 |
|
|
#define CTLR_SHIFT 8
|
64 |
|
|
|
65 |
|
|
static int nr_ctlr = 0;
|
66 |
|
|
static ctlr_info_t *hba[MAX_CTLR] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
67 |
|
|
|
68 |
|
|
#ifdef CONFIG_BLK_CPQ_DA_EISA
|
69 |
|
|
#ifndef MODULE
|
70 |
|
|
static
|
71 |
|
|
#endif
|
72 |
|
|
int eisa[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
73 |
|
|
#endif
|
74 |
|
|
|
75 |
|
|
static char *product_names[] = {
|
76 |
|
|
"Unknown",
|
77 |
|
|
"SMART-2/E",
|
78 |
|
|
"SMART-2/P", /* or SMART-2DH */
|
79 |
|
|
"SMART-2SL",
|
80 |
|
|
"SMART-3200",
|
81 |
|
|
"SMART-3100ES",
|
82 |
|
|
"SMART-221",
|
83 |
|
|
};
|
84 |
|
|
|
85 |
|
|
static struct hd_struct * ida;
|
86 |
|
|
static int * ida_sizes;
|
87 |
|
|
static int * ida_blocksizes;
|
88 |
|
|
static int * ida_hardsizes;
|
89 |
|
|
static int * ida_maxsectors;
|
90 |
|
|
static int * ida_maxsegments;
|
91 |
|
|
static struct gendisk ida_gendisk[MAX_CTLR];
|
92 |
|
|
|
93 |
|
|
|
94 |
|
|
/* Debug... */
|
95 |
|
|
#define DBG(s) s
|
96 |
|
|
/* Debug (general info)... */
|
97 |
|
|
#define DBGINFO(s)
|
98 |
|
|
/* Debug Paranoid... */
|
99 |
|
|
#define DBGP(s) s
|
100 |
|
|
/* Debug Extra Paranoid... */
|
101 |
|
|
#define DBGPX(s)
|
102 |
|
|
|
103 |
|
|
void cpqarray_init(void);
|
104 |
|
|
#ifdef CONFIG_BLK_CPQ_DA_PCI
|
105 |
|
|
static int cpqarray_pci_detect(void);
|
106 |
|
|
static void cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn);
|
107 |
|
|
static ulong remap_pci_mem(ulong base, ulong size);
|
108 |
|
|
#endif
|
109 |
|
|
#ifdef CONFIG_BLK_CPQ_DA_EISA
|
110 |
|
|
static int cpqarray_eisa_detect(void);
|
111 |
|
|
#endif
|
112 |
|
|
static void flushcomplete(int ctlr);
|
113 |
|
|
static int pollcomplete(int ctlr);
|
114 |
|
|
static void getgeometry(int ctlr);
|
115 |
|
|
|
116 |
|
|
static cmdlist_t * cmd_alloc(ctlr_info_t *h);
|
117 |
|
|
static void cmd_free(ctlr_info_t *h, cmdlist_t *c);
|
118 |
|
|
|
119 |
|
|
static int sendcmd(
|
120 |
|
|
__u8 cmd,
|
121 |
|
|
int ctlr,
|
122 |
|
|
void *buff,
|
123 |
|
|
size_t size,
|
124 |
|
|
unsigned int blk,
|
125 |
|
|
unsigned int blkcnt,
|
126 |
|
|
unsigned int log_unit );
|
127 |
|
|
|
128 |
|
|
static int ida_open(struct inode *inode, struct file *filep);
|
129 |
|
|
static void ida_release(struct inode *inode, struct file *filep);
|
130 |
|
|
static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg);
|
131 |
|
|
static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io);
|
132 |
|
|
|
133 |
|
|
static void do_ida_request(int i);
|
134 |
|
|
/*
|
135 |
|
|
* This is a hack. This driver eats a major number for each controller, and
|
136 |
|
|
* sets blkdev[xxx].request_fn to each one of these so the real request
|
137 |
|
|
* function knows what controller its working with.
|
138 |
|
|
*/
|
139 |
|
|
#define DO_IDA_REQUEST(x) { \
|
140 |
|
|
int flags; save_flags(flags); cli(); \
|
141 |
|
|
do_ida_request(x); restore_flags(flags); }
|
142 |
|
|
|
143 |
|
|
static void do_ida_request0(void) DO_IDA_REQUEST(0);
|
144 |
|
|
static void do_ida_request1(void) DO_IDA_REQUEST(1);
|
145 |
|
|
static void do_ida_request2(void) DO_IDA_REQUEST(2);
|
146 |
|
|
static void do_ida_request3(void) DO_IDA_REQUEST(3);
|
147 |
|
|
static void do_ida_request4(void) DO_IDA_REQUEST(4);
|
148 |
|
|
static void do_ida_request5(void) DO_IDA_REQUEST(5);
|
149 |
|
|
static void do_ida_request6(void) DO_IDA_REQUEST(6);
|
150 |
|
|
static void do_ida_request7(void) DO_IDA_REQUEST(7);
|
151 |
|
|
|
152 |
|
|
static void start_io(ctlr_info_t *h);
|
153 |
|
|
|
154 |
|
|
static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c);
|
155 |
|
|
static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c);
|
156 |
|
|
static inline void complete_buffers(struct buffer_head *bh, int ok);
|
157 |
|
|
static inline void complete_command(cmdlist_t *cmd, int timeout);
|
158 |
|
|
|
159 |
|
|
static void do_ida_intr(int irq, void *dev_id, struct pt_regs * regs);
|
160 |
|
|
static void ida_timer(unsigned long tdata);
|
161 |
|
|
static int frevalidate_logvol(kdev_t dev);
|
162 |
|
|
static int revalidate_logvol(kdev_t dev, int maxusage);
|
163 |
|
|
static int revalidate_allvol(kdev_t dev);
|
164 |
|
|
|
165 |
|
|
static void ida_procinit(int i);
|
166 |
|
|
static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int dp);
|
167 |
|
|
|
168 |
|
|
/*
|
169 |
|
|
* These macros control what happens when the driver tries to write to or
|
170 |
|
|
* read from a card. If the driver is configured for EISA only or PCI only,
|
171 |
|
|
* the macros expand to inl/outl or readl/writel. If the drive is configured
|
172 |
|
|
* for both EISA and PCI, the macro expands to a conditional which uses
|
173 |
|
|
* memory mapped IO if the card has it (PCI) or io ports if it doesn't (EISA).
|
174 |
|
|
*/
|
175 |
|
|
#ifdef CONFIG_BLK_CPQ_DA_PCI
|
176 |
|
|
# ifdef CONFIG_BLK_CPQ_DA_EISA
|
177 |
|
|
# define smart2_read(h, offset) ( ((h)->vaddr) ? readl((h)->vaddr+(offset)) : inl((h)->ioaddr+(offset)) )
|
178 |
|
|
# define smart2_write(p, h, offset) ( ((h)->vaddr) ? writel((p), (h)->vaddr+(offset)) : outl((p), (h)->ioaddr+(offset)) )
|
179 |
|
|
# else
|
180 |
|
|
# define smart2_read(h, offset) readl((h)->vaddr+(offset))
|
181 |
|
|
# define smart2_write(p, h, offset) writel((p), (h)->vaddr+(offset))
|
182 |
|
|
# endif
|
183 |
|
|
#else
|
184 |
|
|
# ifdef CONFIG_BLK_CPQ_DA_EISA
|
185 |
|
|
# define smart2_read(h, offset) inl((h)->vaddr+(offset))
|
186 |
|
|
# define smart2_write(p, h, offset) outl((p), (h)->vaddr+(offset))
|
187 |
|
|
# else
|
188 |
|
|
# error "You must enable either SMART2 PCI support or SMART2 EISA support or both!"
|
189 |
|
|
# endif
|
190 |
|
|
#endif
|
191 |
|
|
|
192 |
|
|
void ida_geninit(struct gendisk *g)
|
193 |
|
|
{
|
194 |
|
|
int ctlr = g-ida_gendisk;
|
195 |
|
|
int i,j;
|
196 |
|
|
drv_info_t *drv;
|
197 |
|
|
|
198 |
|
|
for(i=0; i<NWD; i++) {
|
199 |
|
|
drv = &hba[ctlr]->drv[i];
|
200 |
|
|
if (!drv->nr_blks)
|
201 |
|
|
continue;
|
202 |
|
|
ida[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)].nr_sects =
|
203 |
|
|
ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)] =
|
204 |
|
|
drv->nr_blks;
|
205 |
|
|
|
206 |
|
|
for(j=0; j<16; j++) {
|
207 |
|
|
ida_blocksizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)+j] =
|
208 |
|
|
1024;
|
209 |
|
|
ida_hardsizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)+j] =
|
210 |
|
|
drv->blk_size;
|
211 |
|
|
}
|
212 |
|
|
ida_gendisk[ctlr].nr_real++;
|
213 |
|
|
}
|
214 |
|
|
|
215 |
|
|
}
|
216 |
|
|
|
217 |
|
|
struct file_operations ida_fops = {
|
218 |
|
|
NULL, /* lseek - default */
|
219 |
|
|
block_read, /* read - general block-dev read */
|
220 |
|
|
block_write, /* write - general block-dev write */
|
221 |
|
|
NULL, /* readdir - bad */
|
222 |
|
|
NULL, /* select */
|
223 |
|
|
ida_ioctl, /* ioctl */
|
224 |
|
|
NULL, /* mmap */
|
225 |
|
|
ida_open, /* open code */
|
226 |
|
|
ida_release, /* release */
|
227 |
|
|
block_fsync, /* fsync */
|
228 |
|
|
NULL, /* fasync */
|
229 |
|
|
NULL, /* Disk change */
|
230 |
|
|
frevalidate_logvol, /* revalidate */
|
231 |
|
|
};
|
232 |
|
|
|
233 |
|
|
|
234 |
|
|
/*
|
235 |
|
|
* Get us a file in /proc that says something about each controller. Right
|
236 |
|
|
* now, we add entries to /proc, but in the future we should probably get
|
237 |
|
|
* our own subdir in /proc (/proc/array/ida) and put our stuff in there.
|
238 |
|
|
*/
|
239 |
|
|
extern struct inode_operations proc_diskarray_inode_operations;
|
240 |
|
|
struct proc_dir_entry *proc_array = NULL;
|
241 |
|
|
static void ida_procinit(int i)
|
242 |
|
|
{
|
243 |
|
|
struct proc_dir_entry *pd;
|
244 |
|
|
|
245 |
|
|
if (proc_array == NULL) {
|
246 |
|
|
proc_array = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
|
247 |
|
|
if (!proc_array) return;
|
248 |
|
|
memset(proc_array, 0, sizeof(struct proc_dir_entry));
|
249 |
|
|
proc_array->namelen = 5;
|
250 |
|
|
proc_array->name = "array";
|
251 |
|
|
proc_array->mode = S_IFDIR | S_IRUGO | S_IXUGO;
|
252 |
|
|
proc_array->nlink = 2;
|
253 |
|
|
proc_array->uid = 0;
|
254 |
|
|
proc_array->gid = 0;
|
255 |
|
|
proc_array->size = 0;
|
256 |
|
|
proc_array->ops = &proc_dir_inode_operations;
|
257 |
|
|
proc_register_dynamic(&proc_root, proc_array);
|
258 |
|
|
}
|
259 |
|
|
|
260 |
|
|
pd = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
|
261 |
|
|
if (!pd) return;
|
262 |
|
|
memset(pd, 0, sizeof(struct proc_dir_entry));
|
263 |
|
|
pd->namelen = 4;
|
264 |
|
|
pd->name = hba[i]->devname;
|
265 |
|
|
pd->mode = S_IFREG | S_IRUGO;
|
266 |
|
|
pd->nlink = 1;
|
267 |
|
|
pd->uid = 0;
|
268 |
|
|
pd->gid = 0;
|
269 |
|
|
pd->size = 0;
|
270 |
|
|
pd->ops = &proc_diskarray_inode_operations;
|
271 |
|
|
pd->get_info = ida_proc_get_info;
|
272 |
|
|
|
273 |
|
|
hba[i]->proc = (int)pd;
|
274 |
|
|
proc_register_dynamic(proc_array, pd);
|
275 |
|
|
}
|
276 |
|
|
|
277 |
|
|
/*
|
278 |
|
|
* Report information about this controller.
|
279 |
|
|
*/
|
280 |
|
|
static int ida_proc_get_info(char *buffer, char **start, off_t offset, int length, int pd)
|
281 |
|
|
{
|
282 |
|
|
off_t pos = 0;
|
283 |
|
|
off_t len = 0;
|
284 |
|
|
int size, i, ctlr;
|
285 |
|
|
ctlr_info_t *h;
|
286 |
|
|
drv_info_t *drv;
|
287 |
|
|
#ifdef CPQ_PROC_PRINT_QUEUES
|
288 |
|
|
cmdlist_t *c;
|
289 |
|
|
#endif
|
290 |
|
|
|
291 |
|
|
for(ctlr=0; ctlr<nr_ctlr; ctlr++)
|
292 |
|
|
if (hba[ctlr] && hba[ctlr]->proc == pd) break;
|
293 |
|
|
|
294 |
|
|
|
295 |
|
|
if ((h = hba[ctlr]) == NULL)
|
296 |
|
|
return 0;
|
297 |
|
|
|
298 |
|
|
size = sprintf(buffer, "%s: Compaq %s Disk Array Controller\n"
|
299 |
|
|
" Board ID: %08lx\n"
|
300 |
|
|
" Firmware Revision: %c%c%c%c\n"
|
301 |
|
|
" Controller Sig: %08lx\n"
|
302 |
|
|
" Memory Address: %08lx\n"
|
303 |
|
|
" I/O Port: %04x\n"
|
304 |
|
|
" IRQ: %x\n"
|
305 |
|
|
" Logical drives: %d\n"
|
306 |
|
|
" Physical drives: %d\n\n"
|
307 |
|
|
" Current Q depth: %d\n"
|
308 |
|
|
" Max Q depth since init: %d\n\n",
|
309 |
|
|
h->devname,
|
310 |
|
|
product_names[h->product],
|
311 |
|
|
(unsigned long)h->board_id,
|
312 |
|
|
h->firm_rev[0], h->firm_rev[1], h->firm_rev[2], h->firm_rev[3],
|
313 |
|
|
(unsigned long)h->ctlr_sig, (unsigned long)h->vaddr,
|
314 |
|
|
(unsigned int) h->ioaddr, (unsigned int)h->intr,
|
315 |
|
|
h->log_drives, h->phys_drives,
|
316 |
|
|
h->Qdepth, h->maxQsinceinit);
|
317 |
|
|
|
318 |
|
|
pos += size; len += size;
|
319 |
|
|
|
320 |
|
|
size = sprintf(buffer+len, "Logical Drive Info:\n");
|
321 |
|
|
pos += size; len += size;
|
322 |
|
|
|
323 |
|
|
for(i=0; i<h->log_drives; i++) {
|
324 |
|
|
drv = &h->drv[i];
|
325 |
|
|
size = sprintf(buffer+len, "ida/c%dd%d: blksz=%d nr_blks=%d\n",
|
326 |
|
|
ctlr, i, drv->blk_size, drv->nr_blks);
|
327 |
|
|
pos += size; len += size;
|
328 |
|
|
}
|
329 |
|
|
|
330 |
|
|
#ifdef CPQ_PROC_PRINT_QUEUES
|
331 |
|
|
size = sprintf(buffer+len, "\nCurrent Queues:\n");
|
332 |
|
|
pos += size; len += size;
|
333 |
|
|
|
334 |
|
|
c = h->reqQ;
|
335 |
|
|
size = sprintf(buffer+len, "reqQ = %p", c); pos += size; len += size;
|
336 |
|
|
if (c) c=c->next;
|
337 |
|
|
while(c && c != h->reqQ) {
|
338 |
|
|
size = sprintf(buffer+len, "->%p", c);
|
339 |
|
|
pos += size; len += size;
|
340 |
|
|
c=c->next;
|
341 |
|
|
}
|
342 |
|
|
|
343 |
|
|
c = h->cmpQ;
|
344 |
|
|
size = sprintf(buffer+len, "\ncmpQ = %p", c); pos += size; len += size;
|
345 |
|
|
if (c) c=c->next;
|
346 |
|
|
while(c && c != h->cmpQ) {
|
347 |
|
|
size = sprintf(buffer+len, "->%p", c);
|
348 |
|
|
pos += size; len += size;
|
349 |
|
|
c=c->next;
|
350 |
|
|
}
|
351 |
|
|
|
352 |
|
|
size = sprintf(buffer+len, "\n"); pos += size; len += size;
|
353 |
|
|
#endif
|
354 |
|
|
size = sprintf(buffer+len,"nr_allocs = %d\nnr_frees = %d\n",
|
355 |
|
|
h->nr_allocs, h->nr_frees);
|
356 |
|
|
pos += size; len += size;
|
357 |
|
|
|
358 |
|
|
*start = buffer+offset;
|
359 |
|
|
len -= offset;
|
360 |
|
|
if (len>length)
|
361 |
|
|
len = length;
|
362 |
|
|
return len;
|
363 |
|
|
}
|
364 |
|
|
|
365 |
|
|
#ifdef MODULE
|
366 |
|
|
/* This is a hack... */
|
367 |
|
|
#include "proc_array.c"
|
368 |
|
|
int init_module(void)
|
369 |
|
|
{
|
370 |
|
|
int i, j;
|
371 |
|
|
cpqarray_init();
|
372 |
|
|
if (nr_ctlr == 0)
|
373 |
|
|
return -EIO;
|
374 |
|
|
|
375 |
|
|
for(i=0; i<nr_ctlr; i++) {
|
376 |
|
|
ida_geninit(&ida_gendisk[i]);
|
377 |
|
|
for(j=0; j<NWD; j++)
|
378 |
|
|
if (ida_sizes[(i<<CTLR_SHIFT) + (j<<NWD_SHIFT)])
|
379 |
|
|
resetup_one_dev(&ida_gendisk[i], j);
|
380 |
|
|
}
|
381 |
|
|
return 0;
|
382 |
|
|
}
|
383 |
|
|
void cleanup_module(void)
|
384 |
|
|
{
|
385 |
|
|
int i;
|
386 |
|
|
struct gendisk *g;
|
387 |
|
|
|
388 |
|
|
for(i=0; i<nr_ctlr; i++) {
|
389 |
|
|
smart2_write(0, hba[i], INTR_MASK);
|
390 |
|
|
free_irq(hba[i]->intr, hba[i]);
|
391 |
|
|
vfree((void*)hba[i]->vaddr);
|
392 |
|
|
unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
|
393 |
|
|
del_timer(&hba[i]->timer);
|
394 |
|
|
proc_unregister(proc_array,
|
395 |
|
|
((struct proc_dir_entry*)hba[i]->proc)->low_ino);
|
396 |
|
|
kfree(hba[i]->cmd_pool);
|
397 |
|
|
kfree(hba[i]->cmd_pool_bits);
|
398 |
|
|
|
399 |
|
|
if (gendisk_head == &ida_gendisk[i]) {
|
400 |
|
|
gendisk_head = ida_gendisk[i].next;
|
401 |
|
|
} else {
|
402 |
|
|
for(g=gendisk_head; g; g=g->next) {
|
403 |
|
|
if (g->next == &ida_gendisk[i]) {
|
404 |
|
|
g->next = ida_gendisk[i].next;
|
405 |
|
|
break;
|
406 |
|
|
}
|
407 |
|
|
}
|
408 |
|
|
}
|
409 |
|
|
|
410 |
|
|
blk_dev[MAJOR_NR+i].request_fn = NULL;
|
411 |
|
|
blksize_size[MAJOR_NR+i] = NULL;
|
412 |
|
|
hardsect_size[MAJOR_NR+i] = NULL;
|
413 |
|
|
max_sectors[MAJOR_NR+i] = NULL;
|
414 |
|
|
max_segments[MAJOR_NR+i] = NULL;
|
415 |
|
|
}
|
416 |
|
|
proc_unregister(&proc_root, proc_array->low_ino);
|
417 |
|
|
kfree(ida);
|
418 |
|
|
kfree(ida_sizes);
|
419 |
|
|
kfree(ida_hardsizes);
|
420 |
|
|
kfree(ida_blocksizes);
|
421 |
|
|
|
422 |
|
|
kfree(ida_maxsectors);
|
423 |
|
|
kfree(ida_maxsegments);
|
424 |
|
|
|
425 |
|
|
}
|
426 |
|
|
#endif /* MODULE */
|
427 |
|
|
|
428 |
|
|
/*
|
429 |
|
|
* This is it. Find all the controllers and register them. I really hate
|
430 |
|
|
* stealing all these major device numbers.
|
431 |
|
|
*/
|
432 |
|
|
void cpqarray_init(void)
|
433 |
|
|
{
|
434 |
|
|
void (*request_fns[MAX_CTLR])(void) = {
|
435 |
|
|
do_ida_request0, do_ida_request1,
|
436 |
|
|
do_ida_request2, do_ida_request3,
|
437 |
|
|
do_ida_request4, do_ida_request5,
|
438 |
|
|
do_ida_request6, do_ida_request7,
|
439 |
|
|
};
|
440 |
|
|
int i;
|
441 |
|
|
|
442 |
|
|
/* detect controllers */
|
443 |
|
|
#ifdef CONFIG_BLK_CPQ_DA_PCI
|
444 |
|
|
cpqarray_pci_detect();
|
445 |
|
|
#endif
|
446 |
|
|
#ifdef CONFIG_BLK_CPQ_DA_EISA
|
447 |
|
|
cpqarray_eisa_detect();
|
448 |
|
|
#endif
|
449 |
|
|
|
450 |
|
|
if (nr_ctlr == 0)
|
451 |
|
|
return;
|
452 |
|
|
|
453 |
|
|
printk(DRIVER_NAME "\n");
|
454 |
|
|
printk("Found %d controller(s)\n", nr_ctlr);
|
455 |
|
|
|
456 |
|
|
/* allocate space for disk structs */
|
457 |
|
|
ida = kmalloc(sizeof(struct hd_struct)*nr_ctlr*NWD*16, GFP_KERNEL);
|
458 |
|
|
ida_sizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
|
459 |
|
|
ida_blocksizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
|
460 |
|
|
ida_hardsizes = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
|
461 |
|
|
|
462 |
|
|
ida_maxsegments = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
|
463 |
|
|
ida_maxsectors = kmalloc(sizeof(int)*nr_ctlr*NWD*16, GFP_KERNEL);
|
464 |
|
|
|
465 |
|
|
memset(ida, 0, sizeof(struct hd_struct)*nr_ctlr*NWD*16);
|
466 |
|
|
memset(ida_sizes, 0, sizeof(int)*nr_ctlr*NWD*16);
|
467 |
|
|
memset(ida_blocksizes, 0, sizeof(int)*nr_ctlr*NWD*16);
|
468 |
|
|
memset(ida_hardsizes, 0, sizeof(int)*nr_ctlr*NWD*16);
|
469 |
|
|
memset(ida_maxsegments, 0, sizeof(int)*nr_ctlr*NWD*16);
|
470 |
|
|
memset(ida_maxsectors, 0, sizeof(int)*nr_ctlr*NWD*16);
|
471 |
|
|
memset(ida_gendisk, 0, sizeof(struct gendisk)*MAX_CTLR);
|
472 |
|
|
|
473 |
|
|
for(i=0; i<nr_ctlr*NWD*16; i++) {
|
474 |
|
|
ida_maxsegments[i] = SG_MAX;
|
475 |
|
|
ida_maxsectors[i] = 1024;
|
476 |
|
|
}
|
477 |
|
|
/*
|
478 |
|
|
* register block devices
|
479 |
|
|
* Find disks and fill in structs
|
480 |
|
|
* Get an interrupt, set the Q depth and get into /proc
|
481 |
|
|
*/
|
482 |
|
|
for(i=0; i< nr_ctlr; i++) {
|
483 |
|
|
smart2_write(0, hba[i], INTR_MASK); /* No interrupts */
|
484 |
|
|
if (request_irq(hba[i]->intr, do_ida_intr,
|
485 |
|
|
SA_INTERRUPT | SA_SHIRQ, hba[i]->devname, hba[i])) {
|
486 |
|
|
|
487 |
|
|
printk("Unable to get irq %d for %s\n",
|
488 |
|
|
hba[i]->intr, hba[i]->devname);
|
489 |
|
|
continue;
|
490 |
|
|
}
|
491 |
|
|
if (register_blkdev(MAJOR_NR+i, hba[i]->devname, &ida_fops)) {
|
492 |
|
|
printk("Unable to get major number %d for %s\n",
|
493 |
|
|
MAJOR_NR+i, hba[i]->devname);
|
494 |
|
|
continue;
|
495 |
|
|
}
|
496 |
|
|
|
497 |
|
|
hba[i]->cmd_pool = (cmdlist_t*)kmalloc(
|
498 |
|
|
NR_CMDS*sizeof(cmdlist_t), GFP_KERNEL);
|
499 |
|
|
hba[i]->cmd_pool_bits = (__u32*)kmalloc(
|
500 |
|
|
((NR_CMDS+31)/32)*sizeof(__u32), GFP_KERNEL);
|
501 |
|
|
memset(hba[i]->cmd_pool, 0, NR_CMDS*sizeof(cmdlist_t));
|
502 |
|
|
memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+31)/32)*sizeof(__u32));
|
503 |
|
|
|
504 |
|
|
printk("Finding drives on %s", hba[i]->devname);
|
505 |
|
|
getgeometry(i);
|
506 |
|
|
|
507 |
|
|
smart2_write(FIFO_NOT_EMPTY, hba[i], INTR_MASK);
|
508 |
|
|
|
509 |
|
|
ida_procinit(i);
|
510 |
|
|
|
511 |
|
|
ida_gendisk[i].major = MAJOR_NR + i;
|
512 |
|
|
ida_gendisk[i].major_name = "ida";
|
513 |
|
|
ida_gendisk[i].minor_shift = NWD_SHIFT;
|
514 |
|
|
ida_gendisk[i].max_p = 16;
|
515 |
|
|
ida_gendisk[i].max_nr = 16;
|
516 |
|
|
ida_gendisk[i].init = ida_geninit;
|
517 |
|
|
ida_gendisk[i].part = ida + (i*256);
|
518 |
|
|
ida_gendisk[i].sizes = ida_sizes + (i*256);
|
519 |
|
|
/* ida_gendisk[i].nr_real is handled by getgeometry */
|
520 |
|
|
|
521 |
|
|
blk_dev[MAJOR_NR+i].request_fn = request_fns[i];
|
522 |
|
|
blksize_size[MAJOR_NR+i] = ida_blocksizes + (i*256);
|
523 |
|
|
hardsect_size[MAJOR_NR+i] = ida_hardsizes + (i*256);
|
524 |
|
|
read_ahead[MAJOR_NR+i] = READ_AHEAD;
|
525 |
|
|
max_sectors[MAJOR_NR+i] = ida_maxsectors + (i*256);
|
526 |
|
|
max_segments[MAJOR_NR+i] = ida_maxsegments + (i*256);
|
527 |
|
|
|
528 |
|
|
/* Get on the disk list */
|
529 |
|
|
ida_gendisk[i].next = gendisk_head;
|
530 |
|
|
gendisk_head = &ida_gendisk[i];
|
531 |
|
|
|
532 |
|
|
init_timer(&hba[i]->timer);
|
533 |
|
|
hba[i]->timer.expires = jiffies + IDA_TIMER;
|
534 |
|
|
hba[i]->timer.data = (unsigned long)hba[i];
|
535 |
|
|
hba[i]->timer.function = ida_timer;
|
536 |
|
|
add_timer(&hba[i]->timer);
|
537 |
|
|
|
538 |
|
|
}
|
539 |
|
|
/* done ! */
|
540 |
|
|
}
|
541 |
|
|
|
542 |
|
|
#ifdef CONFIG_BLK_CPQ_DA_PCI
|
543 |
|
|
/*
|
544 |
|
|
* Find the controller and initialize it
|
545 |
|
|
*/
|
546 |
|
|
static int cpqarray_pci_detect(void)
|
547 |
|
|
{
|
548 |
|
|
int index;
|
549 |
|
|
unchar bus=0, dev_fn=0;
|
550 |
|
|
|
551 |
|
|
for(index=0; ; index++) {
|
552 |
|
|
if (pcibios_find_device(PCI_VENDOR_ID_COMPAQ,
|
553 |
|
|
PCI_DEVICE_ID_COMPAQ_SMART2P, index, &bus, &dev_fn))
|
554 |
|
|
break;
|
555 |
|
|
|
556 |
|
|
if (index == 1000000) break;
|
557 |
|
|
if (nr_ctlr == 8) {
|
558 |
|
|
printk("This driver supports a maximum of "
|
559 |
|
|
"8 controllers.\n");
|
560 |
|
|
break;
|
561 |
|
|
}
|
562 |
|
|
|
563 |
|
|
hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
|
564 |
|
|
memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
|
565 |
|
|
cpqarray_pci_init(hba[nr_ctlr], bus, dev_fn);
|
566 |
|
|
sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
|
567 |
|
|
hba[nr_ctlr]->ctlr = nr_ctlr;
|
568 |
|
|
nr_ctlr++;
|
569 |
|
|
}
|
570 |
|
|
|
571 |
|
|
return nr_ctlr;
|
572 |
|
|
}
|
573 |
|
|
|
574 |
|
|
/*
|
575 |
|
|
* Find the IO address of the controller, its IRQ and so forth. Fill
|
576 |
|
|
* in some basic stuff into the ctlr_info_t structure.
|
577 |
|
|
*/
|
578 |
|
|
static void cpqarray_pci_init(ctlr_info_t *c, unchar bus, unchar device_fn)
|
579 |
|
|
{
|
580 |
|
|
ushort vendor_id, device_id, command;
|
581 |
|
|
unchar cache_line_size, latency_timer;
|
582 |
|
|
unchar irq, revision;
|
583 |
|
|
uint addr[6];
|
584 |
|
|
|
585 |
|
|
int i;
|
586 |
|
|
|
587 |
|
|
(void) pcibios_read_config_word(bus, device_fn,
|
588 |
|
|
PCI_VENDOR_ID, &vendor_id);
|
589 |
|
|
(void) pcibios_read_config_word(bus, device_fn,
|
590 |
|
|
PCI_DEVICE_ID, &device_id);
|
591 |
|
|
(void) pcibios_read_config_word(bus, device_fn,
|
592 |
|
|
PCI_COMMAND, &command);
|
593 |
|
|
for(i=0; i<6; i++)
|
594 |
|
|
(void) pcibios_read_config_dword(bus, device_fn,
|
595 |
|
|
PCI_BASE_ADDRESS_0 + i*4, addr+i);
|
596 |
|
|
|
597 |
|
|
(void) pcibios_read_config_byte(bus, device_fn,
|
598 |
|
|
PCI_CLASS_REVISION,&revision);
|
599 |
|
|
(void) pcibios_read_config_byte(bus, device_fn,
|
600 |
|
|
PCI_INTERRUPT_LINE, &irq);
|
601 |
|
|
(void) pcibios_read_config_byte(bus, device_fn,
|
602 |
|
|
PCI_CACHE_LINE_SIZE, &cache_line_size);
|
603 |
|
|
(void) pcibios_read_config_byte(bus, device_fn,
|
604 |
|
|
PCI_LATENCY_TIMER, &latency_timer);
|
605 |
|
|
|
606 |
|
|
DBGINFO(
|
607 |
|
|
printk("vendor_id = %x\n", vendor_id);
|
608 |
|
|
printk("device_id = %x\n", device_id);
|
609 |
|
|
printk("command = %x\n", command);
|
610 |
|
|
for(i=0; i<6; i++)
|
611 |
|
|
printk("addr[%d] = %x\n", i, addr[i]);
|
612 |
|
|
printk("revision = %x\n", revision);
|
613 |
|
|
printk("irq = %x\n", irq);
|
614 |
|
|
printk("cache_line_size = %x\n", cache_line_size);
|
615 |
|
|
printk("latency_timer = %x\n", latency_timer);
|
616 |
|
|
);
|
617 |
|
|
|
618 |
|
|
c->intr = irq;
|
619 |
|
|
c->ioaddr = addr[0] & ~0x1;
|
620 |
|
|
|
621 |
|
|
/*
|
622 |
|
|
* Memory base addr is first addr with the first bit _not_ set
|
623 |
|
|
*/
|
624 |
|
|
for(i=0; i<6; i++)
|
625 |
|
|
if (!(addr[i] & 0x1)) {
|
626 |
|
|
c->paddr = addr[i];
|
627 |
|
|
break;
|
628 |
|
|
}
|
629 |
|
|
c->vaddr = remap_pci_mem(c->paddr, 128);
|
630 |
|
|
}
|
631 |
|
|
|
632 |
|
|
/*
|
633 |
|
|
* Map (physical) PCI mem into (virtual) kernel space
|
634 |
|
|
*/
|
635 |
|
|
static ulong remap_pci_mem(ulong base, ulong size)
|
636 |
|
|
{
|
637 |
|
|
ulong page_base = ((ulong) base) & PAGE_MASK;
|
638 |
|
|
ulong page_offs = ((ulong) base) - page_base;
|
639 |
|
|
ulong page_remapped = (ulong) vremap(page_base, page_offs+size);
|
640 |
|
|
|
641 |
|
|
return (ulong) (page_remapped ? (page_remapped + page_offs) : 0UL);
|
642 |
|
|
}
|
643 |
|
|
#endif /* CONFIG_BLK_CPQ_DA_PCI */
|
644 |
|
|
|
645 |
|
|
#ifdef CONFIG_BLK_CPQ_DA_EISA
|
646 |
|
|
/*
|
647 |
|
|
* Copy the contents of the ints[] array passed to us by init.
|
648 |
|
|
*/
|
649 |
|
|
void cpqarray_setup(char *str, int *ints)
|
650 |
|
|
{
|
651 |
|
|
int i;
|
652 |
|
|
if (ints[0] & 1) {
|
653 |
|
|
printk( "SMART2 Parameter Usage:\n"
|
654 |
|
|
" smart2=io,irq,io,irq,...\n");
|
655 |
|
|
return;
|
656 |
|
|
}
|
657 |
|
|
for(i=0; i<ints[0]; i++) {
|
658 |
|
|
eisa[i] = ints[i+1];
|
659 |
|
|
}
|
660 |
|
|
}
|
661 |
|
|
|
662 |
|
|
/*
|
663 |
|
|
* Find an EISA controller's signature. Set up an hba if we find it.
|
664 |
|
|
*/
|
665 |
|
|
static int cpqarray_eisa_detect(void)
|
666 |
|
|
{
|
667 |
|
|
int i=0;
|
668 |
|
|
|
669 |
|
|
while(i<16 && eisa[i]) {
|
670 |
|
|
if (inl(eisa[i]+0xC80) == 0x3040110e) {
|
671 |
|
|
if (nr_ctlr == 8) {
|
672 |
|
|
printk("This driver supports a maximum of "
|
673 |
|
|
"8 controllers.\n");
|
674 |
|
|
break;
|
675 |
|
|
}
|
676 |
|
|
hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
|
677 |
|
|
memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
|
678 |
|
|
hba[nr_ctlr]->ioaddr = eisa[i];
|
679 |
|
|
hba[nr_ctlr]->intr = eisa[i+1];
|
680 |
|
|
sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
|
681 |
|
|
hba[nr_ctlr]->ctlr = nr_ctlr;
|
682 |
|
|
nr_ctlr++;
|
683 |
|
|
} else {
|
684 |
|
|
printk("SMART2: Could not find a controller at io=0x%04x irq=0x%x\n", eisa[i], eisa[i+1]);
|
685 |
|
|
}
|
686 |
|
|
i+=2;
|
687 |
|
|
}
|
688 |
|
|
return nr_ctlr;
|
689 |
|
|
}
|
690 |
|
|
#endif /* CONFIG_BLK_CPQ_DA_EISA */
|
691 |
|
|
|
692 |
|
|
/*
|
693 |
|
|
* Open. Make sure the device is really there.
|
694 |
|
|
*/
|
695 |
|
|
static int ida_open(struct inode *inode, struct file *filep)
|
696 |
|
|
{
|
697 |
|
|
int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
|
698 |
|
|
int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
|
699 |
|
|
|
700 |
|
|
DBGINFO(printk("ida_open %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
|
701 |
|
|
if (ctlr > MAX_CTLR || hba[ctlr] == NULL)
|
702 |
|
|
return -ENXIO;
|
703 |
|
|
|
704 |
|
|
if (!suser() && ida_sizes[(ctlr << CTLR_SHIFT) +
|
705 |
|
|
MINOR(inode->i_rdev)] == 0)
|
706 |
|
|
return -ENXIO;
|
707 |
|
|
|
708 |
|
|
/*
|
709 |
|
|
* Root is allowed to open raw volume zero even if its not configured
|
710 |
|
|
* so array config can still work. I don't think I really like this,
|
711 |
|
|
* but I'm already using way to many device nodes to claim another one
|
712 |
|
|
* for "raw controller".
|
713 |
|
|
*/
|
714 |
|
|
if (suser()
|
715 |
|
|
&& ida_sizes[(ctlr << CTLR_SHIFT) + MINOR(inode->i_rdev)] == 0
|
716 |
|
|
&& MINOR(inode->i_rdev) != 0)
|
717 |
|
|
return -ENXIO;
|
718 |
|
|
|
719 |
|
|
hba[ctlr]->drv[dsk].usage_count++;
|
720 |
|
|
hba[ctlr]->usage_count++;
|
721 |
|
|
MOD_INC_USE_COUNT;
|
722 |
|
|
return 0;
|
723 |
|
|
}
|
724 |
|
|
|
725 |
|
|
/*
|
726 |
|
|
* Close. Sync first.
|
727 |
|
|
*/
|
728 |
|
|
void ida_release(struct inode *inode, struct file *filep)
|
729 |
|
|
{
|
730 |
|
|
int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
|
731 |
|
|
int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
|
732 |
|
|
|
733 |
|
|
DBGINFO(printk("ida_release %x (%x:%x)\n", inode->i_rdev, ctlr, dsk) );
|
734 |
|
|
fsync_dev(inode->i_rdev);
|
735 |
|
|
|
736 |
|
|
hba[ctlr]->drv[dsk].usage_count--;
|
737 |
|
|
hba[ctlr]->usage_count--;
|
738 |
|
|
MOD_DEC_USE_COUNT;
|
739 |
|
|
}
|
740 |
|
|
|
741 |
|
|
/*
|
742 |
|
|
* Enqueuing and dequeuing functions for cmdlists.
|
743 |
|
|
*/
|
744 |
|
|
static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c)
|
745 |
|
|
{
|
746 |
|
|
if (*Qptr == NULL) {
|
747 |
|
|
*Qptr = c;
|
748 |
|
|
c->next = c->prev = c;
|
749 |
|
|
} else {
|
750 |
|
|
c->prev = (*Qptr)->prev;
|
751 |
|
|
c->next = (*Qptr);
|
752 |
|
|
(*Qptr)->prev->next = c;
|
753 |
|
|
(*Qptr)->prev = c;
|
754 |
|
|
}
|
755 |
|
|
}
|
756 |
|
|
|
757 |
|
|
static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c)
|
758 |
|
|
{
|
759 |
|
|
if (c && c->next != c) {
|
760 |
|
|
if (*Qptr == c) *Qptr = c->next;
|
761 |
|
|
c->prev->next = c->next;
|
762 |
|
|
c->next->prev = c->prev;
|
763 |
|
|
} else {
|
764 |
|
|
*Qptr = NULL;
|
765 |
|
|
}
|
766 |
|
|
return c;
|
767 |
|
|
}
|
768 |
|
|
|
769 |
|
|
/*
|
770 |
|
|
* Get a request and submit it to the controller.
|
771 |
|
|
* This routine needs to grab all the requests it possibly can from the
|
772 |
|
|
* req Q and submit them. Interrupts are off (and need to be off) when you
|
773 |
|
|
* are in here (either via the dummy do_ida_request functions or by being
|
774 |
|
|
* called from the interrupt handler
|
775 |
|
|
*/
|
776 |
|
|
void do_ida_request(int ctlr)
|
777 |
|
|
{
|
778 |
|
|
ctlr_info_t *h = hba[ctlr];
|
779 |
|
|
cmdlist_t *c;
|
780 |
|
|
int seg;
|
781 |
|
|
char *lastdataend;
|
782 |
|
|
struct buffer_head *bh;
|
783 |
|
|
struct request *creq;
|
784 |
|
|
|
785 |
|
|
creq = blk_dev[MAJOR_NR+ctlr].current_request;
|
786 |
|
|
if (creq == NULL || creq->rq_status == RQ_INACTIVE)
|
787 |
|
|
goto doreq_done;
|
788 |
|
|
|
789 |
|
|
if (ctlr != MAJOR(creq->rq_dev)-MAJOR_NR ||
|
790 |
|
|
ctlr > nr_ctlr || h == NULL) {
|
791 |
|
|
printk("doreq cmd for %d, %x at %p\n",
|
792 |
|
|
ctlr, creq->rq_dev, creq);
|
793 |
|
|
complete_buffers(creq->bh, 0);
|
794 |
|
|
goto doreq_done;
|
795 |
|
|
}
|
796 |
|
|
|
797 |
|
|
if ((c = cmd_alloc(h)) == NULL)
|
798 |
|
|
goto doreq_done;
|
799 |
|
|
|
800 |
|
|
blk_dev[MAJOR_NR+ctlr].current_request = creq->next;
|
801 |
|
|
creq->rq_status = RQ_INACTIVE;
|
802 |
|
|
|
803 |
|
|
bh = creq->bh;
|
804 |
|
|
|
805 |
|
|
c->ctlr = ctlr;
|
806 |
|
|
c->hdr.unit = MINOR(creq->rq_dev) >> NWD_SHIFT;
|
807 |
|
|
c->hdr.size = sizeof(rblk_t) >> 2;
|
808 |
|
|
c->size += sizeof(rblk_t);
|
809 |
|
|
|
810 |
|
|
c->req.hdr.sg_cnt = creq->nr_segments;
|
811 |
|
|
c->req.hdr.blk = ida[(ctlr<<CTLR_SHIFT) + MINOR(creq->rq_dev)].start_sect + creq->sector;
|
812 |
|
|
c->req.hdr.blk_cnt = creq->nr_sectors;
|
813 |
|
|
c->bh = bh;
|
814 |
|
|
|
815 |
|
|
seg = 0; lastdataend = NULL;
|
816 |
|
|
while(bh) {
|
817 |
|
|
if (bh->b_data == lastdataend) {
|
818 |
|
|
c->req.sg[seg-1].size += bh->b_size;
|
819 |
|
|
lastdataend += bh->b_size;
|
820 |
|
|
} else {
|
821 |
|
|
c->req.sg[seg].size = bh->b_size;
|
822 |
|
|
c->req.sg[seg].addr = (__u32) virt_to_bus(bh->b_data);
|
823 |
|
|
lastdataend = bh->b_data + bh->b_size;
|
824 |
|
|
if (seg++ > SG_MAX)
|
825 |
|
|
panic("SG list overflow\n");
|
826 |
|
|
}
|
827 |
|
|
bh = bh->b_reqnext;
|
828 |
|
|
}
|
829 |
|
|
if (seg != creq->nr_segments)
|
830 |
|
|
panic("seg != nr_segments\n");
|
831 |
|
|
|
832 |
|
|
c->req.hdr.cmd = (creq->cmd == READ) ? IDA_READ : IDA_WRITE;
|
833 |
|
|
c->type = CMD_RWREQ;
|
834 |
|
|
|
835 |
|
|
/* Put the request on the tail of the request queue */
|
836 |
|
|
addQ(&h->reqQ, c);
|
837 |
|
|
h->Qdepth++;
|
838 |
|
|
if (h->Qdepth > h->maxQsinceinit) h->maxQsinceinit = h->Qdepth;
|
839 |
|
|
|
840 |
|
|
wake_up(&wait_for_request);
|
841 |
|
|
doreq_done:
|
842 |
|
|
start_io(h);
|
843 |
|
|
}
|
844 |
|
|
|
845 |
|
|
/*
|
846 |
|
|
* start_io submits everything on a controller's request queue
|
847 |
|
|
* and moves it to the completion queue.
|
848 |
|
|
*
|
849 |
|
|
* Interrupts had better be off if you're in here
|
850 |
|
|
*/
|
851 |
|
|
static void start_io(ctlr_info_t *h)
|
852 |
|
|
{
|
853 |
|
|
cmdlist_t *c;
|
854 |
|
|
|
855 |
|
|
while((c = h->reqQ) != NULL) {
|
856 |
|
|
/* Can't do anything if we're busy */
|
857 |
|
|
if (smart2_read(h, COMMAND_FIFO) == 0)
|
858 |
|
|
return;
|
859 |
|
|
|
860 |
|
|
/* Get the first entry from the request Q */
|
861 |
|
|
removeQ(&h->reqQ, c);
|
862 |
|
|
h->Qdepth--;
|
863 |
|
|
|
864 |
|
|
/* Tell the controller to do our bidding */
|
865 |
|
|
smart2_write(c->busaddr, h, COMMAND_FIFO);
|
866 |
|
|
|
867 |
|
|
/* Get onto the completion Q */
|
868 |
|
|
addQ(&h->cmpQ, c);
|
869 |
|
|
}
|
870 |
|
|
}
|
871 |
|
|
|
872 |
|
|
|
873 |
|
|
static inline void complete_buffers(struct buffer_head *bh, int ok)
|
874 |
|
|
{
|
875 |
|
|
struct buffer_head *xbh;
|
876 |
|
|
while(bh) {
|
877 |
|
|
xbh = bh->b_reqnext;
|
878 |
|
|
bh->b_reqnext = NULL;
|
879 |
|
|
mark_buffer_uptodate(bh, ok);
|
880 |
|
|
unlock_buffer(bh);
|
881 |
|
|
bh = xbh;
|
882 |
|
|
}
|
883 |
|
|
}
|
884 |
|
|
|
885 |
|
|
/*
|
886 |
|
|
* Mark all buffers that cmd was responsible for
|
887 |
|
|
*/
|
888 |
|
|
static inline void complete_command(cmdlist_t *cmd, int timeout)
|
889 |
|
|
{
|
890 |
|
|
char buf[80];
|
891 |
|
|
int ok=1;
|
892 |
|
|
|
893 |
|
|
if (cmd->req.hdr.rcode & RCODE_NONFATAL &&
|
894 |
|
|
(hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) {
|
895 |
|
|
sprintf(buf, "Non Fatal error on ida/c%dd%d\n",
|
896 |
|
|
cmd->ctlr, cmd->hdr.unit);
|
897 |
|
|
console_print(buf);
|
898 |
|
|
hba[cmd->ctlr]->misc_tflags |= MISC_NONFATAL_WARN;
|
899 |
|
|
}
|
900 |
|
|
if (cmd->req.hdr.rcode & RCODE_FATAL) {
|
901 |
|
|
sprintf(buf, "Fatal error on ida/c%dd%d\n",
|
902 |
|
|
cmd->ctlr, cmd->hdr.unit);
|
903 |
|
|
console_print(buf);
|
904 |
|
|
ok = 0;
|
905 |
|
|
}
|
906 |
|
|
if (cmd->req.hdr.rcode & RCODE_INVREQ) {
|
907 |
|
|
sprintf(buf, "Invalid request on ida/c%dd%d = (cmd=%x sect=%d cnt=%d sg=%d ret=%x)\n",
|
908 |
|
|
cmd->ctlr, cmd->hdr.unit, cmd->req.hdr.cmd,
|
909 |
|
|
cmd->req.hdr.blk, cmd->req.hdr.blk_cnt,
|
910 |
|
|
cmd->req.hdr.sg_cnt, cmd->req.hdr.rcode);
|
911 |
|
|
console_print(buf);
|
912 |
|
|
ok = 0;
|
913 |
|
|
}
|
914 |
|
|
if (timeout) {
|
915 |
|
|
sprintf(buf, "Request timeout on ida/c%dd%d\n",
|
916 |
|
|
cmd->ctlr, cmd->hdr.unit);
|
917 |
|
|
console_print(buf);
|
918 |
|
|
ok = 0;
|
919 |
|
|
}
|
920 |
|
|
complete_buffers(cmd->bh, ok);
|
921 |
|
|
}
|
922 |
|
|
|
923 |
|
|
/*
|
924 |
|
|
* The controller will interrupt us upon completion of commands.
|
925 |
|
|
* Find the command on the completion queue, remove it, tell the OS and
|
926 |
|
|
* try to queue up more IO
|
927 |
|
|
*/
|
928 |
|
|
void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs)
|
929 |
|
|
{
|
930 |
|
|
ctlr_info_t *h = dev_id;
|
931 |
|
|
cmdlist_t *c;
|
932 |
|
|
unsigned long istat;
|
933 |
|
|
__u32 a,a1;
|
934 |
|
|
|
935 |
|
|
istat = smart2_read(h, INTR_PENDING);
|
936 |
|
|
/* Is this interrupt for us? */
|
937 |
|
|
if (istat == 0)
|
938 |
|
|
return;
|
939 |
|
|
|
940 |
|
|
/*
|
941 |
|
|
* If there are completed commands in the completion queue,
|
942 |
|
|
* we had better do something about it.
|
943 |
|
|
*/
|
944 |
|
|
if (istat & FIFO_NOT_EMPTY) {
|
945 |
|
|
while((a = smart2_read(h, COMMAND_COMPLETE_FIFO))) {
|
946 |
|
|
a1 = a; a &= ~3;
|
947 |
|
|
if ((c = h->cmpQ) == NULL) goto bad_completion;
|
948 |
|
|
while(c->busaddr != a) {
|
949 |
|
|
c = c->next;
|
950 |
|
|
if (c == h->cmpQ) break;
|
951 |
|
|
}
|
952 |
|
|
/*
|
953 |
|
|
* If we've found the command, take it off the
|
954 |
|
|
* completion Q and free it
|
955 |
|
|
*/
|
956 |
|
|
if (c->busaddr == a) {
|
957 |
|
|
removeQ(&h->cmpQ, c);
|
958 |
|
|
if (c->type == CMD_RWREQ) {
|
959 |
|
|
complete_command(c, 0);
|
960 |
|
|
cmd_free(h, c);
|
961 |
|
|
} else if (c->type == CMD_IOCTL_PEND) {
|
962 |
|
|
c->type = CMD_IOCTL_DONE;
|
963 |
|
|
}
|
964 |
|
|
continue;
|
965 |
|
|
}
|
966 |
|
|
bad_completion:
|
967 |
|
|
printk("Completion of %08lx ignored\n", (unsigned long)a1);
|
968 |
|
|
}
|
969 |
|
|
}
|
970 |
|
|
|
971 |
|
|
/*
|
972 |
|
|
* See if we can queue up some more IO (Is this safe?)
|
973 |
|
|
*/
|
974 |
|
|
do_ida_request(h->ctlr);
|
975 |
|
|
}
|
976 |
|
|
|
977 |
|
|
/*
|
978 |
|
|
* This timer is for timing out requests that haven't happened after
|
979 |
|
|
* IDA_TIMEOUT, or rather it _WAS_ for timing out "dead" requests.
|
980 |
|
|
* That didn't work quite like I expected and would cause crashes
|
981 |
|
|
* and other nonsense.
|
982 |
|
|
*/
|
983 |
|
|
static void ida_timer(unsigned long tdata)
|
984 |
|
|
{
|
985 |
|
|
ctlr_info_t *h = (ctlr_info_t*)tdata;
|
986 |
|
|
|
987 |
|
|
h->timer.expires = jiffies + IDA_TIMER;
|
988 |
|
|
add_timer(&h->timer);
|
989 |
|
|
h->misc_tflags = 0;
|
990 |
|
|
}
|
991 |
|
|
|
992 |
|
|
/*
|
993 |
|
|
* ida_ioctl does some miscellaneous stuff like reporting drive geometry,
|
994 |
|
|
* setting readahead and submitting commands from userspace to the controller.
|
995 |
|
|
*/
|
996 |
|
|
int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg)
|
997 |
|
|
{
|
998 |
|
|
int ctlr = MAJOR(inode->i_rdev) - MAJOR_NR;
|
999 |
|
|
int dsk = MINOR(inode->i_rdev) >> NWD_SHIFT;
|
1000 |
|
|
int error;
|
1001 |
|
|
int diskinfo[4];
|
1002 |
|
|
struct hd_geometry *geo = (struct hd_geometry *)arg;
|
1003 |
|
|
ida_ioctl_t *io = (ida_ioctl_t*)arg;
|
1004 |
|
|
ida_ioctl_t my_io;
|
1005 |
|
|
|
1006 |
|
|
DBGINFO(printk("ida_ioctl %x %x %x\n", inode->i_rdev, cmd, arg));
|
1007 |
|
|
switch(cmd) {
|
1008 |
|
|
case HDIO_GETGEO:
|
1009 |
|
|
error = verify_area(VERIFY_WRITE, geo, sizeof(*geo));
|
1010 |
|
|
if (error) return error;
|
1011 |
|
|
if (hba[ctlr]->drv[dsk].cylinders) {
|
1012 |
|
|
diskinfo[0] = hba[ctlr]->drv[dsk].heads;
|
1013 |
|
|
diskinfo[1] = hba[ctlr]->drv[dsk].sectors;
|
1014 |
|
|
diskinfo[2] = hba[ctlr]->drv[dsk].cylinders;
|
1015 |
|
|
} else {
|
1016 |
|
|
diskinfo[0] = 0xff;
|
1017 |
|
|
diskinfo[1] = 0x3f;
|
1018 |
|
|
diskinfo[2] = hba[ctlr]->drv[dsk].nr_blks / (0xff*0x3f);
|
1019 |
|
|
}
|
1020 |
|
|
put_user(diskinfo[0], &geo->heads);
|
1021 |
|
|
put_user(diskinfo[1], &geo->sectors);
|
1022 |
|
|
put_user(diskinfo[2], &geo->cylinders);
|
1023 |
|
|
put_user(ida[(ctlr<<CTLR_SHIFT)+MINOR(inode->i_rdev)].start_sect, &geo->start);
|
1024 |
|
|
return 0;
|
1025 |
|
|
case IDAGETDRVINFO:
|
1026 |
|
|
error = verify_area(VERIFY_WRITE, io, sizeof(*io));
|
1027 |
|
|
if (error) return error;
|
1028 |
|
|
memcpy_tofs(&io->c.drv,&hba[ctlr]->drv[dsk],sizeof(drv_info_t));
|
1029 |
|
|
return 0;
|
1030 |
|
|
case BLKGETSIZE:
|
1031 |
|
|
if (!arg) return -EINVAL;
|
1032 |
|
|
error = verify_area(VERIFY_WRITE, (long*)arg, sizeof(long));
|
1033 |
|
|
if (error) return error;
|
1034 |
|
|
put_user(ida[(ctlr<<CTLR_SHIFT)+MINOR(inode->i_rdev)].nr_sects, (long*)arg);
|
1035 |
|
|
return 0;
|
1036 |
|
|
case BLKRASET:
|
1037 |
|
|
if (!suser()) return -EACCES;
|
1038 |
|
|
if (!(inode->i_rdev)) return -EINVAL;
|
1039 |
|
|
if (arg>0xff) return -EINVAL;
|
1040 |
|
|
read_ahead[MAJOR(inode->i_rdev)] = arg;
|
1041 |
|
|
return 0;
|
1042 |
|
|
case BLKRAGET:
|
1043 |
|
|
if (!arg) return -EINVAL;
|
1044 |
|
|
error=verify_area(VERIFY_WRITE, (int*)arg, sizeof(int));
|
1045 |
|
|
if (error) return error;
|
1046 |
|
|
put_user(read_ahead[MAJOR(inode->i_rdev)], (int*)arg);
|
1047 |
|
|
return 0;
|
1048 |
|
|
case BLKRRPART:
|
1049 |
|
|
return revalidate_logvol(inode->i_rdev, 1);
|
1050 |
|
|
case IDAPASSTHRU:
|
1051 |
|
|
if (!suser()) return -EPERM;
|
1052 |
|
|
error = verify_area(VERIFY_READ|VERIFY_WRITE, io, sizeof(*io));
|
1053 |
|
|
if (error) return error;
|
1054 |
|
|
memcpy_fromfs(&my_io, io, sizeof(my_io));
|
1055 |
|
|
error = ida_ctlr_ioctl(ctlr, dsk, &my_io);
|
1056 |
|
|
if (error) return error;
|
1057 |
|
|
memcpy_tofs(io, &my_io, sizeof(my_io));
|
1058 |
|
|
return 0;
|
1059 |
|
|
case IDAGETCTLRSIG:
|
1060 |
|
|
if (!arg) return -EINVAL;
|
1061 |
|
|
error=verify_area(VERIFY_WRITE, (int*)arg, sizeof(int));
|
1062 |
|
|
if (error) return error;
|
1063 |
|
|
put_user(hba[ctlr]->ctlr_sig, (int*)arg);
|
1064 |
|
|
return 0;
|
1065 |
|
|
case IDAREVALIDATEVOLS:
|
1066 |
|
|
return revalidate_allvol(inode->i_rdev);
|
1067 |
|
|
|
1068 |
|
|
RO_IOCTLS(inode->i_rdev, arg);
|
1069 |
|
|
|
1070 |
|
|
default:
|
1071 |
|
|
return -EBADRQC;
|
1072 |
|
|
}
|
1073 |
|
|
|
1074 |
|
|
}
|
1075 |
|
|
/*
|
1076 |
|
|
* ida_ctlr_ioctl is for passing commands to the controller from userspace.
|
1077 |
|
|
* The command block (io) has already been copied to kernel space for us,
|
1078 |
|
|
* however, any elements in the sglist need to be copied to kernel space
|
1079 |
|
|
* or copied back to userspace.
|
1080 |
|
|
*
|
1081 |
|
|
* Only root may perform a controller passthru command, however I'm not doing
|
1082 |
|
|
* any serious sanity checking on the arguments. Doing an IDA_WRITE_MEDIA and
|
1083 |
|
|
* putting a 64M buffer in the sglist is probably a *bad* idea.
|
1084 |
|
|
*/
|
1085 |
|
|
int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io)
|
1086 |
|
|
{
|
1087 |
|
|
ctlr_info_t *h = hba[ctlr];
|
1088 |
|
|
cmdlist_t *c;
|
1089 |
|
|
void *p = NULL;
|
1090 |
|
|
unsigned long flags;
|
1091 |
|
|
int error;
|
1092 |
|
|
|
1093 |
|
|
DBGINFO(printk("ida_ctlr_ioctl %d %x %p\n", ctlr, dsk, io));
|
1094 |
|
|
if ((c = cmd_alloc(NULL)) == NULL)
|
1095 |
|
|
return -ENOMEM;
|
1096 |
|
|
c->ctlr = ctlr;
|
1097 |
|
|
c->hdr.unit = (io->unit & UNITVALID) ? io->unit &0x7f : dsk;
|
1098 |
|
|
c->hdr.size = sizeof(rblk_t) >> 2;
|
1099 |
|
|
c->size += sizeof(rblk_t);
|
1100 |
|
|
c->req.hdr.cmd = io->cmd;
|
1101 |
|
|
c->type = CMD_IOCTL_PEND;
|
1102 |
|
|
|
1103 |
|
|
/* Pre submit processing */
|
1104 |
|
|
switch(io->cmd) {
|
1105 |
|
|
case PASSTHRU_A:
|
1106 |
|
|
error = verify_area(VERIFY_READ|VERIFY_WRITE,
|
1107 |
|
|
(void*)io->sg[0].addr, io->sg[0].size);
|
1108 |
|
|
if (error) goto ioctl_err_exit;
|
1109 |
|
|
|
1110 |
|
|
p = kmalloc(io->sg[0].size, GFP_KERNEL);
|
1111 |
|
|
if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
|
1112 |
|
|
memcpy_fromfs(p, (void*)io->sg[0].addr, io->sg[0].size);
|
1113 |
|
|
c->req.bp = virt_to_bus(&(io->c));
|
1114 |
|
|
c->req.sg[0].size = io->sg[0].size;
|
1115 |
|
|
c->req.sg[0].addr = virt_to_bus(p);
|
1116 |
|
|
c->req.hdr.sg_cnt = 1;
|
1117 |
|
|
break;
|
1118 |
|
|
case IDA_READ:
|
1119 |
|
|
error = verify_area(VERIFY_WRITE,
|
1120 |
|
|
(void*)io->sg[0].addr, io->sg[0].size);
|
1121 |
|
|
if (error) goto ioctl_err_exit;
|
1122 |
|
|
p = kmalloc(io->sg[0].size, GFP_KERNEL);
|
1123 |
|
|
if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
|
1124 |
|
|
c->req.sg[0].size = io->sg[0].size;
|
1125 |
|
|
c->req.sg[0].addr = virt_to_bus(p);
|
1126 |
|
|
c->req.hdr.sg_cnt = 1;
|
1127 |
|
|
break;
|
1128 |
|
|
case IDA_WRITE:
|
1129 |
|
|
case IDA_WRITE_MEDIA:
|
1130 |
|
|
case DIAG_PASS_THRU:
|
1131 |
|
|
error = verify_area(VERIFY_READ,
|
1132 |
|
|
(void*)io->sg[0].addr, io->sg[0].size);
|
1133 |
|
|
if (error) goto ioctl_err_exit;
|
1134 |
|
|
p = kmalloc(io->sg[0].size, GFP_KERNEL);
|
1135 |
|
|
if (!p) { error = -ENOMEM; goto ioctl_err_exit; }
|
1136 |
|
|
memcpy_fromfs(p, (void*)io->sg[0].addr, io->sg[0].size);
|
1137 |
|
|
c->req.sg[0].size = io->sg[0].size;
|
1138 |
|
|
c->req.sg[0].addr = virt_to_bus(p);
|
1139 |
|
|
c->req.hdr.sg_cnt = 1;
|
1140 |
|
|
break;
|
1141 |
|
|
default:
|
1142 |
|
|
c->req.sg[0].size = sizeof(io->c);
|
1143 |
|
|
c->req.sg[0].addr = virt_to_bus(&io->c);
|
1144 |
|
|
c->req.hdr.sg_cnt = 1;
|
1145 |
|
|
}
|
1146 |
|
|
|
1147 |
|
|
/* Put the request on the tail of the request queue */
|
1148 |
|
|
save_flags(flags);
|
1149 |
|
|
cli();
|
1150 |
|
|
addQ(&h->reqQ, c);
|
1151 |
|
|
h->Qdepth++;
|
1152 |
|
|
start_io(h);
|
1153 |
|
|
restore_flags(flags);
|
1154 |
|
|
|
1155 |
|
|
/* Wait for completion */
|
1156 |
|
|
while(c->type != CMD_IOCTL_DONE)
|
1157 |
|
|
schedule();
|
1158 |
|
|
|
1159 |
|
|
/* Post submit processing */
|
1160 |
|
|
switch(io->cmd) {
|
1161 |
|
|
case PASSTHRU_A:
|
1162 |
|
|
case IDA_READ:
|
1163 |
|
|
case DIAG_PASS_THRU:
|
1164 |
|
|
memcpy_tofs((void*)io->sg[0].addr, p, io->sg[0].size);
|
1165 |
|
|
/* fall through and free p */
|
1166 |
|
|
case IDA_WRITE:
|
1167 |
|
|
case IDA_WRITE_MEDIA:
|
1168 |
|
|
kfree(p);
|
1169 |
|
|
break;
|
1170 |
|
|
default:
|
1171 |
|
|
/* Nothing to do */
|
1172 |
|
|
}
|
1173 |
|
|
|
1174 |
|
|
io->rcode = c->req.hdr.rcode;
|
1175 |
|
|
error = 0;
|
1176 |
|
|
ioctl_err_exit:
|
1177 |
|
|
cmd_free(NULL, c);
|
1178 |
|
|
return error;
|
1179 |
|
|
}
|
1180 |
|
|
|
1181 |
|
|
/*
|
1182 |
|
|
* Commands are pre-allocated in a large block. Here we use a simple bitmap
|
1183 |
|
|
* scheme to suballocte them to the driver. Operations that are not time
|
1184 |
|
|
* critical (and can wait for kmalloc and possibly sleep) can pass in NULL
|
1185 |
|
|
* as the first argument to get a new command.
|
1186 |
|
|
*/
|
1187 |
|
|
cmdlist_t * cmd_alloc(ctlr_info_t *h)
|
1188 |
|
|
{
|
1189 |
|
|
cmdlist_t * c;
|
1190 |
|
|
int i;
|
1191 |
|
|
|
1192 |
|
|
if (h == NULL) {
|
1193 |
|
|
c = (cmdlist_t*)kmalloc(sizeof(cmdlist_t), GFP_KERNEL);
|
1194 |
|
|
} else {
|
1195 |
|
|
do {
|
1196 |
|
|
i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
|
1197 |
|
|
if (i == NR_CMDS)
|
1198 |
|
|
return NULL;
|
1199 |
|
|
} while(set_bit(i%32, h->cmd_pool_bits+(i/32)) != 0);
|
1200 |
|
|
c = h->cmd_pool + i;
|
1201 |
|
|
h->nr_allocs++;
|
1202 |
|
|
}
|
1203 |
|
|
|
1204 |
|
|
memset(c, 0, sizeof(cmdlist_t));
|
1205 |
|
|
c->busaddr = virt_to_bus(c);
|
1206 |
|
|
return c;
|
1207 |
|
|
}
|
1208 |
|
|
|
1209 |
|
|
void cmd_free(ctlr_info_t *h, cmdlist_t *c)
|
1210 |
|
|
{
|
1211 |
|
|
int i;
|
1212 |
|
|
|
1213 |
|
|
if (h == NULL) {
|
1214 |
|
|
kfree(c);
|
1215 |
|
|
} else {
|
1216 |
|
|
i = c - h->cmd_pool;
|
1217 |
|
|
clear_bit(i%32, h->cmd_pool_bits+(i/32));
|
1218 |
|
|
h->nr_frees++;
|
1219 |
|
|
}
|
1220 |
|
|
}
|
1221 |
|
|
|
1222 |
|
|
/***********************************************************************
|
1223 |
|
|
name: sendcmd
|
1224 |
|
|
Send a command to an IDA using the memory mapped FIFO interface
|
1225 |
|
|
and wait for it to complete.
|
1226 |
|
|
This routine should only be called at init time.
|
1227 |
|
|
***********************************************************************/
|
1228 |
|
|
int sendcmd(
|
1229 |
|
|
__u8 cmd,
|
1230 |
|
|
int ctlr,
|
1231 |
|
|
void *buff,
|
1232 |
|
|
size_t size,
|
1233 |
|
|
unsigned int blk,
|
1234 |
|
|
unsigned int blkcnt,
|
1235 |
|
|
unsigned int log_unit )
|
1236 |
|
|
{
|
1237 |
|
|
cmdlist_t *c;
|
1238 |
|
|
int complete;
|
1239 |
|
|
__u32 base_ptr;
|
1240 |
|
|
unsigned long temp;
|
1241 |
|
|
unsigned long i;
|
1242 |
|
|
ctlr_info_t *info_p = hba[ctlr];
|
1243 |
|
|
|
1244 |
|
|
c = cmd_alloc(info_p);
|
1245 |
|
|
c->ctlr = ctlr;
|
1246 |
|
|
c->hdr.unit = log_unit;
|
1247 |
|
|
c->hdr.prio = 0;
|
1248 |
|
|
c->hdr.size = sizeof(rblk_t) >> 2;
|
1249 |
|
|
c->size += sizeof(rblk_t);
|
1250 |
|
|
|
1251 |
|
|
/* The request information. */
|
1252 |
|
|
c->req.hdr.next = 0;
|
1253 |
|
|
c->req.hdr.rcode = 0;
|
1254 |
|
|
c->req.bp = 0;
|
1255 |
|
|
c->req.hdr.sg_cnt = 1;
|
1256 |
|
|
c->req.hdr.reserved = 0;
|
1257 |
|
|
|
1258 |
|
|
if (size == 0)
|
1259 |
|
|
c->req.sg[0].size = 512;
|
1260 |
|
|
else
|
1261 |
|
|
c->req.sg[0].size = size;
|
1262 |
|
|
|
1263 |
|
|
c->req.hdr.blk = blk;
|
1264 |
|
|
c->req.hdr.blk_cnt = blkcnt;
|
1265 |
|
|
c->req.hdr.cmd = (unsigned char) cmd;
|
1266 |
|
|
c->req.sg[0].addr = (__u32) virt_to_bus(buff);
|
1267 |
|
|
flushcomplete(ctlr);
|
1268 |
|
|
/*
|
1269 |
|
|
* Disable interrupt
|
1270 |
|
|
*/
|
1271 |
|
|
base_ptr = info_p->vaddr;
|
1272 |
|
|
smart2_write(0, info_p, INTR_MASK);
|
1273 |
|
|
/* Make sure there is room in the command FIFO */
|
1274 |
|
|
/* Actually it should be completely empty at this time. */
|
1275 |
|
|
for (i = 200000; i > 0; i--) {
|
1276 |
|
|
temp = smart2_read(info_p, COMMAND_FIFO);
|
1277 |
|
|
if (temp != 0) {
|
1278 |
|
|
break;
|
1279 |
|
|
}
|
1280 |
|
|
udelay(10);
|
1281 |
|
|
DBG(
|
1282 |
|
|
printk("ida%d: idaSendPciCmd FIFO full, waiting!\n",
|
1283 |
|
|
ctlr);
|
1284 |
|
|
);
|
1285 |
|
|
}
|
1286 |
|
|
/*
|
1287 |
|
|
* Send the cmd
|
1288 |
|
|
*/
|
1289 |
|
|
smart2_write(c->busaddr, info_p, COMMAND_FIFO);
|
1290 |
|
|
complete = pollcomplete(ctlr);
|
1291 |
|
|
if (complete != 1) {
|
1292 |
|
|
if (complete != c->busaddr) {
|
1293 |
|
|
printk(
|
1294 |
|
|
"ida%d: idaSendPciCmd "
|
1295 |
|
|
"Invalid command list address returned! (%08lx)\n",
|
1296 |
|
|
ctlr, (unsigned long)complete);
|
1297 |
|
|
cmd_free(info_p, c);
|
1298 |
|
|
return (IO_ERROR);
|
1299 |
|
|
}
|
1300 |
|
|
} else {
|
1301 |
|
|
printk(
|
1302 |
|
|
"ida%d: idaSendPciCmd Timeout out, "
|
1303 |
|
|
"No command list address returned!\n",
|
1304 |
|
|
ctlr);
|
1305 |
|
|
cmd_free(info_p, c);
|
1306 |
|
|
return (IO_ERROR);
|
1307 |
|
|
}
|
1308 |
|
|
|
1309 |
|
|
if (c->req.hdr.rcode & 0x00FE) {
|
1310 |
|
|
if (!(c->req.hdr.rcode & BIG_PROBLEM)) {
|
1311 |
|
|
printk(
|
1312 |
|
|
"ida%d: idaSendPciCmd, error: Controller failed "
|
1313 |
|
|
"at init time "
|
1314 |
|
|
"cmd: 0x%x, return code = 0x%x\n",
|
1315 |
|
|
ctlr, c->req.hdr.cmd, c->req.hdr.rcode);
|
1316 |
|
|
|
1317 |
|
|
cmd_free(info_p, c);
|
1318 |
|
|
return (IO_ERROR);
|
1319 |
|
|
}
|
1320 |
|
|
}
|
1321 |
|
|
cmd_free(info_p, c);
|
1322 |
|
|
return (IO_OK);
|
1323 |
|
|
}
|
1324 |
|
|
|
1325 |
|
|
int frevalidate_logvol(kdev_t dev)
|
1326 |
|
|
{
|
1327 |
|
|
return revalidate_logvol(dev, 0);
|
1328 |
|
|
}
|
1329 |
|
|
|
1330 |
|
|
/*
|
1331 |
|
|
* revalidate_allvol is for online array config utilities. After a
|
1332 |
|
|
* utility reconfigures the drives in the array, it can use this function
|
1333 |
|
|
* (through an ioctl) to make the driver zap any previous disk structs for
|
1334 |
|
|
* that controller and get new ones.
|
1335 |
|
|
*
|
1336 |
|
|
* Right now I'm using the getgeometry() function to do this, but this
|
1337 |
|
|
* function should probably be finer grained and allow you to revalidate one
|
1338 |
|
|
* particualar logical volume (instead of all of them on a particular
|
1339 |
|
|
* controller).
|
1340 |
|
|
*/
|
1341 |
|
|
static int revalidate_allvol(kdev_t dev)
|
1342 |
|
|
{
|
1343 |
|
|
int ctlr, i;
|
1344 |
|
|
unsigned long flags;
|
1345 |
|
|
|
1346 |
|
|
ctlr = MAJOR(dev) - MAJOR_NR;
|
1347 |
|
|
if (MINOR(dev) != 0)
|
1348 |
|
|
return -ENXIO;
|
1349 |
|
|
|
1350 |
|
|
save_flags(flags);
|
1351 |
|
|
cli();
|
1352 |
|
|
if (hba[ctlr]->usage_count > 1) {
|
1353 |
|
|
restore_flags(flags);
|
1354 |
|
|
printk("Device busy for volume revalidation (usage=%d)\n",
|
1355 |
|
|
hba[ctlr]->usage_count);
|
1356 |
|
|
return -EBUSY;
|
1357 |
|
|
}
|
1358 |
|
|
|
1359 |
|
|
hba[ctlr]->usage_count++;
|
1360 |
|
|
restore_flags(flags);
|
1361 |
|
|
|
1362 |
|
|
/*
|
1363 |
|
|
* Set the partition and block size structures for all volumes
|
1364 |
|
|
* on this controller to zero. We will reread all of this data
|
1365 |
|
|
*/
|
1366 |
|
|
memset(ida+(ctlr*256), 0, sizeof(struct hd_struct)*NWD*16);
|
1367 |
|
|
memset(ida_sizes+(ctlr*256), 0, sizeof(int)*NWD*16);
|
1368 |
|
|
memset(ida_blocksizes+(ctlr*256), 0, sizeof(int)*NWD*16);
|
1369 |
|
|
memset(ida_hardsizes+(ctlr*256), 0, sizeof(int)*NWD*16);
|
1370 |
|
|
ida_gendisk[ctlr].nr_real = 0;
|
1371 |
|
|
|
1372 |
|
|
/*
|
1373 |
|
|
* Tell the array controller not to give us any interupts while
|
1374 |
|
|
* we check the new geometry. Then turn interrupts back on when
|
1375 |
|
|
* we're done.
|
1376 |
|
|
*/
|
1377 |
|
|
smart2_write(0, hba[ctlr], INTR_MASK);
|
1378 |
|
|
getgeometry(ctlr);
|
1379 |
|
|
smart2_write(FIFO_NOT_EMPTY, hba[ctlr], INTR_MASK);
|
1380 |
|
|
|
1381 |
|
|
ida_geninit(&ida_gendisk[ctlr]);
|
1382 |
|
|
for(i=0; i<NWD; i++)
|
1383 |
|
|
if (ida_sizes[(ctlr<<CTLR_SHIFT) + (i<<NWD_SHIFT)])
|
1384 |
|
|
revalidate_logvol(dev+(i<<NWD_SHIFT), 2);
|
1385 |
|
|
|
1386 |
|
|
hba[ctlr]->usage_count--;
|
1387 |
|
|
return 0;
|
1388 |
|
|
}
|
1389 |
|
|
|
1390 |
|
|
/* Borrowed and adapted from sd.c */
|
1391 |
|
|
int revalidate_logvol(kdev_t dev, int maxusage)
|
1392 |
|
|
{
|
1393 |
|
|
int ctlr, target;
|
1394 |
|
|
struct gendisk *gdev;
|
1395 |
|
|
unsigned long flags;
|
1396 |
|
|
int max_p;
|
1397 |
|
|
int start;
|
1398 |
|
|
int i;
|
1399 |
|
|
|
1400 |
|
|
target = DEVICE_NR(dev);
|
1401 |
|
|
ctlr = MAJOR(dev) - MAJOR_NR;
|
1402 |
|
|
gdev = &ida_gendisk[ctlr];
|
1403 |
|
|
|
1404 |
|
|
save_flags(flags);
|
1405 |
|
|
cli();
|
1406 |
|
|
if (hba[ctlr]->drv[target].usage_count > maxusage) {
|
1407 |
|
|
restore_flags(flags);
|
1408 |
|
|
printk("Device busy for revalidation (usage=%d)\n",
|
1409 |
|
|
hba[ctlr]->drv[target].usage_count);
|
1410 |
|
|
return -EBUSY;
|
1411 |
|
|
}
|
1412 |
|
|
|
1413 |
|
|
hba[ctlr]->drv[target].usage_count++;
|
1414 |
|
|
restore_flags(flags);
|
1415 |
|
|
|
1416 |
|
|
max_p = gdev->max_p;
|
1417 |
|
|
start = target << gdev->minor_shift;
|
1418 |
|
|
|
1419 |
|
|
for(i=max_p; i>=0; i--) {
|
1420 |
|
|
int minor = start+i;
|
1421 |
|
|
kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor);
|
1422 |
|
|
sync_dev(devi);
|
1423 |
|
|
invalidate_inodes(devi);
|
1424 |
|
|
invalidate_buffers(devi);
|
1425 |
|
|
gdev->part[minor].start_sect = 0;
|
1426 |
|
|
gdev->part[minor].nr_sects = 0;
|
1427 |
|
|
|
1428 |
|
|
/* reset the blocksize so we can read the partition table */
|
1429 |
|
|
blksize_size[MAJOR_NR+ctlr][minor] = 1024;
|
1430 |
|
|
}
|
1431 |
|
|
|
1432 |
|
|
gdev->part[start].nr_sects = hba[ctlr]->drv[target].nr_blks;
|
1433 |
|
|
resetup_one_dev(gdev, target);
|
1434 |
|
|
hba[ctlr]->drv[target].usage_count--;
|
1435 |
|
|
return 0;
|
1436 |
|
|
}
|
1437 |
|
|
|
1438 |
|
|
|
1439 |
|
|
/********************************************************************
|
1440 |
|
|
name: pollcomplete
|
1441 |
|
|
Wait polling for a command to complete.
|
1442 |
|
|
The memory mapped FIFO is polled for the completion.
|
1443 |
|
|
Used only at init time, interrupts disabled.
|
1444 |
|
|
********************************************************************/
|
1445 |
|
|
int pollcomplete(int ctlr)
|
1446 |
|
|
{
|
1447 |
|
|
int done;
|
1448 |
|
|
int i;
|
1449 |
|
|
|
1450 |
|
|
/* Wait (up to 2 seconds) for a command to complete */
|
1451 |
|
|
|
1452 |
|
|
for (i = 200000; i > 0; i--) {
|
1453 |
|
|
done = smart2_read(hba[ctlr], COMMAND_COMPLETE_FIFO);
|
1454 |
|
|
if (done == 0) {
|
1455 |
|
|
udelay(10); /* a short fixed delay */
|
1456 |
|
|
} else
|
1457 |
|
|
return (done);
|
1458 |
|
|
}
|
1459 |
|
|
/* Invalid address to tell caller we ran out of time */
|
1460 |
|
|
return 1;
|
1461 |
|
|
}
|
1462 |
|
|
|
1463 |
|
|
/*
|
1464 |
|
|
* Clear the complete FIFO
|
1465 |
|
|
|
1466 |
|
|
Polling routine.
|
1467 |
|
|
This should only be used at init time.
|
1468 |
|
|
Any commands unexpectedly found in the completed command fifo
|
1469 |
|
|
will be discarded. There should be none.
|
1470 |
|
|
Called in only one place.
|
1471 |
|
|
Note this reads and discards any completed commands but does not
|
1472 |
|
|
wait for any uncompleted commands.
|
1473 |
|
|
This is kinda goofy.
|
1474 |
|
|
|
1475 |
|
|
*/
|
1476 |
|
|
void flushcomplete(int ctlr)
|
1477 |
|
|
{
|
1478 |
|
|
unsigned long ret_addr;
|
1479 |
|
|
unsigned int i;
|
1480 |
|
|
|
1481 |
|
|
for (i = 200000; i > 0; i--) {
|
1482 |
|
|
ret_addr = smart2_read(hba[ctlr], COMMAND_COMPLETE_FIFO);
|
1483 |
|
|
if (ret_addr == 0) {
|
1484 |
|
|
break;
|
1485 |
|
|
}
|
1486 |
|
|
udelay(10);
|
1487 |
|
|
DBG(
|
1488 |
|
|
printk("ida%d: flushcomplete "
|
1489 |
|
|
"Discarding completion %x!\n",
|
1490 |
|
|
ctlr, (unsigned int)ret_addr);
|
1491 |
|
|
);
|
1492 |
|
|
}
|
1493 |
|
|
}
|
1494 |
|
|
|
1495 |
|
|
|
1496 |
|
|
|
1497 |
|
|
/*****************************************************************
|
1498 |
|
|
idaGetGeometry
|
1499 |
|
|
Get ida logical volume geometry from the controller
|
1500 |
|
|
This is a large bit of code which once existed in two flavors,
|
1501 |
|
|
for EISA and PCI. It is used only at init time.
|
1502 |
|
|
****************************************************************
|
1503 |
|
|
*/
|
1504 |
|
|
void getgeometry(int ctlr)
|
1505 |
|
|
{
|
1506 |
|
|
id_log_drv_t *id_ldrive;
|
1507 |
|
|
id_ctlr_t *id_ctlr_buf;
|
1508 |
|
|
sense_log_drv_stat_t *id_lstatus_buf;
|
1509 |
|
|
config_t *sense_config_buf;
|
1510 |
|
|
unsigned int log_unit, log_index;
|
1511 |
|
|
int ret_code, size;
|
1512 |
|
|
drv_info_t *drv;
|
1513 |
|
|
ctlr_info_t *info_p = hba[ctlr];
|
1514 |
|
|
|
1515 |
|
|
id_ldrive = (id_log_drv_t *)kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
|
1516 |
|
|
id_ctlr_buf = (id_ctlr_t *)kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
|
1517 |
|
|
id_lstatus_buf = (sense_log_drv_stat_t *)kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
|
1518 |
|
|
sense_config_buf = (config_t *)kmalloc(sizeof(config_t), GFP_KERNEL);
|
1519 |
|
|
|
1520 |
|
|
memset(id_ldrive, 0, sizeof(id_log_drv_t));
|
1521 |
|
|
memset(id_ctlr_buf, 0, sizeof(id_ctlr_t));
|
1522 |
|
|
memset(id_lstatus_buf, 0, sizeof(sense_log_drv_stat_t));
|
1523 |
|
|
memset(sense_config_buf, 0, sizeof(config_t));
|
1524 |
|
|
|
1525 |
|
|
info_p->phys_drives = 0;
|
1526 |
|
|
info_p->log_drv_map = 0;
|
1527 |
|
|
info_p->drv_assign_map = 0;
|
1528 |
|
|
info_p->drv_spare_map = 0;
|
1529 |
|
|
info_p->mp_failed_drv_map = 0; /* only initialized here */
|
1530 |
|
|
/* Get controllers info for this logical drive */
|
1531 |
|
|
ret_code = sendcmd(ID_CTLR, ctlr, id_ctlr_buf, 0, 0, 0, 0);
|
1532 |
|
|
if (ret_code == IO_ERROR) {
|
1533 |
|
|
/*
|
1534 |
|
|
* If can't get controller info, set the logical drive map to 0,
|
1535 |
|
|
* so the idastubopen will fail on all logical drives
|
1536 |
|
|
* on the controller.
|
1537 |
|
|
*/
|
1538 |
|
|
goto geo_ret; /* release the buf and return */
|
1539 |
|
|
}
|
1540 |
|
|
info_p->log_drives = id_ctlr_buf->nr_drvs;;
|
1541 |
|
|
*(__u32*)(info_p->firm_rev) = *(__u32*)(id_ctlr_buf->firm_rev);
|
1542 |
|
|
info_p->ctlr_sig = id_ctlr_buf->cfg_sig;
|
1543 |
|
|
info_p->board_id = id_ctlr_buf->board_id;
|
1544 |
|
|
|
1545 |
|
|
switch(info_p->board_id) {
|
1546 |
|
|
case 0x0E114030: /* SMART-2/E */
|
1547 |
|
|
info_p->product = 1;
|
1548 |
|
|
break;
|
1549 |
|
|
case 0x40300E11: /* SMART-2/P or SMART-2DH */
|
1550 |
|
|
info_p->product = 2;
|
1551 |
|
|
break;
|
1552 |
|
|
case 0x40310E11: /* SMART-2SL */
|
1553 |
|
|
info_p->product = 3;
|
1554 |
|
|
break;
|
1555 |
|
|
case 0x40320E11: /* SMART-3200 */
|
1556 |
|
|
info_p->product = 4;
|
1557 |
|
|
break;
|
1558 |
|
|
case 0x40330E11: /* SMART-3100ES */
|
1559 |
|
|
info_p->product = 5;
|
1560 |
|
|
break;
|
1561 |
|
|
case 0x40340E11: /* SMART-221 */
|
1562 |
|
|
info_p->product = 6;
|
1563 |
|
|
break;
|
1564 |
|
|
default:
|
1565 |
|
|
/*
|
1566 |
|
|
* Well, its a SMART-2 or better, don't know which
|
1567 |
|
|
* kind.
|
1568 |
|
|
*/
|
1569 |
|
|
info_p->product = 0;
|
1570 |
|
|
}
|
1571 |
|
|
printk(" (%s)\n", product_names[info_p->product]);
|
1572 |
|
|
/*
|
1573 |
|
|
* Initialize logical drive map to zero
|
1574 |
|
|
*/
|
1575 |
|
|
#ifdef REDUNDANT
|
1576 |
|
|
info_p->log_drive_map = 0;
|
1577 |
|
|
#endif /* #ifdef REDUNDANT */
|
1578 |
|
|
log_index = 0;
|
1579 |
|
|
/*
|
1580 |
|
|
* Get drive geometry for all logical drives
|
1581 |
|
|
*/
|
1582 |
|
|
if (id_ctlr_buf->nr_drvs > 16)
|
1583 |
|
|
printk("ida%d: This driver supports 16 logical drives "
|
1584 |
|
|
"per controller. Additional drives will not be "
|
1585 |
|
|
"detected.\n", ctlr);
|
1586 |
|
|
|
1587 |
|
|
for (log_unit = 0;
|
1588 |
|
|
(log_index < id_ctlr_buf->nr_drvs)
|
1589 |
|
|
&& (log_unit < NWD);
|
1590 |
|
|
log_unit++) {
|
1591 |
|
|
|
1592 |
|
|
size = sizeof(sense_log_drv_stat_t);
|
1593 |
|
|
|
1594 |
|
|
/*
|
1595 |
|
|
Send "Identify logical drive status" cmd
|
1596 |
|
|
*/
|
1597 |
|
|
ret_code = sendcmd(SENSE_LOG_DRV_STAT,
|
1598 |
|
|
ctlr, id_lstatus_buf, size, 0, 0, log_unit);
|
1599 |
|
|
if (ret_code == IO_ERROR) {
|
1600 |
|
|
/*
|
1601 |
|
|
If can't get logical drive status, set
|
1602 |
|
|
the logical drive map to 0, so the
|
1603 |
|
|
idastubopen will fail for all logical drives
|
1604 |
|
|
on the controller.
|
1605 |
|
|
*/
|
1606 |
|
|
info_p->log_drv_map = 0;
|
1607 |
|
|
printk(
|
1608 |
|
|
"ida%d: idaGetGeometry - Controller failed "
|
1609 |
|
|
"to report status of logical drive %d\n"
|
1610 |
|
|
"Access to this controller has been disabled\n",
|
1611 |
|
|
ctlr, log_unit);
|
1612 |
|
|
goto geo_ret; /* release the buf and return */
|
1613 |
|
|
|
1614 |
|
|
}
|
1615 |
|
|
/*
|
1616 |
|
|
Make sure the logical drive is configured
|
1617 |
|
|
*/
|
1618 |
|
|
if (id_lstatus_buf->status != LOG_NOT_CONF) {
|
1619 |
|
|
ret_code = sendcmd(ID_LOG_DRV, ctlr, id_ldrive,
|
1620 |
|
|
sizeof(id_log_drv_t), 0, 0, log_unit);
|
1621 |
|
|
/*
|
1622 |
|
|
If error, the bit for this
|
1623 |
|
|
logical drive won't be set and
|
1624 |
|
|
idastubopen will return error.
|
1625 |
|
|
*/
|
1626 |
|
|
if (ret_code != IO_ERROR) {
|
1627 |
|
|
drv = &info_p->drv[log_unit];
|
1628 |
|
|
drv->blk_size = id_ldrive->blk_size;
|
1629 |
|
|
drv->nr_blks = id_ldrive->nr_blks;
|
1630 |
|
|
drv->cylinders = id_ldrive->drv.cyl;
|
1631 |
|
|
drv->heads = id_ldrive->drv.heads;
|
1632 |
|
|
drv->sectors = id_ldrive->drv.sect_per_track;
|
1633 |
|
|
info_p->log_drv_map |= (1 << log_unit);
|
1634 |
|
|
|
1635 |
|
|
printk("ida/c%dd%d: blksz=%d nr_blks=%d\n",
|
1636 |
|
|
ctlr, log_unit, drv->blk_size,
|
1637 |
|
|
drv->nr_blks);
|
1638 |
|
|
ret_code = sendcmd(SENSE_CONFIG,
|
1639 |
|
|
ctlr, sense_config_buf,
|
1640 |
|
|
sizeof(config_t), 0, 0, log_unit);
|
1641 |
|
|
if (ret_code == IO_ERROR) {
|
1642 |
|
|
info_p->log_drv_map = 0;
|
1643 |
|
|
goto geo_ret; /* release the buf and return */
|
1644 |
|
|
}
|
1645 |
|
|
info_p->phys_drives =
|
1646 |
|
|
sense_config_buf->ctlr_phys_drv;
|
1647 |
|
|
info_p->drv_assign_map
|
1648 |
|
|
|= sense_config_buf->drv_asgn_map;
|
1649 |
|
|
info_p->drv_assign_map
|
1650 |
|
|
|= sense_config_buf->spare_asgn_map;
|
1651 |
|
|
info_p->drv_spare_map
|
1652 |
|
|
|= sense_config_buf->spare_asgn_map;
|
1653 |
|
|
} /* end of if no error on id_ldrive */
|
1654 |
|
|
log_index = log_index + 1;
|
1655 |
|
|
} /* end of if logical drive configured */
|
1656 |
|
|
} /* end of for log_unit */
|
1657 |
|
|
geo_ret:
|
1658 |
|
|
kfree(id_ctlr_buf);
|
1659 |
|
|
kfree(id_ldrive);
|
1660 |
|
|
kfree(id_lstatus_buf);
|
1661 |
|
|
kfree(sense_config_buf);
|
1662 |
|
|
}
|