Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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");