File: | obj-scan-build/../linux/src/drivers/scsi/aha1740.c |
Location: | line 200, column 5 |
Description: | Value stored to 'tmp' is never read |
1 | /* $Id: aha1740.c,v 1.1 1999/04/26 05:54:13 tb Exp $ |
2 | * 1993/03/31 |
3 | * linux/kernel/aha1740.c |
4 | * |
5 | * Based loosely on aha1542.c which is |
6 | * Copyright (C) 1992 Tommy Thorn and |
7 | * Modified by Eric Youngdale |
8 | * |
9 | * This file is aha1740.c, written and |
10 | * Copyright (C) 1992,1993 Brad McLean |
11 | * |
12 | * Modifications to makecode and queuecommand |
13 | * for proper handling of multiple devices courteously |
14 | * provided by Michael Weller, March, 1993 |
15 | * |
16 | * Multiple adapter support, extended translation detection, |
17 | * update to current scsi subsystem changes, proc fs support, |
18 | * working (!) module support based on patches from Andreas Arens, |
19 | * by Andreas Degert <ad@papyrus.hamburg.com>, 2/1997 |
20 | * |
21 | * aha1740_makecode may still need even more work |
22 | * if it doesn't work for your devices, take a look. |
23 | */ |
24 | |
25 | #ifdef MODULE |
26 | #include <linux/module.h> |
27 | #endif |
28 | |
29 | #include <linux/kernel.h> |
30 | #include <linux/head.h> |
31 | #include <linux/types.h> |
32 | #include <linux/string.h> |
33 | #include <linux/ioport.h> |
34 | #include <linux/proc_fs.h> |
35 | #include <linux/sched.h> |
36 | #include <asm/dma.h> |
37 | |
38 | #include <asm/system.h> |
39 | #include <asm/io.h> |
40 | #include <linux/blk.h> |
41 | #include "scsi.h" |
42 | #include "hosts.h" |
43 | #include "sd.h" |
44 | |
45 | #include "aha1740.h" |
46 | #include<linux/stat.h> |
47 | |
48 | struct proc_dir_entry proc_scsi_aha1740 = { |
49 | PROC_SCSI_AHA1740, 7, "aha1740", |
50 | S_IFDIR0040000 | S_IRUGO(00400|00040|00004) | S_IXUGO(00100|00010|00001), 2 |
51 | }; |
52 | |
53 | /* IF YOU ARE HAVING PROBLEMS WITH THIS DRIVER, AND WANT TO WATCH |
54 | IT WORK, THEN: |
55 | #define DEBUG |
56 | */ |
57 | #ifdef DEBUG |
58 | #define DEB(x) x |
59 | #else |
60 | #define DEB(x) |
61 | #endif |
62 | |
63 | /* |
64 | static const char RCSid[] = "$Header: cvs/gnumach/linux/src/drivers/scsi/Attic/aha1740.c,v 1.1 1999/04/26 05:54:13 tb Exp $"; |
65 | */ |
66 | |
67 | struct aha1740_hostdata { |
68 | unsigned int slot; |
69 | unsigned int translation; |
70 | unsigned int last_ecb_used; |
71 | struct ecb ecb[AHA1740_ECBS32]; |
72 | }; |
73 | |
74 | #define HOSTDATA(host)((struct aha1740_hostdata *) &host->hostdata) ((struct aha1740_hostdata *) &host->hostdata) |
75 | |
76 | /* One for each IRQ level (9-15) */ |
77 | static struct Scsi_Host * aha_host[8] = {NULL((void *) 0), }; |
78 | |
79 | int aha1740_proc_info(char *buffer, char **start, off_t offset, |
80 | int length, int hostno, int inout) |
81 | { |
82 | int len; |
83 | struct Scsi_Host * shpnt; |
84 | struct aha1740_hostdata *host; |
85 | |
86 | if (inout) |
87 | return(-ENOSYS38); |
88 | |
89 | for (len = 0; len < 8; len++) { |
90 | shpnt = aha_host[len]; |
91 | if (shpnt && shpnt->host_no == hostno) |
92 | break; |
93 | } |
94 | host = HOSTDATA(shpnt)((struct aha1740_hostdata *) &shpnt->hostdata); |
95 | |
96 | len = sprintflinux_sprintf(buffer, "aha174x at IO:%x, IRQ %d, SLOT %d.\n" |
97 | "Extended translation %sabled.\n", |
98 | shpnt->io_port, shpnt->irq, host->slot, |
99 | host->translation ? "en" : "dis"); |
100 | |
101 | if (offset > len) { |
102 | *start = buffer; |
103 | return 0; |
104 | } |
105 | |
106 | *start = buffer + offset; |
107 | len -= offset; |
108 | if (len > length) |
109 | len = length; |
110 | return len; |
111 | } |
112 | |
113 | |
114 | int aha1740_makecode(unchar *sense, unchar *status) |
115 | { |
116 | struct statusword |
117 | { |
118 | ushort don:1, /* Command Done - No Error */ |
119 | du:1, /* Data underrun */ |
120 | :1, qf:1, /* Queue full */ |
121 | sc:1, /* Specification Check */ |
122 | dor:1, /* Data overrun */ |
123 | ch:1, /* Chaining Halted */ |
124 | intr:1, /* Interrupt issued */ |
125 | asa:1, /* Additional Status Available */ |
126 | sns:1, /* Sense information Stored */ |
127 | :1, ini:1, /* Initialization Required */ |
128 | me:1, /* Major error or exception */ |
129 | :1, eca:1, /* Extended Contingent alliance */ |
130 | :1; |
131 | } status_word; |
132 | int retval = DID_OK0x00; |
133 | |
134 | status_word = * (struct statusword *) status; |
135 | #ifdef DEBUG |
136 | printk("makecode from %x,%x,%x,%x %x,%x,%x,%x", |
137 | status[0], status[1], status[2], status[3], |
138 | sense[0], sense[1], sense[2], sense[3]); |
139 | #endif |
140 | if (!status_word.don) /* Anything abnormal was detected */ |
141 | { |
142 | if ( (status[1]&0x18) || status_word.sc ) /*Additional info available*/ |
143 | { |
144 | /* Use the supplied info for further diagnostics */ |
145 | switch ( status[2] ) |
146 | { |
147 | case 0x12: |
148 | if ( status_word.dor ) |
149 | retval=DID_ERROR0x07; /* It's an Overrun */ |
150 | /* If not overrun, assume underrun and ignore it! */ |
151 | case 0x00: /* No info, assume no error, should not occur */ |
152 | break; |
153 | case 0x11: |
154 | case 0x21: |
155 | retval=DID_TIME_OUT0x03; |
156 | break; |
157 | case 0x0a: |
158 | retval=DID_BAD_TARGET0x04; |
159 | break; |
160 | case 0x04: |
161 | case 0x05: |
162 | retval=DID_ABORT0x05; |
163 | /* Either by this driver or the AHA1740 itself */ |
164 | break; |
165 | default: |
166 | retval=DID_ERROR0x07; /* No further diagnostics possible */ |
167 | } |
168 | } |
169 | else |
170 | { /* Michael suggests, and Brad concurs: */ |
171 | if ( status_word.qf ) |
172 | { |
173 | retval = DID_TIME_OUT0x03; /* forces a redo */ |
174 | /* I think this specific one should not happen -Brad */ |
175 | printk("aha1740.c: WARNING: AHA1740 queue overflow!\n"); |
176 | } |
177 | else if ( status[0]&0x60 ) |
178 | { |
179 | retval = DID_ERROR0x07; /* Didn't find a better error */ |
180 | } |
181 | /* In any other case return DID_OK so for example |
182 | CONDITION_CHECKS make it through to the appropriate |
183 | device driver */ |
184 | } |
185 | } |
186 | /* Under all circumstances supply the target status -Michael */ |
187 | return status[3] | retval << 16; |
188 | } |
189 | |
190 | int aha1740_test_port(unsigned int base) |
191 | { |
192 | char name[4], tmp; |
193 | |
194 | /* Okay, look for the EISA ID's */ |
195 | name[0]= 'A' -1 + ((tmp = inb(HID0(base))((__builtin_constant_p(((base + 0x0))) && ((base + 0x0 )) < 256) ? __inbc((base + 0x0)) : __inb((base + 0x0)))) >> 2); /* First character */ |
196 | name[1]= 'A' -1 + ((tmp & 3) << 3); |
197 | name[1]+= ((tmp = inb(HID1(base))((__builtin_constant_p(((base + 0x1))) && ((base + 0x1 )) < 256) ? __inbc((base + 0x1)) : __inb((base + 0x1)))) >> 5)&0x7; /* Second Character */ |
198 | name[2]= 'A' -1 + (tmp & 0x1f); /* Third Character */ |
199 | name[3]=0; |
200 | tmp = inb(HID2(base))((__builtin_constant_p(((base + 0x2))) && ((base + 0x2 )) < 256) ? __inbc((base + 0x2)) : __inb((base + 0x2))); |
Value stored to 'tmp' is never read | |
201 | if ( strcmp ( name, HID_MFG"ADP" ) || inb(HID2(base))((__builtin_constant_p(((base + 0x2))) && ((base + 0x2 )) < 256) ? __inbc((base + 0x2)) : __inb((base + 0x2))) != HID_PRD0 ) |
202 | return 0; /* Not an Adaptec 174x */ |
203 | |
204 | /* if ( inb(HID3(base)) != HID_REV ) |
205 | printk("aha174x: Warning; board revision of %d; expected %d\n", |
206 | inb(HID3(base)),HID_REV); */ |
207 | |
208 | if ( inb(EBCNTRL(base))((__builtin_constant_p(((base + 0x4))) && ((base + 0x4 )) < 256) ? __inbc((base + 0x4)) : __inb((base + 0x4))) != EBCNTRL_VALUE1 ) |
209 | { |
210 | printk("aha174x: Board detected, but EBCNTRL = %x, so disabled it.\n", |
211 | inb(EBCNTRL(base))((__builtin_constant_p(((base + 0x4))) && ((base + 0x4 )) < 256) ? __inbc((base + 0x4)) : __inb((base + 0x4)))); |
212 | return 0; |
213 | } |
214 | |
215 | if ( inb(PORTADR(base))((__builtin_constant_p(((base + 0x40))) && ((base + 0x40 )) < 256) ? __inbc((base + 0x40)) : __inb((base + 0x40))) & PORTADDR_ENH0x80 ) |
216 | return 1; /* Okay, we're all set */ |
217 | |
218 | printk("aha174x: Board detected, but not in enhanced mode, so disabled it.\n"); |
219 | return 0; |
220 | } |
221 | |
222 | /* A "high" level interrupt handler */ |
223 | void aha1740_intr_handle(int irq, void *dev_id, struct pt_regs * regs) |
224 | { |
225 | void (*my_done)(Scsi_Cmnd *); |
226 | int errstatus, adapstat; |
227 | int number_serviced; |
228 | struct ecb *ecbptr; |
229 | Scsi_Cmnd *SCtmp; |
230 | unsigned int base; |
231 | |
232 | if (!aha_host[irq - 9]) |
233 | panic("aha1740.c: Irq from unknown host!\n"); |
234 | base = aha_host[irq - 9]->io_port; |
235 | number_serviced = 0; |
236 | |
237 | while(inb(G2STAT(base))((__builtin_constant_p(((base + 0x57))) && ((base + 0x57 )) < 256) ? __inbc((base + 0x57)) : __inb((base + 0x57))) & G2STAT_INTPEND2) |
238 | { |
239 | DEB(printk("aha1740_intr top of loop.\n")); |
240 | adapstat = inb(G2INTST(base))((__builtin_constant_p(((base + 0x56))) && ((base + 0x56 )) < 256) ? __inbc((base + 0x56)) : __inb((base + 0x56))); |
241 | ecbptr = (struct ecb *) bus_to_virtphys_to_virt(inl(MBOXIN0(base))((__builtin_constant_p(((base + 0x58))) && ((base + 0x58 )) < 256) ? __inlc((base + 0x58)) : __inl((base + 0x58)))); |
242 | outb(G2CNTRL_IRST,G2CNTRL(base))((__builtin_constant_p(((base + 0x55))) && ((base + 0x55 )) < 256) ? __outbc((0x40),((base + 0x55))) : __outb((0x40 ),((base + 0x55)))); /* interrupt reset */ |
243 | |
244 | switch ( adapstat & G2INTST_MASK0xf0 ) |
245 | { |
246 | case G2INTST_CCBRETRY0x50: |
247 | case G2INTST_CCBERROR0xc0: |
248 | case G2INTST_CCBGOOD0x10: |
249 | /* Host Ready -> Mailbox in complete */ |
250 | outb(G2CNTRL_HRDY,G2CNTRL(base))((__builtin_constant_p(((base + 0x55))) && ((base + 0x55 )) < 256) ? __outbc((0x20),((base + 0x55))) : __outb((0x20 ),((base + 0x55)))); |
251 | if (!ecbptr) |
252 | { |
253 | printk("Aha1740 null ecbptr in interrupt (%x,%x,%x,%d)\n", |
254 | inb(G2STAT(base))((__builtin_constant_p(((base + 0x57))) && ((base + 0x57 )) < 256) ? __inbc((base + 0x57)) : __inb((base + 0x57))),adapstat, |
255 | inb(G2INTST(base))((__builtin_constant_p(((base + 0x56))) && ((base + 0x56 )) < 256) ? __inbc((base + 0x56)) : __inb((base + 0x56))), number_serviced++); |
256 | continue; |
257 | } |
258 | SCtmp = ecbptr->SCpnt; |
259 | if (!SCtmp) |
260 | { |
261 | printk("Aha1740 null SCtmp in interrupt (%x,%x,%x,%d)\n", |
262 | inb(G2STAT(base))((__builtin_constant_p(((base + 0x57))) && ((base + 0x57 )) < 256) ? __inbc((base + 0x57)) : __inb((base + 0x57))),adapstat, |
263 | inb(G2INTST(base))((__builtin_constant_p(((base + 0x56))) && ((base + 0x56 )) < 256) ? __inbc((base + 0x56)) : __inb((base + 0x56))), number_serviced++); |
264 | continue; |
265 | } |
266 | if (SCtmp->host_scribble) |
267 | scsi_free(SCtmp->host_scribble, 512); |
268 | /* Fetch the sense data, and tuck it away, in the required slot. |
269 | The Adaptec automatically fetches it, and there is no |
270 | guarantee that we will still have it in the cdb when we come |
271 | back */ |
272 | if ( (adapstat & G2INTST_MASK0xf0) == G2INTST_CCBERROR0xc0 ) |
273 | { |
274 | memcpy(SCtmp->sense_buffer, ecbptr->sense,(__builtin_constant_p(sizeof(SCtmp->sense_buffer)) ? __constant_memcpy ((SCtmp->sense_buffer),(ecbptr->sense),(sizeof(SCtmp-> sense_buffer))) : __memcpy((SCtmp->sense_buffer),(ecbptr-> sense),(sizeof(SCtmp->sense_buffer)))) |
275 | sizeof(SCtmp->sense_buffer))(__builtin_constant_p(sizeof(SCtmp->sense_buffer)) ? __constant_memcpy ((SCtmp->sense_buffer),(ecbptr->sense),(sizeof(SCtmp-> sense_buffer))) : __memcpy((SCtmp->sense_buffer),(ecbptr-> sense),(sizeof(SCtmp->sense_buffer)))); |
276 | errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status); |
277 | } |
278 | else |
279 | errstatus = 0; |
280 | DEB(if (errstatus) printk("aha1740_intr_handle: returning %6x\n", |
281 | errstatus)); |
282 | SCtmp->result = errstatus; |
283 | my_done = ecbptr->done; |
284 | memset(ecbptr,0,sizeof(struct ecb))(__builtin_constant_p(0) ? (__builtin_constant_p((sizeof(struct ecb))) ? __constant_c_and_count_memset(((ecbptr)),((0x01010101UL *(unsigned char)(0))),((sizeof(struct ecb)))) : __constant_c_memset (((ecbptr)),((0x01010101UL*(unsigned char)(0))),((sizeof(struct ecb))))) : (__builtin_constant_p((sizeof(struct ecb))) ? __memset_generic ((((ecbptr))),(((0))),(((sizeof(struct ecb))))) : __memset_generic (((ecbptr)),((0)),((sizeof(struct ecb)))))); |
285 | if ( my_done ) |
286 | my_done(SCtmp); |
287 | break; |
288 | case G2INTST_HARDFAIL0x70: |
289 | printk(KERN_ALERT"<1>" "aha1740 hardware failure!\n"); |
290 | panic("aha1740.c"); /* Goodbye */ |
291 | case G2INTST_ASNEVENT0xd0: |
292 | printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n", |
293 | adapstat, inb(MBOXIN0(base))((__builtin_constant_p(((base + 0x58))) && ((base + 0x58 )) < 256) ? __inbc((base + 0x58)) : __inb((base + 0x58))), inb(MBOXIN1(base))((__builtin_constant_p(((base + 0x59))) && ((base + 0x59 )) < 256) ? __inbc((base + 0x59)) : __inb((base + 0x59))), |
294 | inb(MBOXIN2(base))((__builtin_constant_p(((base + 0x5a))) && ((base + 0x5a )) < 256) ? __inbc((base + 0x5a)) : __inb((base + 0x5a))), inb(MBOXIN3(base))((__builtin_constant_p(((base + 0x5b))) && ((base + 0x5b )) < 256) ? __inbc((base + 0x5b)) : __inb((base + 0x5b)))); /* Say What? */ |
295 | /* Host Ready -> Mailbox in complete */ |
296 | outb(G2CNTRL_HRDY,G2CNTRL(base))((__builtin_constant_p(((base + 0x55))) && ((base + 0x55 )) < 256) ? __outbc((0x20),((base + 0x55))) : __outb((0x20 ),((base + 0x55)))); |
297 | break; |
298 | case G2INTST_CMDGOOD0xa0: |
299 | /* set immediate command success flag here: */ |
300 | break; |
301 | case G2INTST_CMDERROR0xe0: |
302 | /* Set immediate command failure flag here: */ |
303 | break; |
304 | } |
305 | number_serviced++; |
306 | } |
307 | } |
308 | |
309 | int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) |
310 | { |
311 | unchar direction; |
312 | unchar *cmd = (unchar *) SCpnt->cmnd; |
313 | unchar target = SCpnt->target; |
314 | struct aha1740_hostdata *host = HOSTDATA(SCpnt->host)((struct aha1740_hostdata *) &SCpnt->host->hostdata ); |
315 | unsigned long flags; |
316 | void *buff = SCpnt->request_buffer; |
317 | int bufflen = SCpnt->request_bufflen; |
318 | int ecbno; |
319 | DEB(int i); |
320 | |
321 | if(*cmd == REQUEST_SENSE0x03) |
322 | { |
323 | if (bufflen != sizeof(SCpnt->sense_buffer)) |
324 | { |
325 | printk("Wrong buffer length supplied for request sense (%d)\n", |
326 | bufflen); |
327 | } |
328 | SCpnt->result = 0; |
329 | done(SCpnt); |
330 | return 0; |
331 | } |
332 | |
333 | #ifdef DEBUG |
334 | if (*cmd == READ_100x28 || *cmd == WRITE_100x2a) |
335 | i = xscsi2int(cmd+2)( (((long)(cmd+2)[0]) << 24) + (((long)(cmd+2)[1]) << 16) + (((long)(cmd+2)[2]) << 8) + ((long)(cmd+2)[3]) ); |
336 | else if (*cmd == READ_60x08 || *cmd == WRITE_60x0a) |
337 | i = scsi2int(cmd+2)( (((long)*(cmd+2)) << 16) + (((long)(cmd+2)[1]) << 8) + ((long)(cmd+2)[2]) ); |
338 | else |
339 | i = -1; |
340 | printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", |
341 | target, *cmd, i, bufflen); |
342 | printk("scsi cmd:"); |
343 | for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]); |
344 | printk("\n"); |
345 | #endif |
346 | |
347 | /* locate an available ecb */ |
348 | save_flags(flags)__asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory" ); |
349 | cli()__asm__ __volatile__ ("cli": : :"memory"); |
350 | ecbno = host->last_ecb_used + 1; /* An optimization */ |
351 | if (ecbno >= AHA1740_ECBS32) |
352 | ecbno = 0; |
353 | do { |
354 | if (!host->ecb[ecbno].cmdw) |
355 | break; |
356 | ecbno++; |
357 | if (ecbno >= AHA1740_ECBS32) |
358 | ecbno = 0; |
359 | } while (ecbno != host->last_ecb_used); |
360 | |
361 | if (host->ecb[ecbno].cmdw) |
362 | panic("Unable to find empty ecb for aha1740.\n"); |
363 | |
364 | host->ecb[ecbno].cmdw = AHA1740CMD_INIT0x01; /* SCSI Initiator Command |
365 | doubles as reserved flag */ |
366 | |
367 | host->last_ecb_used = ecbno; |
368 | restore_flags(flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory"); |
369 | |
370 | #ifdef DEBUG |
371 | printk("Sending command (%d %x)...", ecbno, done); |
372 | #endif |
373 | |
374 | host->ecb[ecbno].cdblen = SCpnt->cmd_len; /* SCSI Command Descriptor Block Length */ |
375 | |
376 | direction = 0; |
377 | if (*cmd == READ_100x28 || *cmd == READ_60x08) |
378 | direction = 1; |
379 | else if (*cmd == WRITE_100x2a || *cmd == WRITE_60x0a) |
380 | direction = 0; |
381 | |
382 | memcpy(host->ecb[ecbno].cdb, cmd, SCpnt->cmd_len)(__builtin_constant_p(SCpnt->cmd_len) ? __constant_memcpy( (host->ecb[ecbno].cdb),(cmd),(SCpnt->cmd_len)) : __memcpy ((host->ecb[ecbno].cdb),(cmd),(SCpnt->cmd_len))); |
383 | |
384 | if (SCpnt->use_sg) |
385 | { |
386 | struct scatterlist * sgpnt; |
387 | struct aha1740_chain * cptr; |
388 | int i; |
389 | DEB(unsigned char * ptr); |
390 | |
391 | host->ecb[ecbno].sg = 1; /* SCSI Initiator Command w/scatter-gather*/ |
392 | SCpnt->host_scribble = (unsigned char *) scsi_malloc(512); |
393 | sgpnt = (struct scatterlist *) SCpnt->request_buffer; |
394 | cptr = (struct aha1740_chain *) SCpnt->host_scribble; |
395 | if (cptr == NULL((void *) 0)) panic("aha1740.c: unable to allocate DMA memory\n"); |
396 | for(i=0; i<SCpnt->use_sg; i++) |
397 | { |
398 | cptr[i].datalen = sgpnt[i].length; |
399 | cptr[i].dataptr = virt_to_busvirt_to_phys(sgpnt[i].address); |
400 | } |
401 | host->ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain); |
402 | host->ecb[ecbno].dataptr = virt_to_busvirt_to_phys(cptr); |
403 | #ifdef DEBUG |
404 | printk("cptr %x: ",cptr); |
405 | ptr = (unsigned char *) cptr; |
406 | for(i=0;i<24;i++) printk("%02x ", ptr[i]); |
407 | #endif |
408 | } |
409 | else |
410 | { |
411 | SCpnt->host_scribble = NULL((void *) 0); |
412 | host->ecb[ecbno].datalen = bufflen; |
413 | host->ecb[ecbno].dataptr = virt_to_busvirt_to_phys(buff); |
414 | } |
415 | host->ecb[ecbno].lun = SCpnt->lun; |
416 | host->ecb[ecbno].ses = 1; /* Suppress underrun errors */ |
417 | host->ecb[ecbno].dir = direction; |
418 | host->ecb[ecbno].ars = 1; /* Yes, get the sense on an error */ |
419 | host->ecb[ecbno].senselen = 12; |
420 | host->ecb[ecbno].senseptr = virt_to_busvirt_to_phys(host->ecb[ecbno].sense); |
421 | host->ecb[ecbno].statusptr = virt_to_busvirt_to_phys(host->ecb[ecbno].status); |
422 | host->ecb[ecbno].done = done; |
423 | host->ecb[ecbno].SCpnt = SCpnt; |
424 | #ifdef DEBUG |
425 | { |
426 | int i; |
427 | printk("aha1740_command: sending.. "); |
428 | for (i = 0; i < sizeof(host->ecb[ecbno]) - 10; i++) |
429 | printk("%02x ", ((unchar *)&host->ecb[ecbno])[i]); |
430 | } |
431 | printk("\n"); |
432 | #endif |
433 | if (done) |
434 | { /* The Adaptec Spec says the card is so fast that the loops will |
435 | only be executed once in the code below. Even if this was true |
436 | with the fastest processors when the spec was written, it doesn't |
437 | seem to be true with todays fast processors. We print a warning |
438 | if the code is executed more often than LOOPCNT_WARN. If this |
439 | happens, it should be investigated. If the count reaches |
440 | LOOPCNT_MAX, we assume something is broken; since there is no |
441 | way to return an error (the return value is ignored by the |
442 | mid-level scsi layer) we have to panic (and maybe that's the |
443 | best thing we can do then anyhow). */ |
444 | |
445 | #define LOOPCNT_WARN10 10 /* excessive mbxout wait -> syslog-msg */ |
446 | #define LOOPCNT_MAX1000000 1000000 /* mbxout deadlock -> panic() after ~ 2 sec. */ |
447 | int loopcnt; |
448 | unsigned int base = SCpnt->host->io_port; |
449 | DEB(printk("aha1740[%d] critical section\n",ecbno)); |
450 | save_flags(flags)__asm__ __volatile__("pushf ; pop %0" : "=r" (flags): :"memory" ); |
451 | cli()__asm__ __volatile__ ("cli": : :"memory"); |
452 | for (loopcnt = 0; ; loopcnt++) { |
453 | if (inb(G2STAT(base))((__builtin_constant_p(((base + 0x57))) && ((base + 0x57 )) < 256) ? __inbc((base + 0x57)) : __inb((base + 0x57))) & G2STAT_MBXOUT4) break; |
454 | if (loopcnt == LOOPCNT_WARN10) { |
455 | printk("aha1740[%d]_mbxout wait!\n",ecbno); |
456 | cli()__asm__ __volatile__ ("cli": : :"memory"); /* printk may have done a sti()! */ |
457 | } |
458 | if (loopcnt == LOOPCNT_MAX1000000) |
459 | panic("aha1740.c: mbxout busy!\n"); |
460 | } |
461 | outl(virt_to_bus(host->ecb + ecbno), MBOXOUT0(base))((__builtin_constant_p(((base + 0x50))) && ((base + 0x50 )) < 256) ? __outlc((virt_to_phys(host->ecb + ecbno)),( (base + 0x50))) : __outl((virt_to_phys(host->ecb + ecbno)) ,((base + 0x50)))); |
462 | for (loopcnt = 0; ; loopcnt++) { |
463 | if (! (inb(G2STAT(base))((__builtin_constant_p(((base + 0x57))) && ((base + 0x57 )) < 256) ? __inbc((base + 0x57)) : __inb((base + 0x57))) & G2STAT_BUSY1)) break; |
464 | if (loopcnt == LOOPCNT_WARN10) { |
465 | printk("aha1740[%d]_attn wait!\n",ecbno); |
466 | cli()__asm__ __volatile__ ("cli": : :"memory"); |
467 | } |
468 | if (loopcnt == LOOPCNT_MAX1000000) |
469 | panic("aha1740.c: attn wait failed!\n"); |
470 | } |
471 | outb(ATTN_START | (target & 7), ATTN(base))((__builtin_constant_p(((base + 0x54))) && ((base + 0x54 )) < 256) ? __outbc((0x40 | (target & 7)),((base + 0x54 ))) : __outb((0x40 | (target & 7)),((base + 0x54)))); /* Start it up */ |
472 | restore_flags(flags)__asm__ __volatile__("push %0 ; popf": :"g" (flags):"memory"); |
473 | DEB(printk("aha1740[%d] request queued.\n",ecbno)); |
474 | } |
475 | else |
476 | printk(KERN_ALERT"<1>" "aha1740_queuecommand: done can't be NULL\n"); |
477 | return 0; |
478 | } |
479 | |
480 | static void internal_done(Scsi_Cmnd * SCpnt) |
481 | { |
482 | SCpnt->SCp.Status++; |
483 | } |
484 | |
485 | int aha1740_command(Scsi_Cmnd * SCpnt) |
486 | { |
487 | aha1740_queuecommand(SCpnt, internal_done); |
488 | SCpnt->SCp.Status = 0; |
489 | while (!SCpnt->SCp.Status) |
490 | barrier()__asm__ __volatile__("": : :"memory"); |
491 | return SCpnt->result; |
492 | } |
493 | |
494 | /* Query the board for its irq_level. Nothing else matters |
495 | in enhanced mode on an EISA bus. */ |
496 | |
497 | void aha1740_getconfig(unsigned int base, unsigned int *irq_level, |
498 | unsigned int *translation) |
499 | { |
500 | static int intab[] = { 9, 10, 11, 12, 0, 14, 15, 0 }; |
501 | |
502 | *irq_level = intab[inb(INTDEF(base))((__builtin_constant_p(((base + 0x42))) && ((base + 0x42 )) < 256) ? __inbc((base + 0x42)) : __inb((base + 0x42))) & 0x7]; |
503 | *translation = inb(RESV1(base))((__builtin_constant_p(((base + 0x46))) && ((base + 0x46 )) < 256) ? __inbc((base + 0x46)) : __inb((base + 0x46))) & 0x1; |
504 | outb(inb(INTDEF(base)) | 0x10, INTDEF(base))((__builtin_constant_p(((base + 0x42))) && ((base + 0x42 )) < 256) ? __outbc((((__builtin_constant_p(((base + 0x42) )) && ((base + 0x42)) < 256) ? __inbc((base + 0x42 )) : __inb((base + 0x42))) | 0x10),((base + 0x42))) : __outb( (((__builtin_constant_p(((base + 0x42))) && ((base + 0x42 )) < 256) ? __inbc((base + 0x42)) : __inb((base + 0x42))) | 0x10),((base + 0x42)))); |
505 | } |
506 | |
507 | int aha1740_detect(Scsi_Host_Template * tpnt) |
508 | { |
509 | int count = 0, slot; |
510 | |
511 | DEB(printk("aha1740_detect: \n")); |
512 | |
513 | for ( slot=MINEISA1; slot <= MAXEISA8; slot++ ) |
514 | { |
515 | int slotbase; |
516 | unsigned int irq_level, translation; |
517 | struct Scsi_Host *shpnt; |
518 | struct aha1740_hostdata *host; |
519 | slotbase = SLOTBASE(slot)((slot << 12) + 0xc80); |
520 | /* |
521 | * The ioports for eisa boards are generally beyond that used in the |
522 | * check/allocate region code, but this may change at some point, |
523 | * so we go through the motions. |
524 | */ |
525 | if (check_region(slotbase, SLOTSIZE0x5c)) /* See if in use */ |
526 | continue; |
527 | if (!aha1740_test_port(slotbase)) |
528 | continue; |
529 | aha1740_getconfig(slotbase,&irq_level,&translation); |
530 | if ((inb(G2STAT(slotbase))((__builtin_constant_p(((slotbase + 0x57))) && ((slotbase + 0x57)) < 256) ? __inbc((slotbase + 0x57)) : __inb((slotbase + 0x57))) & |
531 | (G2STAT_MBXOUT4|G2STAT_BUSY1)) != G2STAT_MBXOUT4) |
532 | { /* If the card isn't ready, hard reset it */ |
533 | outb(G2CNTRL_HRST, G2CNTRL(slotbase))((__builtin_constant_p(((slotbase + 0x55))) && ((slotbase + 0x55)) < 256) ? __outbc((0x80),((slotbase + 0x55))) : __outb ((0x80),((slotbase + 0x55)))); |
534 | outb(0, G2CNTRL(slotbase))((__builtin_constant_p(((slotbase + 0x55))) && ((slotbase + 0x55)) < 256) ? __outbc((0),((slotbase + 0x55))) : __outb ((0),((slotbase + 0x55)))); |
535 | } |
536 | printk("Configuring aha174x at IO:%x, IRQ %d\n", slotbase, irq_level); |
537 | printk("aha174x: Extended translation %sabled.\n", |
538 | translation ? "en" : "dis"); |
539 | DEB(printk("aha1740_detect: enable interrupt channel %d\n",irq_level)); |
540 | if (request_irq(irq_level,aha1740_intr_handle,0,"aha1740",NULL((void *) 0))) { |
541 | printk("Unable to allocate IRQ for adaptec controller.\n"); |
542 | continue; |
543 | } |
544 | shpnt = scsi_register(tpnt, sizeof(struct aha1740_hostdata)); |
545 | request_region(slotbase, SLOTSIZE0x5c, "aha1740"); |
546 | shpnt->base = 0; |
547 | shpnt->io_port = slotbase; |
548 | shpnt->n_io_port = SLOTSIZE0x5c; |
549 | shpnt->irq = irq_level; |
550 | shpnt->dma_channel = 0xff; |
551 | host = HOSTDATA(shpnt)((struct aha1740_hostdata *) &shpnt->hostdata); |
552 | host->slot = slot; |
553 | host->translation = translation; |
554 | aha_host[irq_level - 9] = shpnt; |
555 | count++; |
556 | } |
557 | return count; |
558 | } |
559 | |
560 | /* Note: They following two functions do not apply very well to the Adaptec, |
561 | which basically manages its own affairs quite well without our interference, |
562 | so I haven't put anything into them. I can faintly imagine someone with a |
563 | *very* badly behaved SCSI target (perhaps an old tape?) wanting the abort(), |
564 | but it hasn't happened yet, and doing aborts brings the Adaptec to its |
565 | knees. I cannot (at this moment in time) think of any reason to reset the |
566 | card once it's running. So there. */ |
567 | |
568 | int aha1740_abort(Scsi_Cmnd * SCpnt) |
569 | { |
570 | DEB(printk("aha1740_abort called\n")); |
571 | return SCSI_ABORT_SNOOZE0; |
572 | } |
573 | |
574 | /* We do not implement a reset function here, but the upper level code assumes |
575 | that it will get some kind of response for the command in SCpnt. We must |
576 | oblige, or the command will hang the scsi system */ |
577 | |
578 | int aha1740_reset(Scsi_Cmnd * SCpnt, unsigned int ignored) |
579 | { |
580 | DEB(printk("aha1740_reset called\n")); |
581 | return SCSI_RESET_PUNT1; |
582 | } |
583 | |
584 | int aha1740_biosparam(Disk * disk, kdev_t dev, int* ip) |
585 | { |
586 | int size = disk->capacity; |
587 | int extended = HOSTDATA(disk->device->host)((struct aha1740_hostdata *) &disk->device->host-> hostdata)->translation; |
588 | |
589 | DEB(printk("aha1740_biosparam\n")); |
590 | if (extended && (ip[2] > 1024)) |
591 | { |
592 | ip[0] = 255; |
593 | ip[1] = 63; |
594 | ip[2] = size / (255 * 63); |
595 | } |
596 | else |
597 | { |
598 | ip[0] = 64; |
599 | ip[1] = 32; |
600 | ip[2] = size >> 11; |
601 | } |
602 | return 0; |
603 | } |
604 | |
605 | #ifdef MODULE |
606 | /* Eventually this will go into an include file, but this will be later */ |
607 | Scsi_Host_Template driver_template = AHA1740{((void *) 0), ((void *) 0), &proc_scsi_aha1740, aha1740_proc_info , "Adaptec 174x (EISA)", aha1740_detect, ((void *) 0), ((void *) 0), aha1740_command, aha1740_queuecommand, aha1740_abort, aha1740_reset, ((void *) 0), aha1740_biosparam, 32, 7, 16, 1 , 0, 0, 1}; |
608 | |
609 | #include "scsi_module.c" |
610 | #endif |
611 | |
612 | /* Okay, you made it all the way through. As of this writing, 3/31/93, I'm |
613 | brad@saturn.gaylord.com or brad@bradpc.gaylord.com. I'll try to help as time |
614 | permits if you have any trouble with this driver. Happy Linuxing! */ |