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