[PATCH] sem2mutex: iprune
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / scsi / fd_mcs.c
blobcca485a2b438b87e748f6cdcd7387d53076b2146
1 /* fd_mcs.c -- Future Domain MCS 600/700 (or IBM OEM) driver
3 * FutureDomain MCS-600/700 v0.2 03/11/1998 by ZP Gu (zpg@castle.net)
5 * This driver is cloned from fdomain.* to specifically support
6 * the Future Domain MCS 600/700 MCA SCSI adapters. Some PS/2s
7 * also equipped with IBM Fast SCSI Adapter/A which is an OEM
8 * of MCS 700.
10 * This driver also supports Reply SB16/SCSI card (the SCSI part).
12 * What makes this driver different is that this driver is MCA only
13 * and it supports multiple adapters in the same system, IRQ
14 * sharing, some driver statistics, and maps highest SCSI id to sda.
15 * All cards are auto-detected.
17 * Assumptions: TMC-1800/18C50/18C30, BIOS >= 3.4
19 * LILO command-line options:
20 * fd_mcs=<FIFO_COUNT>[,<FIFO_SIZE>]
22 * ********************************************************
23 * Please see Copyrights/Comments in fdomain.* for credits.
24 * Following is from fdomain.c for acknowledgement:
26 * Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu
27 * Revised: Wed Oct 2 11:10:55 1996 by r.faith@ieee.org
28 * Author: Rickard E. Faith, faith@cs.unc.edu
29 * Copyright 1992, 1993, 1994, 1995, 1996 Rickard E. Faith
31 * $Id: fdomain.c,v 5.45 1996/10/02 15:13:06 root Exp $
33 * This program is free software; you can redistribute it and/or modify it
34 * under the terms of the GNU General Public License as published by the
35 * Free Software Foundation; either version 2, or (at your option) any
36 * later version.
38 * This program is distributed in the hope that it will be useful, but
39 * WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41 * General Public License for more details.
43 * You should have received a copy of the GNU General Public License along
44 * with this program; if not, write to the Free Software Foundation, Inc.,
45 * 675 Mass Ave, Cambridge, MA 02139, USA.
47 **************************************************************************
49 NOTES ON USER DEFINABLE OPTIONS:
51 DEBUG: This turns on the printing of various debug information.
53 ENABLE_PARITY: This turns on SCSI parity checking. With the current
54 driver, all attached devices must support SCSI parity. If none of your
55 devices support parity, then you can probably get the driver to work by
56 turning this option off. I have no way of testing this, however, and it
57 would appear that no one ever uses this option.
59 FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the
60 18C30 chip have a 2k cache). When this many 512 byte blocks are filled by
61 the SCSI device, an interrupt will be raised. Therefore, this could be as
62 low as 0, or as high as 16. Note, however, that values which are too high
63 or too low seem to prevent any interrupts from occurring, and thereby lock
64 up the machine. I have found that 2 is a good number, but throughput may
65 be increased by changing this value to values which are close to 2.
66 Please let me know if you try any different values.
67 [*****Now a runtime option*****]
69 RESELECTION: This is no longer an option, since I gave up trying to
70 implement it in version 4.x of this driver. It did not improve
71 performance at all and made the driver unstable (because I never found one
72 of the two race conditions which were introduced by the multiple
73 outstanding command code). The instability seems a very high price to pay
74 just so that you don't have to wait for the tape to rewind. If you want
75 this feature implemented, send me patches. I'll be happy to send a copy
76 of my (broken) driver to anyone who would like to see a copy.
78 **************************************************************************/
80 #include <linux/module.h>
81 #include <linux/init.h>
82 #include <linux/interrupt.h>
83 #include <linux/blkdev.h>
84 #include <linux/errno.h>
85 #include <linux/string.h>
86 #include <linux/ioport.h>
87 #include <linux/proc_fs.h>
88 #include <linux/delay.h>
89 #include <linux/mca.h>
90 #include <linux/spinlock.h>
91 #include <scsi/scsicam.h>
92 #include <linux/mca-legacy.h>
94 #include <asm/io.h>
95 #include <asm/system.h>
97 #include "scsi.h"
98 #include <scsi/scsi_host.h>
100 #define DRIVER_VERSION "v0.2 by ZP Gu<zpg@castle.net>"
102 /* START OF USER DEFINABLE OPTIONS */
104 #define DEBUG 0 /* Enable debugging output */
105 #define ENABLE_PARITY 1 /* Enable SCSI Parity */
107 /* END OF USER DEFINABLE OPTIONS */
109 #if DEBUG
110 #define EVERY_ACCESS 0 /* Write a line on every scsi access */
111 #define ERRORS_ONLY 1 /* Only write a line if there is an error */
112 #define DEBUG_MESSAGES 1 /* Debug MESSAGE IN phase */
113 #define DEBUG_ABORT 1 /* Debug abort() routine */
114 #define DEBUG_RESET 1 /* Debug reset() routine */
115 #define DEBUG_RACE 1 /* Debug interrupt-driven race condition */
116 #else
117 #define EVERY_ACCESS 0 /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
118 #define ERRORS_ONLY 0
119 #define DEBUG_MESSAGES 0
120 #define DEBUG_ABORT 0
121 #define DEBUG_RESET 0
122 #define DEBUG_RACE 0
123 #endif
125 /* Errors are reported on the line, so we don't need to report them again */
126 #if EVERY_ACCESS
127 #undef ERRORS_ONLY
128 #define ERRORS_ONLY 0
129 #endif
131 #if ENABLE_PARITY
132 #define PARITY_MASK 0x08
133 #else
134 #define PARITY_MASK 0x00
135 #endif
137 enum chip_type {
138 unknown = 0x00,
139 tmc1800 = 0x01,
140 tmc18c50 = 0x02,
141 tmc18c30 = 0x03,
144 enum {
145 in_arbitration = 0x02,
146 in_selection = 0x04,
147 in_other = 0x08,
148 disconnect = 0x10,
149 aborted = 0x20,
150 sent_ident = 0x40,
153 enum in_port_type {
154 Read_SCSI_Data = 0,
155 SCSI_Status = 1,
156 TMC_Status = 2,
157 FIFO_Status = 3, /* tmc18c50/tmc18c30 only */
158 Interrupt_Cond = 4, /* tmc18c50/tmc18c30 only */
159 LSB_ID_Code = 5,
160 MSB_ID_Code = 6,
161 Read_Loopback = 7,
162 SCSI_Data_NoACK = 8,
163 Interrupt_Status = 9,
164 Configuration1 = 10,
165 Configuration2 = 11, /* tmc18c50/tmc18c30 only */
166 Read_FIFO = 12,
167 FIFO_Data_Count = 14
170 enum out_port_type {
171 Write_SCSI_Data = 0,
172 SCSI_Cntl = 1,
173 Interrupt_Cntl = 2,
174 SCSI_Mode_Cntl = 3,
175 TMC_Cntl = 4,
176 Memory_Cntl = 5, /* tmc18c50/tmc18c30 only */
177 Write_Loopback = 7,
178 IO_Control = 11, /* tmc18c30 only */
179 Write_FIFO = 12
182 struct fd_hostdata {
183 unsigned long _bios_base;
184 int _bios_major;
185 int _bios_minor;
186 volatile int _in_command;
187 Scsi_Cmnd *_current_SC;
188 enum chip_type _chip;
189 int _adapter_mask;
190 int _fifo_count; /* Number of 512 byte blocks before INTR */
192 char _adapter_name[64];
193 #if DEBUG_RACE
194 volatile int _in_interrupt_flag;
195 #endif
197 int _SCSI_Mode_Cntl_port;
198 int _FIFO_Data_Count_port;
199 int _Interrupt_Cntl_port;
200 int _Interrupt_Status_port;
201 int _Interrupt_Cond_port;
202 int _Read_FIFO_port;
203 int _Read_SCSI_Data_port;
204 int _SCSI_Cntl_port;
205 int _SCSI_Data_NoACK_port;
206 int _SCSI_Status_port;
207 int _TMC_Cntl_port;
208 int _TMC_Status_port;
209 int _Write_FIFO_port;
210 int _Write_SCSI_Data_port;
212 int _FIFO_Size; /* = 0x2000; 8k FIFO for
213 pre-tmc18c30 chips */
214 /* simple stats */
215 int _Bytes_Read;
216 int _Bytes_Written;
217 int _INTR_Processed;
220 #define FD_MAX_HOSTS 3 /* enough? */
222 #define HOSTDATA(shpnt) ((struct fd_hostdata *) shpnt->hostdata)
223 #define bios_base (HOSTDATA(shpnt)->_bios_base)
224 #define bios_major (HOSTDATA(shpnt)->_bios_major)
225 #define bios_minor (HOSTDATA(shpnt)->_bios_minor)
226 #define in_command (HOSTDATA(shpnt)->_in_command)
227 #define current_SC (HOSTDATA(shpnt)->_current_SC)
228 #define chip (HOSTDATA(shpnt)->_chip)
229 #define adapter_mask (HOSTDATA(shpnt)->_adapter_mask)
230 #define FIFO_COUNT (HOSTDATA(shpnt)->_fifo_count)
231 #define adapter_name (HOSTDATA(shpnt)->_adapter_name)
232 #if DEBUG_RACE
233 #define in_interrupt_flag (HOSTDATA(shpnt)->_in_interrupt_flag)
234 #endif
235 #define SCSI_Mode_Cntl_port (HOSTDATA(shpnt)->_SCSI_Mode_Cntl_port)
236 #define FIFO_Data_Count_port (HOSTDATA(shpnt)->_FIFO_Data_Count_port)
237 #define Interrupt_Cntl_port (HOSTDATA(shpnt)->_Interrupt_Cntl_port)
238 #define Interrupt_Status_port (HOSTDATA(shpnt)->_Interrupt_Status_port)
239 #define Interrupt_Cond_port (HOSTDATA(shpnt)->_Interrupt_Cond_port)
240 #define Read_FIFO_port (HOSTDATA(shpnt)->_Read_FIFO_port)
241 #define Read_SCSI_Data_port (HOSTDATA(shpnt)->_Read_SCSI_Data_port)
242 #define SCSI_Cntl_port (HOSTDATA(shpnt)->_SCSI_Cntl_port)
243 #define SCSI_Data_NoACK_port (HOSTDATA(shpnt)->_SCSI_Data_NoACK_port)
244 #define SCSI_Status_port (HOSTDATA(shpnt)->_SCSI_Status_port)
245 #define TMC_Cntl_port (HOSTDATA(shpnt)->_TMC_Cntl_port)
246 #define TMC_Status_port (HOSTDATA(shpnt)->_TMC_Status_port)
247 #define Write_FIFO_port (HOSTDATA(shpnt)->_Write_FIFO_port)
248 #define Write_SCSI_Data_port (HOSTDATA(shpnt)->_Write_SCSI_Data_port)
249 #define FIFO_Size (HOSTDATA(shpnt)->_FIFO_Size)
250 #define Bytes_Read (HOSTDATA(shpnt)->_Bytes_Read)
251 #define Bytes_Written (HOSTDATA(shpnt)->_Bytes_Written)
252 #define INTR_Processed (HOSTDATA(shpnt)->_INTR_Processed)
254 struct fd_mcs_adapters_struct {
255 char *name;
256 int id;
257 enum chip_type fd_chip;
258 int fifo_size;
259 int fifo_count;
262 #define REPLY_ID 0x5137
264 static struct fd_mcs_adapters_struct fd_mcs_adapters[] = {
265 {"Future Domain SCSI Adapter MCS-700(18C50)",
266 0x60e9,
267 tmc18c50,
268 0x2000,
270 {"Future Domain SCSI Adapter MCS-600/700(TMC-1800)",
271 0x6127,
272 tmc1800,
273 0x2000,
275 {"Reply Sound Blaster/SCSI Adapter",
276 REPLY_ID,
277 tmc18c30,
278 0x800,
282 #define FD_BRDS sizeof(fd_mcs_adapters)/sizeof(struct fd_mcs_adapters_struct)
284 static irqreturn_t fd_mcs_intr(int irq, void *dev_id, struct pt_regs *regs);
286 static unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000 };
287 static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
288 static unsigned short interrupts[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
290 /* host information */
291 static int found = 0;
292 static struct Scsi_Host *hosts[FD_MAX_HOSTS + 1] = { NULL };
294 static int user_fifo_count = 0;
295 static int user_fifo_size = 0;
297 static int __init fd_mcs_setup(char *str)
299 static int done_setup = 0;
300 int ints[3];
302 get_options(str, 3, ints);
303 if (done_setup++ || ints[0] < 1 || ints[0] > 2 || ints[1] < 1 || ints[1] > 16) {
304 printk("fd_mcs: usage: fd_mcs=FIFO_COUNT, FIFO_SIZE\n");
305 return 0;
308 user_fifo_count = ints[0] >= 1 ? ints[1] : 0;
309 user_fifo_size = ints[0] >= 2 ? ints[2] : 0;
310 return 1;
313 __setup("fd_mcs=", fd_mcs_setup);
315 static void print_banner(struct Scsi_Host *shpnt)
317 printk("scsi%d <fd_mcs>: ", shpnt->host_no);
319 if (bios_base) {
320 printk("BIOS at 0x%lX", bios_base);
321 } else {
322 printk("No BIOS");
325 printk(", HostID %d, %s Chip, IRQ %d, IO 0x%lX\n", shpnt->this_id, chip == tmc18c50 ? "TMC-18C50" : (chip == tmc18c30 ? "TMC-18C30" : (chip == tmc1800 ? "TMC-1800" : "Unknown")), shpnt->irq, shpnt->io_port);
329 static void do_pause(unsigned amount)
330 { /* Pause for amount*10 milliseconds */
331 do {
332 mdelay(10);
333 } while (--amount);
336 static void fd_mcs_make_bus_idle(struct Scsi_Host *shpnt)
338 outb(0, SCSI_Cntl_port);
339 outb(0, SCSI_Mode_Cntl_port);
340 if (chip == tmc18c50 || chip == tmc18c30)
341 outb(0x21 | PARITY_MASK, TMC_Cntl_port); /* Clear forced intr. */
342 else
343 outb(0x01 | PARITY_MASK, TMC_Cntl_port);
346 static int fd_mcs_detect(struct scsi_host_template * tpnt)
348 int loop;
349 struct Scsi_Host *shpnt;
351 /* get id, port, bios, irq */
352 int slot;
353 u_char pos2, pos3, pos4;
354 int id, port, irq;
355 unsigned long bios;
357 /* if not MCA machine, return */
358 if (!MCA_bus)
359 return 0;
361 /* changeable? */
362 id = 7;
364 for (loop = 0; loop < FD_BRDS; loop++) {
365 slot = 0;
366 while (MCA_NOTFOUND != (slot = mca_find_adapter(fd_mcs_adapters[loop].id, slot))) {
368 /* if we get this far, an adapter has been detected and is
369 enabled */
371 printk(KERN_INFO "scsi <fd_mcs>: %s at slot %d\n", fd_mcs_adapters[loop].name, slot + 1);
373 pos2 = mca_read_stored_pos(slot, 2);
374 pos3 = mca_read_stored_pos(slot, 3);
375 pos4 = mca_read_stored_pos(slot, 4);
377 /* ready for next probe */
378 slot++;
380 if (fd_mcs_adapters[loop].id == REPLY_ID) { /* reply card */
381 static int reply_irq[] = { 10, 11, 14, 15 };
383 bios = 0; /* no bios */
385 if (pos2 & 0x2)
386 port = ports[pos4 & 0x3];
387 else
388 continue;
390 /* can't really disable it, same as irq=10 */
391 irq = reply_irq[((pos4 >> 2) & 0x1) + 2 * ((pos4 >> 4) & 0x1)];
392 } else {
393 bios = addresses[pos2 >> 6];
394 port = ports[(pos2 >> 4) & 0x03];
395 irq = interrupts[(pos2 >> 1) & 0x07];
398 if (irq) {
399 /* claim the slot */
400 mca_set_adapter_name(slot - 1, fd_mcs_adapters[loop].name);
402 /* check irq/region */
403 if (request_irq(irq, fd_mcs_intr, SA_SHIRQ, "fd_mcs", hosts)) {
404 printk(KERN_ERR "fd_mcs: interrupt is not available, skipping...\n");
405 continue;
408 /* request I/O region */
409 if (request_region(port, 0x10, "fd_mcs")) {
410 printk(KERN_ERR "fd_mcs: I/O region is already in use, skipping...\n");
411 continue;
413 /* register */
414 if (!(shpnt = scsi_register(tpnt, sizeof(struct fd_hostdata)))) {
415 printk(KERN_ERR "fd_mcs: scsi_register() failed\n");
416 release_region(port, 0x10);
417 free_irq(irq, hosts);
418 continue;
422 /* save name */
423 strcpy(adapter_name, fd_mcs_adapters[loop].name);
425 /* chip/fifo */
426 chip = fd_mcs_adapters[loop].fd_chip;
427 /* use boot time value if available */
428 FIFO_COUNT = user_fifo_count ? user_fifo_count : fd_mcs_adapters[loop].fifo_count;
429 FIFO_Size = user_fifo_size ? user_fifo_size : fd_mcs_adapters[loop].fifo_size;
431 /* FIXME: Do we need to keep this bit of code inside NOT_USED around at all? */
432 #ifdef NOT_USED
433 /* *************************************************** */
434 /* Try to toggle 32-bit mode. This only
435 works on an 18c30 chip. (User reports
436 say this works, so we should switch to
437 it in the near future.) */
438 outb(0x80, port + IO_Control);
439 if ((inb(port + Configuration2) & 0x80) == 0x80) {
440 outb(0x00, port + IO_Control);
441 if ((inb(port + Configuration2) & 0x80) == 0x00) {
442 chip = tmc18c30;
443 FIFO_Size = 0x800; /* 2k FIFO */
445 printk("FIRST: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size);
449 /* That should have worked, but appears to
450 have problems. Let's assume it is an
451 18c30 if the RAM is disabled. */
453 if (inb(port + Configuration2) & 0x02) {
454 chip = tmc18c30;
455 FIFO_Size = 0x800; /* 2k FIFO */
457 printk("SECOND: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size);
459 /* *************************************************** */
460 #endif
462 /* IBM/ANSI scsi scan ordering */
463 /* Stick this back in when the scsi.c changes are there */
464 shpnt->reverse_ordering = 1;
467 /* saving info */
468 hosts[found++] = shpnt;
470 shpnt->this_id = id;
471 shpnt->irq = irq;
472 shpnt->io_port = port;
473 shpnt->n_io_port = 0x10;
475 /* save */
476 bios_base = bios;
477 adapter_mask = (1 << id);
479 /* save more */
480 SCSI_Mode_Cntl_port = port + SCSI_Mode_Cntl;
481 FIFO_Data_Count_port = port + FIFO_Data_Count;
482 Interrupt_Cntl_port = port + Interrupt_Cntl;
483 Interrupt_Status_port = port + Interrupt_Status;
484 Interrupt_Cond_port = port + Interrupt_Cond;
485 Read_FIFO_port = port + Read_FIFO;
486 Read_SCSI_Data_port = port + Read_SCSI_Data;
487 SCSI_Cntl_port = port + SCSI_Cntl;
488 SCSI_Data_NoACK_port = port + SCSI_Data_NoACK;
489 SCSI_Status_port = port + SCSI_Status;
490 TMC_Cntl_port = port + TMC_Cntl;
491 TMC_Status_port = port + TMC_Status;
492 Write_FIFO_port = port + Write_FIFO;
493 Write_SCSI_Data_port = port + Write_SCSI_Data;
495 Bytes_Read = 0;
496 Bytes_Written = 0;
497 INTR_Processed = 0;
499 /* say something */
500 print_banner(shpnt);
502 /* reset */
503 outb(1, SCSI_Cntl_port);
504 do_pause(2);
505 outb(0, SCSI_Cntl_port);
506 do_pause(115);
507 outb(0, SCSI_Mode_Cntl_port);
508 outb(PARITY_MASK, TMC_Cntl_port);
509 /* done reset */
513 if (found == FD_MAX_HOSTS) {
514 printk("fd_mcs: detecting reached max=%d host adapters.\n", FD_MAX_HOSTS);
515 break;
519 return found;
522 static const char *fd_mcs_info(struct Scsi_Host *shpnt)
524 return adapter_name;
527 static int TOTAL_INTR = 0;
530 * inout : decides on the direction of the dataflow and the meaning of the
531 * variables
532 * buffer: If inout==FALSE data is being written to it else read from it
533 * *start: If inout==FALSE start of the valid data in the buffer
534 * offset: If inout==FALSE offset from the beginning of the imaginary file
535 * from which we start writing into the buffer
536 * length: If inout==FALSE max number of bytes to be written into the buffer
537 * else number of bytes in the buffer
539 static int fd_mcs_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout)
541 int len = 0;
543 if (inout)
544 return (-ENOSYS);
546 *start = buffer + offset;
548 len += sprintf(buffer + len, "Future Domain MCS-600/700 Driver %s\n", DRIVER_VERSION);
549 len += sprintf(buffer + len, "HOST #%d: %s\n", shpnt->host_no, adapter_name);
550 len += sprintf(buffer + len, "FIFO Size=0x%x, FIFO Count=%d\n", FIFO_Size, FIFO_COUNT);
551 len += sprintf(buffer + len, "DriverCalls=%d, Interrupts=%d, BytesRead=%d, BytesWrite=%d\n\n", TOTAL_INTR, INTR_Processed, Bytes_Read, Bytes_Written);
553 if ((len -= offset) <= 0)
554 return 0;
555 if (len > length)
556 len = length;
557 return len;
560 static int fd_mcs_select(struct Scsi_Host *shpnt, int target)
562 int status;
563 unsigned long timeout;
565 outb(0x82, SCSI_Cntl_port); /* Bus Enable + Select */
566 outb(adapter_mask | (1 << target), SCSI_Data_NoACK_port);
568 /* Stop arbitration and enable parity */
569 outb(PARITY_MASK, TMC_Cntl_port);
571 timeout = 350; /* 350mS -- because of timeouts
572 (was 250mS) */
574 do {
575 status = inb(SCSI_Status_port); /* Read adapter status */
576 if (status & 1) { /* Busy asserted */
577 /* Enable SCSI Bus (on error, should make bus idle with 0) */
578 outb(0x80, SCSI_Cntl_port);
579 return 0;
581 udelay(1000); /* wait one msec */
582 } while (--timeout);
584 /* Make bus idle */
585 fd_mcs_make_bus_idle(shpnt);
586 #if EVERY_ACCESS
587 if (!target)
588 printk("Selection failed\n");
589 #endif
590 #if ERRORS_ONLY
591 if (!target) {
592 static int flag = 0;
594 if (!flag) /* Skip first failure for all chips. */
595 ++flag;
596 else
597 printk("fd_mcs: Selection failed\n");
599 #endif
600 return 1;
603 static void my_done(struct Scsi_Host *shpnt, int error)
605 if (in_command) {
606 in_command = 0;
607 outb(0x00, Interrupt_Cntl_port);
608 fd_mcs_make_bus_idle(shpnt);
609 current_SC->result = error;
610 current_SC->scsi_done(current_SC);
611 } else {
612 panic("fd_mcs: my_done() called outside of command\n");
614 #if DEBUG_RACE
615 in_interrupt_flag = 0;
616 #endif
619 /* only my_done needs to be protected */
620 static irqreturn_t fd_mcs_intr(int irq, void *dev_id, struct pt_regs *regs)
622 unsigned long flags;
623 int status;
624 int done = 0;
625 unsigned data_count, tmp_count;
627 int i = 0;
628 struct Scsi_Host *shpnt;
630 TOTAL_INTR++;
632 /* search for one adapter-response on shared interrupt */
633 while ((shpnt = hosts[i++])) {
634 if ((inb(TMC_Status_port)) & 1)
635 break;
638 /* return if some other device on this IRQ caused the interrupt */
639 if (!shpnt) {
640 return IRQ_NONE;
643 INTR_Processed++;
645 outb(0x00, Interrupt_Cntl_port);
647 /* Abort calls my_done, so we do nothing here. */
648 if (current_SC->SCp.phase & aborted) {
649 #if DEBUG_ABORT
650 printk("Interrupt after abort, ignoring\n");
651 #endif
652 /* return IRQ_HANDLED; */
654 #if DEBUG_RACE
655 ++in_interrupt_flag;
656 #endif
658 if (current_SC->SCp.phase & in_arbitration) {
659 status = inb(TMC_Status_port); /* Read adapter status */
660 if (!(status & 0x02)) {
661 #if EVERY_ACCESS
662 printk(" AFAIL ");
663 #endif
664 spin_lock_irqsave(shpnt->host_lock, flags);
665 my_done(shpnt, DID_BUS_BUSY << 16);
666 spin_unlock_irqrestore(shpnt->host_lock, flags);
667 return IRQ_HANDLED;
669 current_SC->SCp.phase = in_selection;
671 outb(0x40 | FIFO_COUNT, Interrupt_Cntl_port);
673 outb(0x82, SCSI_Cntl_port); /* Bus Enable + Select */
674 outb(adapter_mask | (1 << scmd_id(current_SC)), SCSI_Data_NoACK_port);
676 /* Stop arbitration and enable parity */
677 outb(0x10 | PARITY_MASK, TMC_Cntl_port);
678 #if DEBUG_RACE
679 in_interrupt_flag = 0;
680 #endif
681 return IRQ_HANDLED;
682 } else if (current_SC->SCp.phase & in_selection) {
683 status = inb(SCSI_Status_port);
684 if (!(status & 0x01)) {
685 /* Try again, for slow devices */
686 if (fd_mcs_select(shpnt, scmd_id(current_SC))) {
687 #if EVERY_ACCESS
688 printk(" SFAIL ");
689 #endif
690 spin_lock_irqsave(shpnt->host_lock, flags);
691 my_done(shpnt, DID_NO_CONNECT << 16);
692 spin_unlock_irqrestore(shpnt->host_lock, flags);
693 return IRQ_HANDLED;
694 } else {
695 #if EVERY_ACCESS
696 printk(" AltSel ");
697 #endif
698 /* Stop arbitration and enable parity */
699 outb(0x10 | PARITY_MASK, TMC_Cntl_port);
702 current_SC->SCp.phase = in_other;
703 outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port);
704 outb(0x80, SCSI_Cntl_port);
705 #if DEBUG_RACE
706 in_interrupt_flag = 0;
707 #endif
708 return IRQ_HANDLED;
711 /* current_SC->SCp.phase == in_other: this is the body of the routine */
713 status = inb(SCSI_Status_port);
715 if (status & 0x10) { /* REQ */
717 switch (status & 0x0e) {
719 case 0x08: /* COMMAND OUT */
720 outb(current_SC->cmnd[current_SC->SCp.sent_command++], Write_SCSI_Data_port);
721 #if EVERY_ACCESS
722 printk("CMD = %x,", current_SC->cmnd[current_SC->SCp.sent_command - 1]);
723 #endif
724 break;
725 case 0x00: /* DATA OUT -- tmc18c50/tmc18c30 only */
726 if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
727 current_SC->SCp.have_data_in = -1;
728 outb(0xd0 | PARITY_MASK, TMC_Cntl_port);
730 break;
731 case 0x04: /* DATA IN -- tmc18c50/tmc18c30 only */
732 if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
733 current_SC->SCp.have_data_in = 1;
734 outb(0x90 | PARITY_MASK, TMC_Cntl_port);
736 break;
737 case 0x0c: /* STATUS IN */
738 current_SC->SCp.Status = inb(Read_SCSI_Data_port);
739 #if EVERY_ACCESS
740 printk("Status = %x, ", current_SC->SCp.Status);
741 #endif
742 #if ERRORS_ONLY
743 if (current_SC->SCp.Status && current_SC->SCp.Status != 2 && current_SC->SCp.Status != 8) {
744 printk("ERROR fd_mcs: target = %d, command = %x, status = %x\n", current_SC->device->id, current_SC->cmnd[0], current_SC->SCp.Status);
746 #endif
747 break;
748 case 0x0a: /* MESSAGE OUT */
749 outb(MESSAGE_REJECT, Write_SCSI_Data_port); /* Reject */
750 break;
751 case 0x0e: /* MESSAGE IN */
752 current_SC->SCp.Message = inb(Read_SCSI_Data_port);
753 #if EVERY_ACCESS
754 printk("Message = %x, ", current_SC->SCp.Message);
755 #endif
756 if (!current_SC->SCp.Message)
757 ++done;
758 #if DEBUG_MESSAGES || EVERY_ACCESS
759 if (current_SC->SCp.Message) {
760 printk("fd_mcs: message = %x\n", current_SC->SCp.Message);
762 #endif
763 break;
767 if (chip == tmc1800 && !current_SC->SCp.have_data_in && (current_SC->SCp.sent_command >= current_SC->cmd_len)) {
768 /* We have to get the FIFO direction
769 correct, so I've made a table based
770 on the SCSI Standard of which commands
771 appear to require a DATA OUT phase.
774 p. 94: Command for all device types
775 CHANGE DEFINITION 40 DATA OUT
776 COMPARE 39 DATA OUT
777 COPY 18 DATA OUT
778 COPY AND VERIFY 3a DATA OUT
779 INQUIRY 12
780 LOG SELECT 4c DATA OUT
781 LOG SENSE 4d
782 MODE SELECT (6) 15 DATA OUT
783 MODE SELECT (10) 55 DATA OUT
784 MODE SENSE (6) 1a
785 MODE SENSE (10) 5a
786 READ BUFFER 3c
787 RECEIVE DIAGNOSTIC RESULTS 1c
788 REQUEST SENSE 03
789 SEND DIAGNOSTIC 1d DATA OUT
790 TEST UNIT READY 00
791 WRITE BUFFER 3b DATA OUT
793 p.178: Commands for direct-access devices (not listed on p. 94)
794 FORMAT UNIT 04 DATA OUT
795 LOCK-UNLOCK CACHE 36
796 PRE-FETCH 34
797 PREVENT-ALLOW MEDIUM REMOVAL 1e
798 READ (6)/RECEIVE 08
799 READ (10) 3c
800 READ CAPACITY 25
801 READ DEFECT DATA (10) 37
802 READ LONG 3e
803 REASSIGN BLOCKS 07 DATA OUT
804 RELEASE 17
805 RESERVE 16 DATA OUT
806 REZERO UNIT/REWIND 01
807 SEARCH DATA EQUAL (10) 31 DATA OUT
808 SEARCH DATA HIGH (10) 30 DATA OUT
809 SEARCH DATA LOW (10) 32 DATA OUT
810 SEEK (6) 0b
811 SEEK (10) 2b
812 SET LIMITS (10) 33
813 START STOP UNIT 1b
814 SYNCHRONIZE CACHE 35
815 VERIFY (10) 2f
816 WRITE (6)/PRINT/SEND 0a DATA OUT
817 WRITE (10)/SEND 2a DATA OUT
818 WRITE AND VERIFY (10) 2e DATA OUT
819 WRITE LONG 3f DATA OUT
820 WRITE SAME 41 DATA OUT ?
822 p. 261: Commands for sequential-access devices (not previously listed)
823 ERASE 19
824 LOAD UNLOAD 1b
825 LOCATE 2b
826 READ BLOCK LIMITS 05
827 READ POSITION 34
828 READ REVERSE 0f
829 RECOVER BUFFERED DATA 14
830 SPACE 11
831 WRITE FILEMARKS 10 ?
833 p. 298: Commands for printer devices (not previously listed)
834 ****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) *****
835 SLEW AND PRINT 0b DATA OUT -- same as seek
836 STOP PRINT 1b
837 SYNCHRONIZE BUFFER 10
839 p. 315: Commands for processor devices (not previously listed)
841 p. 321: Commands for write-once devices (not previously listed)
842 MEDIUM SCAN 38
843 READ (12) a8
844 SEARCH DATA EQUAL (12) b1 DATA OUT
845 SEARCH DATA HIGH (12) b0 DATA OUT
846 SEARCH DATA LOW (12) b2 DATA OUT
847 SET LIMITS (12) b3
848 VERIFY (12) af
849 WRITE (12) aa DATA OUT
850 WRITE AND VERIFY (12) ae DATA OUT
852 p. 332: Commands for CD-ROM devices (not previously listed)
853 PAUSE/RESUME 4b
854 PLAY AUDIO (10) 45
855 PLAY AUDIO (12) a5
856 PLAY AUDIO MSF 47
857 PLAY TRACK RELATIVE (10) 49
858 PLAY TRACK RELATIVE (12) a9
859 READ HEADER 44
860 READ SUB-CHANNEL 42
861 READ TOC 43
863 p. 370: Commands for scanner devices (not previously listed)
864 GET DATA BUFFER STATUS 34
865 GET WINDOW 25
866 OBJECT POSITION 31
867 SCAN 1b
868 SET WINDOW 24 DATA OUT
870 p. 391: Commands for optical memory devices (not listed)
871 ERASE (10) 2c
872 ERASE (12) ac
873 MEDIUM SCAN 38 DATA OUT
874 READ DEFECT DATA (12) b7
875 READ GENERATION 29
876 READ UPDATED BLOCK 2d
877 UPDATE BLOCK 3d DATA OUT
879 p. 419: Commands for medium changer devices (not listed)
880 EXCHANGE MEDIUM 46
881 INITIALIZE ELEMENT STATUS 07
882 MOVE MEDIUM a5
883 POSITION TO ELEMENT 2b
884 READ ELEMENT STATUS b8
885 REQUEST VOL. ELEMENT ADDRESS b5
886 SEND VOLUME TAG b6 DATA OUT
888 p. 454: Commands for communications devices (not listed previously)
889 GET MESSAGE (6) 08
890 GET MESSAGE (10) 28
891 GET MESSAGE (12) a8
894 switch (current_SC->cmnd[0]) {
895 case CHANGE_DEFINITION:
896 case COMPARE:
897 case COPY:
898 case COPY_VERIFY:
899 case LOG_SELECT:
900 case MODE_SELECT:
901 case MODE_SELECT_10:
902 case SEND_DIAGNOSTIC:
903 case WRITE_BUFFER:
905 case FORMAT_UNIT:
906 case REASSIGN_BLOCKS:
907 case RESERVE:
908 case SEARCH_EQUAL:
909 case SEARCH_HIGH:
910 case SEARCH_LOW:
911 case WRITE_6:
912 case WRITE_10:
913 case WRITE_VERIFY:
914 case 0x3f:
915 case 0x41:
917 case 0xb1:
918 case 0xb0:
919 case 0xb2:
920 case 0xaa:
921 case 0xae:
923 case 0x24:
925 case 0x38:
926 case 0x3d:
928 case 0xb6:
930 case 0xea: /* alternate number for WRITE LONG */
932 current_SC->SCp.have_data_in = -1;
933 outb(0xd0 | PARITY_MASK, TMC_Cntl_port);
934 break;
936 case 0x00:
937 default:
939 current_SC->SCp.have_data_in = 1;
940 outb(0x90 | PARITY_MASK, TMC_Cntl_port);
941 break;
945 if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */
946 while ((data_count = FIFO_Size - inw(FIFO_Data_Count_port)) > 512) {
947 #if EVERY_ACCESS
948 printk("DC=%d, ", data_count);
949 #endif
950 if (data_count > current_SC->SCp.this_residual)
951 data_count = current_SC->SCp.this_residual;
952 if (data_count > 0) {
953 #if EVERY_ACCESS
954 printk("%d OUT, ", data_count);
955 #endif
956 if (data_count == 1) {
957 Bytes_Written++;
959 outb(*current_SC->SCp.ptr++, Write_FIFO_port);
960 --current_SC->SCp.this_residual;
961 } else {
962 data_count >>= 1;
963 tmp_count = data_count << 1;
964 outsw(Write_FIFO_port, current_SC->SCp.ptr, data_count);
965 current_SC->SCp.ptr += tmp_count;
966 Bytes_Written += tmp_count;
967 current_SC->SCp.this_residual -= tmp_count;
970 if (!current_SC->SCp.this_residual) {
971 if (current_SC->SCp.buffers_residual) {
972 --current_SC->SCp.buffers_residual;
973 ++current_SC->SCp.buffer;
974 current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
975 current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
976 } else
977 break;
980 } else if (current_SC->SCp.have_data_in == 1) { /* DATA IN */
981 while ((data_count = inw(FIFO_Data_Count_port)) > 0) {
982 #if EVERY_ACCESS
983 printk("DC=%d, ", data_count);
984 #endif
985 if (data_count > current_SC->SCp.this_residual)
986 data_count = current_SC->SCp.this_residual;
987 if (data_count) {
988 #if EVERY_ACCESS
989 printk("%d IN, ", data_count);
990 #endif
991 if (data_count == 1) {
992 Bytes_Read++;
993 *current_SC->SCp.ptr++ = inb(Read_FIFO_port);
994 --current_SC->SCp.this_residual;
995 } else {
996 data_count >>= 1; /* Number of words */
997 tmp_count = data_count << 1;
998 insw(Read_FIFO_port, current_SC->SCp.ptr, data_count);
999 current_SC->SCp.ptr += tmp_count;
1000 Bytes_Read += tmp_count;
1001 current_SC->SCp.this_residual -= tmp_count;
1004 if (!current_SC->SCp.this_residual && current_SC->SCp.buffers_residual) {
1005 --current_SC->SCp.buffers_residual;
1006 ++current_SC->SCp.buffer;
1007 current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
1008 current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
1013 if (done) {
1014 #if EVERY_ACCESS
1015 printk(" ** IN DONE %d ** ", current_SC->SCp.have_data_in);
1016 #endif
1018 #if ERRORS_ONLY
1019 if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
1020 if ((unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f) {
1021 unsigned char key;
1022 unsigned char code;
1023 unsigned char qualifier;
1025 key = (unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f;
1026 code = (unsigned char) (*((char *) current_SC->request_buffer + 12));
1027 qualifier = (unsigned char) (*((char *) current_SC->request_buffer + 13));
1029 if (key != UNIT_ATTENTION && !(key == NOT_READY && code == 0x04 && (!qualifier || qualifier == 0x02 || qualifier == 0x01))
1030 && !(key == ILLEGAL_REQUEST && (code == 0x25 || code == 0x24 || !code)))
1032 printk("fd_mcs: REQUEST SENSE " "Key = %x, Code = %x, Qualifier = %x\n", key, code, qualifier);
1035 #endif
1036 #if EVERY_ACCESS
1037 printk("BEFORE MY_DONE. . .");
1038 #endif
1039 spin_lock_irqsave(shpnt->host_lock, flags);
1040 my_done(shpnt, (current_SC->SCp.Status & 0xff)
1041 | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
1042 spin_unlock_irqrestore(shpnt->host_lock, flags);
1043 #if EVERY_ACCESS
1044 printk("RETURNING.\n");
1045 #endif
1047 } else {
1048 if (current_SC->SCp.phase & disconnect) {
1049 outb(0xd0 | FIFO_COUNT, Interrupt_Cntl_port);
1050 outb(0x00, SCSI_Cntl_port);
1051 } else {
1052 outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port);
1055 #if DEBUG_RACE
1056 in_interrupt_flag = 0;
1057 #endif
1058 return IRQ_HANDLED;
1061 static int fd_mcs_release(struct Scsi_Host *shpnt)
1063 int i, this_host, irq_usage;
1065 release_region(shpnt->io_port, shpnt->n_io_port);
1067 this_host = -1;
1068 irq_usage = 0;
1069 for (i = 0; i < found; i++) {
1070 if (shpnt == hosts[i])
1071 this_host = i;
1072 if (shpnt->irq == hosts[i]->irq)
1073 irq_usage++;
1076 /* only for the last one */
1077 if (1 == irq_usage)
1078 free_irq(shpnt->irq, hosts);
1080 found--;
1082 for (i = this_host; i < found; i++)
1083 hosts[i] = hosts[i + 1];
1085 hosts[found] = NULL;
1087 return 0;
1090 static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
1092 struct Scsi_Host *shpnt = SCpnt->device->host;
1094 if (in_command) {
1095 panic("fd_mcs: fd_mcs_queue() NOT REENTRANT!\n");
1097 #if EVERY_ACCESS
1098 printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->target, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
1099 #endif
1101 fd_mcs_make_bus_idle(shpnt);
1103 SCpnt->scsi_done = done; /* Save this for the done function */
1104 current_SC = SCpnt;
1106 /* Initialize static data */
1108 if (current_SC->use_sg) {
1109 current_SC->SCp.buffer = (struct scatterlist *) current_SC->request_buffer;
1110 current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
1111 current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
1112 current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
1113 } else {
1114 current_SC->SCp.ptr = (char *) current_SC->request_buffer;
1115 current_SC->SCp.this_residual = current_SC->request_bufflen;
1116 current_SC->SCp.buffer = NULL;
1117 current_SC->SCp.buffers_residual = 0;
1121 current_SC->SCp.Status = 0;
1122 current_SC->SCp.Message = 0;
1123 current_SC->SCp.have_data_in = 0;
1124 current_SC->SCp.sent_command = 0;
1125 current_SC->SCp.phase = in_arbitration;
1127 /* Start arbitration */
1128 outb(0x00, Interrupt_Cntl_port);
1129 outb(0x00, SCSI_Cntl_port); /* Disable data drivers */
1130 outb(adapter_mask, SCSI_Data_NoACK_port); /* Set our id bit */
1131 in_command = 1;
1132 outb(0x20, Interrupt_Cntl_port);
1133 outb(0x14 | PARITY_MASK, TMC_Cntl_port); /* Start arbitration */
1135 return 0;
1138 #if DEBUG_ABORT || DEBUG_RESET
1139 static void fd_mcs_print_info(Scsi_Cmnd * SCpnt)
1141 unsigned int imr;
1142 unsigned int irr;
1143 unsigned int isr;
1144 struct Scsi_Host *shpnt = SCpnt->host;
1146 if (!SCpnt || !SCpnt->host) {
1147 printk("fd_mcs: cannot provide detailed information\n");
1150 printk("%s\n", fd_mcs_info(SCpnt->host));
1151 print_banner(SCpnt->host);
1152 switch (SCpnt->SCp.phase) {
1153 case in_arbitration:
1154 printk("arbitration ");
1155 break;
1156 case in_selection:
1157 printk("selection ");
1158 break;
1159 case in_other:
1160 printk("other ");
1161 break;
1162 default:
1163 printk("unknown ");
1164 break;
1167 printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
1168 printk("sent_command = %d, have_data_in = %d, timeout = %d\n", SCpnt->SCp.sent_command, SCpnt->SCp.have_data_in, SCpnt->timeout);
1169 #if DEBUG_RACE
1170 printk("in_interrupt_flag = %d\n", in_interrupt_flag);
1171 #endif
1173 imr = (inb(0x0a1) << 8) + inb(0x21);
1174 outb(0x0a, 0xa0);
1175 irr = inb(0xa0) << 8;
1176 outb(0x0a, 0x20);
1177 irr += inb(0x20);
1178 outb(0x0b, 0xa0);
1179 isr = inb(0xa0) << 8;
1180 outb(0x0b, 0x20);
1181 isr += inb(0x20);
1183 /* Print out interesting information */
1184 printk("IMR = 0x%04x", imr);
1185 if (imr & (1 << shpnt->irq))
1186 printk(" (masked)");
1187 printk(", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr);
1189 printk("SCSI Status = 0x%02x\n", inb(SCSI_Status_port));
1190 printk("TMC Status = 0x%02x", inb(TMC_Status_port));
1191 if (inb(TMC_Status_port) & 1)
1192 printk(" (interrupt)");
1193 printk("\n");
1194 printk("Interrupt Status = 0x%02x", inb(Interrupt_Status_port));
1195 if (inb(Interrupt_Status_port) & 0x08)
1196 printk(" (enabled)");
1197 printk("\n");
1198 if (chip == tmc18c50 || chip == tmc18c30) {
1199 printk("FIFO Status = 0x%02x\n", inb(shpnt->io_port + FIFO_Status));
1200 printk("Int. Condition = 0x%02x\n", inb(shpnt->io_port + Interrupt_Cond));
1202 printk("Configuration 1 = 0x%02x\n", inb(shpnt->io_port + Configuration1));
1203 if (chip == tmc18c50 || chip == tmc18c30)
1204 printk("Configuration 2 = 0x%02x\n", inb(shpnt->io_port + Configuration2));
1206 #endif
1208 static int fd_mcs_abort(Scsi_Cmnd * SCpnt)
1210 struct Scsi_Host *shpnt = SCpnt->device->host;
1212 unsigned long flags;
1213 #if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
1214 printk("fd_mcs: abort ");
1215 #endif
1217 spin_lock_irqsave(shpnt->host_lock, flags);
1218 if (!in_command) {
1219 #if EVERY_ACCESS || ERRORS_ONLY
1220 printk(" (not in command)\n");
1221 #endif
1222 spin_unlock_irqrestore(shpnt->host_lock, flags);
1223 return FAILED;
1224 } else
1225 printk("\n");
1227 #if DEBUG_ABORT
1228 fd_mcs_print_info(SCpnt);
1229 #endif
1231 fd_mcs_make_bus_idle(shpnt);
1233 current_SC->SCp.phase |= aborted;
1235 current_SC->result = DID_ABORT << 16;
1237 /* Aborts are not done well. . . */
1238 my_done(shpnt, DID_ABORT << 16);
1240 spin_unlock_irqrestore(shpnt->host_lock, flags);
1241 return SUCCESS;
1244 static int fd_mcs_bus_reset(Scsi_Cmnd * SCpnt) {
1245 struct Scsi_Host *shpnt = SCpnt->device->host;
1246 unsigned long flags;
1248 #if DEBUG_RESET
1249 static int called_once = 0;
1250 #endif
1252 #if ERRORS_ONLY
1253 if (SCpnt)
1254 printk("fd_mcs: SCSI Bus Reset\n");
1255 #endif
1257 #if DEBUG_RESET
1258 if (called_once)
1259 fd_mcs_print_info(current_SC);
1260 called_once = 1;
1261 #endif
1263 spin_lock_irqsave(shpnt->host_lock, flags);
1265 outb(1, SCSI_Cntl_port);
1266 do_pause(2);
1267 outb(0, SCSI_Cntl_port);
1268 do_pause(115);
1269 outb(0, SCSI_Mode_Cntl_port);
1270 outb(PARITY_MASK, TMC_Cntl_port);
1272 spin_unlock_irqrestore(shpnt->host_lock, flags);
1274 /* Unless this is the very first call (i.e., SCPnt == NULL), everything
1275 is probably hosed at this point. We will, however, try to keep
1276 things going by informing the high-level code that we need help. */
1277 return SUCCESS;
1280 #include <scsi/scsi_ioctl.h>
1282 static int fd_mcs_biosparam(struct scsi_device * disk, struct block_device *bdev,
1283 sector_t capacity, int *info_array)
1285 unsigned char *p = scsi_bios_ptable(bdev);
1286 int size = capacity;
1288 /* BIOS >= 3.4 for MCA cards */
1289 /* This algorithm was provided by Future Domain (much thanks!). */
1291 if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */
1292 && p[4]) { /* Partition type */
1293 /* The partition table layout is as follows:
1295 Start: 0x1b3h
1296 Offset: 0 = partition status
1297 1 = starting head
1298 2 = starting sector and cylinder (word, encoded)
1299 4 = partition type
1300 5 = ending head
1301 6 = ending sector and cylinder (word, encoded)
1302 8 = starting absolute sector (double word)
1303 c = number of sectors (double word)
1304 Signature: 0x1fe = 0x55aa
1306 So, this algorithm assumes:
1307 1) the first partition table is in use,
1308 2) the data in the first entry is correct, and
1309 3) partitions never divide cylinders
1311 Note that (1) may be FALSE for NetBSD (and other BSD flavors),
1312 as well as for Linux. Note also, that Linux doesn't pay any
1313 attention to the fields that are used by this algorithm -- it
1314 only uses the absolute sector data. Recent versions of Linux's
1315 fdisk(1) will fill this data in correctly, and forthcoming
1316 versions will check for consistency.
1318 Checking for a non-zero partition type is not part of the
1319 Future Domain algorithm, but it seemed to be a reasonable thing
1320 to do, especially in the Linux and BSD worlds. */
1322 info_array[0] = p[5] + 1; /* heads */
1323 info_array[1] = p[6] & 0x3f; /* sectors */
1324 } else {
1325 /* Note that this new method guarantees that there will always be
1326 less than 1024 cylinders on a platter. This is good for drives
1327 up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
1328 if ((unsigned int) size >= 0x7e0000U)
1330 info_array[0] = 0xff; /* heads = 255 */
1331 info_array[1] = 0x3f; /* sectors = 63 */
1332 } else if ((unsigned int) size >= 0x200000U) {
1333 info_array[0] = 0x80; /* heads = 128 */
1334 info_array[1] = 0x3f; /* sectors = 63 */
1335 } else {
1336 info_array[0] = 0x40; /* heads = 64 */
1337 info_array[1] = 0x20; /* sectors = 32 */
1340 /* For both methods, compute the cylinders */
1341 info_array[2] = (unsigned int) size / (info_array[0] * info_array[1]);
1342 kfree(p);
1343 return 0;
1346 static struct scsi_host_template driver_template = {
1347 .proc_name = "fd_mcs",
1348 .proc_info = fd_mcs_proc_info,
1349 .detect = fd_mcs_detect,
1350 .release = fd_mcs_release,
1351 .info = fd_mcs_info,
1352 .queuecommand = fd_mcs_queue,
1353 .eh_abort_handler = fd_mcs_abort,
1354 .eh_bus_reset_handler = fd_mcs_bus_reset,
1355 .bios_param = fd_mcs_biosparam,
1356 .can_queue = 1,
1357 .this_id = 7,
1358 .sg_tablesize = 64,
1359 .cmd_per_lun = 1,
1360 .use_clustering = DISABLE_CLUSTERING,
1362 #include "scsi_module.c"
1364 MODULE_LICENSE("GPL");