^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Driver for Future Domain TMC-16x0 and TMC-3260 SCSI host adapters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright 2019 Ondrej Zary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Original driver by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Rickard E. Faith, faith@cs.unc.edu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Future Domain BIOS versions supported for autodetect:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * 2.0, 3.0, 3.2, 3.4 (1.0), 3.5 (2.0), 3.6, 3.61
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Chips supported:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * TMC-1800, TMC-18C50, TMC-18C30, TMC-36C70
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Boards supported:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Future Domain TMC-1650, TMC-1660, TMC-1670, TMC-1680, TMC-1610M/MER/MEX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Future Domain TMC-3260 (PCI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Quantum ISA-200S, ISA-250MG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * Adaptec AHA-2920A (PCI) [BUT *NOT* AHA-2920C -- use aic7xxx instead]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * IBM ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * NOTE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * The Adaptec AHA-2920C has an Adaptec AIC-7850 chip on it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * Use the aic7xxx driver for this board.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * The Adaptec AHA-2920A has a Future Domain chip on it, so this is the right
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * driver for that card. Unfortunately, the boxes will probably just say
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * "2920", so you'll have to look on the card for a Future Domain logo, or a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * letter after the 2920.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * If you have a TMC-8xx or TMC-9xx board, then this is not the driver for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * your board.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * DESCRIPTION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * TMC-1650/1670, and TMC-3260 SCSI host adapters. The 1650 and 1670 have a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * 25-pin external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * high-density external connector. The 1670 and 1680 have floppy disk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * controllers built in. The TMC-3260 is a PCI bus card.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * Future Domain's older boards are based on the TMC-1800 chip, and this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * driver was originally written for a TMC-1680 board with the TMC-1800 chip.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * More recently, boards are being produced with the TMC-18C50 and TMC-18C30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * chips.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * Please note that the drive ordering that Future Domain implemented in BIOS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * versions 3.4 and 3.5 is the opposite of the order (currently) used by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * rest of the SCSI industry.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * REFERENCES USED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * 1990.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * "Technical Reference Manual: 18C50 SCSI Host Adapter Chip", Future Domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * Corporation, January 1992.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * "LXT SCSI Products: Specifications and OEM Technical Manual (Revision
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * B/September 1991)", Maxtor Corporation, 1991.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * "7213S product Manual (Revision P3)", Maxtor Corporation, 1992.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * "Draft Proposed American National Standard: Small Computer System
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * revision 10h, October 17, 1991)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * Youngdale (ericy@cais.com), 1992.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * Private communication, Tuong Le (Future Domain Engineering department),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * 1994. (Disk geometry computations for Future Domain BIOS version 3.4, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * TMC-18C30 detection.)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * Hogan, Thom. The Programmer's PC Sourcebook. Microsoft Press, 1988. Page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * 60 (2.39: Disk Partition Table Layout).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * "18C30 Technical Reference Manual", Future Domain Corporation, 1993, page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * 6-1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #include <scsi/scsicam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #include <scsi/scsi_cmnd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #include <scsi/scsi_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #include <scsi/scsi_host.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #include "fdomain.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * 18C30 chip have a 2k cache). When this many 512 byte blocks are filled by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * the SCSI device, an interrupt will be raised. Therefore, this could be as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * low as 0, or as high as 16. Note, however, that values which are too high
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * or too low seem to prevent any interrupts from occurring, and thereby lock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * up the machine.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #define FIFO_COUNT 2 /* Number of 512 byte blocks before INTR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define PARITY_MASK ACTL_PAREN /* Parity enabled, 0 = disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) enum chip_type {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) unknown = 0x00,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) tmc1800 = 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) tmc18c50 = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) tmc18c30 = 0x03,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct fdomain {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) int base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct scsi_cmnd *cur_cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) enum chip_type chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct work_struct work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static inline void fdomain_make_bus_idle(struct fdomain *fd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) outb(0, fd->base + REG_BCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) outb(0, fd->base + REG_MCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (fd->chip == tmc18c50 || fd->chip == tmc18c30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* Clear forced intr. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) outb(ACTL_RESET | ACTL_CLRFIRQ | PARITY_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) fd->base + REG_ACTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) outb(ACTL_RESET | PARITY_MASK, fd->base + REG_ACTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) static enum chip_type fdomain_identify(int port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) u16 id = inb(port + REG_ID_LSB) | inb(port + REG_ID_MSB) << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) switch (id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) case 0x6127:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) return tmc1800;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) case 0x60e9: /* 18c50 or 18c30 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return unknown;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /* Try to toggle 32-bit mode. This only works on an 18c30 chip. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) outb(CFG2_32BIT, port + REG_CFG2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if ((inb(port + REG_CFG2) & CFG2_32BIT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) outb(0, port + REG_CFG2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if ((inb(port + REG_CFG2) & CFG2_32BIT) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return tmc18c30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) /* If that failed, we are an 18c50. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return tmc18c50;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static int fdomain_test_loopback(int base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) for (i = 0; i < 255; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) outb(i, base + REG_LOOPBACK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (inb(base + REG_LOOPBACK) != i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static void fdomain_reset(int base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) outb(BCTL_RST, base + REG_BCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) mdelay(20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) outb(0, base + REG_BCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) mdelay(1150);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) outb(0, base + REG_MCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) outb(PARITY_MASK, base + REG_ACTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) static int fdomain_select(struct Scsi_Host *sh, int target)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) struct fdomain *fd = shost_priv(sh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) outb(BIT(sh->this_id) | BIT(target), fd->base + REG_SCSI_DATA_NOACK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) /* Stop arbitration and enable parity */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) outb(PARITY_MASK, fd->base + REG_ACTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) timeout = 350; /* 350 msec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) status = inb(fd->base + REG_BSTAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (status & BSTAT_BSY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) /* Enable SCSI Bus */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) /* (on error, should make bus idle with 0) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) outb(BCTL_BUSEN, fd->base + REG_BCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) mdelay(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) } while (--timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) fdomain_make_bus_idle(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) static void fdomain_finish_cmd(struct fdomain *fd, int result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) outb(0, fd->base + REG_ICTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) fdomain_make_bus_idle(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) fd->cur_cmd->result = result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) fd->cur_cmd->scsi_done(fd->cur_cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) fd->cur_cmd = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) static void fdomain_read_data(struct scsi_cmnd *cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) struct fdomain *fd = shost_priv(cmd->device->host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) unsigned char *virt, *ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) size_t offset, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) while ((len = inw(fd->base + REG_FIFO_COUNT)) > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) offset = scsi_bufflen(cmd) - scsi_get_resid(cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) &offset, &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) ptr = virt + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (len & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) *ptr++ = inb(fd->base + REG_FIFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (len > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) insw(fd->base + REG_FIFO, ptr, len >> 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) scsi_set_resid(cmd, scsi_get_resid(cmd) - len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) scsi_kunmap_atomic_sg(virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) static void fdomain_write_data(struct scsi_cmnd *cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) struct fdomain *fd = shost_priv(cmd->device->host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) /* 8k FIFO for pre-tmc18c30 chips, 2k FIFO for tmc18c30 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) int FIFO_Size = fd->chip == tmc18c30 ? 0x800 : 0x2000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) unsigned char *virt, *ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) size_t offset, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) while ((len = FIFO_Size - inw(fd->base + REG_FIFO_COUNT)) > 512) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) offset = scsi_bufflen(cmd) - scsi_get_resid(cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (len + offset > scsi_bufflen(cmd)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) len = scsi_bufflen(cmd) - offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (len == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) &offset, &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) ptr = virt + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (len & 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) outb(*ptr++, fd->base + REG_FIFO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (len > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) outsw(fd->base + REG_FIFO, ptr, len >> 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) scsi_set_resid(cmd, scsi_get_resid(cmd) - len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) scsi_kunmap_atomic_sg(virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) static void fdomain_work(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) struct fdomain *fd = container_of(work, struct fdomain, work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct Scsi_Host *sh = container_of((void *)fd, struct Scsi_Host,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) hostdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) struct scsi_cmnd *cmd = fd->cur_cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) int done = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) spin_lock_irqsave(sh->host_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) if (cmd->SCp.phase & in_arbitration) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) status = inb(fd->base + REG_ASTAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (!(status & ASTAT_ARB)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) fdomain_finish_cmd(fd, DID_BUS_BUSY << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) cmd->SCp.phase = in_selection;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) outb(ICTL_SEL | FIFO_COUNT, fd->base + REG_ICTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) outb(BIT(cmd->device->host->this_id) | BIT(scmd_id(cmd)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) fd->base + REG_SCSI_DATA_NOACK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) /* Stop arbitration and enable parity */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) } else if (cmd->SCp.phase & in_selection) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) status = inb(fd->base + REG_BSTAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (!(status & BSTAT_BSY)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /* Try again, for slow devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (fdomain_select(cmd->device->host, scmd_id(cmd))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) fdomain_finish_cmd(fd, DID_NO_CONNECT << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) /* Stop arbitration and enable parity */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) cmd->SCp.phase = in_other;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT, fd->base + REG_ICTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) outb(BCTL_BUSEN, fd->base + REG_BCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) /* cur_cmd->SCp.phase == in_other: this is the body of the routine */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) status = inb(fd->base + REG_BSTAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (status & BSTAT_REQ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) switch (status & (BSTAT_MSG | BSTAT_CMD | BSTAT_IO)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) case BSTAT_CMD: /* COMMAND OUT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) outb(cmd->cmnd[cmd->SCp.sent_command++],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) fd->base + REG_SCSI_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) case 0: /* DATA OUT -- tmc18c50/tmc18c30 only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) cmd->SCp.have_data_in = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) PARITY_MASK, fd->base + REG_ACTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) case BSTAT_IO: /* DATA IN -- tmc18c50/tmc18c30 only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) cmd->SCp.have_data_in = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) fd->base + REG_ACTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) case BSTAT_CMD | BSTAT_IO: /* STATUS IN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) cmd->SCp.Status = inb(fd->base + REG_SCSI_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) case BSTAT_MSG | BSTAT_CMD: /* MESSAGE OUT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) outb(MESSAGE_REJECT, fd->base + REG_SCSI_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) case BSTAT_MSG | BSTAT_CMD | BSTAT_IO: /* MESSAGE IN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) cmd->SCp.Message = inb(fd->base + REG_SCSI_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (!cmd->SCp.Message)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) ++done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (fd->chip == tmc1800 && !cmd->SCp.have_data_in &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) cmd->SCp.sent_command >= cmd->cmd_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) if (cmd->sc_data_direction == DMA_TO_DEVICE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) cmd->SCp.have_data_in = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) PARITY_MASK, fd->base + REG_ACTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) cmd->SCp.have_data_in = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) fd->base + REG_ACTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (cmd->SCp.have_data_in == -1) /* DATA OUT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) fdomain_write_data(cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) if (cmd->SCp.have_data_in == 1) /* DATA IN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) fdomain_read_data(cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (done) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) fdomain_finish_cmd(fd, (cmd->SCp.Status & 0xff) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) ((cmd->SCp.Message & 0xff) << 8) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) (DID_OK << 16));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) if (cmd->SCp.phase & disconnect) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) outb(ICTL_FIFO | ICTL_SEL | ICTL_REQ | FIFO_COUNT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) fd->base + REG_ICTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) outb(0, fd->base + REG_BCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) fd->base + REG_ICTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) spin_unlock_irqrestore(sh->host_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) static irqreturn_t fdomain_irq(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) struct fdomain *fd = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) /* Is it our IRQ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if ((inb(fd->base + REG_ASTAT) & ASTAT_IRQ) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) outb(0, fd->base + REG_ICTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) /* We usually have one spurious interrupt after each command. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) if (!fd->cur_cmd) /* Spurious interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) schedule_work(&fd->work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) static int fdomain_queue(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) struct fdomain *fd = shost_priv(cmd->device->host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) cmd->SCp.Status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) cmd->SCp.Message = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) cmd->SCp.have_data_in = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) cmd->SCp.sent_command = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) cmd->SCp.phase = in_arbitration;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) scsi_set_resid(cmd, scsi_bufflen(cmd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) spin_lock_irqsave(sh->host_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) fd->cur_cmd = cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) fdomain_make_bus_idle(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) /* Start arbitration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) outb(0, fd->base + REG_ICTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) outb(0, fd->base + REG_BCTL); /* Disable data drivers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) /* Set our id bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) outb(BIT(cmd->device->host->this_id), fd->base + REG_SCSI_DATA_NOACK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) outb(ICTL_ARB, fd->base + REG_ICTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) /* Start arbitration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) outb(ACTL_ARB | ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) spin_unlock_irqrestore(sh->host_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) static int fdomain_abort(struct scsi_cmnd *cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) struct Scsi_Host *sh = cmd->device->host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) struct fdomain *fd = shost_priv(sh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) if (!fd->cur_cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) return FAILED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) spin_lock_irqsave(sh->host_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) fdomain_make_bus_idle(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) fd->cur_cmd->SCp.phase |= aborted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) fd->cur_cmd->result = DID_ABORT << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) /* Aborts are not done well. . . */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) fdomain_finish_cmd(fd, DID_ABORT << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) spin_unlock_irqrestore(sh->host_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) return SUCCESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) static int fdomain_host_reset(struct scsi_cmnd *cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) struct Scsi_Host *sh = cmd->device->host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) struct fdomain *fd = shost_priv(sh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) spin_lock_irqsave(sh->host_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) fdomain_reset(fd->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) spin_unlock_irqrestore(sh->host_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) return SUCCESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) static int fdomain_biosparam(struct scsi_device *sdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) struct block_device *bdev, sector_t capacity,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) int geom[])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) unsigned char *p = scsi_bios_ptable(bdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) && p[4]) { /* Partition type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) geom[0] = p[5] + 1; /* heads */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) geom[1] = p[6] & 0x3f; /* sectors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) if (capacity >= 0x7e0000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) geom[0] = 255; /* heads */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) geom[1] = 63; /* sectors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) } else if (capacity >= 0x200000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) geom[0] = 128; /* heads */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) geom[1] = 63; /* sectors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) geom[0] = 64; /* heads */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) geom[1] = 32; /* sectors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) geom[2] = sector_div(capacity, geom[0] * geom[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) kfree(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) static struct scsi_host_template fdomain_template = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) .module = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) .name = "Future Domain TMC-16x0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) .proc_name = "fdomain",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) .queuecommand = fdomain_queue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) .eh_abort_handler = fdomain_abort,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) .eh_host_reset_handler = fdomain_host_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) .bios_param = fdomain_biosparam,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) .can_queue = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) .this_id = 7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) .sg_tablesize = 64,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) .dma_boundary = PAGE_SIZE - 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) struct Scsi_Host *fdomain_create(int base, int irq, int this_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) struct Scsi_Host *sh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) struct fdomain *fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) enum chip_type chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) static const char * const chip_names[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) "Unknown", "TMC-1800", "TMC-18C50", "TMC-18C30"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) unsigned long irq_flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) chip = fdomain_identify(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (!chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) fdomain_reset(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) if (fdomain_test_loopback(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) if (!irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) dev_err(dev, "card has no IRQ assigned");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) sh = scsi_host_alloc(&fdomain_template, sizeof(struct fdomain));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) if (!sh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) if (this_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) sh->this_id = this_id & 0x07;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) sh->irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) sh->io_port = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) sh->n_io_port = FDOMAIN_REGION_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) fd = shost_priv(sh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) fd->base = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) fd->chip = chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) INIT_WORK(&fd->work, fdomain_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) if (dev_is_pci(dev) || !strcmp(dev->bus->name, "pcmcia"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) irq_flags = IRQF_SHARED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) if (request_irq(irq, fdomain_irq, irq_flags, "fdomain", fd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) goto fail_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) shost_printk(KERN_INFO, sh, "%s chip at 0x%x irq %d SCSI ID %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) dev_is_pci(dev) ? "TMC-36C70 (PCI bus)" : chip_names[chip],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) base, irq, sh->this_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) if (scsi_add_host(sh, dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) goto fail_free_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) scsi_scan_host(sh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) return sh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) fail_free_irq:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) free_irq(irq, fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) fail_put:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) scsi_host_put(sh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) EXPORT_SYMBOL_GPL(fdomain_create);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) int fdomain_destroy(struct Scsi_Host *sh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) struct fdomain *fd = shost_priv(sh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) cancel_work_sync(&fd->work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) scsi_remove_host(sh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (sh->irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) free_irq(sh->irq, fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) scsi_host_put(sh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) EXPORT_SYMBOL_GPL(fdomain_destroy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) static int fdomain_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) struct fdomain *fd = shost_priv(dev_get_drvdata(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) fdomain_reset(fd->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) static SIMPLE_DEV_PM_OPS(fdomain_pm_ops, NULL, fdomain_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) #endif /* CONFIG_PM_SLEEP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) MODULE_DESCRIPTION("Future Domain TMC-16x0/TMC-3260 SCSI driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) MODULE_LICENSE("GPL");