blob: 2ad95aa8f58536a664a4c7d2114c4505d27355fe [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* fd_mcs.c -- Future Domain MCS 600/700 (or IBM OEM) driver
2 *
3 * FutureDomain MCS-600/700 v0.2 03/11/1998 by ZP Gu (zpg@castle.net)
4 *
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.
9 *
10 * This driver also supports Reply SB16/SCSI card (the SCSI part).
11 *
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.
16 *
17 * Assumptions: TMC-1800/18C50/18C30, BIOS >= 3.4
18 *
19 * LILO command-line options:
20 * fd_mcs=<FIFO_COUNT>[,<FIFO_SIZE>]
21 *
22 * ********************************************************
23 * Please see Copyrights/Comments in fdomain.* for credits.
24 * Following is from fdomain.c for acknowledgement:
25 *
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
30 *
31 * $Id: fdomain.c,v 5.45 1996/10/02 15:13:06 root Exp $
32
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.
37
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.
42
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.
46
47 **************************************************************************
48
49 NOTES ON USER DEFINABLE OPTIONS:
50
51 DEBUG: This turns on the printing of various debug information.
52
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.
58
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*****]
68
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.
77
78 **************************************************************************/
79
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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090091#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070092#include <scsi/scsicam.h>
93#include <linux/mca-legacy.h>
94
95#include <asm/io.h>
96#include <asm/system.h>
97
98#include "scsi.h"
99#include <scsi/scsi_host.h>
100
101#define DRIVER_VERSION "v0.2 by ZP Gu<zpg@castle.net>"
102
103/* START OF USER DEFINABLE OPTIONS */
104
105#define DEBUG 0 /* Enable debugging output */
106#define ENABLE_PARITY 1 /* Enable SCSI Parity */
107
108/* END OF USER DEFINABLE OPTIONS */
109
110#if DEBUG
111#define EVERY_ACCESS 0 /* Write a line on every scsi access */
112#define ERRORS_ONLY 1 /* Only write a line if there is an error */
113#define DEBUG_MESSAGES 1 /* Debug MESSAGE IN phase */
114#define DEBUG_ABORT 1 /* Debug abort() routine */
115#define DEBUG_RESET 1 /* Debug reset() routine */
116#define DEBUG_RACE 1 /* Debug interrupt-driven race condition */
117#else
118#define EVERY_ACCESS 0 /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
119#define ERRORS_ONLY 0
120#define DEBUG_MESSAGES 0
121#define DEBUG_ABORT 0
122#define DEBUG_RESET 0
123#define DEBUG_RACE 0
124#endif
125
126/* Errors are reported on the line, so we don't need to report them again */
127#if EVERY_ACCESS
128#undef ERRORS_ONLY
129#define ERRORS_ONLY 0
130#endif
131
132#if ENABLE_PARITY
133#define PARITY_MASK 0x08
134#else
135#define PARITY_MASK 0x00
136#endif
137
138enum chip_type {
139 unknown = 0x00,
140 tmc1800 = 0x01,
141 tmc18c50 = 0x02,
142 tmc18c30 = 0x03,
143};
144
145enum {
146 in_arbitration = 0x02,
147 in_selection = 0x04,
148 in_other = 0x08,
149 disconnect = 0x10,
150 aborted = 0x20,
151 sent_ident = 0x40,
152};
153
154enum in_port_type {
155 Read_SCSI_Data = 0,
156 SCSI_Status = 1,
157 TMC_Status = 2,
158 FIFO_Status = 3, /* tmc18c50/tmc18c30 only */
159 Interrupt_Cond = 4, /* tmc18c50/tmc18c30 only */
160 LSB_ID_Code = 5,
161 MSB_ID_Code = 6,
162 Read_Loopback = 7,
163 SCSI_Data_NoACK = 8,
164 Interrupt_Status = 9,
165 Configuration1 = 10,
166 Configuration2 = 11, /* tmc18c50/tmc18c30 only */
167 Read_FIFO = 12,
168 FIFO_Data_Count = 14
169};
170
171enum out_port_type {
172 Write_SCSI_Data = 0,
173 SCSI_Cntl = 1,
174 Interrupt_Cntl = 2,
175 SCSI_Mode_Cntl = 3,
176 TMC_Cntl = 4,
177 Memory_Cntl = 5, /* tmc18c50/tmc18c30 only */
178 Write_Loopback = 7,
179 IO_Control = 11, /* tmc18c30 only */
180 Write_FIFO = 12
181};
182
183struct fd_hostdata {
184 unsigned long _bios_base;
185 int _bios_major;
186 int _bios_minor;
187 volatile int _in_command;
188 Scsi_Cmnd *_current_SC;
189 enum chip_type _chip;
190 int _adapter_mask;
191 int _fifo_count; /* Number of 512 byte blocks before INTR */
192
193 char _adapter_name[64];
194#if DEBUG_RACE
195 volatile int _in_interrupt_flag;
196#endif
197
198 int _SCSI_Mode_Cntl_port;
199 int _FIFO_Data_Count_port;
200 int _Interrupt_Cntl_port;
201 int _Interrupt_Status_port;
202 int _Interrupt_Cond_port;
203 int _Read_FIFO_port;
204 int _Read_SCSI_Data_port;
205 int _SCSI_Cntl_port;
206 int _SCSI_Data_NoACK_port;
207 int _SCSI_Status_port;
208 int _TMC_Cntl_port;
209 int _TMC_Status_port;
210 int _Write_FIFO_port;
211 int _Write_SCSI_Data_port;
212
213 int _FIFO_Size; /* = 0x2000; 8k FIFO for
214 pre-tmc18c30 chips */
215 /* simple stats */
216 int _Bytes_Read;
217 int _Bytes_Written;
218 int _INTR_Processed;
219};
220
221#define FD_MAX_HOSTS 3 /* enough? */
222
223#define HOSTDATA(shpnt) ((struct fd_hostdata *) shpnt->hostdata)
224#define bios_base (HOSTDATA(shpnt)->_bios_base)
225#define bios_major (HOSTDATA(shpnt)->_bios_major)
226#define bios_minor (HOSTDATA(shpnt)->_bios_minor)
227#define in_command (HOSTDATA(shpnt)->_in_command)
228#define current_SC (HOSTDATA(shpnt)->_current_SC)
229#define chip (HOSTDATA(shpnt)->_chip)
230#define adapter_mask (HOSTDATA(shpnt)->_adapter_mask)
231#define FIFO_COUNT (HOSTDATA(shpnt)->_fifo_count)
232#define adapter_name (HOSTDATA(shpnt)->_adapter_name)
233#if DEBUG_RACE
234#define in_interrupt_flag (HOSTDATA(shpnt)->_in_interrupt_flag)
235#endif
236#define SCSI_Mode_Cntl_port (HOSTDATA(shpnt)->_SCSI_Mode_Cntl_port)
237#define FIFO_Data_Count_port (HOSTDATA(shpnt)->_FIFO_Data_Count_port)
238#define Interrupt_Cntl_port (HOSTDATA(shpnt)->_Interrupt_Cntl_port)
239#define Interrupt_Status_port (HOSTDATA(shpnt)->_Interrupt_Status_port)
240#define Interrupt_Cond_port (HOSTDATA(shpnt)->_Interrupt_Cond_port)
241#define Read_FIFO_port (HOSTDATA(shpnt)->_Read_FIFO_port)
242#define Read_SCSI_Data_port (HOSTDATA(shpnt)->_Read_SCSI_Data_port)
243#define SCSI_Cntl_port (HOSTDATA(shpnt)->_SCSI_Cntl_port)
244#define SCSI_Data_NoACK_port (HOSTDATA(shpnt)->_SCSI_Data_NoACK_port)
245#define SCSI_Status_port (HOSTDATA(shpnt)->_SCSI_Status_port)
246#define TMC_Cntl_port (HOSTDATA(shpnt)->_TMC_Cntl_port)
247#define TMC_Status_port (HOSTDATA(shpnt)->_TMC_Status_port)
248#define Write_FIFO_port (HOSTDATA(shpnt)->_Write_FIFO_port)
249#define Write_SCSI_Data_port (HOSTDATA(shpnt)->_Write_SCSI_Data_port)
250#define FIFO_Size (HOSTDATA(shpnt)->_FIFO_Size)
251#define Bytes_Read (HOSTDATA(shpnt)->_Bytes_Read)
252#define Bytes_Written (HOSTDATA(shpnt)->_Bytes_Written)
253#define INTR_Processed (HOSTDATA(shpnt)->_INTR_Processed)
254
255struct fd_mcs_adapters_struct {
256 char *name;
257 int id;
258 enum chip_type fd_chip;
259 int fifo_size;
260 int fifo_count;
261};
262
263#define REPLY_ID 0x5137
264
265static struct fd_mcs_adapters_struct fd_mcs_adapters[] = {
266 {"Future Domain SCSI Adapter MCS-700(18C50)",
267 0x60e9,
268 tmc18c50,
269 0x2000,
270 4},
271 {"Future Domain SCSI Adapter MCS-600/700(TMC-1800)",
272 0x6127,
273 tmc1800,
274 0x2000,
275 4},
276 {"Reply Sound Blaster/SCSI Adapter",
277 REPLY_ID,
278 tmc18c30,
279 0x800,
280 2},
281};
282
Tobias Klauser6391a112006-06-08 22:23:48 -0700283#define FD_BRDS ARRAY_SIZE(fd_mcs_adapters)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
David Howells7d12e782006-10-05 14:55:46 +0100285static irqreturn_t fd_mcs_intr(int irq, void *dev_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287static unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000 };
288static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
289static unsigned short interrupts[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
290
291/* host information */
292static int found = 0;
293static struct Scsi_Host *hosts[FD_MAX_HOSTS + 1] = { NULL };
294
295static int user_fifo_count = 0;
296static int user_fifo_size = 0;
297
Jeff Garzikdb3a8812006-11-08 19:56:20 -0800298#ifndef MODULE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299static int __init fd_mcs_setup(char *str)
300{
301 static int done_setup = 0;
302 int ints[3];
303
304 get_options(str, 3, ints);
305 if (done_setup++ || ints[0] < 1 || ints[0] > 2 || ints[1] < 1 || ints[1] > 16) {
306 printk("fd_mcs: usage: fd_mcs=FIFO_COUNT, FIFO_SIZE\n");
307 return 0;
308 }
309
310 user_fifo_count = ints[0] >= 1 ? ints[1] : 0;
311 user_fifo_size = ints[0] >= 2 ? ints[2] : 0;
312 return 1;
313}
314
315__setup("fd_mcs=", fd_mcs_setup);
Jeff Garzikdb3a8812006-11-08 19:56:20 -0800316#endif /* !MODULE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318static void print_banner(struct Scsi_Host *shpnt)
319{
320 printk("scsi%d <fd_mcs>: ", shpnt->host_no);
321
322 if (bios_base) {
323 printk("BIOS at 0x%lX", bios_base);
324 } else {
325 printk("No BIOS");
326 }
327
328 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}
330
331
332static void do_pause(unsigned amount)
333{ /* Pause for amount*10 milliseconds */
334 do {
335 mdelay(10);
336 } while (--amount);
337}
338
339static void fd_mcs_make_bus_idle(struct Scsi_Host *shpnt)
340{
341 outb(0, SCSI_Cntl_port);
342 outb(0, SCSI_Mode_Cntl_port);
343 if (chip == tmc18c50 || chip == tmc18c30)
344 outb(0x21 | PARITY_MASK, TMC_Cntl_port); /* Clear forced intr. */
345 else
346 outb(0x01 | PARITY_MASK, TMC_Cntl_port);
347}
348
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +0100349static int fd_mcs_detect(struct scsi_host_template * tpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
351 int loop;
352 struct Scsi_Host *shpnt;
353
354 /* get id, port, bios, irq */
355 int slot;
356 u_char pos2, pos3, pos4;
357 int id, port, irq;
358 unsigned long bios;
359
360 /* if not MCA machine, return */
361 if (!MCA_bus)
362 return 0;
363
364 /* changeable? */
365 id = 7;
366
367 for (loop = 0; loop < FD_BRDS; loop++) {
368 slot = 0;
369 while (MCA_NOTFOUND != (slot = mca_find_adapter(fd_mcs_adapters[loop].id, slot))) {
370
371 /* if we get this far, an adapter has been detected and is
372 enabled */
373
374 printk(KERN_INFO "scsi <fd_mcs>: %s at slot %d\n", fd_mcs_adapters[loop].name, slot + 1);
375
376 pos2 = mca_read_stored_pos(slot, 2);
377 pos3 = mca_read_stored_pos(slot, 3);
378 pos4 = mca_read_stored_pos(slot, 4);
379
380 /* ready for next probe */
381 slot++;
382
383 if (fd_mcs_adapters[loop].id == REPLY_ID) { /* reply card */
384 static int reply_irq[] = { 10, 11, 14, 15 };
385
386 bios = 0; /* no bios */
387
388 if (pos2 & 0x2)
389 port = ports[pos4 & 0x3];
390 else
391 continue;
392
393 /* can't really disable it, same as irq=10 */
394 irq = reply_irq[((pos4 >> 2) & 0x1) + 2 * ((pos4 >> 4) & 0x1)];
395 } else {
396 bios = addresses[pos2 >> 6];
397 port = ports[(pos2 >> 4) & 0x03];
398 irq = interrupts[(pos2 >> 1) & 0x07];
399 }
400
401 if (irq) {
402 /* claim the slot */
403 mca_set_adapter_name(slot - 1, fd_mcs_adapters[loop].name);
404
405 /* check irq/region */
Thomas Gleixner1d6f3592006-07-01 19:29:42 -0700406 if (request_irq(irq, fd_mcs_intr, IRQF_SHARED, "fd_mcs", hosts)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 printk(KERN_ERR "fd_mcs: interrupt is not available, skipping...\n");
408 continue;
409 }
410
411 /* request I/O region */
412 if (request_region(port, 0x10, "fd_mcs")) {
413 printk(KERN_ERR "fd_mcs: I/O region is already in use, skipping...\n");
414 continue;
415 }
416 /* register */
417 if (!(shpnt = scsi_register(tpnt, sizeof(struct fd_hostdata)))) {
418 printk(KERN_ERR "fd_mcs: scsi_register() failed\n");
419 release_region(port, 0x10);
420 free_irq(irq, hosts);
421 continue;
422 }
423
424
425 /* save name */
426 strcpy(adapter_name, fd_mcs_adapters[loop].name);
427
428 /* chip/fifo */
429 chip = fd_mcs_adapters[loop].fd_chip;
430 /* use boot time value if available */
431 FIFO_COUNT = user_fifo_count ? user_fifo_count : fd_mcs_adapters[loop].fifo_count;
432 FIFO_Size = user_fifo_size ? user_fifo_size : fd_mcs_adapters[loop].fifo_size;
433
434/* FIXME: Do we need to keep this bit of code inside NOT_USED around at all? */
435#ifdef NOT_USED
436 /* *************************************************** */
437 /* Try to toggle 32-bit mode. This only
438 works on an 18c30 chip. (User reports
439 say this works, so we should switch to
440 it in the near future.) */
441 outb(0x80, port + IO_Control);
442 if ((inb(port + Configuration2) & 0x80) == 0x80) {
443 outb(0x00, port + IO_Control);
444 if ((inb(port + Configuration2) & 0x80) == 0x00) {
445 chip = tmc18c30;
446 FIFO_Size = 0x800; /* 2k FIFO */
447
448 printk("FIRST: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size);
449 }
450 }
451
452 /* That should have worked, but appears to
453 have problems. Let's assume it is an
454 18c30 if the RAM is disabled. */
455
456 if (inb(port + Configuration2) & 0x02) {
457 chip = tmc18c30;
458 FIFO_Size = 0x800; /* 2k FIFO */
459
460 printk("SECOND: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size);
461 }
462 /* *************************************************** */
463#endif
464
465 /* IBM/ANSI scsi scan ordering */
466 /* Stick this back in when the scsi.c changes are there */
467 shpnt->reverse_ordering = 1;
468
469
470 /* saving info */
471 hosts[found++] = shpnt;
472
473 shpnt->this_id = id;
474 shpnt->irq = irq;
475 shpnt->io_port = port;
476 shpnt->n_io_port = 0x10;
477
478 /* save */
479 bios_base = bios;
480 adapter_mask = (1 << id);
481
482 /* save more */
483 SCSI_Mode_Cntl_port = port + SCSI_Mode_Cntl;
484 FIFO_Data_Count_port = port + FIFO_Data_Count;
485 Interrupt_Cntl_port = port + Interrupt_Cntl;
486 Interrupt_Status_port = port + Interrupt_Status;
487 Interrupt_Cond_port = port + Interrupt_Cond;
488 Read_FIFO_port = port + Read_FIFO;
489 Read_SCSI_Data_port = port + Read_SCSI_Data;
490 SCSI_Cntl_port = port + SCSI_Cntl;
491 SCSI_Data_NoACK_port = port + SCSI_Data_NoACK;
492 SCSI_Status_port = port + SCSI_Status;
493 TMC_Cntl_port = port + TMC_Cntl;
494 TMC_Status_port = port + TMC_Status;
495 Write_FIFO_port = port + Write_FIFO;
496 Write_SCSI_Data_port = port + Write_SCSI_Data;
497
498 Bytes_Read = 0;
499 Bytes_Written = 0;
500 INTR_Processed = 0;
501
502 /* say something */
503 print_banner(shpnt);
504
505 /* reset */
506 outb(1, SCSI_Cntl_port);
507 do_pause(2);
508 outb(0, SCSI_Cntl_port);
509 do_pause(115);
510 outb(0, SCSI_Mode_Cntl_port);
511 outb(PARITY_MASK, TMC_Cntl_port);
512 /* done reset */
513 }
514 }
515
516 if (found == FD_MAX_HOSTS) {
517 printk("fd_mcs: detecting reached max=%d host adapters.\n", FD_MAX_HOSTS);
518 break;
519 }
520 }
521
522 return found;
523}
524
525static const char *fd_mcs_info(struct Scsi_Host *shpnt)
526{
527 return adapter_name;
528}
529
530static int TOTAL_INTR = 0;
531
532/*
533 * inout : decides on the direction of the dataflow and the meaning of the
534 * variables
535 * buffer: If inout==FALSE data is being written to it else read from it
536 * *start: If inout==FALSE start of the valid data in the buffer
537 * offset: If inout==FALSE offset from the beginning of the imaginary file
538 * from which we start writing into the buffer
539 * length: If inout==FALSE max number of bytes to be written into the buffer
540 * else number of bytes in the buffer
541 */
542static int fd_mcs_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout)
543{
544 int len = 0;
545
546 if (inout)
547 return (-ENOSYS);
548
549 *start = buffer + offset;
550
551 len += sprintf(buffer + len, "Future Domain MCS-600/700 Driver %s\n", DRIVER_VERSION);
552 len += sprintf(buffer + len, "HOST #%d: %s\n", shpnt->host_no, adapter_name);
553 len += sprintf(buffer + len, "FIFO Size=0x%x, FIFO Count=%d\n", FIFO_Size, FIFO_COUNT);
554 len += sprintf(buffer + len, "DriverCalls=%d, Interrupts=%d, BytesRead=%d, BytesWrite=%d\n\n", TOTAL_INTR, INTR_Processed, Bytes_Read, Bytes_Written);
555
556 if ((len -= offset) <= 0)
557 return 0;
558 if (len > length)
559 len = length;
560 return len;
561}
562
563static int fd_mcs_select(struct Scsi_Host *shpnt, int target)
564{
565 int status;
566 unsigned long timeout;
567
568 outb(0x82, SCSI_Cntl_port); /* Bus Enable + Select */
569 outb(adapter_mask | (1 << target), SCSI_Data_NoACK_port);
570
571 /* Stop arbitration and enable parity */
572 outb(PARITY_MASK, TMC_Cntl_port);
573
574 timeout = 350; /* 350mS -- because of timeouts
575 (was 250mS) */
576
577 do {
578 status = inb(SCSI_Status_port); /* Read adapter status */
579 if (status & 1) { /* Busy asserted */
580 /* Enable SCSI Bus (on error, should make bus idle with 0) */
581 outb(0x80, SCSI_Cntl_port);
582 return 0;
583 }
584 udelay(1000); /* wait one msec */
585 } while (--timeout);
586
587 /* Make bus idle */
588 fd_mcs_make_bus_idle(shpnt);
589#if EVERY_ACCESS
590 if (!target)
591 printk("Selection failed\n");
592#endif
593#if ERRORS_ONLY
594 if (!target) {
595 static int flag = 0;
596
597 if (!flag) /* Skip first failure for all chips. */
598 ++flag;
599 else
600 printk("fd_mcs: Selection failed\n");
601 }
602#endif
603 return 1;
604}
605
606static void my_done(struct Scsi_Host *shpnt, int error)
607{
608 if (in_command) {
609 in_command = 0;
610 outb(0x00, Interrupt_Cntl_port);
611 fd_mcs_make_bus_idle(shpnt);
612 current_SC->result = error;
613 current_SC->scsi_done(current_SC);
614 } else {
615 panic("fd_mcs: my_done() called outside of command\n");
616 }
617#if DEBUG_RACE
618 in_interrupt_flag = 0;
619#endif
620}
621
622/* only my_done needs to be protected */
David Howells7d12e782006-10-05 14:55:46 +0100623static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624{
625 unsigned long flags;
626 int status;
627 int done = 0;
628 unsigned data_count, tmp_count;
629
630 int i = 0;
631 struct Scsi_Host *shpnt;
632
633 TOTAL_INTR++;
634
635 /* search for one adapter-response on shared interrupt */
636 while ((shpnt = hosts[i++])) {
637 if ((inb(TMC_Status_port)) & 1)
638 break;
639 }
640
641 /* return if some other device on this IRQ caused the interrupt */
642 if (!shpnt) {
643 return IRQ_NONE;
644 }
645
646 INTR_Processed++;
647
648 outb(0x00, Interrupt_Cntl_port);
649
650 /* Abort calls my_done, so we do nothing here. */
651 if (current_SC->SCp.phase & aborted) {
652#if DEBUG_ABORT
653 printk("Interrupt after abort, ignoring\n");
654#endif
655 /* return IRQ_HANDLED; */
656 }
657#if DEBUG_RACE
658 ++in_interrupt_flag;
659#endif
660
661 if (current_SC->SCp.phase & in_arbitration) {
662 status = inb(TMC_Status_port); /* Read adapter status */
663 if (!(status & 0x02)) {
664#if EVERY_ACCESS
665 printk(" AFAIL ");
666#endif
667 spin_lock_irqsave(shpnt->host_lock, flags);
668 my_done(shpnt, DID_BUS_BUSY << 16);
669 spin_unlock_irqrestore(shpnt->host_lock, flags);
670 return IRQ_HANDLED;
671 }
672 current_SC->SCp.phase = in_selection;
673
674 outb(0x40 | FIFO_COUNT, Interrupt_Cntl_port);
675
676 outb(0x82, SCSI_Cntl_port); /* Bus Enable + Select */
Jeff Garzik422c0d62005-10-24 18:05:09 -0400677 outb(adapter_mask | (1 << scmd_id(current_SC)), SCSI_Data_NoACK_port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
679 /* Stop arbitration and enable parity */
680 outb(0x10 | PARITY_MASK, TMC_Cntl_port);
681#if DEBUG_RACE
682 in_interrupt_flag = 0;
683#endif
684 return IRQ_HANDLED;
685 } else if (current_SC->SCp.phase & in_selection) {
686 status = inb(SCSI_Status_port);
687 if (!(status & 0x01)) {
688 /* Try again, for slow devices */
Jeff Garzik422c0d62005-10-24 18:05:09 -0400689 if (fd_mcs_select(shpnt, scmd_id(current_SC))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690#if EVERY_ACCESS
691 printk(" SFAIL ");
692#endif
693 spin_lock_irqsave(shpnt->host_lock, flags);
694 my_done(shpnt, DID_NO_CONNECT << 16);
695 spin_unlock_irqrestore(shpnt->host_lock, flags);
696 return IRQ_HANDLED;
697 } else {
698#if EVERY_ACCESS
699 printk(" AltSel ");
700#endif
701 /* Stop arbitration and enable parity */
702 outb(0x10 | PARITY_MASK, TMC_Cntl_port);
703 }
704 }
705 current_SC->SCp.phase = in_other;
706 outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port);
707 outb(0x80, SCSI_Cntl_port);
708#if DEBUG_RACE
709 in_interrupt_flag = 0;
710#endif
711 return IRQ_HANDLED;
712 }
713
714 /* current_SC->SCp.phase == in_other: this is the body of the routine */
715
716 status = inb(SCSI_Status_port);
717
718 if (status & 0x10) { /* REQ */
719
720 switch (status & 0x0e) {
721
722 case 0x08: /* COMMAND OUT */
723 outb(current_SC->cmnd[current_SC->SCp.sent_command++], Write_SCSI_Data_port);
724#if EVERY_ACCESS
725 printk("CMD = %x,", current_SC->cmnd[current_SC->SCp.sent_command - 1]);
726#endif
727 break;
728 case 0x00: /* DATA OUT -- tmc18c50/tmc18c30 only */
729 if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
730 current_SC->SCp.have_data_in = -1;
731 outb(0xd0 | PARITY_MASK, TMC_Cntl_port);
732 }
733 break;
734 case 0x04: /* DATA IN -- tmc18c50/tmc18c30 only */
735 if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
736 current_SC->SCp.have_data_in = 1;
737 outb(0x90 | PARITY_MASK, TMC_Cntl_port);
738 }
739 break;
740 case 0x0c: /* STATUS IN */
741 current_SC->SCp.Status = inb(Read_SCSI_Data_port);
742#if EVERY_ACCESS
743 printk("Status = %x, ", current_SC->SCp.Status);
744#endif
745#if ERRORS_ONLY
746 if (current_SC->SCp.Status && current_SC->SCp.Status != 2 && current_SC->SCp.Status != 8) {
747 printk("ERROR fd_mcs: target = %d, command = %x, status = %x\n", current_SC->device->id, current_SC->cmnd[0], current_SC->SCp.Status);
748 }
749#endif
750 break;
751 case 0x0a: /* MESSAGE OUT */
752 outb(MESSAGE_REJECT, Write_SCSI_Data_port); /* Reject */
753 break;
754 case 0x0e: /* MESSAGE IN */
755 current_SC->SCp.Message = inb(Read_SCSI_Data_port);
756#if EVERY_ACCESS
757 printk("Message = %x, ", current_SC->SCp.Message);
758#endif
759 if (!current_SC->SCp.Message)
760 ++done;
761#if DEBUG_MESSAGES || EVERY_ACCESS
762 if (current_SC->SCp.Message) {
763 printk("fd_mcs: message = %x\n", current_SC->SCp.Message);
764 }
765#endif
766 break;
767 }
768 }
769
770 if (chip == tmc1800 && !current_SC->SCp.have_data_in && (current_SC->SCp.sent_command >= current_SC->cmd_len)) {
771 /* We have to get the FIFO direction
772 correct, so I've made a table based
773 on the SCSI Standard of which commands
774 appear to require a DATA OUT phase.
775 */
776 /*
777 p. 94: Command for all device types
778 CHANGE DEFINITION 40 DATA OUT
779 COMPARE 39 DATA OUT
780 COPY 18 DATA OUT
781 COPY AND VERIFY 3a DATA OUT
782 INQUIRY 12
783 LOG SELECT 4c DATA OUT
784 LOG SENSE 4d
785 MODE SELECT (6) 15 DATA OUT
786 MODE SELECT (10) 55 DATA OUT
787 MODE SENSE (6) 1a
788 MODE SENSE (10) 5a
789 READ BUFFER 3c
790 RECEIVE DIAGNOSTIC RESULTS 1c
791 REQUEST SENSE 03
792 SEND DIAGNOSTIC 1d DATA OUT
793 TEST UNIT READY 00
794 WRITE BUFFER 3b DATA OUT
795
796 p.178: Commands for direct-access devices (not listed on p. 94)
797 FORMAT UNIT 04 DATA OUT
798 LOCK-UNLOCK CACHE 36
799 PRE-FETCH 34
800 PREVENT-ALLOW MEDIUM REMOVAL 1e
801 READ (6)/RECEIVE 08
802 READ (10) 3c
803 READ CAPACITY 25
804 READ DEFECT DATA (10) 37
805 READ LONG 3e
806 REASSIGN BLOCKS 07 DATA OUT
807 RELEASE 17
808 RESERVE 16 DATA OUT
809 REZERO UNIT/REWIND 01
810 SEARCH DATA EQUAL (10) 31 DATA OUT
811 SEARCH DATA HIGH (10) 30 DATA OUT
812 SEARCH DATA LOW (10) 32 DATA OUT
813 SEEK (6) 0b
814 SEEK (10) 2b
815 SET LIMITS (10) 33
816 START STOP UNIT 1b
817 SYNCHRONIZE CACHE 35
818 VERIFY (10) 2f
819 WRITE (6)/PRINT/SEND 0a DATA OUT
820 WRITE (10)/SEND 2a DATA OUT
821 WRITE AND VERIFY (10) 2e DATA OUT
822 WRITE LONG 3f DATA OUT
823 WRITE SAME 41 DATA OUT ?
824
825 p. 261: Commands for sequential-access devices (not previously listed)
826 ERASE 19
827 LOAD UNLOAD 1b
828 LOCATE 2b
829 READ BLOCK LIMITS 05
830 READ POSITION 34
831 READ REVERSE 0f
832 RECOVER BUFFERED DATA 14
833 SPACE 11
834 WRITE FILEMARKS 10 ?
835
836 p. 298: Commands for printer devices (not previously listed)
837 ****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) *****
838 SLEW AND PRINT 0b DATA OUT -- same as seek
839 STOP PRINT 1b
840 SYNCHRONIZE BUFFER 10
841
842 p. 315: Commands for processor devices (not previously listed)
843
844 p. 321: Commands for write-once devices (not previously listed)
845 MEDIUM SCAN 38
846 READ (12) a8
847 SEARCH DATA EQUAL (12) b1 DATA OUT
848 SEARCH DATA HIGH (12) b0 DATA OUT
849 SEARCH DATA LOW (12) b2 DATA OUT
850 SET LIMITS (12) b3
851 VERIFY (12) af
852 WRITE (12) aa DATA OUT
853 WRITE AND VERIFY (12) ae DATA OUT
854
855 p. 332: Commands for CD-ROM devices (not previously listed)
856 PAUSE/RESUME 4b
857 PLAY AUDIO (10) 45
858 PLAY AUDIO (12) a5
859 PLAY AUDIO MSF 47
860 PLAY TRACK RELATIVE (10) 49
861 PLAY TRACK RELATIVE (12) a9
862 READ HEADER 44
863 READ SUB-CHANNEL 42
864 READ TOC 43
865
866 p. 370: Commands for scanner devices (not previously listed)
867 GET DATA BUFFER STATUS 34
868 GET WINDOW 25
869 OBJECT POSITION 31
870 SCAN 1b
871 SET WINDOW 24 DATA OUT
872
873 p. 391: Commands for optical memory devices (not listed)
874 ERASE (10) 2c
875 ERASE (12) ac
876 MEDIUM SCAN 38 DATA OUT
877 READ DEFECT DATA (12) b7
878 READ GENERATION 29
879 READ UPDATED BLOCK 2d
880 UPDATE BLOCK 3d DATA OUT
881
882 p. 419: Commands for medium changer devices (not listed)
883 EXCHANGE MEDIUM 46
884 INITIALIZE ELEMENT STATUS 07
885 MOVE MEDIUM a5
886 POSITION TO ELEMENT 2b
887 READ ELEMENT STATUS b8
888 REQUEST VOL. ELEMENT ADDRESS b5
889 SEND VOLUME TAG b6 DATA OUT
890
891 p. 454: Commands for communications devices (not listed previously)
892 GET MESSAGE (6) 08
893 GET MESSAGE (10) 28
894 GET MESSAGE (12) a8
895 */
896
897 switch (current_SC->cmnd[0]) {
898 case CHANGE_DEFINITION:
899 case COMPARE:
900 case COPY:
901 case COPY_VERIFY:
902 case LOG_SELECT:
903 case MODE_SELECT:
904 case MODE_SELECT_10:
905 case SEND_DIAGNOSTIC:
906 case WRITE_BUFFER:
907
908 case FORMAT_UNIT:
909 case REASSIGN_BLOCKS:
910 case RESERVE:
911 case SEARCH_EQUAL:
912 case SEARCH_HIGH:
913 case SEARCH_LOW:
914 case WRITE_6:
915 case WRITE_10:
916 case WRITE_VERIFY:
917 case 0x3f:
918 case 0x41:
919
920 case 0xb1:
921 case 0xb0:
922 case 0xb2:
923 case 0xaa:
924 case 0xae:
925
926 case 0x24:
927
928 case 0x38:
929 case 0x3d:
930
931 case 0xb6:
932
933 case 0xea: /* alternate number for WRITE LONG */
934
935 current_SC->SCp.have_data_in = -1;
936 outb(0xd0 | PARITY_MASK, TMC_Cntl_port);
937 break;
938
939 case 0x00:
940 default:
941
942 current_SC->SCp.have_data_in = 1;
943 outb(0x90 | PARITY_MASK, TMC_Cntl_port);
944 break;
945 }
946 }
947
948 if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */
949 while ((data_count = FIFO_Size - inw(FIFO_Data_Count_port)) > 512) {
950#if EVERY_ACCESS
951 printk("DC=%d, ", data_count);
952#endif
953 if (data_count > current_SC->SCp.this_residual)
954 data_count = current_SC->SCp.this_residual;
955 if (data_count > 0) {
956#if EVERY_ACCESS
957 printk("%d OUT, ", data_count);
958#endif
959 if (data_count == 1) {
960 Bytes_Written++;
961
962 outb(*current_SC->SCp.ptr++, Write_FIFO_port);
963 --current_SC->SCp.this_residual;
964 } else {
965 data_count >>= 1;
966 tmp_count = data_count << 1;
967 outsw(Write_FIFO_port, current_SC->SCp.ptr, data_count);
968 current_SC->SCp.ptr += tmp_count;
969 Bytes_Written += tmp_count;
970 current_SC->SCp.this_residual -= tmp_count;
971 }
972 }
973 if (!current_SC->SCp.this_residual) {
974 if (current_SC->SCp.buffers_residual) {
975 --current_SC->SCp.buffers_residual;
976 ++current_SC->SCp.buffer;
Jens Axboe45711f12007-10-22 21:19:53 +0200977 current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
979 } else
980 break;
981 }
982 }
983 } else if (current_SC->SCp.have_data_in == 1) { /* DATA IN */
984 while ((data_count = inw(FIFO_Data_Count_port)) > 0) {
985#if EVERY_ACCESS
986 printk("DC=%d, ", data_count);
987#endif
988 if (data_count > current_SC->SCp.this_residual)
989 data_count = current_SC->SCp.this_residual;
990 if (data_count) {
991#if EVERY_ACCESS
992 printk("%d IN, ", data_count);
993#endif
994 if (data_count == 1) {
995 Bytes_Read++;
996 *current_SC->SCp.ptr++ = inb(Read_FIFO_port);
997 --current_SC->SCp.this_residual;
998 } else {
999 data_count >>= 1; /* Number of words */
1000 tmp_count = data_count << 1;
1001 insw(Read_FIFO_port, current_SC->SCp.ptr, data_count);
1002 current_SC->SCp.ptr += tmp_count;
1003 Bytes_Read += tmp_count;
1004 current_SC->SCp.this_residual -= tmp_count;
1005 }
1006 }
1007 if (!current_SC->SCp.this_residual && current_SC->SCp.buffers_residual) {
1008 --current_SC->SCp.buffers_residual;
1009 ++current_SC->SCp.buffer;
Jens Axboe45711f12007-10-22 21:19:53 +02001010 current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
1012 }
1013 }
1014 }
1015
1016 if (done) {
1017#if EVERY_ACCESS
1018 printk(" ** IN DONE %d ** ", current_SC->SCp.have_data_in);
1019#endif
1020
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021#if EVERY_ACCESS
1022 printk("BEFORE MY_DONE. . .");
1023#endif
1024 spin_lock_irqsave(shpnt->host_lock, flags);
1025 my_done(shpnt, (current_SC->SCp.Status & 0xff)
1026 | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
1027 spin_unlock_irqrestore(shpnt->host_lock, flags);
1028#if EVERY_ACCESS
1029 printk("RETURNING.\n");
1030#endif
1031
1032 } else {
1033 if (current_SC->SCp.phase & disconnect) {
1034 outb(0xd0 | FIFO_COUNT, Interrupt_Cntl_port);
1035 outb(0x00, SCSI_Cntl_port);
1036 } else {
1037 outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port);
1038 }
1039 }
1040#if DEBUG_RACE
1041 in_interrupt_flag = 0;
1042#endif
1043 return IRQ_HANDLED;
1044}
1045
1046static int fd_mcs_release(struct Scsi_Host *shpnt)
1047{
1048 int i, this_host, irq_usage;
1049
1050 release_region(shpnt->io_port, shpnt->n_io_port);
1051
1052 this_host = -1;
1053 irq_usage = 0;
1054 for (i = 0; i < found; i++) {
1055 if (shpnt == hosts[i])
1056 this_host = i;
1057 if (shpnt->irq == hosts[i]->irq)
1058 irq_usage++;
1059 }
1060
1061 /* only for the last one */
1062 if (1 == irq_usage)
1063 free_irq(shpnt->irq, hosts);
1064
1065 found--;
1066
1067 for (i = this_host; i < found; i++)
1068 hosts[i] = hosts[i + 1];
1069
1070 hosts[found] = NULL;
1071
1072 return 0;
1073}
1074
1075static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
1076{
1077 struct Scsi_Host *shpnt = SCpnt->device->host;
1078
1079 if (in_command) {
1080 panic("fd_mcs: fd_mcs_queue() NOT REENTRANT!\n");
1081 }
1082#if EVERY_ACCESS
Boaz Harrosh8e31f1f2007-09-09 21:12:24 +03001083 printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
1084 SCpnt->target, *(unsigned char *) SCpnt->cmnd,
1085 scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086#endif
1087
1088 fd_mcs_make_bus_idle(shpnt);
1089
1090 SCpnt->scsi_done = done; /* Save this for the done function */
1091 current_SC = SCpnt;
1092
1093 /* Initialize static data */
1094
Boaz Harrosh8e31f1f2007-09-09 21:12:24 +03001095 if (scsi_bufflen(current_SC)) {
1096 current_SC->SCp.buffer = scsi_sglist(current_SC);
Jens Axboe45711f12007-10-22 21:19:53 +02001097 current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
Boaz Harrosh8e31f1f2007-09-09 21:12:24 +03001099 current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 } else {
Boaz Harrosh8e31f1f2007-09-09 21:12:24 +03001101 current_SC->SCp.ptr = NULL;
1102 current_SC->SCp.this_residual = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 current_SC->SCp.buffer = NULL;
1104 current_SC->SCp.buffers_residual = 0;
1105 }
1106
1107
1108 current_SC->SCp.Status = 0;
1109 current_SC->SCp.Message = 0;
1110 current_SC->SCp.have_data_in = 0;
1111 current_SC->SCp.sent_command = 0;
1112 current_SC->SCp.phase = in_arbitration;
1113
1114 /* Start arbitration */
1115 outb(0x00, Interrupt_Cntl_port);
1116 outb(0x00, SCSI_Cntl_port); /* Disable data drivers */
1117 outb(adapter_mask, SCSI_Data_NoACK_port); /* Set our id bit */
1118 in_command = 1;
1119 outb(0x20, Interrupt_Cntl_port);
1120 outb(0x14 | PARITY_MASK, TMC_Cntl_port); /* Start arbitration */
1121
1122 return 0;
1123}
1124
1125#if DEBUG_ABORT || DEBUG_RESET
1126static void fd_mcs_print_info(Scsi_Cmnd * SCpnt)
1127{
1128 unsigned int imr;
1129 unsigned int irr;
1130 unsigned int isr;
1131 struct Scsi_Host *shpnt = SCpnt->host;
1132
1133 if (!SCpnt || !SCpnt->host) {
1134 printk("fd_mcs: cannot provide detailed information\n");
1135 }
1136
1137 printk("%s\n", fd_mcs_info(SCpnt->host));
1138 print_banner(SCpnt->host);
1139 switch (SCpnt->SCp.phase) {
1140 case in_arbitration:
1141 printk("arbitration ");
1142 break;
1143 case in_selection:
1144 printk("selection ");
1145 break;
1146 case in_other:
1147 printk("other ");
1148 break;
1149 default:
1150 printk("unknown ");
1151 break;
1152 }
1153
Boaz Harrosh8e31f1f2007-09-09 21:12:24 +03001154 printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
1155 SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd,
1156 scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 printk("sent_command = %d, have_data_in = %d, timeout = %d\n", SCpnt->SCp.sent_command, SCpnt->SCp.have_data_in, SCpnt->timeout);
1158#if DEBUG_RACE
1159 printk("in_interrupt_flag = %d\n", in_interrupt_flag);
1160#endif
1161
1162 imr = (inb(0x0a1) << 8) + inb(0x21);
1163 outb(0x0a, 0xa0);
1164 irr = inb(0xa0) << 8;
1165 outb(0x0a, 0x20);
1166 irr += inb(0x20);
1167 outb(0x0b, 0xa0);
1168 isr = inb(0xa0) << 8;
1169 outb(0x0b, 0x20);
1170 isr += inb(0x20);
1171
1172 /* Print out interesting information */
1173 printk("IMR = 0x%04x", imr);
1174 if (imr & (1 << shpnt->irq))
1175 printk(" (masked)");
1176 printk(", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr);
1177
1178 printk("SCSI Status = 0x%02x\n", inb(SCSI_Status_port));
1179 printk("TMC Status = 0x%02x", inb(TMC_Status_port));
1180 if (inb(TMC_Status_port) & 1)
1181 printk(" (interrupt)");
1182 printk("\n");
1183 printk("Interrupt Status = 0x%02x", inb(Interrupt_Status_port));
1184 if (inb(Interrupt_Status_port) & 0x08)
1185 printk(" (enabled)");
1186 printk("\n");
1187 if (chip == tmc18c50 || chip == tmc18c30) {
1188 printk("FIFO Status = 0x%02x\n", inb(shpnt->io_port + FIFO_Status));
1189 printk("Int. Condition = 0x%02x\n", inb(shpnt->io_port + Interrupt_Cond));
1190 }
1191 printk("Configuration 1 = 0x%02x\n", inb(shpnt->io_port + Configuration1));
1192 if (chip == tmc18c50 || chip == tmc18c30)
1193 printk("Configuration 2 = 0x%02x\n", inb(shpnt->io_port + Configuration2));
1194}
1195#endif
1196
1197static int fd_mcs_abort(Scsi_Cmnd * SCpnt)
1198{
1199 struct Scsi_Host *shpnt = SCpnt->device->host;
1200
1201 unsigned long flags;
1202#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
1203 printk("fd_mcs: abort ");
1204#endif
1205
1206 spin_lock_irqsave(shpnt->host_lock, flags);
1207 if (!in_command) {
1208#if EVERY_ACCESS || ERRORS_ONLY
1209 printk(" (not in command)\n");
1210#endif
1211 spin_unlock_irqrestore(shpnt->host_lock, flags);
1212 return FAILED;
1213 } else
1214 printk("\n");
1215
1216#if DEBUG_ABORT
1217 fd_mcs_print_info(SCpnt);
1218#endif
1219
1220 fd_mcs_make_bus_idle(shpnt);
1221
1222 current_SC->SCp.phase |= aborted;
1223
1224 current_SC->result = DID_ABORT << 16;
1225
1226 /* Aborts are not done well. . . */
1227 my_done(shpnt, DID_ABORT << 16);
1228
1229 spin_unlock_irqrestore(shpnt->host_lock, flags);
1230 return SUCCESS;
1231}
1232
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233static int fd_mcs_bus_reset(Scsi_Cmnd * SCpnt) {
1234 struct Scsi_Host *shpnt = SCpnt->device->host;
Jeff Garzik 68b3aa72005-05-28 07:56:31 -04001235 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
1237#if DEBUG_RESET
1238 static int called_once = 0;
1239#endif
1240
1241#if ERRORS_ONLY
1242 if (SCpnt)
1243 printk("fd_mcs: SCSI Bus Reset\n");
1244#endif
1245
1246#if DEBUG_RESET
1247 if (called_once)
1248 fd_mcs_print_info(current_SC);
1249 called_once = 1;
1250#endif
1251
Jeff Garzik 68b3aa72005-05-28 07:56:31 -04001252 spin_lock_irqsave(shpnt->host_lock, flags);
1253
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 outb(1, SCSI_Cntl_port);
1255 do_pause(2);
1256 outb(0, SCSI_Cntl_port);
1257 do_pause(115);
1258 outb(0, SCSI_Mode_Cntl_port);
1259 outb(PARITY_MASK, TMC_Cntl_port);
1260
Jeff Garzik 68b3aa72005-05-28 07:56:31 -04001261 spin_unlock_irqrestore(shpnt->host_lock, flags);
1262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 /* Unless this is the very first call (i.e., SCPnt == NULL), everything
1264 is probably hosed at this point. We will, however, try to keep
1265 things going by informing the high-level code that we need help. */
1266 return SUCCESS;
1267}
1268
1269#include <scsi/scsi_ioctl.h>
1270
1271static int fd_mcs_biosparam(struct scsi_device * disk, struct block_device *bdev,
1272 sector_t capacity, int *info_array)
1273{
1274 unsigned char *p = scsi_bios_ptable(bdev);
1275 int size = capacity;
1276
1277 /* BIOS >= 3.4 for MCA cards */
1278 /* This algorithm was provided by Future Domain (much thanks!). */
1279
1280 if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */
1281 && p[4]) { /* Partition type */
1282 /* The partition table layout is as follows:
1283
1284 Start: 0x1b3h
1285 Offset: 0 = partition status
1286 1 = starting head
1287 2 = starting sector and cylinder (word, encoded)
1288 4 = partition type
1289 5 = ending head
1290 6 = ending sector and cylinder (word, encoded)
1291 8 = starting absolute sector (double word)
1292 c = number of sectors (double word)
1293 Signature: 0x1fe = 0x55aa
1294
1295 So, this algorithm assumes:
1296 1) the first partition table is in use,
1297 2) the data in the first entry is correct, and
1298 3) partitions never divide cylinders
1299
1300 Note that (1) may be FALSE for NetBSD (and other BSD flavors),
1301 as well as for Linux. Note also, that Linux doesn't pay any
1302 attention to the fields that are used by this algorithm -- it
1303 only uses the absolute sector data. Recent versions of Linux's
1304 fdisk(1) will fill this data in correctly, and forthcoming
1305 versions will check for consistency.
1306
1307 Checking for a non-zero partition type is not part of the
1308 Future Domain algorithm, but it seemed to be a reasonable thing
1309 to do, especially in the Linux and BSD worlds. */
1310
1311 info_array[0] = p[5] + 1; /* heads */
1312 info_array[1] = p[6] & 0x3f; /* sectors */
1313 } else {
1314 /* Note that this new method guarantees that there will always be
1315 less than 1024 cylinders on a platter. This is good for drives
1316 up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
1317 if ((unsigned int) size >= 0x7e0000U)
1318 {
1319 info_array[0] = 0xff; /* heads = 255 */
1320 info_array[1] = 0x3f; /* sectors = 63 */
1321 } else if ((unsigned int) size >= 0x200000U) {
1322 info_array[0] = 0x80; /* heads = 128 */
1323 info_array[1] = 0x3f; /* sectors = 63 */
1324 } else {
1325 info_array[0] = 0x40; /* heads = 64 */
1326 info_array[1] = 0x20; /* sectors = 32 */
1327 }
1328 }
1329 /* For both methods, compute the cylinders */
1330 info_array[2] = (unsigned int) size / (info_array[0] * info_array[1]);
1331 kfree(p);
1332 return 0;
1333}
1334
Christoph Hellwigd0be4a7d2005-10-31 18:31:40 +01001335static struct scsi_host_template driver_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 .proc_name = "fd_mcs",
1337 .proc_info = fd_mcs_proc_info,
1338 .detect = fd_mcs_detect,
1339 .release = fd_mcs_release,
1340 .info = fd_mcs_info,
1341 .queuecommand = fd_mcs_queue,
1342 .eh_abort_handler = fd_mcs_abort,
1343 .eh_bus_reset_handler = fd_mcs_bus_reset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 .bios_param = fd_mcs_biosparam,
1345 .can_queue = 1,
1346 .this_id = 7,
1347 .sg_tablesize = 64,
1348 .cmd_per_lun = 1,
1349 .use_clustering = DISABLE_CLUSTERING,
1350};
1351#include "scsi_module.c"
Randy.Dunlapd39a9422005-09-13 21:43:56 -07001352
1353MODULE_LICENSE("GPL");