Lines Matching +full:industry +full:- +full:standard
1 // SPDX-License-Identifier: GPL-2.0
3 * Driver for Future Domain TMC-16x0 and TMC-3260 SCSI host adapters
12 * TMC-1800, TMC-18C50, TMC-18C30, TMC-36C70
14 * Future Domain TMC-1650, TMC-1660, TMC-1670, TMC-1680, TMC-1610M/MER/MEX
15 * Future Domain TMC-3260 (PCI)
16 * Quantum ISA-200S, ISA-250MG
17 * Adaptec AHA-2920A (PCI) [BUT *NOT* AHA-2920C -- use aic7xxx instead]
22 * The Adaptec AHA-2920C has an Adaptec AIC-7850 chip on it.
25 * The Adaptec AHA-2920A has a Future Domain chip on it, so this is the right
30 * If you have a TMC-8xx or TMC-9xx board, then this is not the driver for
35 * This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680
36 * TMC-1650/1670, and TMC-3260 SCSI host adapters. The 1650 and 1670 have a
37 * 25-pin external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin
38 * high-density external connector. The 1670 and 1680 have floppy disk
39 * controllers built in. The TMC-3260 is a PCI bus card.
41 * Future Domain's older boards are based on the TMC-1800 chip, and this
42 * driver was originally written for a TMC-1680 board with the TMC-1800 chip.
43 * More recently, boards are being produced with the TMC-18C50 and TMC-18C30
48 * rest of the SCSI industry.
53 * "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation,
64 * "Draft Proposed American National Standard: Small Computer System
65 * Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109,
73 * TMC-18C30 detection.)
79 * 6-1.
125 outb(0, fd->base + REG_BCTL); in fdomain_make_bus_idle()
126 outb(0, fd->base + REG_MCTL); in fdomain_make_bus_idle()
127 if (fd->chip == tmc18c50 || fd->chip == tmc18c30) in fdomain_make_bus_idle()
130 fd->base + REG_ACTL); in fdomain_make_bus_idle()
132 outb(ACTL_RESET | PARITY_MASK, fd->base + REG_ACTL); in fdomain_make_bus_idle()
148 /* Try to toggle 32-bit mode. This only works on an 18c30 chip. */ in fdomain_identify()
188 outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL); in fdomain_select()
189 outb(BIT(sh->this_id) | BIT(target), fd->base + REG_SCSI_DATA_NOACK); in fdomain_select()
192 outb(PARITY_MASK, fd->base + REG_ACTL); in fdomain_select()
197 status = inb(fd->base + REG_BSTAT); in fdomain_select()
201 outb(BCTL_BUSEN, fd->base + REG_BCTL); in fdomain_select()
205 } while (--timeout); in fdomain_select()
212 outb(0, fd->base + REG_ICTL); in fdomain_finish_cmd()
214 scsi_done(fd->cur_cmd); in fdomain_finish_cmd()
215 fd->cur_cmd = NULL; in fdomain_finish_cmd()
220 struct fdomain *fd = shost_priv(cmd->device->host); in fdomain_read_data()
224 while ((len = inw(fd->base + REG_FIFO_COUNT)) > 0) { in fdomain_read_data()
225 offset = scsi_bufflen(cmd) - scsi_get_resid(cmd); in fdomain_read_data()
230 *ptr++ = inb(fd->base + REG_FIFO); in fdomain_read_data()
232 insw(fd->base + REG_FIFO, ptr, len >> 1); in fdomain_read_data()
233 scsi_set_resid(cmd, scsi_get_resid(cmd) - len); in fdomain_read_data()
240 struct fdomain *fd = shost_priv(cmd->device->host); in fdomain_write_data()
241 /* 8k FIFO for pre-tmc18c30 chips, 2k FIFO for tmc18c30 */ in fdomain_write_data()
242 int FIFO_Size = fd->chip == tmc18c30 ? 0x800 : 0x2000; in fdomain_write_data()
246 while ((len = FIFO_Size - inw(fd->base + REG_FIFO_COUNT)) > 512) { in fdomain_write_data()
247 offset = scsi_bufflen(cmd) - scsi_get_resid(cmd); in fdomain_write_data()
249 len = scsi_bufflen(cmd) - offset; in fdomain_write_data()
257 outb(*ptr++, fd->base + REG_FIFO); in fdomain_write_data()
259 outsw(fd->base + REG_FIFO, ptr, len >> 1); in fdomain_write_data()
260 scsi_set_resid(cmd, scsi_get_resid(cmd) - len); in fdomain_write_data()
270 struct scsi_cmnd *cmd = fd->cur_cmd; in fdomain_work()
276 spin_lock_irqsave(sh->host_lock, flags); in fdomain_work()
278 if (scsi_pointer->phase & in_arbitration) { in fdomain_work()
279 status = inb(fd->base + REG_ASTAT); in fdomain_work()
285 scsi_pointer->phase = in_selection; in fdomain_work()
287 outb(ICTL_SEL | FIFO_COUNT, fd->base + REG_ICTL); in fdomain_work()
288 outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL); in fdomain_work()
289 outb(BIT(cmd->device->host->this_id) | BIT(scmd_id(cmd)), in fdomain_work()
290 fd->base + REG_SCSI_DATA_NOACK); in fdomain_work()
292 outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL); in fdomain_work()
294 } else if (scsi_pointer->phase & in_selection) { in fdomain_work()
295 status = inb(fd->base + REG_BSTAT); in fdomain_work()
298 if (fdomain_select(cmd->device->host, scmd_id(cmd))) { in fdomain_work()
304 outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL); in fdomain_work()
306 scsi_pointer->phase = in_other; in fdomain_work()
307 outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT, fd->base + REG_ICTL); in fdomain_work()
308 outb(BCTL_BUSEN, fd->base + REG_BCTL); in fdomain_work()
312 /* fdomain_scsi_pointer(cur_cmd)->phase == in_other: this is the body of the routine */ in fdomain_work()
313 status = inb(fd->base + REG_BSTAT); in fdomain_work()
318 outb(cmd->cmnd[scsi_pointer->sent_command++], in fdomain_work()
319 fd->base + REG_SCSI_DATA); in fdomain_work()
321 case 0: /* DATA OUT -- tmc18c50/tmc18c30 only */ in fdomain_work()
322 if (fd->chip != tmc1800 && !scsi_pointer->have_data_in) { in fdomain_work()
323 scsi_pointer->have_data_in = -1; in fdomain_work()
325 PARITY_MASK, fd->base + REG_ACTL); in fdomain_work()
328 case BSTAT_IO: /* DATA IN -- tmc18c50/tmc18c30 only */ in fdomain_work()
329 if (fd->chip != tmc1800 && !scsi_pointer->have_data_in) { in fdomain_work()
330 scsi_pointer->have_data_in = 1; in fdomain_work()
332 fd->base + REG_ACTL); in fdomain_work()
336 scsi_pointer->Status = inb(fd->base + REG_SCSI_DATA); in fdomain_work()
339 outb(MESSAGE_REJECT, fd->base + REG_SCSI_DATA); in fdomain_work()
342 scsi_pointer->Message = inb(fd->base + REG_SCSI_DATA); in fdomain_work()
343 if (scsi_pointer->Message == COMMAND_COMPLETE) in fdomain_work()
349 if (fd->chip == tmc1800 && !scsi_pointer->have_data_in && in fdomain_work()
350 scsi_pointer->sent_command >= cmd->cmd_len) { in fdomain_work()
351 if (cmd->sc_data_direction == DMA_TO_DEVICE) { in fdomain_work()
352 scsi_pointer->have_data_in = -1; in fdomain_work()
354 PARITY_MASK, fd->base + REG_ACTL); in fdomain_work()
356 scsi_pointer->have_data_in = 1; in fdomain_work()
358 fd->base + REG_ACTL); in fdomain_work()
362 if (scsi_pointer->have_data_in == -1) /* DATA OUT */ in fdomain_work()
365 if (scsi_pointer->have_data_in == 1) /* DATA IN */ in fdomain_work()
369 set_status_byte(cmd, scsi_pointer->Status); in fdomain_work()
371 scsi_msg_to_host_byte(cmd, scsi_pointer->Message); in fdomain_work()
374 if (scsi_pointer->phase & disconnect) { in fdomain_work()
376 fd->base + REG_ICTL); in fdomain_work()
377 outb(0, fd->base + REG_BCTL); in fdomain_work()
380 fd->base + REG_ICTL); in fdomain_work()
383 spin_unlock_irqrestore(sh->host_lock, flags); in fdomain_work()
391 if ((inb(fd->base + REG_ASTAT) & ASTAT_IRQ) == 0) in fdomain_irq()
394 outb(0, fd->base + REG_ICTL); in fdomain_irq()
397 if (!fd->cur_cmd) /* Spurious interrupt */ in fdomain_irq()
400 schedule_work(&fd->work); in fdomain_irq()
408 struct fdomain *fd = shost_priv(cmd->device->host); in fdomain_queue()
411 scsi_pointer->Status = 0; in fdomain_queue()
412 scsi_pointer->Message = 0; in fdomain_queue()
413 scsi_pointer->have_data_in = 0; in fdomain_queue()
414 scsi_pointer->sent_command = 0; in fdomain_queue()
415 scsi_pointer->phase = in_arbitration; in fdomain_queue()
418 spin_lock_irqsave(sh->host_lock, flags); in fdomain_queue()
420 fd->cur_cmd = cmd; in fdomain_queue()
425 outb(0, fd->base + REG_ICTL); in fdomain_queue()
426 outb(0, fd->base + REG_BCTL); /* Disable data drivers */ in fdomain_queue()
428 outb(BIT(cmd->device->host->this_id), fd->base + REG_SCSI_DATA_NOACK); in fdomain_queue()
429 outb(ICTL_ARB, fd->base + REG_ICTL); in fdomain_queue()
431 outb(ACTL_ARB | ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL); in fdomain_queue()
433 spin_unlock_irqrestore(sh->host_lock, flags); in fdomain_queue()
440 struct Scsi_Host *sh = cmd->device->host; in fdomain_abort()
444 if (!fd->cur_cmd) in fdomain_abort()
447 spin_lock_irqsave(sh->host_lock, flags); in fdomain_abort()
450 fdomain_scsi_pointer(fd->cur_cmd)->phase |= aborted; in fdomain_abort()
453 set_host_byte(fd->cur_cmd, DID_ABORT); in fdomain_abort()
455 spin_unlock_irqrestore(sh->host_lock, flags); in fdomain_abort()
461 struct Scsi_Host *sh = cmd->device->host; in fdomain_host_reset()
465 spin_lock_irqsave(sh->host_lock, flags); in fdomain_host_reset()
466 fdomain_reset(fd->base); in fdomain_host_reset()
467 spin_unlock_irqrestore(sh->host_lock, flags); in fdomain_host_reset()
501 .name = "Future Domain TMC-16x0",
510 .dma_boundary = PAGE_SIZE - 1,
521 "Unknown", "TMC-1800", "TMC-18C50", "TMC-18C30" in fdomain_create()
544 sh->this_id = this_id & 0x07; in fdomain_create()
546 sh->irq = irq; in fdomain_create()
547 sh->io_port = base; in fdomain_create()
548 sh->n_io_port = FDOMAIN_REGION_SIZE; in fdomain_create()
551 fd->base = base; in fdomain_create()
552 fd->chip = chip; in fdomain_create()
553 INIT_WORK(&fd->work, fdomain_work); in fdomain_create()
555 if (dev_is_pci(dev) || !strcmp(dev->bus->name, "pcmcia")) in fdomain_create()
562 dev_is_pci(dev) ? "TMC-36C70 (PCI bus)" : chip_names[chip], in fdomain_create()
563 base, irq, sh->this_id); in fdomain_create()
584 cancel_work_sync(&fd->work); in fdomain_destroy()
586 if (sh->irq) in fdomain_destroy()
587 free_irq(sh->irq, fd); in fdomain_destroy()
598 fdomain_reset(fd->base); in fdomain_resume()
606 MODULE_DESCRIPTION("Future Domain TMC-16x0/TMC-3260 SCSI driver");