1 /*----------------------------------------------------------------*/
2 /*
3 Qlogic linux driver - work in progress. No Warranty express or implied.
4 Use at your own risk. Support Tort Reform so you won't have to read all
5 these silly disclaimers.
6
7 Copyright 1994, Tom Zerucha.
8 zerucha@shell.portal.com
9
10 Additional Code, and much appreciated help by
11 Michael A. Griffith
12 grif@cs.ucr.edu
13
14 Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
15 (you can reference it, but it is incomplete and inaccurate in places)
16
17 Version 0.38a
18
19 This also works with loadable SCSI as a module. Check configuration
20 options QL_INT_ACTIVE_HIGH and QL_TURBO_PDMA for PCMCIA usage (which
21 also requires an enabler).
22
23 Redistributable under terms of the GNU Public License
24
25 */
26 /*----------------------------------------------------------------*/
27 /* Configuration */
28
29 /* Set the following to 2 to use normal interrupt (active high/totempole-
30 tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
31 drain */
32 #define QL_INT_ACTIVE_HIGH 2
33
34 /* Set the following to 1 to enable the use of interrupts. Note that 0 tends
35 to be more stable, but slower (or ties up the system more) */
36 #define QL_USE_IRQ 1
37
38 /* Set the following to max out the speed of the PIO PseudoDMA transfers,
39 again, 0 tends to be slower, but more stable. THIS SHOULD BE ZERO FOR
40 PCMCIA */
41 #define QL_TURBO_PDMA 1
42
43 /* This will reset all devices when the driver is initialized (during bootup).
44 The other linux drivers don't do this, but the DOS drivers do, and after
45 using DOS or some kind of crash or lockup this will bring things back */
46 #define QL_RESET_AT_START 1
47
48 /* This will set fast (10Mhz) synchronous timing, FASTCLK must also be 1*/
49 #define FASTSCSI 0
50
51 /* This will set a faster sync transfer rate */
52 #define FASTCLK 0
53
54 /* This bit needs to be set to 1 if your cabling is long or noisy */
55 #define SLOWCABLE 0
56
57 /* This is the sync transfer divisor, 40Mhz/X will be the data rate
58 The power on default is 5, the maximum normal value is 5 */
59 #define SYNCXFRPD 4
60
61 /* This is the count of how many synchronous transfers can take place
62 i.e. how many reqs can occur before an ack is given.
63 The maximum value for this is 15, the upper bits can modify
64 REQ/ACK assertion and deassertion during synchronous transfers
65 If this is 0, the bus will only transfer asynchronously */
66 #define SYNCOFFST 0
67 /* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles
68 of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will
69 cause the deassertion to be early by 1/2 clock. Bits 5&4 control
70 the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */
71
72 /*----------------------------------------------------------------*/
73
74 #include "../block/blk.h" /* to get disk capacity */
75 #include <linux/kernel.h>
76 #include <linux/string.h>
77 #include <linux/ioport.h>
78 #include <linux/sched.h>
79 #include <unistd.h>
80 #include <asm/io.h>
81 #include <asm/irq.h>
82 #include "sd.h"
83 #include "hosts.h"
84 #include "qlogic.h"
85
86 /*----------------------------------------------------------------*/
87 /* driver state info, local to driver */
88 static int qbase; /* Port */
89 static int qinitid; /* initiator ID */
90 static int qabort; /* Flag to cause an abort */
91 static int qlirq; /* IRQ being used */
92 static char qinfo[80]; /* description */
93 static Scsi_Cmnd *qlcmd; /* current command being processed */
94
95 /*----------------------------------------------------------------*/
96
97 #define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
98 #define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd ))
99
100 /* following is watchdog timeout */
101 #define WATCHDOG 5000000
102
103 /*----------------------------------------------------------------*/
104 /* the following will set the monitor border color (useful to find
105 where something crashed or gets stuck at and as a simple profiler) */
106
107 #if 0
108 #define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
109 #else
110 #define rtrc(i) {}
111 #endif
112
113 /*----------------------------------------------------------------*/
114 /* local functions */
115 /*----------------------------------------------------------------*/
116 static void ql_zap(void);
117 /* error recovery - reset everything */
118 void ql_zap()
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
119 {
120 int x;
121 cli();
122 x = inb(qbase + 0xd);
123 REG0;
124 outb(3, qbase + 3); /* reset SCSI */
125 outb(2, qbase + 3); /* reset chip */
126 if (x & 0x80)
127 REG1;
128 sti();
129 }
130
131 /*----------------------------------------------------------------*/
132 /* do pseudo-dma */
133 static int ql_pdma(int phase, char *request, int reqlen)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
134 {
135 int j;
136 j = 0;
137 if (phase & 1) { /* in */
138 #if QL_TURBO_PDMA
139 /* empty fifo in large chunks */
140 if( reqlen >= 128 && (inb( qbase + 8 ) & 2) ) { /* full */
141 insl( qbase + 4, request, 32 );
142 reqlen -= 128;
143 request += 128;
144 }
145 while( reqlen >= 84 && !( j & 0xc0 ) ) /* 2/3 */
146 if( (j=inb( qbase + 8 )) & 4 ) {
147 insl( qbase + 4, request, 21 );
148 reqlen -= 84;
149 request += 84;
150 }
151 if( reqlen >= 44 && (inb( qbase + 8 ) & 8) ) { /* 1/3 */
152 insl( qbase + 4, request, 11 );
153 reqlen -= 44;
154 request += 44;
155 }
156 #endif
157 /* until both empty and int (or until reclen is 0) */
158 j = 0;
159 while( reqlen && !( (j & 0x10) && (j & 0xc0) ) ) {
160 /* while bytes to receive and not empty */
161 j &= 0xc0;
162 while ( reqlen && !( (j=inb(qbase + 8)) & 0x10 ) ) {
163 *request++ = inb(qbase + 4);
164 reqlen--;
165 }
166 if( j & 0x10 )
167 j = inb(qbase+8);
168
169 }
170 }
171 else { /* out */
172 #if QL_TURBO_PDMA
173 if( reqlen >= 128 && inb( qbase + 8 ) & 0x10 ) { /* empty */
174 outsl(qbase + 4, request, 32 );
175 reqlen -= 128;
176 request += 128;
177 }
178 while( reqlen >= 84 && !( j & 0xc0 ) ) /* 1/3 */
179 if( !((j=inb( qbase + 8 )) & 8) ) {
180 outsl( qbase + 4, request, 21 );
181 reqlen -= 84;
182 request += 84;
183 }
184 if( reqlen >= 40 && !(inb( qbase + 8 ) & 4 ) ) { /* 2/3 */
185 outsl( qbase + 4, request, 10 );
186 reqlen -= 40;
187 request += 40;
188 }
189 #endif
190 /* until full and int (or until reclen is 0) */
191 j = 0;
192 while( reqlen && !( (j & 2) && (j & 0xc0) ) ) {
193 /* while bytes to send and not full */
194 while ( reqlen && !( (j=inb(qbase + 8)) & 2 ) ) {
195 outb(*request++, qbase + 4);
196 reqlen--;
197 }
198 if( j & 2 )
199 j = inb(qbase+8);
200 }
201 }
202 /* maybe return reqlen */
203 return inb( qbase + 8 ) & 0xc0;
204 }
205
206 /*----------------------------------------------------------------*/
207 /* wait for interrupt flag (polled - not real hardware interrupt) */
208 static int ql_wai(void)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
209 {
210 int i,k;
211 i = jiffies + WATCHDOG;
212 while ( i > jiffies && !qabort && !((k = inb(qbase + 4)) & 0xe0));
213 if (i <= jiffies)
214 return (DID_TIME_OUT);
215 if (qabort)
216 return (qabort == 1 ? DID_ABORT : DID_RESET);
217 if (k & 0x60)
218 ql_zap();
219 if (k & 0x20)
220 return (DID_PARITY);
221 if (k & 0x40)
222 return (DID_ERROR);
223 return 0;
224 }
225
226 /*----------------------------------------------------------------*/
227 /* initiate scsi command - queueing handler */
228 static void ql_icmd(Scsi_Cmnd * cmd)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
229 {
230 unsigned int i;
231 qabort = 0;
232
233 cli();
234 REG0;
235 /* clearing of interrupts and the fifo is needed */
236 inb(qbase + 5); /* clear interrupts */
237 if (inb(qbase + 5)) /* if still interrupting */
238 outb(2, qbase + 3); /* reset chip */
239 else if (inb(qbase + 7) & 0x1f)
240 outb(1, qbase + 3); /* clear fifo */
241 while (inb(qbase + 5)); /* clear ints */
242 REG1;
243 outb(1, qbase + 8); /* set for PIO pseudo DMA */
244 outb(0, qbase + 0xb); /* disable ints */
245 inb(qbase + 8); /* clear int bits */
246 REG0;
247 outb(0x40, qbase + 0xb); /* enable features */
248
249 /* configurables */
250 #if FASTSCSI
251 #if FASTCLK
252 outb(0x18, qbase + 0xc);
253 #else
254 outb(0x10, qbase + 0xc);
255 #endif
256 #else
257 #if FASTCLK
258 outb(8, qbase + 0xc);
259 #endif
260 #endif
261
262 #if SLOWCABLE
263 outb(0xd0 | qinitid, qbase + 8); /* (initiator) bus id */
264 #else
265 outb(0x50 | qinitid, qbase + 8); /* (initiator) bus id */
266 #endif
267 outb( SYNCOFFST , qbase + 7 );
268 outb( SYNCXFRPD , qbase + 6 );
269 /**/
270 outb(0x99, qbase + 5); /* timer */
271 outb(cmd->target, qbase + 4);
272
273 for (i = 0; i < cmd->cmd_len; i++)
274 outb(cmd->cmnd[i], qbase + 2);
275 qlcmd = cmd;
276 outb(0x41, qbase + 3); /* select and send command */
277 sti();
278 }
279 /*----------------------------------------------------------------*/
280 /* process scsi command - usually after interrupt */
281 static unsigned int ql_pcmd(Scsi_Cmnd * cmd)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
282 {
283 unsigned int i, j, k;
284 unsigned int result; /* ultimate return result */
285 unsigned int status; /* scsi returned status */
286 unsigned int message; /* scsi returned message */
287 unsigned int phase; /* recorded scsi phase */
288 unsigned int reqlen; /* total length of transfer */
289 struct scatterlist *sglist; /* scatter-gather list pointer */
290 unsigned int sgcount; /* sg counter */
291
292 j = inb(qbase + 6);
293 i = inb(qbase + 5);
294 if (i == 0x20) {
295 return (DID_NO_CONNECT << 16);
296 }
297 i |= inb(qbase + 5); /* the 0x10 bit can be set after the 0x08 */
298 if (i != 0x18) {
299 printk("Ql:Bad Interrupt status:%02x\n", i);
300 ql_zap();
301 return (DID_BAD_INTR << 16);
302 }
303 j &= 7; /* j = inb( qbase + 7 ) >> 5; */
304 /* correct status is supposed to be step 4 */
305 /* it sometimes returns step 3 but with 0 bytes left to send */
306 /* We can try stuffing the FIFO with the max each time, but we will get a
307 sequence of 3 if any bytes are left (but we do flush the FIFO anyway */
308 if(j != 3 && j != 4) {
309 printk("Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb( qbase+7 ) & 0x1f );
310 ql_zap();
311 return (DID_ERROR << 16);
312 }
313 result = DID_OK;
314 if (inb(qbase + 7) & 0x1f) /* if some bytes in fifo */
315 outb(1, qbase + 3); /* clear fifo */
316 /* note that request_bufflen is the total xfer size when sg is used */
317 reqlen = cmd->request_bufflen;
318 /* note that it won't work if transfers > 16M are requested */
319 if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */
320 rtrc(1)
321 outb(reqlen, qbase); /* low-mid xfer cnt */
322 outb(reqlen >> 8, qbase+1); /* low-mid xfer cnt */
323 outb(reqlen >> 16, qbase + 0xe); /* high xfer cnt */
324 outb(0x90, qbase + 3); /* command do xfer */
325 /* PIO pseudo DMA to buffer or sglist */
326 REG1;
327 if (!cmd->use_sg)
328 ql_pdma(phase, cmd->request_buffer, cmd->request_bufflen);
329 else {
330 sgcount = cmd->use_sg;
331 sglist = cmd->request_buffer;
332 while (sgcount--) {
333 if (qabort) {
334 REG0;
335 return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
336 }
337 if (ql_pdma(phase, sglist->address, sglist->length))
338 break;
339 sglist++;
340 }
341 }
342 REG0;
343 rtrc(2)
344 /* wait for irq (split into second state of irq handler if this can take time) */
345 if ((k = ql_wai()))
346 return (k << 16);
347 k = inb(qbase + 5); /* should be 0x10, bus service */
348 }
349 /*** Enter Status (and Message In) Phase ***/
350 k = jiffies + WATCHDOG;
351 rtrc(4)
352 while ( k > jiffies && !qabort && !(inb(qbase + 4) & 6)); /* wait for status phase */
353 if ( k <= jiffies ) {
354 ql_zap();
355 return (DID_TIME_OUT << 16);
356 }
357 while (inb(qbase + 5)); /* clear pending ints */
358 if (qabort)
359 return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
360 outb(0x11, qbase + 3); /* get status and message */
361 if ((k = ql_wai()))
362 return (k << 16);
363 i = inb(qbase + 5); /* get chip irq stat */
364 j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */
365 status = inb(qbase + 2);
366 message = inb(qbase + 2);
367 /* should get function complete int if Status and message, else bus serv if only status */
368 if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
369 printk("Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
370 result = DID_ERROR;
371 }
372 outb(0x12, qbase + 3); /* done, disconnect */
373 rtrc(3)
374 if ((k = ql_wai()))
375 return (k << 16);
376 /* should get bus service interrupt and disconnect interrupt */
377 i = inb(qbase + 5); /* should be bus service */
378 while (!qabort && ((i & 0x20) != 0x20))
379 i |= inb(qbase + 5);
380 rtrc(0)
381 if (qabort)
382 return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16);
383 return (result << 16) | (message << 8) | (status & STATUS_MASK);
384 }
385
386 #if QL_USE_IRQ
387 /*----------------------------------------------------------------*/
388 /* interrupt handler */
389 static void ql_ihandl(int irq, struct pt_regs * regs)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
390 {
391 Scsi_Cmnd *icmd;
392 REG0;
393 if (!(inb(qbase + 4) & 0x80)) /* false alarm? */
394 return;
395 if (qlcmd == NULL) { /* no command to process? */
396 while (inb(qbase + 5)); /* maybe also ql_zap() */
397 return;
398 }
399 icmd = qlcmd;
400 icmd->result = ql_pcmd(icmd);
401 qlcmd = NULL;
402 /* if result is CHECK CONDITION done calls qcommand to request sense */
403 (icmd->scsi_done) (icmd);
404 }
405 #endif
406
407 /*----------------------------------------------------------------*/
408 /* global functions */
409 /*----------------------------------------------------------------*/
410 /* non queued command */
411 #if QL_USE_IRQ
412 static void qlidone(Scsi_Cmnd * cmd) {}; /* null function */
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
413 #endif
414
415 /* command process */
416 int qlogic_command(Scsi_Cmnd * cmd)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
417 {
418 int k;
419 #if QL_USE_IRQ
420 if (qlirq >= 0) {
421 qlogic_queuecommand(cmd, qlidone);
422 while (qlcmd != NULL);
423 return cmd->result;
424 }
425 #endif
426 /* non-irq version */
427 if (cmd->target == qinitid)
428 return (DID_BAD_TARGET << 16);
429 ql_icmd(cmd);
430 if ((k = ql_wai()))
431 return (k << 16);
432 return ql_pcmd(cmd);
433
434 }
435
436 #if QL_USE_IRQ
437 /*----------------------------------------------------------------*/
438 /* queued command */
439 int qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
440 {
441 if(cmd->target == qinitid) {
442 cmd->result = DID_BAD_TARGET << 16;
443 done(cmd);
444 return 0;
445 }
446
447 cmd->scsi_done = done;
448 /* wait for the last command's interrupt to finish */
449 while (qlcmd != NULL);
450 ql_icmd(cmd);
451 return 0;
452 }
453 #else
454 int qlogic_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
455 {
456 return 1;
457 }
458 #endif
459
460 /*----------------------------------------------------------------*/
461 /* look for qlogic card and init if found */
462 int qlogic_detect(Scsi_Host_Template * host)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
463 {
464 int i, j; /* these are only used by IRQ detect */
465 int qltyp; /* type of chip */
466 struct Scsi_Host *hreg; /* registered host structure */
467
468 /* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the
469 address - I check 230 first since MIDI cards are typically at 330
470 Note that this will not work for 2 Qlogic cards in 1 system. The
471 easiest way to do that is to create 2 versions of this file, one for
472 230 and one for 330.
473
474 Alternately, the Scsi_Host structure now stores the i/o port and can
475 be used to set the port (go through and replace qbase with
476 (struct Scsi_Cmnd *) cmd->host->io_port, or for efficiency, set a local
477 copy of qbase. There will also need to be something similar within the
478 IRQ handlers to sort out which board it came from and thus which port.
479 */
480
481 for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {
482 if( check_region( qbase , 0x10 ) )
483 continue;
484 REG1;
485 if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 )
486 && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) )
487 break;
488 }
489 if (qbase == 0x430)
490 return 0;
491
492 qltyp = inb(qbase + 0xe) & 0xf8;
493 qinitid = host->this_id;
494 if (qinitid < 0)
495 qinitid = 7; /* if no ID, use 7 */
496 outb(1, qbase + 8); /* set for PIO pseudo DMA */
497 REG0;
498 outb(0xd0 | qinitid, qbase + 8); /* (ini) bus id, disable scsi rst */
499 outb(0x99, qbase + 5); /* select timer */
500 qlirq = -1;
501 #if QL_RESET_AT_START
502 outb( 3 , qbase + 3 );
503 REG1;
504 while( inb( qbase + 0xf ) & 4 );
505 REG0;
506 #endif
507 #if QL_USE_IRQ
508 /* IRQ probe - toggle pin and check request pending */
509 cli();
510 i = 0xffff;
511 j = 3;
512 outb(0x90, qbase + 3); /* illegal command - cause interrupt */
513 REG1;
514 outb(10, 0x20); /* access pending interrupt map */
515 outb(10, 0xa0);
516 while (j--) {
517 outb(0xb0 | QL_INT_ACTIVE_HIGH , qbase + 0xd); /* int pin off */
518 i &= ~(inb(0x20) | (inb(0xa0) << 8)); /* find IRQ off */
519 outb(0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd); /* int pin on */
520 i &= inb(0x20) | (inb(0xa0) << 8); /* find IRQ on */
521 }
522 REG0;
523 while (inb(qbase + 5)); /* purge int */
524 while (i) /* find on bit */
525 i >>= 1, qlirq++; /* should check for exactly 1 on */
526 if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, SA_INTERRUPT, "qlogic"))
527 host->can_queue = 1;
528 sti();
529 #endif
530 request_region( qbase , 0x10 ,"qlogic");
531
532 hreg = scsi_register( host , 0 ); /* no host data */
533 hreg->io_port = qbase;
534 hreg->n_io_port = 16;
535 if( qlirq != -1 )
536 hreg->irq = qlirq;
537
538 sprintf(qinfo, "Qlogic Driver version 0.38a, chip %02X at %03X, IRQ %d", qltyp, qbase, qlirq);
539 host->name = qinfo;
540
541 return 1;
542 }
543
544 /*----------------------------------------------------------------*/
545 /* return bios parameters */
546 int qlogic_biosparam(Disk * disk, int dev, int ip[])
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
547 {
548 /* This should mimic the DOS Qlogic driver's behavior exactly */
549 ip[0] = 0x40;
550 ip[1] = 0x20;
551 ip[2] = disk->capacity / (ip[0] * ip[1]);
552 if (ip[2] > 1024) {
553 ip[0] = 0xff;
554 ip[1] = 0x3f;
555 ip[2] = disk->capacity / (ip[0] * ip[1]);
556 if (ip[2] > 1023)
557 ip[2] = 1023;
558 }
559 return 0;
560 }
561
562 /*----------------------------------------------------------------*/
563 /* abort command in progress */
564 int qlogic_abort(Scsi_Cmnd * cmd)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
565 {
566 qabort = 1;
567 ql_zap();
568 return 0;
569 }
570
571 /*----------------------------------------------------------------*/
572 /* reset SCSI bus */
573 int qlogic_reset(Scsi_Cmnd * cmd)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
574 {
575 qabort = 2;
576 ql_zap();
577 return 1;
578 }
579
580 /*----------------------------------------------------------------*/
581 /* return info string */
582 const char *qlogic_info(struct Scsi_Host * host)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
583 {
584 return qinfo;
585 }
586
587 #ifdef MODULE
588 /* Eventually this will go into an include file, but this will be later */
589 Scsi_Host_Template driver_template = QLOGIC;
590
591 #include "scsi_module.c"
592 #endif