summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/3w-xxxx.c11
-rw-r--r--drivers/scsi/BusLogic.c73
-rw-r--r--drivers/scsi/Kconfig34
-rw-r--r--drivers/scsi/Makefile5
-rw-r--r--drivers/scsi/aacraid/aachba.c402
-rw-r--r--drivers/scsi/aacraid/aacraid.h76
-rw-r--r--drivers/scsi/aacraid/commctrl.c286
-rw-r--r--drivers/scsi/aacraid/comminit.c4
-rw-r--r--drivers/scsi/aacraid/commsup.c112
-rw-r--r--drivers/scsi/aacraid/dpcsup.c36
-rw-r--r--drivers/scsi/aacraid/linit.c65
-rw-r--r--drivers/scsi/aacraid/nark.c3
-rw-r--r--drivers/scsi/aacraid/rkt.c3
-rw-r--r--drivers/scsi/aacraid/rx.c115
-rw-r--r--drivers/scsi/aacraid/sa.c1
-rw-r--r--drivers/scsi/aha1542.c1
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic79xx12
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic7xxx10
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c6
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.h5
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c1
-rw-r--r--drivers/scsi/arcmsr/arcmsr_attr.c1
-rw-r--r--drivers/scsi/atari_NCR5380.c4398
-rw-r--r--drivers/scsi/atari_scsi.c377
-rw-r--r--drivers/scsi/atari_scsi.h174
-rw-r--r--drivers/scsi/constants.c274
-rw-r--r--drivers/scsi/dpt/dpti_i2o.h48
-rw-r--r--drivers/scsi/dpt/dpti_ioctl.h2
-rw-r--r--drivers/scsi/dpt/dptsig.h4
-rw-r--r--drivers/scsi/dpt_i2o.c2
-rw-r--r--drivers/scsi/eata_generic.h7
-rw-r--r--drivers/scsi/esp.c4394
-rw-r--r--drivers/scsi/esp.h406
-rw-r--r--drivers/scsi/esp_scsi.c2711
-rw-r--r--drivers/scsi/esp_scsi.h560
-rw-r--r--drivers/scsi/gdth.c2
-rw-r--r--drivers/scsi/hosts.c4
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c80
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.h2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c44
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c3
-rw-r--r--drivers/scsi/ipr.c293
-rw-r--r--drivers/scsi/ipr.h45
-rw-r--r--drivers/scsi/iscsi_tcp.c21
-rw-r--r--drivers/scsi/libiscsi.c29
-rw-r--r--drivers/scsi/libsas/sas_expander.c1
-rw-r--r--drivers/scsi/libsrp.c13
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c7
-rw-r--r--drivers/scsi/megaraid.c2
-rw-r--r--drivers/scsi/osst.c1
-rw-r--r--drivers/scsi/pci2000.h197
-rw-r--r--drivers/scsi/pcmcia/Kconfig9
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h13
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c177
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c16
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c11
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qlogicpti.c4
-rw-r--r--drivers/scsi/scsi.c47
-rw-r--r--drivers/scsi/scsi_error.c21
-rw-r--r--drivers/scsi/scsi_lib.c10
-rw-r--r--drivers/scsi/scsi_netlink.c5
-rw-r--r--drivers/scsi/scsi_scan.c2
-rw-r--r--drivers/scsi/scsi_sysfs.c68
-rw-r--r--drivers/scsi/scsi_tgt_if.c6
-rw-r--r--drivers/scsi/scsi_tgt_lib.c261
-rw-r--r--drivers/scsi/scsi_tgt_priv.h5
-rw-r--r--drivers/scsi/scsi_transport_fc.c2
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c10
-rw-r--r--drivers/scsi/sd.c405
-rw-r--r--drivers/scsi/sg.c13
-rw-r--r--drivers/scsi/sr.c2
-rw-r--r--drivers/scsi/st.c1
-rw-r--r--drivers/scsi/sun_esp.c635
-rw-r--r--drivers/scsi/tmscsim.c2
78 files changed, 8212 insertions, 8889 deletions
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index bf5d63e1bee..656bdb1352d 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -1864,10 +1864,17 @@ static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
/* This function will handle the request sense scsi command */
static int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
{
+ char request_buffer[18];
+
dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
- /* For now we just zero the request buffer */
- memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+ memset(request_buffer, 0, sizeof(request_buffer));
+ request_buffer[0] = 0x70; /* Immediate fixed format */
+ request_buffer[7] = 10; /* minimum size per SPC: 18 bytes */
+ /* leave all other fields zero, giving effectively NO_SENSE return */
+ tw_transfer_internal(tw_dev, request_id, request_buffer,
+ sizeof(request_buffer));
+
tw_dev->state[request_id] = TW_S_COMPLETED;
tw_state_request_finish(tw_dev, request_id);
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index e874b894487..96f4cab0761 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -579,17 +579,17 @@ static void __init BusLogic_InitializeProbeInfoListISA(struct BusLogic_HostAdapt
/*
Append the list of standard BusLogic MultiMaster ISA I/O Addresses.
*/
- if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)
+ if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe330)
BusLogic_AppendProbeAddressISA(0x330);
- if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)
+ if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe334)
BusLogic_AppendProbeAddressISA(0x334);
- if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)
+ if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe230)
BusLogic_AppendProbeAddressISA(0x230);
- if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)
+ if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe234)
BusLogic_AppendProbeAddressISA(0x234);
- if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)
+ if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe130)
BusLogic_AppendProbeAddressISA(0x130);
- if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)
+ if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe134)
BusLogic_AppendProbeAddressISA(0x134);
}
@@ -795,7 +795,9 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
host adapters are probed.
*/
if (!BusLogic_ProbeOptions.NoProbeISA)
- if (PrimaryProbeInfo->IO_Address == 0 && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)) {
+ if (PrimaryProbeInfo->IO_Address == 0 &&
+ (!BusLogic_ProbeOptions.LimitedProbeISA ||
+ BusLogic_ProbeOptions.Probe330)) {
PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
PrimaryProbeInfo->IO_Address = 0x330;
@@ -805,15 +807,25 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
omitting the Primary I/O Address which has already been handled.
*/
if (!BusLogic_ProbeOptions.NoProbeISA) {
- if (!StandardAddressSeen[1] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0))
+ if (!StandardAddressSeen[1] &&
+ (!BusLogic_ProbeOptions.LimitedProbeISA ||
+ BusLogic_ProbeOptions.Probe334))
BusLogic_AppendProbeAddressISA(0x334);
- if (!StandardAddressSeen[2] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0))
+ if (!StandardAddressSeen[2] &&
+ (!BusLogic_ProbeOptions.LimitedProbeISA ||
+ BusLogic_ProbeOptions.Probe230))
BusLogic_AppendProbeAddressISA(0x230);
- if (!StandardAddressSeen[3] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0))
+ if (!StandardAddressSeen[3] &&
+ (!BusLogic_ProbeOptions.LimitedProbeISA ||
+ BusLogic_ProbeOptions.Probe234))
BusLogic_AppendProbeAddressISA(0x234);
- if (!StandardAddressSeen[4] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0))
+ if (!StandardAddressSeen[4] &&
+ (!BusLogic_ProbeOptions.LimitedProbeISA ||
+ BusLogic_ProbeOptions.Probe130))
BusLogic_AppendProbeAddressISA(0x130);
- if (!StandardAddressSeen[5] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0))
+ if (!StandardAddressSeen[5] &&
+ (!BusLogic_ProbeOptions.LimitedProbeISA ||
+ BusLogic_ProbeOptions.Probe134))
BusLogic_AppendProbeAddressISA(0x134);
}
/*
@@ -2220,22 +2232,35 @@ static int __init BusLogic_init(void)
HostAdapter->PCI_Device = ProbeInfo->PCI_Device;
HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel;
HostAdapter->AddressCount = BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType];
+
+ /*
+ Make sure region is free prior to probing.
+ */
+ if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount,
+ "BusLogic"))
+ continue;
/*
Probe the Host Adapter. If unsuccessful, abort further initialization.
*/
- if (!BusLogic_ProbeHostAdapter(HostAdapter))
+ if (!BusLogic_ProbeHostAdapter(HostAdapter)) {
+ release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
continue;
+ }
/*
Hard Reset the Host Adapter. If unsuccessful, abort further
initialization.
*/
- if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true))
+ if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) {
+ release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
continue;
+ }
/*
Check the Host Adapter. If unsuccessful, abort further initialization.
*/
- if (!BusLogic_CheckHostAdapter(HostAdapter))
+ if (!BusLogic_CheckHostAdapter(HostAdapter)) {
+ release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
continue;
+ }
/*
Initialize the Driver Options field if provided.
*/
@@ -2247,16 +2272,6 @@ static int __init BusLogic_init(void)
*/
BusLogic_AnnounceDriver(HostAdapter);
/*
- Register usage of the I/O Address range. From this point onward, any
- failure will be assumed to be due to a problem with the Host Adapter,
- rather than due to having mistakenly identified this port as belonging
- to a BusLogic Host Adapter. The I/O Address range will not be
- released, thereby preventing it from being incorrectly identified as
- any other type of Host Adapter.
- */
- if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, "BusLogic"))
- continue;
- /*
Register the SCSI Host structure.
*/
@@ -2280,6 +2295,12 @@ static int __init BusLogic_init(void)
Acquire the System Resources necessary to use the Host Adapter, then
Create the Initial CCBs, Initialize the Host Adapter, and finally
perform Target Device Inquiry.
+
+ From this point onward, any failure will be assumed to be due to a
+ problem with the Host Adapter, rather than due to having mistakenly
+ identified this port as belonging to a BusLogic Host Adapter. The
+ I/O Address range will not be released, thereby preventing it from
+ being incorrectly identified as any other type of Host Adapter.
*/
if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) &&
BusLogic_ReportHostAdapterConfiguration(HostAdapter) &&
@@ -3598,6 +3619,7 @@ static void __exit BusLogic_exit(void)
__setup("BusLogic=", BusLogic_Setup);
+#ifdef MODULE
static struct pci_device_id BusLogic_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -3607,6 +3629,7 @@ static struct pci_device_id BusLogic_pci_tbl[] __devinitdata = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ }
};
+#endif
MODULE_DEVICE_TABLE(pci, BusLogic_pci_tbl);
module_init(BusLogic_init);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 4cd280e8696..e62d23f6518 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -170,7 +170,7 @@ config CHR_DEV_SCH
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/modules.txt> and
+ say M here and read <file:Documentation/kbuild/modules.txt> and
<file:Documentation/scsi.txt>. The module will be called ch.o.
If unsure, say N.
@@ -241,6 +241,12 @@ config SCSI_SCAN_ASYNC
You can override this choice by specifying "scsi_mod.scan=sync"
or async on the kernel's command line.
+config SCSI_WAIT_SCAN
+ tristate
+ default m
+ depends on SCSI
+ depends on MODULES
+
menu "SCSI Transports"
depends on SCSI
@@ -1194,17 +1200,6 @@ config SCSI_NCR53C8XX_SYNC
There is no safe option other than using good cabling, right
terminations and SCSI conformant devices.
-config SCSI_NCR53C8XX_PROFILE
- bool "enable profiling"
- depends on SCSI_ZALON || SCSI_NCR_Q720
- help
- This option allows you to enable profiling information gathering.
- These statistics are not very accurate due to the low frequency
- of the kernel clock (100 Hz on i386) and have performance impact
- on systems that use very fast devices.
-
- The normal answer therefore is N.
-
config SCSI_NCR53C8XX_NO_DISCONNECT
bool "not allow targets to disconnect"
depends on (SCSI_ZALON || SCSI_NCR_Q720) && SCSI_NCR53C8XX_DEFAULT_TAGS=0
@@ -1334,11 +1329,6 @@ config SCSI_SIM710
It currently supports Compaq EISA cards and NCR MCA cards
-config 53C700_IO_MAPPED
- bool
- depends on SCSI_SIM710
- default y
-
config SCSI_SYM53C416
tristate "Symbios 53c416 SCSI support"
depends on ISA && SCSI
@@ -1649,7 +1639,7 @@ config OKTAGON_SCSI
config ATARI_SCSI
tristate "Atari native SCSI support"
- depends on ATARI && SCSI && BROKEN
+ depends on ATARI && SCSI
select SCSI_SPI_ATTRS
---help---
If you have an Atari with built-in NCR5380 SCSI controller (TT,
@@ -1763,9 +1753,15 @@ config SUN3X_ESP
The ESP was an on-board SCSI controller used on Sun 3/80
machines. Say Y here to compile in support for it.
+config SCSI_ESP_CORE
+ tristate "ESP Scsi Driver Core"
+ depends on SCSI
+ select SCSI_SPI_ATTRS
+
config SCSI_SUNESP
tristate "Sparc ESP Scsi Driver"
depends on SBUS && SCSI
+ select SCSI_ESP_CORE
help
This is the driver for the Sun ESP SCSI host adapter. The ESP
chipset is present in most SPARC SBUS-based computers.
@@ -1787,7 +1783,7 @@ config ZFCP
This driver is also available as a module. This module will be
called zfcp. If you want to compile it as a module, say M here
- and read <file:Documentation/modules.txt>.
+ and read <file:Documentation/kbuild/modules.txt>.
config SCSI_SRP
tristate "SCSI RDMA Protocol helper library"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 79ecf4ebe6e..51e884fa10b 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -106,7 +106,8 @@ obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o
obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/
obj-$(CONFIG_MEGARAID_SAS) += megaraid/
obj-$(CONFIG_SCSI_ACARD) += atp870u.o
-obj-$(CONFIG_SCSI_SUNESP) += esp.o
+obj-$(CONFIG_SCSI_ESP_CORE) += esp_scsi.o
+obj-$(CONFIG_SCSI_SUNESP) += sun_esp.o
obj-$(CONFIG_SCSI_GDTH) += gdth.o
obj-$(CONFIG_SCSI_INITIO) += initio.o
obj-$(CONFIG_SCSI_INIA100) += a100u2w.o
@@ -145,7 +146,7 @@ obj-$(CONFIG_CHR_DEV_SCH) += ch.o
# This goes last, so that "real" scsi devices probe earlier
obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
-obj-$(CONFIG_SCSI) += scsi_wait_scan.o
+obj-$(CONFIG_SCSI_WAIT_SCAN) += scsi_wait_scan.o
scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \
scsicam.o scsi_error.o scsi_lib.o \
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index d789e61bdc4..1e82c69b36b 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -172,6 +172,30 @@ MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size.
int expose_physicals = -1;
module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on");
+
+
+static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
+ struct fib *fibptr) {
+ struct scsi_device *device;
+
+ if (unlikely(!scsicmd || !scsicmd->scsi_done )) {
+ dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"))
+;
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ return 0;
+ }
+ scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+ device = scsicmd->device;
+ if (unlikely(!device || !scsi_device_online(device))) {
+ dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n"));
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ return 0;
+ }
+ return 1;
+}
+
/**
* aac_get_config_status - check the adapter configuration
* @common: adapter to query
@@ -258,13 +282,10 @@ int aac_get_containers(struct aac_dev *dev)
u32 index;
int status = 0;
struct fib * fibptr;
- unsigned instance;
struct aac_get_container_count *dinfo;
struct aac_get_container_count_resp *dresp;
int maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
- instance = dev->scsi_host_ptr->unique_id;
-
if (!(fibptr = aac_fib_alloc(dev)))
return -ENOMEM;
@@ -284,88 +305,35 @@ int aac_get_containers(struct aac_dev *dev)
maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries);
aac_fib_complete(fibptr);
}
+ aac_fib_free(fibptr);
if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
- fsa_dev_ptr = kmalloc(
- sizeof(*fsa_dev_ptr) * maximum_num_containers, GFP_KERNEL);
- if (!fsa_dev_ptr) {
- aac_fib_free(fibptr);
+ fsa_dev_ptr = kmalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers,
+ GFP_KERNEL);
+ if (!fsa_dev_ptr)
return -ENOMEM;
- }
memset(fsa_dev_ptr, 0, sizeof(*fsa_dev_ptr) * maximum_num_containers);
dev->fsa_dev = fsa_dev_ptr;
dev->maximum_num_containers = maximum_num_containers;
- for (index = 0; index < dev->maximum_num_containers; index++) {
- struct aac_query_mount *dinfo;
- struct aac_mount *dresp;
-
+ for (index = 0; index < dev->maximum_num_containers; ) {
fsa_dev_ptr[index].devname[0] = '\0';
- aac_fib_init(fibptr);
- dinfo = (struct aac_query_mount *) fib_data(fibptr);
-
- dinfo->command = cpu_to_le32(VM_NameServe);
- dinfo->count = cpu_to_le32(index);
- dinfo->type = cpu_to_le32(FT_FILESYS);
+ status = aac_probe_container(dev, index);
- status = aac_fib_send(ContainerCommand,
- fibptr,
- sizeof (struct aac_query_mount),
- FsaNormal,
- 1, 1,
- NULL, NULL);
- if (status < 0 ) {
+ if (status < 0) {
printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n");
break;
}
- dresp = (struct aac_mount *)fib_data(fibptr);
- if ((le32_to_cpu(dresp->status) == ST_OK) &&
- (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) {
- dinfo->command = cpu_to_le32(VM_NameServe64);
- dinfo->count = cpu_to_le32(index);
- dinfo->type = cpu_to_le32(FT_FILESYS);
-
- if (aac_fib_send(ContainerCommand,
- fibptr,
- sizeof(struct aac_query_mount),
- FsaNormal,
- 1, 1,
- NULL, NULL) < 0)
- continue;
- } else
- dresp->mnt[0].capacityhigh = 0;
-
- dprintk ((KERN_DEBUG
- "VM_NameServe cid=%d status=%d vol=%d state=%d cap=%llu\n",
- (int)index, (int)le32_to_cpu(dresp->status),
- (int)le32_to_cpu(dresp->mnt[0].vol),
- (int)le32_to_cpu(dresp->mnt[0].state),
- ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
- (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32)));
- if ((le32_to_cpu(dresp->status) == ST_OK) &&
- (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
- (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
- fsa_dev_ptr[index].valid = 1;
- fsa_dev_ptr[index].type = le32_to_cpu(dresp->mnt[0].vol);
- fsa_dev_ptr[index].size
- = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
- (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
- if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
- fsa_dev_ptr[index].ro = 1;
- }
- aac_fib_complete(fibptr);
/*
* If there are no more containers, then stop asking.
*/
- if ((index + 1) >= le32_to_cpu(dresp->count)){
+ if (++index >= status)
break;
- }
}
- aac_fib_free(fibptr);
return status;
}
@@ -382,8 +350,9 @@ static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigne
buf = scsicmd->request_buffer;
transfer_len = min(scsicmd->request_bufflen, len + offset);
}
-
- memcpy(buf + offset, data, transfer_len - offset);
+ transfer_len -= offset;
+ if (buf && transfer_len)
+ memcpy(buf + offset, data, transfer_len);
if (scsicmd->use_sg)
kunmap_atomic(buf - sg->offset, KM_IRQ0);
@@ -396,7 +365,9 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
struct scsi_cmnd * scsicmd;
scsicmd = (struct scsi_cmnd *) context;
- scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+ if (!aac_valid_context(scsicmd, fibptr))
+ return;
dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies));
BUG_ON(fibptr == NULL);
@@ -431,7 +402,7 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
/**
* aac_get_container_name - get container name, none blocking.
*/
-static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid)
+static int aac_get_container_name(struct scsi_cmnd * scsicmd)
{
int status;
struct aac_get_name *dinfo;
@@ -448,7 +419,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid)
dinfo->command = cpu_to_le32(VM_ContainerConfig);
dinfo->type = cpu_to_le32(CT_READ_NAME);
- dinfo->cid = cpu_to_le32(cid);
+ dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
status = aac_fib_send(ContainerCommand,
@@ -473,85 +444,192 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid)
return -1;
}
-/**
- * aac_probe_container - query a logical volume
- * @dev: device to query
- * @cid: container identifier
- *
- * Queries the controller about the given volume. The volume information
- * is updated in the struct fsa_dev_info structure rather than returned.
- */
-
-int aac_probe_container(struct aac_dev *dev, int cid)
+static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd)
+{
+ struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
+
+ if (fsa_dev_ptr[scmd_id(scsicmd)].valid)
+ return aac_scsi_cmd(scsicmd);
+
+ scsicmd->result = DID_NO_CONNECT << 16;
+ scsicmd->scsi_done(scsicmd);
+ return 0;
+}
+
+static int _aac_probe_container2(void * context, struct fib * fibptr)
{
struct fsa_dev_info *fsa_dev_ptr;
- int status;
+ int (*callback)(struct scsi_cmnd *);
+ struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context;
+
+ if (!aac_valid_context(scsicmd, fibptr))
+ return 0;
+
+ fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
+
+ scsicmd->SCp.Status = 0;
+ if (fsa_dev_ptr) {
+ struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr);
+ fsa_dev_ptr += scmd_id(scsicmd);
+
+ if ((le32_to_cpu(dresp->status) == ST_OK) &&
+ (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
+ (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
+ fsa_dev_ptr->valid = 1;
+ fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol);
+ fsa_dev_ptr->size
+ = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
+ (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
+ fsa_dev_ptr->ro = ((le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) != 0);
+ }
+ if ((fsa_dev_ptr->valid & 1) == 0)
+ fsa_dev_ptr->valid = 0;
+ scsicmd->SCp.Status = le32_to_cpu(dresp->count);
+ }
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr);
+ scsicmd->SCp.ptr = NULL;
+ return (*callback)(scsicmd);
+}
+
+static int _aac_probe_container1(void * context, struct fib * fibptr)
+{
+ struct scsi_cmnd * scsicmd;
+ struct aac_mount * dresp;
struct aac_query_mount *dinfo;
- struct aac_mount *dresp;
- struct fib * fibptr;
- unsigned instance;
+ int status;
- fsa_dev_ptr = dev->fsa_dev;
- if (!fsa_dev_ptr)
- return -ENOMEM;
- instance = dev->scsi_host_ptr->unique_id;
+ dresp = (struct aac_mount *) fib_data(fibptr);
+ dresp->mnt[0].capacityhigh = 0;
+ if ((le32_to_cpu(dresp->status) != ST_OK) ||
+ (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE))
+ return _aac_probe_container2(context, fibptr);
+ scsicmd = (struct scsi_cmnd *) context;
+ scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
- if (!(fibptr = aac_fib_alloc(dev)))
- return -ENOMEM;
+ if (!aac_valid_context(scsicmd, fibptr))
+ return 0;
aac_fib_init(fibptr);
dinfo = (struct aac_query_mount *)fib_data(fibptr);
- dinfo->command = cpu_to_le32(VM_NameServe);
- dinfo->count = cpu_to_le32(cid);
+ dinfo->command = cpu_to_le32(VM_NameServe64);
+ dinfo->count = cpu_to_le32(scmd_id(scsicmd));
dinfo->type = cpu_to_le32(FT_FILESYS);
status = aac_fib_send(ContainerCommand,
- fibptr,
- sizeof(struct aac_query_mount),
- FsaNormal,
- 1, 1,
- NULL, NULL);
+ fibptr,
+ sizeof(struct aac_query_mount),
+ FsaNormal,
+ 0, 1,
+ (fib_callback) _aac_probe_container2,
+ (void *) scsicmd);
+ /*
+ * Check that the command queued to the controller
+ */
+ if (status == -EINPROGRESS) {
+ scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+ return 0;
+ }
if (status < 0) {
- printk(KERN_WARNING "aacraid: aac_probe_container query failed.\n");
- goto error;
+ /* Inherit results from VM_NameServe, if any */
+ dresp->status = cpu_to_le32(ST_OK);
+ return _aac_probe_container2(context, fibptr);
}
+ return 0;
+}
- dresp = (struct aac_mount *) fib_data(fibptr);
+static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *))
+{
+ struct fib * fibptr;
+ int status = -ENOMEM;
- if ((le32_to_cpu(dresp->status) == ST_OK) &&
- (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) {
- dinfo->command = cpu_to_le32(VM_NameServe64);
- dinfo->count = cpu_to_le32(cid);
- dinfo->type = cpu_to_le32(FT_FILESYS);
+ if ((fibptr = aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) {
+ struct aac_query_mount *dinfo;
- if (aac_fib_send(ContainerCommand,
- fibptr,
- sizeof(struct aac_query_mount),
- FsaNormal,
- 1, 1,
- NULL, NULL) < 0)
- goto error;
- } else
- dresp->mnt[0].capacityhigh = 0;
+ aac_fib_init(fibptr);
+
+ dinfo = (struct aac_query_mount *)fib_data(fibptr);
+
+ dinfo->command = cpu_to_le32(VM_NameServe);
+ dinfo->count = cpu_to_le32(scmd_id(scsicmd));
+ dinfo->type = cpu_to_le32(FT_FILESYS);
+ scsicmd->SCp.ptr = (char *)callback;
- if ((le32_to_cpu(dresp->status) == ST_OK) &&
- (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
- (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
- fsa_dev_ptr[cid].valid = 1;
- fsa_dev_ptr[cid].type = le32_to_cpu(dresp->mnt[0].vol);
- fsa_dev_ptr[cid].size
- = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
- (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
- if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
- fsa_dev_ptr[cid].ro = 1;
+ status = aac_fib_send(ContainerCommand,
+ fibptr,
+ sizeof(struct aac_query_mount),
+ FsaNormal,
+ 0, 1,
+ (fib_callback) _aac_probe_container1,
+ (void *) scsicmd);
+ /*
+ * Check that the command queued to the controller
+ */
+ if (status == -EINPROGRESS) {
+ scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+ return 0;
+ }
+ if (status < 0) {
+ scsicmd->SCp.ptr = NULL;
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ }
}
+ if (status < 0) {
+ struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
+ if (fsa_dev_ptr) {
+ fsa_dev_ptr += scmd_id(scsicmd);
+ if ((fsa_dev_ptr->valid & 1) == 0) {
+ fsa_dev_ptr->valid = 0;
+ return (*callback)(scsicmd);
+ }
+ }
+ }
+ return status;
+}
-error:
- aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
+/**
+ * aac_probe_container - query a logical volume
+ * @dev: device to query
+ * @cid: container identifier
+ *
+ * Queries the controller about the given volume. The volume information
+ * is updated in the struct fsa_dev_info structure rather than returned.
+ */
+static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd)
+{
+ scsicmd->device = NULL;
+ return 0;
+}
+
+int aac_probe_container(struct aac_dev *dev, int cid)
+{
+ struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL);
+ struct scsi_device *scsidev = kmalloc(sizeof(*scsidev), GFP_KERNEL);
+ int status;
+ if (!scsicmd || !scsidev) {
+ kfree(scsicmd);
+ kfree(scsidev);
+ return -ENOMEM;
+ }
+ scsicmd->list.next = NULL;
+ scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))_aac_probe_container1;
+
+ scsicmd->device = scsidev;
+ scsidev->sdev_state = 0;
+ scsidev->id = cid;
+ scsidev->host = dev->scsi_host_ptr;
+
+ if (_aac_probe_container(scsicmd, aac_probe_container_callback1) == 0)
+ while (scsicmd->device == scsidev)
+ schedule();
+ kfree(scsidev);
+ status = scsicmd->SCp.Status;
+ kfree(scsicmd);
return status;
}
@@ -1115,6 +1193,12 @@ int aac_get_adapter_info(struct aac_dev* dev)
printk(KERN_INFO "%s%d: serial %x\n",
dev->name, dev->id,
le32_to_cpu(dev->adapter_info.serial[0]));
+ if (dev->supplement_adapter_info.VpdInfo.Tsid[0]) {
+ printk(KERN_INFO "%s%d: TSID %.*s\n",
+ dev->name, dev->id,
+ (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
+ dev->supplement_adapter_info.VpdInfo.Tsid);
+ }
}
dev->nondasd_support = 0;
@@ -1241,7 +1325,9 @@ static void io_callback(void *context, struct fib * fibptr)
u32 cid;
scsicmd = (struct scsi_cmnd *) context;
- scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+ if (!aac_valid_context(scsicmd, fibptr))
+ return;
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
cid = scmd_id(scsicmd);
@@ -1317,7 +1403,7 @@ static void io_callback(void *context, struct fib * fibptr)
scsicmd->scsi_done(scsicmd);
}
-static int aac_read(struct scsi_cmnd * scsicmd, int cid)
+static int aac_read(struct scsi_cmnd * scsicmd)
{
u64 lba;
u32 count;
@@ -1331,7 +1417,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
*/
switch (scsicmd->cmnd[0]) {
case READ_6:
- dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd)));
lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
(scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
@@ -1341,7 +1427,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
count = 256;
break;
case READ_16:
- dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 56) |
((u64)scsicmd->cmnd[3] << 48) |
@@ -1355,7 +1441,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
break;
case READ_12:
- dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 24) |
(scsicmd->cmnd[3] << 16) |
@@ -1365,7 +1451,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
break;
default:
- dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 24) |
(scsicmd->cmnd[3] << 16) |
@@ -1405,7 +1491,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
return 0;
}
-static int aac_write(struct scsi_cmnd * scsicmd, int cid)
+static int aac_write(struct scsi_cmnd * scsicmd)
{
u64 lba;
u32 count;
@@ -1424,7 +1510,7 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
if (count == 0)
count = 256;
} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
- dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 56) |
((u64)scsicmd->cmnd[3] << 48) |
@@ -1436,14 +1522,14 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
} else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */
- dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16)
| (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16)
| (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
} else {
- dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
}
@@ -1488,7 +1574,9 @@ static void synchronize_callback(void *context, struct fib *fibptr)
struct scsi_cmnd *cmd;
cmd = context;
- cmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+ if (!aac_valid_context(cmd, fibptr))
+ return;
dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n",
smp_processor_id(), jiffies));
@@ -1523,7 +1611,7 @@ static void synchronize_callback(void *context, struct fib *fibptr)
cmd->scsi_done(cmd);
}
-static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
+static int aac_synchronize(struct scsi_cmnd *scsicmd)
{
int status;
struct fib *cmd_fibcontext;
@@ -1568,7 +1656,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
synchronizecmd = fib_data(cmd_fibcontext);
synchronizecmd->command = cpu_to_le32(VM_ContainerConfig);
synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE);
- synchronizecmd->cid = cpu_to_le32(cid);
+ synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd));
synchronizecmd->count =
cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
@@ -1646,29 +1734,12 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case TEST_UNIT_READY:
if (dev->in_reset)
return -1;
- spin_unlock_irq(host->host_lock);
- aac_probe_container(dev, cid);
- if ((fsa_dev_ptr[cid].valid & 1) == 0)
- fsa_dev_ptr[cid].valid = 0;
- spin_lock_irq(host->host_lock);
- if (fsa_dev_ptr[cid].valid == 0) {
- scsicmd->result = DID_NO_CONNECT << 16;
- scsicmd->scsi_done(scsicmd);
- return 0;
- }
+ return _aac_probe_container(scsicmd,
+ aac_probe_container_callback2);
default:
break;
}
}
- /*
- * If the target container still doesn't exist,
- * return failure
- */
- if (fsa_dev_ptr[cid].valid == 0) {
- scsicmd->result = DID_BAD_TARGET << 16;
- scsicmd->scsi_done(scsicmd);
- return 0;
- }
} else { /* check for physical non-dasd devices */
if ((dev->nondasd_support == 1) || expose_physicals) {
if (dev->in_reset)
@@ -1733,7 +1804,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */
aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
- return aac_get_container_name(scsicmd, cid);
+ return aac_get_container_name(scsicmd);
}
case SERVICE_ACTION_IN:
if (!(dev->raw_io_interface) ||
@@ -1899,7 +1970,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
min(sizeof(fsa_dev_ptr[cid].devname),
sizeof(scsicmd->request->rq_disk->disk_name) + 1));
- return aac_read(scsicmd, cid);
+ return aac_read(scsicmd);
case WRITE_6:
case WRITE_10:
@@ -1907,11 +1978,11 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case WRITE_16:
if (dev->in_reset)
return -1;
- return aac_write(scsicmd, cid);
+ return aac_write(scsicmd);
case SYNCHRONIZE_CACHE:
/* Issue FIB to tell Firmware to flush it's cache */
- return aac_synchronize(scsicmd, cid);
+ return aac_synchronize(scsicmd);
default:
/*
@@ -2058,7 +2129,10 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
struct scsi_cmnd *scsicmd;
scsicmd = (struct scsi_cmnd *) context;
- scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+ if (!aac_valid_context(scsicmd, fibptr))
+ return;
+
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
BUG_ON(fibptr == NULL);
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 39ecd0d22eb..45ca3e80161 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,8 +12,8 @@
*----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2423
-# define AAC_DRIVER_BRANCH "-mh3"
+# define AAC_DRIVER_BUILD 2437
+# define AAC_DRIVER_BRANCH "-mh4"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -48,49 +48,13 @@ struct diskparm
/*
- * DON'T CHANGE THE ORDER, this is set by the firmware
+ * Firmware constants
*/
#define CT_NONE 0
-#define CT_VOLUME 1
-#define CT_MIRROR 2
-#define CT_STRIPE 3
-#define CT_RAID5 4
-#define CT_SSRW 5
-#define CT_SSRO 6
-#define CT_MORPH 7
-#define CT_PASSTHRU 8
-#define CT_RAID4 9
-#define CT_RAID10 10 /* stripe of mirror */
-#define CT_RAID00 11 /* stripe of stripe */
-#define CT_VOLUME_OF_MIRRORS 12 /* volume of mirror */
-#define CT_PSEUDO_RAID 13 /* really raid4 */
-#define CT_LAST_VOLUME_TYPE 14
#define CT_OK 218
-
-/*
- * Types of objects addressable in some fashion by the client.
- * This is a superset of those objects handled just by the filesystem
- * and includes "raw" objects that an administrator would use to
- * configure containers and filesystems.
- */
-
-#define FT_REG 1 /* regular file */
-#define FT_DIR 2 /* directory */
-#define FT_BLK 3 /* "block" device - reserved */
-#define FT_CHR 4 /* "character special" device - reserved */
-#define FT_LNK 5 /* symbolic link */
-#define FT_SOCK 6 /* socket */
-#define FT_FIFO 7 /* fifo */
#define FT_FILESYS 8 /* ADAPTEC's "FSA"(tm) filesystem */
#define FT_DRIVE 9 /* physical disk - addressable in scsi by bus/id/lun */
-#define FT_SLICE 10 /* virtual disk - raw volume - slice */
-#define FT_PARTITION 11 /* FSA partition - carved out of a slice - building block for containers */
-#define FT_VOLUME 12 /* Container - Volume Set */
-#define FT_STRIPE 13 /* Container - Stripe Set */
-#define FT_MIRROR 14 /* Container - Mirror Set */
-#define FT_RAID5 15 /* Container - Raid 5 Set */
-#define FT_DATABASE 16 /* Storage object with "foreign" content manager */
/*
* Host side memory scatter gather list
@@ -497,6 +461,7 @@ struct adapter_ops
void (*adapter_enable_int)(struct aac_dev *dev);
int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4);
int (*adapter_check_health)(struct aac_dev *dev);
+ int (*adapter_restart)(struct aac_dev *dev, int bled);
/* Transport operations */
int (*adapter_ioremap)(struct aac_dev * dev, u32 size);
irqreturn_t (*adapter_intr)(int irq, void *dev_id);
@@ -833,7 +798,7 @@ struct fib {
*/
struct list_head fiblink;
void *data;
- struct hw_fib *hw_fib; /* Actual shared object */
+ struct hw_fib *hw_fib_va; /* Actual shared object */
dma_addr_t hw_fib_pa; /* physical address of hw_fib*/
};
@@ -878,10 +843,25 @@ struct aac_supplement_adapter_info
__le32 Version;
__le32 FeatureBits;
u8 SlotNumber;
- u8 ReservedPad0[0];
+ u8 ReservedPad0[3];
u8 BuildDate[12];
__le32 CurrentNumberPorts;
- __le32 ReservedGrowth[24];
+ struct {
+ u8 AssemblyPn[8];
+ u8 FruPn[8];
+ u8 BatteryFruPn[8];
+ u8 EcVersionString[8];
+ u8 Tsid[12];
+ } VpdInfo;
+ __le32 FlashFirmwareRevision;
+ __le32 FlashFirmwareBuild;
+ __le32 RaidTypeMorphOptions;
+ __le32 FlashFirmwareBootRevision;
+ __le32 FlashFirmwareBootBuild;
+ u8 MfgPcbaSerialNo[12];
+ u8 MfgWWNName[8];
+ __le32 MoreFeatureBits;
+ __le32 ReservedGrowth[1];
};
#define AAC_FEATURE_FALCON 0x00000010
#define AAC_SIS_VERSION_V3 3
@@ -970,7 +950,6 @@ struct aac_dev
struct fib *fibs;
struct fib *free_fib;
- struct fib *timeout_fib;
spinlock_t fib_lock;
struct aac_queue_block *queues;
@@ -1060,6 +1039,9 @@ struct aac_dev
#define aac_adapter_check_health(dev) \
(dev)->a_ops.adapter_check_health(dev)
+#define aac_adapter_restart(dev,bled) \
+ (dev)->a_ops.adapter_restart(dev,bled)
+
#define aac_adapter_ioremap(dev, size) \
(dev)->a_ops.adapter_ioremap(dev, size)
@@ -1516,8 +1498,7 @@ struct aac_mntent {
struct creation_info create_info; /* if applicable */
__le32 capacity;
__le32 vol; /* substrate structure */
- __le32 obj; /* FT_FILESYS,
- FT_DATABASE, etc. */
+ __le32 obj; /* FT_FILESYS, etc. */
__le32 state; /* unready for mounting,
readonly, etc. */
union aac_contentinfo fileinfo; /* Info specific to content
@@ -1817,7 +1798,7 @@ int aac_fib_send(u16 command, struct fib * context, unsigned long size, int prio
int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry);
void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
int aac_fib_complete(struct fib * context);
-#define fib_data(fibctx) ((void *)(fibctx)->hw_fib->data)
+#define fib_data(fibctx) ((void *)(fibctx)->hw_fib_va->data)
struct aac_dev *aac_init_adapter(struct aac_dev *dev);
int aac_get_config_status(struct aac_dev *dev, int commit_flag);
int aac_get_containers(struct aac_dev *dev);
@@ -1840,8 +1821,11 @@ struct aac_driver_ident* aac_get_driver_ident(int devtype);
int aac_get_adapter_info(struct aac_dev* dev);
int aac_send_shutdown(struct aac_dev *dev);
int aac_probe_container(struct aac_dev *dev, int cid);
+int _aac_rx_init(struct aac_dev *dev);
+int aac_rx_select_comm(struct aac_dev *dev, int comm);
extern int numacb;
extern int acbsize;
extern char aac_driver_version[];
extern int startup_timeout;
extern int aif_timeout;
+extern int expose_physicals;
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index e21070f4eac..72b0393b459 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -64,12 +64,15 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
unsigned size;
int retval;
+ if (dev->in_reset) {
+ return -EBUSY;
+ }
fibptr = aac_fib_alloc(dev);
if(fibptr == NULL) {
return -ENOMEM;
}
- kfib = fibptr->hw_fib;
+ kfib = fibptr->hw_fib_va;
/*
* First copy in the header so that we can check the size field.
*/
@@ -91,9 +94,9 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
goto cleanup;
}
/* Highjack the hw_fib */
- hw_fib = fibptr->hw_fib;
+ hw_fib = fibptr->hw_fib_va;
hw_fib_pa = fibptr->hw_fib_pa;
- fibptr->hw_fib = kfib = pci_alloc_consistent(dev->pdev, size, &fibptr->hw_fib_pa);
+ fibptr->hw_fib_va = kfib = pci_alloc_consistent(dev->pdev, size, &fibptr->hw_fib_pa);
memset(((char *)kfib) + dev->max_fib_size, 0, size - dev->max_fib_size);
memcpy(kfib, hw_fib, dev->max_fib_size);
}
@@ -137,7 +140,7 @@ cleanup:
if (hw_fib) {
pci_free_consistent(dev->pdev, size, kfib, fibptr->hw_fib_pa);
fibptr->hw_fib_pa = hw_fib_pa;
- fibptr->hw_fib = hw_fib;
+ fibptr->hw_fib_va = hw_fib;
}
if (retval != -EINTR)
aac_fib_free(fibptr);
@@ -282,15 +285,15 @@ return_fib:
fib = list_entry(entry, struct fib, fiblink);
fibctx->count--;
spin_unlock_irqrestore(&dev->fib_lock, flags);
- if (copy_to_user(f.fib, fib->hw_fib, sizeof(struct hw_fib))) {
- kfree(fib->hw_fib);
+ if (copy_to_user(f.fib, fib->hw_fib_va, sizeof(struct hw_fib))) {
+ kfree(fib->hw_fib_va);
kfree(fib);
return -EFAULT;
}
/*
* Free the space occupied by this copy of the fib.
*/
- kfree(fib->hw_fib);
+ kfree(fib->hw_fib_va);
kfree(fib);
status = 0;
} else {
@@ -340,7 +343,7 @@ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
/*
* Free the space occupied by this copy of the fib.
*/
- kfree(fib->hw_fib);
+ kfree(fib->hw_fib_va);
kfree(fib);
}
/*
@@ -388,10 +391,8 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
/*
* Extract the fibctx from the input parameters
*/
- if (fibctx->unique == (u32)(unsigned long)arg) {
- /* We found a winner */
+ if (fibctx->unique == (u32)(ptrdiff_t)arg) /* We found a winner */
break;
- }
entry = entry->next;
fibctx = NULL;
}
@@ -465,16 +466,20 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
void *sg_list[32];
u32 sg_indx = 0;
u32 byte_count = 0;
- u32 actual_fibsize = 0;
+ u32 actual_fibsize64, actual_fibsize = 0;
int i;
+ if (dev->in_reset) {
+ dprintk((KERN_DEBUG"aacraid: send raw srb -EBUSY\n"));
+ return -EBUSY;
+ }
if (!capable(CAP_SYS_ADMIN)){
dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n"));
return -EPERM;
}
/*
- * Allocate and initialize a Fib then setup a BlockWrite command
+ * Allocate and initialize a Fib then setup a SRB command
*/
if (!(srbfib = aac_fib_alloc(dev))) {
return -ENOMEM;
@@ -541,129 +546,183 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
rcode = -EINVAL;
goto cleanup;
}
- if (dev->dac_support == 1) {
+ actual_fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) +
+ ((user_srbcmd->sg.count & 0xff) * sizeof(struct sgentry));
+ actual_fibsize64 = actual_fibsize + (user_srbcmd->sg.count & 0xff) *
+ (sizeof(struct sgentry64) - sizeof(struct sgentry));
+ /* User made a mistake - should not continue */
+ if ((actual_fibsize != fibsize) && (actual_fibsize64 != fibsize)) {
+ dprintk((KERN_DEBUG"aacraid: Bad Size specified in "
+ "Raw SRB command calculated fibsize=%lu;%lu "
+ "user_srbcmd->sg.count=%d aac_srb=%lu sgentry=%lu;%lu "
+ "issued fibsize=%d\n",
+ actual_fibsize, actual_fibsize64, user_srbcmd->sg.count,
+ sizeof(struct aac_srb), sizeof(struct sgentry),
+ sizeof(struct sgentry64), fibsize));
+ rcode = -EINVAL;
+ goto cleanup;
+ }
+ if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) {
+ dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"));
+ rcode = -EINVAL;
+ goto cleanup;
+ }
+ byte_count = 0;
+ if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) {
struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg;
struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg;
- struct user_sgmap* usg;
- byte_count = 0;
/*
* This should also catch if user used the 32 bit sgmap
*/
- actual_fibsize = sizeof(struct aac_srb) -
- sizeof(struct sgentry) +
- ((upsg->count & 0xff) *
- sizeof(struct sgentry));
- if(actual_fibsize != fibsize){ // User made a mistake - should not continue
- dprintk((KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n"));
- rcode = -EINVAL;
- goto cleanup;
- }
- usg = kmalloc(actual_fibsize - sizeof(struct aac_srb)
- + sizeof(struct sgmap), GFP_KERNEL);
- if (!usg) {
- dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n"));
- rcode = -ENOMEM;
- goto cleanup;
- }
- memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb)
- + sizeof(struct sgmap));
- actual_fibsize = sizeof(struct aac_srb) -
- sizeof(struct sgentry) + ((usg->count & 0xff) *
- sizeof(struct sgentry64));
- if ((data_dir == DMA_NONE) && upsg->count) {
- kfree (usg);
- dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"));
- rcode = -EINVAL;
- goto cleanup;
- }
+ if (actual_fibsize64 == fibsize) {
+ actual_fibsize = actual_fibsize64;
+ for (i = 0; i < upsg->count; i++) {
+ u64 addr;
+ void* p;
+ /* Does this really need to be GFP_DMA? */
+ p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+ if(p == 0) {
+ dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+ upsg->sg[i].count,i,upsg->count));
+ rcode = -ENOMEM;
+ goto cleanup;
+ }
+ addr = (u64)upsg->sg[i].addr[0];
+ addr += ((u64)upsg->sg[i].addr[1]) << 32;
+ sg_user[i] = (void __user *)(ptrdiff_t)addr;
+ sg_list[i] = p; // save so we can clean up later
+ sg_indx = i;
+
+ if( flags & SRB_DataOut ){
+ if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+ dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+ rcode = -EFAULT;
+ goto cleanup;
+ }
+ }
+ addr = pci_map_single(dev->pdev, p, upsg->sg[i].count, data_dir);
- for (i = 0; i < usg->count; i++) {
- u64 addr;
- void* p;
- /* Does this really need to be GFP_DMA? */
- p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
- if(p == 0) {
- kfree (usg);
- dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
- usg->sg[i].count,i,usg->count));
+ psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
+ psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
+ byte_count += upsg->sg[i].count;
+ psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);
+ }
+ } else {
+ struct user_sgmap* usg;
+ usg = kmalloc(actual_fibsize - sizeof(struct aac_srb)
+ + sizeof(struct sgmap), GFP_KERNEL);
+ if (!usg) {
+ dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n"));
rcode = -ENOMEM;
goto cleanup;
}
- sg_user[i] = (void __user *)(long)usg->sg[i].addr;
- sg_list[i] = p; // save so we can clean up later
- sg_indx = i;
-
- if( flags & SRB_DataOut ){
- if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+ memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb)
+ + sizeof(struct sgmap));
+ actual_fibsize = actual_fibsize64;
+
+ for (i = 0; i < usg->count; i++) {
+ u64 addr;
+ void* p;
+ /* Does this really need to be GFP_DMA? */
+ p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+ if(p == 0) {
kfree (usg);
- dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
- rcode = -EFAULT;
+ dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+ usg->sg[i].count,i,usg->count));
+ rcode = -ENOMEM;
goto cleanup;
}
- }
- addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir);
+ sg_user[i] = (void __user *)(ptrdiff_t)usg->sg[i].addr;
+ sg_list[i] = p; // save so we can clean up later
+ sg_indx = i;
+
+ if( flags & SRB_DataOut ){
+ if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+ kfree (usg);
+ dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+ rcode = -EFAULT;
+ goto cleanup;
+ }
+ }
+ addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir);
- psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
- psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
- psg->sg[i].count = cpu_to_le32(usg->sg[i].count);
- byte_count += usg->sg[i].count;
+ psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
+ psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
+ byte_count += usg->sg[i].count;
+ psg->sg[i].count = cpu_to_le32(usg->sg[i].count);
+ }
+ kfree (usg);
}
- kfree (usg);
-
srbcmd->count = cpu_to_le32(byte_count);
psg->count = cpu_to_le32(sg_indx+1);
status = aac_fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL);
} else {
struct user_sgmap* upsg = &user_srbcmd->sg;
struct sgmap* psg = &srbcmd->sg;
- byte_count = 0;
-
- actual_fibsize = sizeof (struct aac_srb) + (((user_srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
- if(actual_fibsize != fibsize){ // User made a mistake - should not continue
- dprintk((KERN_DEBUG"aacraid: Bad Size specified in "
- "Raw SRB command calculated fibsize=%d "
- "user_srbcmd->sg.count=%d aac_srb=%d sgentry=%d "
- "issued fibsize=%d\n",
- actual_fibsize, user_srbcmd->sg.count,
- sizeof(struct aac_srb), sizeof(struct sgentry),
- fibsize));
- rcode = -EINVAL;
- goto cleanup;
- }
- if ((data_dir == DMA_NONE) && upsg->count) {
- dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"));
- rcode = -EINVAL;
- goto cleanup;
- }
- for (i = 0; i < upsg->count; i++) {
- dma_addr_t addr;
- void* p;
- p = kmalloc(upsg->sg[i].count, GFP_KERNEL);
- if(p == 0) {
- dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
- upsg->sg[i].count, i, upsg->count));
- rcode = -ENOMEM;
- goto cleanup;
- }
- sg_user[i] = (void __user *)(long)upsg->sg[i].addr;
- sg_list[i] = p; // save so we can clean up later
- sg_indx = i;
-
- if( flags & SRB_DataOut ){
- if(copy_from_user(p, sg_user[i],
- upsg->sg[i].count)) {
- dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
- rcode = -EFAULT;
+
+ if (actual_fibsize64 == fibsize) {
+ struct user_sgmap64* usg = (struct user_sgmap64 *)upsg;
+ for (i = 0; i < upsg->count; i++) {
+ u64 addr;
+ void* p;
+ /* Does this really need to be GFP_DMA? */
+ p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+ if(p == 0) {
+ dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+ usg->sg[i].count,i,usg->count));
+ rcode = -ENOMEM;
goto cleanup;
}
+ addr = (u64)usg->sg[i].addr[0];
+ addr += ((u64)usg->sg[i].addr[1]) << 32;
+ sg_user[i] = (void __user *)(ptrdiff_t)addr;
+ sg_list[i] = p; // save so we can clean up later
+ sg_indx = i;
+
+ if( flags & SRB_DataOut ){
+ if(copy_from_user(p,sg_user[i],usg->sg[i].count)){
+ dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+ rcode = -EFAULT;
+ goto cleanup;
+ }
+ }
+ addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir);
+
+ psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff);
+ byte_count += usg->sg[i].count;
+ psg->sg[i].count = cpu_to_le32(usg->sg[i].count);
}
- addr = pci_map_single(dev->pdev, p,
- upsg->sg[i].count, data_dir);
+ } else {
+ for (i = 0; i < upsg->count; i++) {
+ dma_addr_t addr;
+ void* p;
+ p = kmalloc(upsg->sg[i].count, GFP_KERNEL);
+ if(p == 0) {
+ dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+ upsg->sg[i].count, i, upsg->count));
+ rcode = -ENOMEM;
+ goto cleanup;
+ }
+ sg_user[i] = (void __user *)(ptrdiff_t)upsg->sg[i].addr;
+ sg_list[i] = p; // save so we can clean up later
+ sg_indx = i;
+
+ if( flags & SRB_DataOut ){
+ if(copy_from_user(p, sg_user[i],
+ upsg->sg[i].count)) {
+ dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+ rcode = -EFAULT;
+ goto cleanup;
+ }
+ }
+ addr = pci_map_single(dev->pdev, p,
+ upsg->sg[i].count, data_dir);
- psg->sg[i].addr = cpu_to_le32(addr);
- psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);
- byte_count += upsg->sg[i].count;
+ psg->sg[i].addr = cpu_to_le32(addr);
+ byte_count += upsg->sg[i].count;
+ psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);
+ }
}
srbcmd->count = cpu_to_le32(byte_count);
psg->count = cpu_to_le32(sg_indx+1);
@@ -682,7 +741,8 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
if( flags & SRB_DataIn ) {
for(i = 0 ; i <= sg_indx; i++){
- byte_count = le32_to_cpu((dev->dac_support == 1)
+ byte_count = le32_to_cpu(
+ (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)
? ((struct sgmap64*)&srbcmd->sg)->sg[i].count
: srbcmd->sg.sg[i].count);
if(copy_to_user(sg_user[i], sg_list[i], byte_count)){
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index ae34768987a..33682ce96a5 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -110,7 +110,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
/*
* Align the beginning of Headers to commalign
*/
- align = (commalign - ((unsigned long)(base) & (commalign - 1)));
+ align = (commalign - ((ptrdiff_t)(base) & (commalign - 1)));
base = base + align;
phys = phys + align;
/*
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 1b97f60652b..5824a757a75 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -94,7 +94,7 @@ void aac_fib_map_free(struct aac_dev *dev)
int aac_fib_setup(struct aac_dev * dev)
{
struct fib *fibptr;
- struct hw_fib *hw_fib_va;
+ struct hw_fib *hw_fib;
dma_addr_t hw_fib_pa;
int i;
@@ -106,24 +106,24 @@ int aac_fib_setup(struct aac_dev * dev)
if (i<0)
return -ENOMEM;
- hw_fib_va = dev->hw_fib_va;
+ hw_fib = dev->hw_fib_va;
hw_fib_pa = dev->hw_fib_pa;
- memset(hw_fib_va, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
+ memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
/*
* Initialise the fibs
*/
for (i = 0, fibptr = &dev->fibs[i]; i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); i++, fibptr++)
{
fibptr->dev = dev;
- fibptr->hw_fib = hw_fib_va;
- fibptr->data = (void *) fibptr->hw_fib->data;
+ fibptr->hw_fib_va = hw_fib;
+ fibptr->data = (void *) fibptr->hw_fib_va->data;
fibptr->next = fibptr+1; /* Forward chain the fibs */
init_MUTEX_LOCKED(&fibptr->event_wait);
spin_lock_init(&fibptr->event_lock);
- hw_fib_va->header.XferState = cpu_to_le32(0xffffffff);
- hw_fib_va->header.SenderSize = cpu_to_le16(dev->max_fib_size);
+ hw_fib->header.XferState = cpu_to_le32(0xffffffff);
+ hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size);
fibptr->hw_fib_pa = hw_fib_pa;
- hw_fib_va = (struct hw_fib *)((unsigned char *)hw_fib_va + dev->max_fib_size);
+ hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + dev->max_fib_size);
hw_fib_pa = hw_fib_pa + dev->max_fib_size;
}
/*
@@ -166,7 +166,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
* Null out fields that depend on being zero at the start of
* each I/O
*/
- fibptr->hw_fib->header.XferState = 0;
+ fibptr->hw_fib_va->header.XferState = 0;
fibptr->callback = NULL;
fibptr->callback_data = NULL;
@@ -178,7 +178,6 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
* @fibptr: fib to free up
*
* Frees up a fib and places it on the appropriate queue
- * (either free or timed out)
*/
void aac_fib_free(struct fib *fibptr)
@@ -186,19 +185,15 @@ void aac_fib_free(struct fib *fibptr)
unsigned long flags;
spin_lock_irqsave(&fibptr->dev->fib_lock, flags);
- if (fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT) {
+ if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
aac_config.fib_timeouts++;
- fibptr->next = fibptr->dev->timeout_fib;
- fibptr->dev->timeout_fib = fibptr;
- } else {
- if (fibptr->hw_fib->header.XferState != 0) {
- printk(KERN_WARNING "aac_fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n",
- (void*)fibptr,
- le32_to_cpu(fibptr->hw_fib->header.XferState));
- }
- fibptr->next = fibptr->dev->free_fib;
- fibptr->dev->free_fib = fibptr;
- }
+ if (fibptr->hw_fib_va->header.XferState != 0) {
+ printk(KERN_WARNING "aac_fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n",
+ (void*)fibptr,
+ le32_to_cpu(fibptr->hw_fib_va->header.XferState));
+ }
+ fibptr->next = fibptr->dev->free_fib;
+ fibptr->dev->free_fib = fibptr;
spin_unlock_irqrestore(&fibptr->dev->fib_lock, flags);
}
@@ -211,7 +206,7 @@ void aac_fib_free(struct fib *fibptr)
void aac_fib_init(struct fib *fibptr)
{
- struct hw_fib *hw_fib = fibptr->hw_fib;
+ struct hw_fib *hw_fib = fibptr->hw_fib_va;
hw_fib->header.StructType = FIB_MAGIC;
hw_fib->header.Size = cpu_to_le16(fibptr->dev->max_fib_size);
@@ -231,7 +226,7 @@ void aac_fib_init(struct fib *fibptr)
static void fib_dealloc(struct fib * fibptr)
{
- struct hw_fib *hw_fib = fibptr->hw_fib;
+ struct hw_fib *hw_fib = fibptr->hw_fib_va;
BUG_ON(hw_fib->header.StructType != FIB_MAGIC);
hw_fib->header.XferState = 0;
}
@@ -386,7 +381,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
void *callback_data)
{
struct aac_dev * dev = fibptr->dev;
- struct hw_fib * hw_fib = fibptr->hw_fib;
+ struct hw_fib * hw_fib = fibptr->hw_fib_va;
unsigned long flags = 0;
unsigned long qflags;
@@ -430,7 +425,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
*/
hw_fib->header.Command = cpu_to_le16(command);
hw_fib->header.XferState |= cpu_to_le32(SentFromHost);
- fibptr->hw_fib->header.Flags = 0; /* 0 the flags field - internal only*/
+ fibptr->hw_fib_va->header.Flags = 0; /* 0 the flags field - internal only*/
/*
* Set the size of the Fib we want to send to the adapter
*/
@@ -462,7 +457,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
dprintk((KERN_DEBUG " Command = %d.\n", le32_to_cpu(hw_fib->header.Command)));
dprintk((KERN_DEBUG " SubCommand = %d.\n", le32_to_cpu(((struct aac_query_mount *)fib_data(fibptr))->command)));
dprintk((KERN_DEBUG " XferState = %x.\n", le32_to_cpu(hw_fib->header.XferState)));
- dprintk((KERN_DEBUG " hw_fib va being sent=%p\n",fibptr->hw_fib));
+ dprintk((KERN_DEBUG " hw_fib va being sent=%p\n",fibptr->hw_fib_va));
dprintk((KERN_DEBUG " hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));
dprintk((KERN_DEBUG " fib being sent=%p\n",fibptr));
@@ -513,22 +508,20 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
}
udelay(5);
}
- } else if (down_interruptible(&fibptr->event_wait)) {
- spin_lock_irqsave(&fibptr->event_lock, flags);
- if (fibptr->done == 0) {
- fibptr->done = 2; /* Tell interrupt we aborted */
- spin_unlock_irqrestore(&fibptr->event_lock, flags);
- return -EINTR;
- }
+ } else
+ (void)down_interruptible(&fibptr->event_wait);
+ spin_lock_irqsave(&fibptr->event_lock, flags);
+ if (fibptr->done == 0) {
+ fibptr->done = 2; /* Tell interrupt we aborted */
spin_unlock_irqrestore(&fibptr->event_lock, flags);
+ return -EINTR;
}
+ spin_unlock_irqrestore(&fibptr->event_lock, flags);
BUG_ON(fibptr->done == 0);
- if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)){
+ if(unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
return -ETIMEDOUT;
- } else {
- return 0;
- }
+ return 0;
}
/*
* If the user does not want a response than return success otherwise
@@ -624,7 +617,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
{
- struct hw_fib * hw_fib = fibptr->hw_fib;
+ struct hw_fib * hw_fib = fibptr->hw_fib_va;
struct aac_dev * dev = fibptr->dev;
struct aac_queue * q;
unsigned long nointr = 0;
@@ -688,7 +681,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
int aac_fib_complete(struct fib *fibptr)
{
- struct hw_fib * hw_fib = fibptr->hw_fib;
+ struct hw_fib * hw_fib = fibptr->hw_fib_va;
/*
* Check for a fib which has already been completed
@@ -774,9 +767,8 @@ void aac_printf(struct aac_dev *dev, u32 val)
#define AIF_SNIFF_TIMEOUT (30*HZ)
static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
{
- struct hw_fib * hw_fib = fibptr->hw_fib;
+ struct hw_fib * hw_fib = fibptr->hw_fib_va;
struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data;
- int busy;
u32 container;
struct scsi_device *device;
enum {
@@ -988,9 +980,6 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
* behind you.
*/
- busy = 0;
-
-
/*
* Find the scsi_device associated with the SCSI address,
* and mark it as changed, invalidating the cache. This deals
@@ -1035,7 +1024,6 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
static int _aac_reset_adapter(struct aac_dev *aac)
{
int index, quirks;
- u32 ret;
int retval;
struct Scsi_Host *host;
struct scsi_device *dev;
@@ -1059,35 +1047,29 @@ static int _aac_reset_adapter(struct aac_dev *aac)
* If a positive health, means in a known DEAD PANIC
* state and the adapter could be reset to `try again'.
*/
- retval = aac_adapter_check_health(aac);
- if (retval == 0)
- retval = aac_adapter_sync_cmd(aac, IOP_RESET_ALWAYS,
- 0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL);
- if (retval)
- retval = aac_adapter_sync_cmd(aac, IOP_RESET,
- 0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL);
+ retval = aac_adapter_restart(aac, aac_adapter_check_health(aac));
if (retval)
goto out;
- if (ret != 0x00000001) {
- retval = -ENODEV;
- goto out;
- }
/*
* Loop through the fibs, close the synchronous FIBS
*/
- for (index = 0; index < (aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); index++) {
+ for (retval = 1, index = 0; index < (aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); index++) {
struct fib *fib = &aac->fibs[index];
- if (!(fib->hw_fib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) &&
- (fib->hw_fib->header.XferState & cpu_to_le32(ResponseExpected))) {
+ if (!(fib->hw_fib_va->header.XferState & cpu_to_le32(NoResponseExpected | Async)) &&
+ (fib->hw_fib_va->header.XferState & cpu_to_le32(ResponseExpected))) {
unsigned long flagv;
spin_lock_irqsave(&fib->event_lock, flagv);
up(&fib->event_wait);
spin_unlock_irqrestore(&fib->event_lock, flagv);
schedule();
+ retval = 0;
}
}
+ /* Give some extra time for ioctls to complete. */
+ if (retval == 0)
+ ssleep(2);
index = aac->cardtype;
/*
@@ -1248,7 +1230,7 @@ int aac_check_health(struct aac_dev * aac)
memset(hw_fib, 0, sizeof(struct hw_fib));
memset(fib, 0, sizeof(struct fib));
- fib->hw_fib = hw_fib;
+ fib->hw_fib_va = hw_fib;
fib->dev = aac;
aac_fib_init(fib);
fib->type = FSAFS_NTC_FIB_CONTEXT;
@@ -1354,11 +1336,11 @@ int aac_command_thread(void *data)
* do anything at this point since we don't have
* anything defined for this thread to do.
*/
- hw_fib = fib->hw_fib;
+ hw_fib = fib->hw_fib_va;
memset(fib, 0, sizeof(struct fib));
fib->type = FSAFS_NTC_FIB_CONTEXT;
fib->size = sizeof( struct fib );
- fib->hw_fib = hw_fib;
+ fib->hw_fib_va = hw_fib;
fib->data = hw_fib->data;
fib->dev = dev;
/*
@@ -1485,7 +1467,7 @@ int aac_command_thread(void *data)
*/
memcpy(hw_newfib, hw_fib, sizeof(struct hw_fib));
memcpy(newfib, fib, sizeof(struct fib));
- newfib->hw_fib = hw_newfib;
+ newfib->hw_fib_va = hw_newfib;
/*
* Put the FIB onto the
* fibctx's fibs
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index d38b628be1a..42c7dcda6d9 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/completion.h>
@@ -73,7 +72,7 @@ unsigned int aac_response_normal(struct aac_queue * q)
u32 index = le32_to_cpu(entry->addr);
fast = index & 0x01;
fib = &dev->fibs[index >> 2];
- hwfib = fib->hw_fib;
+ hwfib = fib->hw_fib_va;
aac_consumer_free(dev, q, HostNormRespQueue);
/*
@@ -84,11 +83,13 @@ unsigned int aac_response_normal(struct aac_queue * q)
* continue. The caller has already been notified that
* the fib timed out.
*/
- if (!(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
- dev->queues->queue[AdapNormCmdQueue].numpending--;
- else {
- printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
- printk(KERN_DEBUG"aacraid: hwfib=%p fib index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib);
+ dev->queues->queue[AdapNormCmdQueue].numpending--;
+
+ if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
+ spin_unlock_irqrestore(q->lock, flags);
+ aac_fib_complete(fib);
+ aac_fib_free(fib);
+ spin_lock_irqsave(q->lock, flags);
continue;
}
spin_unlock_irqrestore(q->lock, flags);
@@ -193,7 +194,7 @@ unsigned int aac_command_normal(struct aac_queue *q)
INIT_LIST_HEAD(&fib->fiblink);
fib->type = FSAFS_NTC_FIB_CONTEXT;
fib->size = sizeof(struct fib);
- fib->hw_fib = hw_fib;
+ fib->hw_fib_va = hw_fib;
fib->data = hw_fib->data;
fib->dev = dev;
@@ -254,12 +255,13 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
return 1;
}
memset(hw_fib, 0, sizeof(struct hw_fib));
- memcpy(hw_fib, (struct hw_fib *)(((unsigned long)(dev->regs.sa)) + (index & ~0x00000002L)), sizeof(struct hw_fib));
+ memcpy(hw_fib, (struct hw_fib *)(((ptrdiff_t)(dev->regs.sa)) +
+ (index & ~0x00000002L)), sizeof(struct hw_fib));
memset(fib, 0, sizeof(struct fib));
INIT_LIST_HEAD(&fib->fiblink);
fib->type = FSAFS_NTC_FIB_CONTEXT;
fib->size = sizeof(struct fib);
- fib->hw_fib = hw_fib;
+ fib->hw_fib_va = hw_fib;
fib->data = hw_fib->data;
fib->dev = dev;
@@ -271,7 +273,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
} else {
int fast = index & 0x01;
struct fib * fib = &dev->fibs[index >> 2];
- struct hw_fib * hwfib = fib->hw_fib;
+ struct hw_fib * hwfib = fib->hw_fib_va;
/*
* Remove this fib from the Outstanding I/O queue.
@@ -281,14 +283,14 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
* continue. The caller has already been notified that
* the fib timed out.
*/
- if ((fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
- printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
- printk(KERN_DEBUG"aacraid: hwfib=%p index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib);
+ dev->queues->queue[AdapNormCmdQueue].numpending--;
+
+ if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
+ aac_fib_complete(fib);
+ aac_fib_free(fib);
return 0;
}
- dev->queues->queue[AdapNormCmdQueue].numpending--;
-
if (fast) {
/*
* Doctor the fib
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 0f948c2fb60..350ea7feb61 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -82,8 +82,6 @@ static LIST_HEAD(aac_devices);
static int aac_cfg_major = -1;
char aac_driver_version[] = AAC_DRIVER_FULL_VERSION;
-extern int expose_physicals;
-
/*
* Because of the way Linux names scsi devices, the order in this table has
* become important. Check for on-board Raid first, add-in cards second.
@@ -247,7 +245,19 @@ static struct aac_driver_ident aac_drivers[] = {
static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
+ struct Scsi_Host *host = cmd->device->host;
+ struct aac_dev *dev = (struct aac_dev *)host->hostdata;
+ u32 count = 0;
cmd->scsi_done = done;
+ for (; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
+ struct fib * fib = &dev->fibs[count];
+ struct scsi_cmnd * command;
+ if (fib->hw_fib_va->header.XferState &&
+ ((command = fib->callback_data)) &&
+ (command == cmd) &&
+ (cmd->SCp.phase == AAC_OWNER_FIRMWARE))
+ return 0; /* Already owned by Adapter */
+ }
cmd->SCp.phase = AAC_OWNER_LOWLEVEL;
return (aac_scsi_cmd(cmd) ? FAILED : 0);
}
@@ -446,6 +456,40 @@ static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg)
return aac_do_ioctl(dev, cmd, arg);
}
+static int aac_eh_abort(struct scsi_cmnd* cmd)
+{
+ struct scsi_device * dev = cmd->device;
+ struct Scsi_Host * host = dev->host;
+ struct aac_dev * aac = (struct aac_dev *)host->hostdata;
+ int count;
+ int ret = FAILED;
+
+ printk(KERN_ERR "%s: Host adapter abort request (%d,%d,%d,%d)\n",
+ AAC_DRIVERNAME,
+ host->host_no, sdev_channel(dev), sdev_id(dev), dev->lun);
+ switch (cmd->cmnd[0]) {
+ case SERVICE_ACTION_IN:
+ if (!(aac->raw_io_interface) ||
+ !(aac->raw_io_64) ||
+ ((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
+ break;
+ case INQUIRY:
+ case READ_CAPACITY:
+ case TEST_UNIT_READY:
+ /* Mark associated FIB to not complete, eh handler does this */
+ for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
+ struct fib * fib = &aac->fibs[count];
+ if (fib->hw_fib_va->header.XferState &&
+ (fib->callback_data == cmd)) {
+ fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
+ cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+ ret = SUCCESS;
+ }
+ }
+ }
+ return ret;
+}
+
/*
* aac_eh_reset - Reset command handling
* @scsi_cmd: SCSI command block causing the reset
@@ -457,12 +501,20 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
struct Scsi_Host * host = dev->host;
struct scsi_cmnd * command;
int count;
- struct aac_dev * aac;
+ struct aac_dev * aac = (struct aac_dev *)host->hostdata;
unsigned long flags;
+ /* Mark the associated FIB to not complete, eh handler does this */
+ for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
+ struct fib * fib = &aac->fibs[count];
+ if (fib->hw_fib_va->header.XferState &&
+ (fib->callback_data == cmd)) {
+ fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
+ cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+ }
+ }
printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n",
AAC_DRIVERNAME);
- aac = (struct aac_dev *)host->hostdata;
if ((count = aac_check_health(aac)))
return count;
@@ -496,7 +548,7 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
ssleep(1);
}
printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME);
- return -ETIMEDOUT;
+ return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
}
/**
@@ -796,6 +848,7 @@ static struct scsi_host_template aac_driver_template = {
.bios_param = aac_biosparm,
.shost_attrs = aac_attrs,
.slave_configure = aac_slave_configure,
+ .eh_abort_handler = aac_eh_abort,
.eh_host_reset_handler = aac_eh_reset,
.can_queue = AAC_NUM_IO_FIB,
.this_id = MAXIMUM_NUM_CONTAINERS,
diff --git a/drivers/scsi/aacraid/nark.c b/drivers/scsi/aacraid/nark.c
index c76b611b6af..a8ace567781 100644
--- a/drivers/scsi/aacraid/nark.c
+++ b/drivers/scsi/aacraid/nark.c
@@ -74,9 +74,6 @@ static int aac_nark_ioremap(struct aac_dev * dev, u32 size)
int aac_nark_init(struct aac_dev * dev)
{
- extern int _aac_rx_init(struct aac_dev *dev);
- extern int aac_rx_select_comm(struct aac_dev *dev, int comm);
-
/*
* Fill in the function dispatch table.
*/
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
index d953c3fe998..9c5fcfb398c 100644
--- a/drivers/scsi/aacraid/rkt.c
+++ b/drivers/scsi/aacraid/rkt.c
@@ -45,7 +45,6 @@
static int aac_rkt_select_comm(struct aac_dev *dev, int comm)
{
int retval;
- extern int aac_rx_select_comm(struct aac_dev *dev, int comm);
retval = aac_rx_select_comm(dev, comm);
if (comm == AAC_COMM_MESSAGE) {
/*
@@ -97,8 +96,6 @@ static int aac_rkt_ioremap(struct aac_dev * dev, u32 size)
int aac_rkt_init(struct aac_dev *dev)
{
- extern int _aac_rx_init(struct aac_dev *dev);
-
/*
* Fill in the function dispatch table.
*/
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index d242e2611d6..0c71315cbf1 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -57,25 +57,25 @@ static irqreturn_t aac_rx_intr_producer(int irq, void *dev_id)
* been enabled.
* Check to see if this is our interrupt. If it isn't just return
*/
- if (intstat & ~(dev->OIMR)) {
+ if (likely(intstat & ~(dev->OIMR))) {
bellbits = rx_readl(dev, OutboundDoorbellReg);
- if (bellbits & DoorBellPrintfReady) {
+ if (unlikely(bellbits & DoorBellPrintfReady)) {
aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5]));
rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
}
- else if (bellbits & DoorBellAdapterNormCmdReady) {
+ else if (unlikely(bellbits & DoorBellAdapterNormCmdReady)) {
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
}
- else if (bellbits & DoorBellAdapterNormRespReady) {
+ else if (likely(bellbits & DoorBellAdapterNormRespReady)) {
rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
}
- else if (bellbits & DoorBellAdapterNormCmdNotFull) {
+ else if (unlikely(bellbits & DoorBellAdapterNormCmdNotFull)) {
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
}
- else if (bellbits & DoorBellAdapterNormRespNotFull) {
+ else if (unlikely(bellbits & DoorBellAdapterNormRespNotFull)) {
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
}
@@ -88,11 +88,11 @@ static irqreturn_t aac_rx_intr_message(int irq, void *dev_id)
{
struct aac_dev *dev = dev_id;
u32 Index = rx_readl(dev, MUnit.OutboundQueue);
- if (Index == 0xFFFFFFFFL)
+ if (unlikely(Index == 0xFFFFFFFFL))
Index = rx_readl(dev, MUnit.OutboundQueue);
- if (Index != 0xFFFFFFFFL) {
+ if (likely(Index != 0xFFFFFFFFL)) {
do {
- if (aac_intr_normal(dev, Index)) {
+ if (unlikely(aac_intr_normal(dev, Index))) {
rx_writel(dev, MUnit.OutboundQueue, Index);
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady);
}
@@ -204,7 +204,7 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command,
*/
msleep(1);
}
- if (ok != 1) {
+ if (unlikely(ok != 1)) {
/*
* Restore interrupt mask even though we timed out
*/
@@ -294,7 +294,7 @@ static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)
* Start up processing on an i960 based AAC adapter
*/
-void aac_rx_start_adapter(struct aac_dev *dev)
+static void aac_rx_start_adapter(struct aac_dev *dev)
{
struct aac_init *init;
@@ -319,12 +319,12 @@ static int aac_rx_check_health(struct aac_dev *dev)
/*
* Check to see if the board failed any self tests.
*/
- if (status & SELF_TEST_FAILED)
+ if (unlikely(status & SELF_TEST_FAILED))
return -1;
/*
* Check to see if the board panic'd.
*/
- if (status & KERNEL_PANIC) {
+ if (unlikely(status & KERNEL_PANIC)) {
char * buffer;
struct POSTSTATUS {
__le32 Post_Command;
@@ -333,15 +333,15 @@ static int aac_rx_check_health(struct aac_dev *dev)
dma_addr_t paddr, baddr;
int ret;
- if ((status & 0xFF000000L) == 0xBC000000L)
+ if (likely((status & 0xFF000000L) == 0xBC000000L))
return (status >> 16) & 0xFF;
buffer = pci_alloc_consistent(dev->pdev, 512, &baddr);
ret = -2;
- if (buffer == NULL)
+ if (unlikely(buffer == NULL))
return ret;
post = pci_alloc_consistent(dev->pdev,
sizeof(struct POSTSTATUS), &paddr);
- if (post == NULL) {
+ if (unlikely(post == NULL)) {
pci_free_consistent(dev->pdev, 512, buffer, baddr);
return ret;
}
@@ -353,7 +353,7 @@ static int aac_rx_check_health(struct aac_dev *dev)
NULL, NULL, NULL, NULL, NULL);
pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS),
post, paddr);
- if ((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X'))) {
+ if (likely((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X')))) {
ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10);
ret <<= 4;
ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10);
@@ -364,7 +364,7 @@ static int aac_rx_check_health(struct aac_dev *dev)
/*
* Wait for the adapter to be up and running.
*/
- if (!(status & KERNEL_UP_AND_RUNNING))
+ if (unlikely(!(status & KERNEL_UP_AND_RUNNING)))
return -3;
/*
* Everything is OK
@@ -387,7 +387,7 @@ static int aac_rx_deliver_producer(struct fib * fib)
unsigned long nointr = 0;
spin_lock_irqsave(q->lock, qflags);
- aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib, 1, fib, &nointr);
+ aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib_va, 1, fib, &nointr);
q->numpending++;
*(q->headers.producer) = cpu_to_le32(Index + 1);
@@ -419,9 +419,9 @@ static int aac_rx_deliver_message(struct fib * fib)
spin_unlock_irqrestore(q->lock, qflags);
for(;;) {
Index = rx_readl(dev, MUnit.InboundQueue);
- if (Index == 0xFFFFFFFFL)
+ if (unlikely(Index == 0xFFFFFFFFL))
Index = rx_readl(dev, MUnit.InboundQueue);
- if (Index != 0xFFFFFFFFL)
+ if (likely(Index != 0xFFFFFFFFL))
break;
if (--count == 0) {
spin_lock_irqsave(q->lock, qflags);
@@ -437,7 +437,7 @@ static int aac_rx_deliver_message(struct fib * fib)
device += sizeof(u32);
writel((u32)(addr >> 32), device);
device += sizeof(u32);
- writel(le16_to_cpu(fib->hw_fib->header.Size), device);
+ writel(le16_to_cpu(fib->hw_fib_va->header.Size), device);
rx_writel(dev, MUnit.InboundQueue, Index);
return 0;
}
@@ -460,22 +460,34 @@ static int aac_rx_ioremap(struct aac_dev * dev, u32 size)
return 0;
}
-static int aac_rx_restart_adapter(struct aac_dev *dev)
+static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
{
u32 var;
- printk(KERN_ERR "%s%d: adapter kernel panic'd.\n",
- dev->name, dev->id);
-
- if (aac_rx_check_health(dev) <= 0)
- return 1;
- if (rx_sync_cmd(dev, IOP_RESET, 0, 0, 0, 0, 0, 0,
- &var, NULL, NULL, NULL, NULL))
- return 1;
+ if (bled)
+ printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
+ dev->name, dev->id, bled);
+ else {
+ bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
+ 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
+ if (!bled && (var != 0x00000001))
+ bled = -EINVAL;
+ }
+ if (bled && (bled != -ETIMEDOUT))
+ bled = aac_adapter_sync_cmd(dev, IOP_RESET,
+ 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
+
+ if (bled && (bled != -ETIMEDOUT))
+ return -EINVAL;
+ if (bled || (var == 0x3803000F)) { /* USE_OTHER_METHOD */
+ rx_writel(dev, MUnit.reserved2, 3);
+ msleep(5000); /* Delay 5 seconds */
+ var = 0x00000001;
+ }
if (var != 0x00000001)
- return 1;
+ return -EINVAL;
if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
- return 1;
+ return -ENODEV;
return 0;
}
@@ -517,24 +529,29 @@ int _aac_rx_init(struct aac_dev *dev)
{
unsigned long start;
unsigned long status;
- int instance;
- const char * name;
-
- instance = dev->id;
- name = dev->name;
+ int restart = 0;
+ int instance = dev->id;
+ const char * name = dev->name;
if (aac_adapter_ioremap(dev, dev->base_size)) {
printk(KERN_WARNING "%s: unable to map adapter.\n", name);
goto error_iounmap;
}
+ /* Failure to reset here is an option ... */
+ dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
+ if ((((status & 0xff) != 0xff) || reset_devices) &&
+ !aac_rx_restart_adapter(dev, 0))
+ ++restart;
/*
* Check to see if the board panic'd while booting.
*/
status = rx_readl(dev, MUnit.OMRx[0]);
- if (status & KERNEL_PANIC)
- if (aac_rx_restart_adapter(dev))
+ if (status & KERNEL_PANIC) {
+ if (aac_rx_restart_adapter(dev, aac_rx_check_health(dev)))
goto error_iounmap;
+ ++restart;
+ }
/*
* Check to see if the board failed any self tests.
*/
@@ -556,12 +573,23 @@ int _aac_rx_init(struct aac_dev *dev)
*/
while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING))
{
- if(time_after(jiffies, start+startup_timeout*HZ))
- {
+ if ((restart &&
+ (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
+ time_after(jiffies, start+HZ*startup_timeout)) {
printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
dev->name, instance, status);
goto error_iounmap;
}
+ if (!restart &&
+ ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) ||
+ time_after(jiffies, start + HZ *
+ ((startup_timeout > 60)
+ ? (startup_timeout - 60)
+ : (startup_timeout / 2))))) {
+ if (likely(!aac_rx_restart_adapter(dev, aac_rx_check_health(dev))))
+ start = jiffies;
+ ++restart;
+ }
msleep(1);
}
/*
@@ -572,6 +600,7 @@ int _aac_rx_init(struct aac_dev *dev)
dev->a_ops.adapter_notify = aac_rx_notify_adapter;
dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
dev->a_ops.adapter_check_health = aac_rx_check_health;
+ dev->a_ops.adapter_restart = aac_rx_restart_adapter;
/*
* First clear out all interrupts. Then enable the one's that we
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index 6f1a1780efc..f4b5e9742ab 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 1d239f6c010..cbbfbc9f3e0 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -35,7 +35,6 @@
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <linux/pci.h>
#include <linux/isapnp.h>
#include <linux/blkdev.h>
#include <linux/mca.h>
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx
index 911ea1756e5..5e6620f8dab 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic79xx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx
@@ -57,18 +57,6 @@ config AIC79XX_BUILD_FIRMWARE
or modify the assembler Makefile or the files it includes if your
build environment is different than that of the author.
-config AIC79XX_ENABLE_RD_STRM
- bool "Enable Read Streaming for All Targets"
- depends on SCSI_AIC79XX
- default n
- help
- Read Streaming is a U320 protocol option that should enhance
- performance. Early U320 drive firmware actually performs slower
- with read streaming enabled so it is disabled by default. Read
- Streaming can be configured in much the same way as tagged queueing
- using the "rd_strm" command line option. See
- drivers/scsi/aic7xxx/README.aic79xx for details.
-
config AIC79XX_DEBUG_ENABLE
bool "Compile in Debugging Code"
depends on SCSI_AIC79XX
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
index cd93f9a8611..88da670a791 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
@@ -50,16 +50,6 @@ config AIC7XXX_RESET_DELAY_MS
Default: 5000 (5 seconds)
-config AIC7XXX_PROBE_EISA_VL
- bool "Probe for EISA and VL AIC7XXX Adapters"
- depends on SCSI_AIC7XXX && EISA
- help
- Probe for EISA and VLB Aic7xxx controllers. In many newer systems,
- the invasive probes necessary to detect these controllers can cause
- other devices to fail. For this reason, the non-PCI probe code is
- disabled by default. The current value of this option can be "toggled"
- via the no_probe kernel command line option.
-
config AIC7XXX_BUILD_FIRMWARE
bool "Build Adapter Firmware with Kernel Build"
depends on SCSI_AIC7XXX && !PREVENT_FIRMWARE_BUILD
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 2be03e975d9..6054881f21f 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -363,6 +363,8 @@ static int ahd_linux_run_command(struct ahd_softc*,
struct scsi_cmnd *);
static void ahd_linux_setup_tag_info_global(char *p);
static int aic79xx_setup(char *c);
+static void ahd_freeze_simq(struct ahd_softc *ahd);
+static void ahd_release_simq(struct ahd_softc *ahd);
static int ahd_linux_unit;
@@ -2016,13 +2018,13 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd)
cmd->scsi_done(cmd);
}
-void
+static void
ahd_freeze_simq(struct ahd_softc *ahd)
{
scsi_block_requests(ahd->platform_data->host);
}
-void
+static void
ahd_release_simq(struct ahd_softc *ahd)
{
scsi_unblock_requests(ahd->platform_data->host);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 147c83c456a..9218f29314f 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -837,8 +837,6 @@ int ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg);
void ahd_platform_free(struct ahd_softc *ahd);
void ahd_platform_init(struct ahd_softc *ahd);
void ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb);
-void ahd_freeze_simq(struct ahd_softc *ahd);
-void ahd_release_simq(struct ahd_softc *ahd);
static __inline void
ahd_freeze_scb(struct scb *scb)
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index 954c7c24501..e1bd57b9f23 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -1278,11 +1278,6 @@ typedef enum {
AHC_QUEUE_TAGGED
} ahc_queue_alg;
-void ahc_set_tags(struct ahc_softc *ahc,
- struct scsi_cmnd *cmd,
- struct ahc_devinfo *devinfo,
- ahc_queue_alg alg);
-
/**************************** Target Mode *************************************/
#ifdef AHC_TARGET_MODE
void ahc_send_lstate_events(struct ahc_softc *,
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 50ef785224d..75733b09f27 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -2073,7 +2073,7 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
/*
* Update the current state of tagged queuing for a given target.
*/
-void
+static void
ahc_set_tags(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
struct ahc_devinfo *devinfo, ahc_queue_alg alg)
{
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index 8f43ff772f2..db6ab1a3b81 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -24,7 +24,6 @@
*
*/
-#include <linux/pci.h>
#include <scsi/scsi_host.h>
#include "aic94xx.h"
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
index 12497da5529..03bfed61bff 100644
--- a/drivers/scsi/arcmsr/arcmsr_attr.c
+++ b/drivers/scsi/arcmsr/arcmsr_attr.c
@@ -49,7 +49,6 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/delay.h>
-#include <linux/pci.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 0f920c84ac0..eff846ae0af 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -1,19 +1,19 @@
-/*
+/*
* NCR 5380 generic driver routines. These should make it *trivial*
- * to implement 5380 SCSI drivers under Linux with a non-trantor
+ * to implement 5380 SCSI drivers under Linux with a non-trantor
* architecture.
*
* Note that these routines also work with NR53c400 family chips.
*
* Copyright 1993, Drew Eckhardt
- * Visionary Computing
+ * Visionary Computing
* (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
+ * drew@colorado.edu
* +1 (303) 666-5836
*
- * DISTRIBUTION RELEASE 6.
+ * DISTRIBUTION RELEASE 6.
*
- * For more information, please consult
+ * For more information, please consult
*
* NCR 5380 Family
* SCSI Protocol Controller
@@ -57,7 +57,7 @@
* - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
* and USLEEP, because these were messing up readability and will never be
* needed for Atari SCSI.
- *
+ *
* - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
* stuff), and 'main' is executed in a bottom half if awoken by an
* interrupt.
@@ -69,21 +69,29 @@
*/
/*
- * Further development / testing that should be done :
- * 1. Test linked command handling code after Eric is ready with
+ * Further development / testing that should be done :
+ * 1. Test linked command handling code after Eric is ready with
* the high level code.
*/
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_transport_spi.h>
#if (NDEBUG & NDEBUG_LISTS)
-#define LIST(x,y) \
- { printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \
- if ((x)==(y)) udelay(5); }
-#define REMOVE(w,x,y,z) \
- { printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, \
- (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \
- if ((x)==(y)) udelay(5); }
+#define LIST(x, y) \
+ do { \
+ printk("LINE:%d Adding %p to %p\n", \
+ __LINE__, (void*)(x), (void*)(y)); \
+ if ((x) == (y)) \
+ udelay(5); \
+ } while (0)
+#define REMOVE(w, x, y, z) \
+ do { \
+ printk("LINE:%d Removing: %p->%p %p->%p \n", \
+ __LINE__, (void*)(w), (void*)(x), \
+ (void*)(y), (void*)(z)); \
+ if ((x) == (y)) \
+ udelay(5); \
+ } while (0)
#else
#define LIST(x,y)
#define REMOVE(w,x,y,z)
@@ -103,62 +111,62 @@
* more difficult than it has to be.
*
* Also, many of the SCSI drivers were written before the command queuing
- * routines were implemented, meaning their implementations of queued
+ * routines were implemented, meaning their implementations of queued
* commands were hacked on rather than designed in from the start.
*
- * When I designed the Linux SCSI drivers I figured that
+ * When I designed the Linux SCSI drivers I figured that
* while having two different SCSI boards in a system might be useful
* for debugging things, two of the same type wouldn't be used.
* Well, I was wrong and a number of users have mailed me about running
* multiple high-performance SCSI boards in a server.
*
- * Finally, when I get questions from users, I have no idea what
+ * Finally, when I get questions from users, I have no idea what
* revision of my driver they are running.
*
* This driver attempts to address these problems :
- * This is a generic 5380 driver. To use it on a different platform,
+ * This is a generic 5380 driver. To use it on a different platform,
* one simply writes appropriate system specific macros (ie, data
- * transfer - some PC's will use the I/O bus, 68K's must use
+ * transfer - some PC's will use the I/O bus, 68K's must use
* memory mapped) and drops this file in their 'C' wrapper.
*
- * As far as command queueing, two queues are maintained for
+ * As far as command queueing, two queues are maintained for
* each 5380 in the system - commands that haven't been issued yet,
- * and commands that are currently executing. This means that an
- * unlimited number of commands may be queued, letting
- * more commands propagate from the higher driver levels giving higher
- * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
- * allowing multiple commands to propagate all the way to a SCSI-II device
+ * and commands that are currently executing. This means that an
+ * unlimited number of commands may be queued, letting
+ * more commands propagate from the higher driver levels giving higher
+ * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
+ * allowing multiple commands to propagate all the way to a SCSI-II device
* while a command is already executing.
*
- * To solve the multiple-boards-in-the-same-system problem,
+ * To solve the multiple-boards-in-the-same-system problem,
* there is a separate instance structure for each instance
* of a 5380 in the system. So, multiple NCR5380 drivers will
* be able to coexist with appropriate changes to the high level
- * SCSI code.
+ * SCSI code.
*
* A NCR5380_PUBLIC_REVISION macro is provided, with the release
- * number (updated for each public release) printed by the
- * NCR5380_print_options command, which should be called from the
+ * number (updated for each public release) printed by the
+ * NCR5380_print_options command, which should be called from the
* wrapper detect function, so that I know what release of the driver
* users are using.
*
- * Issues specific to the NCR5380 :
+ * Issues specific to the NCR5380 :
*
- * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
- * piece of hardware that requires you to sit in a loop polling for
- * the REQ signal as long as you are connected. Some devices are
- * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
+ * piece of hardware that requires you to sit in a loop polling for
+ * the REQ signal as long as you are connected. Some devices are
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
* while doing long seek operations.
- *
+ *
* The workaround for this is to keep track of devices that have
* disconnected. If the device hasn't disconnected, for commands that
- * should disconnect, we do something like
+ * should disconnect, we do something like
*
* while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
- *
- * Some tweaking of N and M needs to be done. An algorithm based
+ *
+ * Some tweaking of N and M needs to be done. An algorithm based
* on "time to data" would give the best results as long as short time
- * to datas (ie, on the same track) were considered, however these
+ * to datas (ie, on the same track) were considered, however these
* broken devices are the exception rather than the rule and I'd rather
* spend my time optimizing for the normal case.
*
@@ -167,9 +175,9 @@
* At the heart of the design is a coroutine, NCR5380_main,
* which is started when not running by the interrupt handler,
* timer, and queue command function. It attempts to establish
- * I_T_L or I_T_L_Q nexuses by removing the commands from the
- * issue queue and calling NCR5380_select() if a nexus
- * is not established.
+ * I_T_L or I_T_L_Q nexuses by removing the commands from the
+ * issue queue and calling NCR5380_select() if a nexus
+ * is not established.
*
* Once a nexus is established, the NCR5380_information_transfer()
* phase goes through the various phases as instructed by the target.
@@ -183,10 +191,10 @@
* calling NCR5380_intr() which will in turn call NCR5380_reselect
* to reestablish a nexus. This will run main if necessary.
*
- * On command termination, the done function will be called as
+ * On command termination, the done function will be called as
* appropriate.
*
- * SCSI pointers are maintained in the SCp field of SCSI command
+ * SCSI pointers are maintained in the SCp field of SCSI command
* structures, being initialized after the command is connected
* in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
* Note that in violation of the standard, an implicit SAVE POINTERS operation
@@ -196,12 +204,12 @@
/*
* Using this file :
* This file a skeleton Linux SCSI driver for the NCR 5380 series
- * of chips. To use it, you write an architecture specific functions
+ * of chips. To use it, you write an architecture specific functions
* and macros and include this file in your driver.
*
- * These macros control options :
+ * These macros control options :
* AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- * for commands that return with a CHECK CONDITION status.
+ * for commands that return with a CHECK CONDITION status.
*
* LINKED - if defined, linked commands are supported.
*
@@ -210,18 +218,18 @@
* SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible
*
* These macros MUST be defined :
- *
+ *
* NCR5380_read(register) - read from the specified register
*
- * NCR5380_write(register, value) - write to the specific register
+ * NCR5380_write(register, value) - write to the specific register
*
* Either real DMA *or* pseudo DMA may be implemented
- * REAL functions :
+ * REAL functions :
* NCR5380_REAL_DMA should be defined if real DMA is to be used.
- * Note that the DMA setup functions should return the number of bytes
+ * Note that the DMA setup functions should return the number of bytes
* that they were able to program the controller for.
*
- * Also note that generic i386/PC versions of these macros are
+ * Also note that generic i386/PC versions of these macros are
* available as NCR5380_i386_dma_write_setup,
* NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
*
@@ -234,14 +242,14 @@
* NCR5380_pread(instance, dst, count);
*
* If nothing specific to this implementation needs doing (ie, with external
- * hardware), you must also define
- *
+ * hardware), you must also define
+ *
* NCR5380_queue_command
* NCR5380_reset
* NCR5380_abort
* NCR5380_proc_info
*
- * to be the global entry points into the specific driver, ie
+ * to be the global entry points into the specific driver, ie
* #define NCR5380_queue_command t128_queue_command.
*
* If this is not done, the routines will be defined as static functions
@@ -249,7 +257,7 @@
* accessible wrapper function.
*
* The generic driver is initialized by calling NCR5380_init(instance),
- * after setting the appropriate host specific fields and ID. If the
+ * after setting the appropriate host specific fields and ID. If the
* driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
* possible) function may be used. Before the specific driver initialization
* code finishes, NCR5380_print_options should be called.
@@ -264,8 +272,9 @@ static struct scsi_host_template *the_template = NULL;
(struct NCR5380_hostdata *)(in)->hostdata
#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
-#define NEXT(cmd) ((Scsi_Cmnd *)((cmd)->host_scribble))
-#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble))
+#define NEXT(cmd) ((Scsi_Cmnd *)(cmd)->host_scribble)
+#define SET_NEXT(cmd,next) ((cmd)->host_scribble = (void *)(next))
+#define NEXTADDR(cmd) ((Scsi_Cmnd **)&(cmd)->host_scribble)
#define HOSTNO instance->host_no
#define H_NO(cmd) (cmd)->device->host->host_no
@@ -312,34 +321,34 @@ static struct scsi_host_template *the_template = NULL;
#define TAG_NONE 0xff
typedef struct {
- DECLARE_BITMAP(allocated, MAX_TAGS);
- int nr_allocated;
- int queue_size;
+ DECLARE_BITMAP(allocated, MAX_TAGS);
+ int nr_allocated;
+ int queue_size;
} TAG_ALLOC;
-static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
+static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
-static void __init init_tags( void )
+static void __init init_tags(void)
{
- int target, lun;
- TAG_ALLOC *ta;
-
- if (!setup_use_tagged_queuing)
- return;
-
- for( target = 0; target < 8; ++target ) {
- for( lun = 0; lun < 8; ++lun ) {
- ta = &TagAlloc[target][lun];
- bitmap_zero(ta->allocated, MAX_TAGS);
- ta->nr_allocated = 0;
- /* At the beginning, assume the maximum queue size we could
- * support (MAX_TAGS). This value will be decreased if the target
- * returns QUEUE_FULL status.
- */
- ta->queue_size = MAX_TAGS;
+ int target, lun;
+ TAG_ALLOC *ta;
+
+ if (!setup_use_tagged_queuing)
+ return;
+
+ for (target = 0; target < 8; ++target) {
+ for (lun = 0; lun < 8; ++lun) {
+ ta = &TagAlloc[target][lun];
+ bitmap_zero(ta->allocated, MAX_TAGS);
+ ta->nr_allocated = 0;
+ /* At the beginning, assume the maximum queue size we could
+ * support (MAX_TAGS). This value will be decreased if the target
+ * returns QUEUE_FULL status.
+ */
+ ta->queue_size = MAX_TAGS;
+ }
}
- }
}
@@ -348,24 +357,24 @@ static void __init init_tags( void )
* check that there is a free tag and the target's queue won't overflow. This
* function should be called with interrupts disabled to avoid race
* conditions.
- */
+ */
-static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
+static int is_lun_busy(Scsi_Cmnd *cmd, int should_be_tagged)
{
- SETUP_HOSTDATA(cmd->device->host);
-
- if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
- return( 1 );
- if (!should_be_tagged ||
- !setup_use_tagged_queuing || !cmd->device->tagged_supported)
- return( 0 );
- if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
- TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) {
- TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
- H_NO(cmd), cmd->device->id, cmd->device->lun );
- return( 1 );
- }
- return( 0 );
+ SETUP_HOSTDATA(cmd->device->host);
+
+ if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
+ return 1;
+ if (!should_be_tagged ||
+ !setup_use_tagged_queuing || !cmd->device->tagged_supported)
+ return 0;
+ if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
+ TagAlloc[cmd->device->id][cmd->device->lun].queue_size) {
+ TAG_PRINTK("scsi%d: target %d lun %d: no free tags\n",
+ H_NO(cmd), cmd->device->id, cmd->device->lun);
+ return 1;
+ }
+ return 0;
}
@@ -374,31 +383,30 @@ static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
* untagged.
*/
-static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
+static void cmd_get_tag(Scsi_Cmnd *cmd, int should_be_tagged)
{
- SETUP_HOSTDATA(cmd->device->host);
-
- /* If we or the target don't support tagged queuing, allocate the LUN for
- * an untagged command.
- */
- if (!should_be_tagged ||
- !setup_use_tagged_queuing || !cmd->device->tagged_supported) {
- cmd->tag = TAG_NONE;
- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
- TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
- "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun );
- }
- else {
- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
-
- cmd->tag = find_first_zero_bit( ta->allocated, MAX_TAGS );
- set_bit( cmd->tag, ta->allocated );
- ta->nr_allocated++;
- TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
- "(now %d tags in use)\n",
- H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun,
- ta->nr_allocated );
- }
+ SETUP_HOSTDATA(cmd->device->host);
+
+ /* If we or the target don't support tagged queuing, allocate the LUN for
+ * an untagged command.
+ */
+ if (!should_be_tagged ||
+ !setup_use_tagged_queuing || !cmd->device->tagged_supported) {
+ cmd->tag = TAG_NONE;
+ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+ TAG_PRINTK("scsi%d: target %d lun %d now allocated by untagged "
+ "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun);
+ } else {
+ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+
+ cmd->tag = find_first_zero_bit(ta->allocated, MAX_TAGS);
+ set_bit(cmd->tag, ta->allocated);
+ ta->nr_allocated++;
+ TAG_PRINTK("scsi%d: using tag %d for target %d lun %d "
+ "(now %d tags in use)\n",
+ H_NO(cmd), cmd->tag, cmd->device->id,
+ cmd->device->lun, ta->nr_allocated);
+ }
}
@@ -406,44 +414,42 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
* unlock the LUN.
*/
-static void cmd_free_tag( Scsi_Cmnd *cmd )
+static void cmd_free_tag(Scsi_Cmnd *cmd)
{
- SETUP_HOSTDATA(cmd->device->host);
-
- if (cmd->tag == TAG_NONE) {
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
- TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
- H_NO(cmd), cmd->device->id, cmd->device->lun );
- }
- else if (cmd->tag >= MAX_TAGS) {
- printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
- H_NO(cmd), cmd->tag );
- }
- else {
- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
- clear_bit( cmd->tag, ta->allocated );
- ta->nr_allocated--;
- TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
- H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun );
- }
+ SETUP_HOSTDATA(cmd->device->host);
+
+ if (cmd->tag == TAG_NONE) {
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ TAG_PRINTK("scsi%d: target %d lun %d untagged cmd finished\n",
+ H_NO(cmd), cmd->device->id, cmd->device->lun);
+ } else if (cmd->tag >= MAX_TAGS) {
+ printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
+ H_NO(cmd), cmd->tag);
+ } else {
+ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+ clear_bit(cmd->tag, ta->allocated);
+ ta->nr_allocated--;
+ TAG_PRINTK("scsi%d: freed tag %d for target %d lun %d\n",
+ H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun);
+ }
}
-static void free_all_tags( void )
+static void free_all_tags(void)
{
- int target, lun;
- TAG_ALLOC *ta;
-
- if (!setup_use_tagged_queuing)
- return;
-
- for( target = 0; target < 8; ++target ) {
- for( lun = 0; lun < 8; ++lun ) {
- ta = &TagAlloc[target][lun];
- bitmap_zero(ta->allocated, MAX_TAGS);
- ta->nr_allocated = 0;
+ int target, lun;
+ TAG_ALLOC *ta;
+
+ if (!setup_use_tagged_queuing)
+ return;
+
+ for (target = 0; target < 8; ++target) {
+ for (lun = 0; lun < 8; ++lun) {
+ ta = &TagAlloc[target][lun];
+ bitmap_zero(ta->allocated, MAX_TAGS);
+ ta->nr_allocated = 0;
+ }
}
- }
}
#endif /* SUPPORT_TAGS */
@@ -461,89 +467,94 @@ static void free_all_tags( void )
* assumed to be already transfered into ptr/this_residual.
*/
-static void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+static void merge_contiguous_buffers(Scsi_Cmnd *cmd)
{
- unsigned long endaddr;
+ unsigned long endaddr;
#if (NDEBUG & NDEBUG_MERGING)
- unsigned long oldlen = cmd->SCp.this_residual;
- int cnt = 1;
+ unsigned long oldlen = cmd->SCp.this_residual;
+ int cnt = 1;
#endif
- for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
- cmd->SCp.buffers_residual &&
- virt_to_phys(page_address(cmd->SCp.buffer[1].page)+
- cmd->SCp.buffer[1].offset) == endaddr; ) {
- MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
- cmd->SCp.buffer[1].address, endaddr);
+ for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
+ cmd->SCp.buffers_residual &&
+ virt_to_phys(page_address(cmd->SCp.buffer[1].page) +
+ cmd->SCp.buffer[1].offset) == endaddr;) {
+ MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
+ page_address(cmd->SCp.buffer[1].page), endaddr);
#if (NDEBUG & NDEBUG_MERGING)
- ++cnt;
+ ++cnt;
#endif
- ++cmd->SCp.buffer;
- --cmd->SCp.buffers_residual;
- cmd->SCp.this_residual += cmd->SCp.buffer->length;
- endaddr += cmd->SCp.buffer->length;
- }
+ ++cmd->SCp.buffer;
+ --cmd->SCp.buffers_residual;
+ cmd->SCp.this_residual += cmd->SCp.buffer->length;
+ endaddr += cmd->SCp.buffer->length;
+ }
#if (NDEBUG & NDEBUG_MERGING)
- if (oldlen != cmd->SCp.this_residual)
- MER_PRINTK("merged %d buffers from %p, new length %08x\n",
- cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
+ if (oldlen != cmd->SCp.this_residual)
+ MER_PRINTK("merged %d buffers from %p, new length %08x\n",
+ cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
#endif
}
/*
* Function : void initialize_SCp(Scsi_Cmnd *cmd)
*
- * Purpose : initialize the saved data pointers for cmd to point to the
+ * Purpose : initialize the saved data pointers for cmd to point to the
* start of the buffer.
*
* Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
*/
-static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
+static inline void initialize_SCp(Scsi_Cmnd *cmd)
{
- /*
- * Initialize the Scsi Pointer field so that all of the commands in the
- * various queues are valid.
- */
-
- if (cmd->use_sg) {
- cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
- cmd->SCp.buffers_residual = cmd->use_sg - 1;
- cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+
- cmd->SCp.buffer->offset;
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- /* ++roman: Try to merge some scatter-buffers if they are at
- * contiguous physical addresses.
+ /*
+ * Initialize the Scsi Pointer field so that all of the commands in the
+ * various queues are valid.
*/
- merge_contiguous_buffers( cmd );
- } else {
- cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
- cmd->SCp.ptr = (char *) cmd->request_buffer;
- cmd->SCp.this_residual = cmd->request_bufflen;
- }
+
+ if (cmd->use_sg) {
+ cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer;
+ cmd->SCp.buffers_residual = cmd->use_sg - 1;
+ cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page) +
+ cmd->SCp.buffer->offset;
+ cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ /* ++roman: Try to merge some scatter-buffers if they are at
+ * contiguous physical addresses.
+ */
+ merge_contiguous_buffers(cmd);
+ } else {
+ cmd->SCp.buffer = NULL;
+ cmd->SCp.buffers_residual = 0;
+ cmd->SCp.ptr = (char *)cmd->request_buffer;
+ cmd->SCp.this_residual = cmd->request_bufflen;
+ }
}
#include <linux/delay.h>
#if NDEBUG
static struct {
- unsigned char mask;
- const char * name;}
-signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
- { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" },
- { SR_SEL, "SEL" }, {0, NULL}},
-basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
-icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
- {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
- {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
- {0, NULL}},
-mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
- {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
- "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
- {MR_MONITOR_BSY, "MODE MONITOR BSY"},
- {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
- {0, NULL}};
+ unsigned char mask;
+ const char *name;
+} signals[] = {
+ { SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
+ { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" },
+ { SR_SEL, "SEL" }, {0, NULL}
+}, basrs[] = {
+ {BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}
+}, icrs[] = {
+ {ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
+ {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
+ {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
+ {0, NULL}
+}, mrs[] = {
+ {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
+ {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
+ "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+ {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+ {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
+ {0, NULL}
+};
/*
* Function : void NCR5380_print(struct Scsi_Host *instance)
@@ -553,45 +564,47 @@ mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
* Input : instance - which NCR5380
*/
-static void NCR5380_print(struct Scsi_Host *instance) {
- unsigned char status, data, basr, mr, icr, i;
- unsigned long flags;
-
- local_irq_save(flags);
- data = NCR5380_read(CURRENT_SCSI_DATA_REG);
- status = NCR5380_read(STATUS_REG);
- mr = NCR5380_read(MODE_REG);
- icr = NCR5380_read(INITIATOR_COMMAND_REG);
- basr = NCR5380_read(BUS_AND_STATUS_REG);
- local_irq_restore(flags);
- printk("STATUS_REG: %02x ", status);
- for (i = 0; signals[i].mask ; ++i)
- if (status & signals[i].mask)
- printk(",%s", signals[i].name);
- printk("\nBASR: %02x ", basr);
- for (i = 0; basrs[i].mask ; ++i)
- if (basr & basrs[i].mask)
- printk(",%s", basrs[i].name);
- printk("\nICR: %02x ", icr);
- for (i = 0; icrs[i].mask; ++i)
- if (icr & icrs[i].mask)
- printk(",%s", icrs[i].name);
- printk("\nMODE: %02x ", mr);
- for (i = 0; mrs[i].mask; ++i)
- if (mr & mrs[i].mask)
- printk(",%s", mrs[i].name);
- printk("\n");
+static void NCR5380_print(struct Scsi_Host *instance)
+{
+ unsigned char status, data, basr, mr, icr, i;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ data = NCR5380_read(CURRENT_SCSI_DATA_REG);
+ status = NCR5380_read(STATUS_REG);
+ mr = NCR5380_read(MODE_REG);
+ icr = NCR5380_read(INITIATOR_COMMAND_REG);
+ basr = NCR5380_read(BUS_AND_STATUS_REG);
+ local_irq_restore(flags);
+ printk("STATUS_REG: %02x ", status);
+ for (i = 0; signals[i].mask; ++i)
+ if (status & signals[i].mask)
+ printk(",%s", signals[i].name);
+ printk("\nBASR: %02x ", basr);
+ for (i = 0; basrs[i].mask; ++i)
+ if (basr & basrs[i].mask)
+ printk(",%s", basrs[i].name);
+ printk("\nICR: %02x ", icr);
+ for (i = 0; icrs[i].mask; ++i)
+ if (icr & icrs[i].mask)
+ printk(",%s", icrs[i].name);
+ printk("\nMODE: %02x ", mr);
+ for (i = 0; mrs[i].mask; ++i)
+ if (mr & mrs[i].mask)
+ printk(",%s", mrs[i].name);
+ printk("\n");
}
static struct {
- unsigned char value;
- const char *name;
+ unsigned char value;
+ const char *name;
} phases[] = {
- {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
- {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
- {PHASE_UNKNOWN, "UNKNOWN"}};
+ {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
+ {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+ {PHASE_UNKNOWN, "UNKNOWN"}
+};
-/*
+/*
* Function : void NCR5380_print_phase(struct Scsi_Host *instance)
*
* Purpose : print the current SCSI phase for debugging purposes
@@ -601,30 +614,35 @@ static struct {
static void NCR5380_print_phase(struct Scsi_Host *instance)
{
- unsigned char status;
- int i;
-
- status = NCR5380_read(STATUS_REG);
- if (!(status & SR_REQ))
- printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
- else {
- for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
- (phases[i].value != (status & PHASE_MASK)); ++i);
- printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
- }
+ unsigned char status;
+ int i;
+
+ status = NCR5380_read(STATUS_REG);
+ if (!(status & SR_REQ))
+ printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+ else {
+ for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
+ (phases[i].value != (status & PHASE_MASK)); ++i)
+ ;
+ printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
+ }
}
#else /* !NDEBUG */
/* dummies... */
-__inline__ void NCR5380_print(struct Scsi_Host *instance) { };
-__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
+static inline void NCR5380_print(struct Scsi_Host *instance)
+{
+};
+static inline void NCR5380_print_phase(struct Scsi_Host *instance)
+{
+};
#endif
/*
* ++roman: New scheme of calling NCR5380_main()
- *
+ *
* If we're not in an interrupt, we can call our main directly, it cannot be
* already running. Else, we queue it on a task queue, if not 'main_running'
* tells us that a lower level is already executing it. This way,
@@ -638,33 +656,33 @@ __inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
#include <linux/workqueue.h>
#include <linux/interrupt.h>
-static volatile int main_running = 0;
-static DECLARE_WORK(NCR5380_tqueue, (void (*)(void*))NCR5380_main, NULL);
+static volatile int main_running;
+static DECLARE_WORK(NCR5380_tqueue, NCR5380_main);
-static __inline__ void queue_main(void)
+static inline void queue_main(void)
{
- if (!main_running) {
- /* If in interrupt and NCR5380_main() not already running,
- queue it on the 'immediate' task queue, to be processed
- immediately after the current interrupt processing has
- finished. */
- schedule_work(&NCR5380_tqueue);
- }
- /* else: nothing to do: the running NCR5380_main() will pick up
- any newly queued command. */
+ if (!main_running) {
+ /* If in interrupt and NCR5380_main() not already running,
+ queue it on the 'immediate' task queue, to be processed
+ immediately after the current interrupt processing has
+ finished. */
+ schedule_work(&NCR5380_tqueue);
+ }
+ /* else: nothing to do: the running NCR5380_main() will pick up
+ any newly queued command. */
}
-static inline void NCR5380_all_init (void)
+static inline void NCR5380_all_init(void)
{
- static int done = 0;
- if (!done) {
- INI_PRINTK("scsi : NCR5380_all_init()\n");
- done = 1;
- }
+ static int done = 0;
+ if (!done) {
+ INI_PRINTK("scsi : NCR5380_all_init()\n");
+ done = 1;
+ }
}
-
+
/*
* Function : void NCR58380_print_options (struct Scsi_Host *instance)
*
@@ -674,23 +692,23 @@ static inline void NCR5380_all_init (void)
* Inputs : instance, pointer to this instance. Unused.
*/
-static void __init NCR5380_print_options (struct Scsi_Host *instance)
+static void __init NCR5380_print_options(struct Scsi_Host *instance)
{
- printk(" generic options"
-#ifdef AUTOSENSE
- " AUTOSENSE"
+ printk(" generic options"
+#ifdef AUTOSENSE
+ " AUTOSENSE"
#endif
#ifdef REAL_DMA
- " REAL DMA"
+ " REAL DMA"
#endif
#ifdef PARITY
- " PARITY"
+ " PARITY"
#endif
#ifdef SUPPORT_TAGS
- " SCSI-2 TAGGED QUEUING"
+ " SCSI-2 TAGGED QUEUING"
#endif
- );
- printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+ );
+ printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
}
/*
@@ -699,27 +717,27 @@ static void __init NCR5380_print_options (struct Scsi_Host *instance)
* Purpose : print commands in the various queues, called from
* NCR5380_abort and NCR5380_debug to aid debugging.
*
- * Inputs : instance, pointer to this instance.
+ * Inputs : instance, pointer to this instance.
*/
-static void NCR5380_print_status (struct Scsi_Host *instance)
+static void NCR5380_print_status(struct Scsi_Host *instance)
{
- char *pr_bfr;
- char *start;
- int len;
-
- NCR_PRINT(NDEBUG_ANY);
- NCR_PRINT_PHASE(NDEBUG_ANY);
-
- pr_bfr = (char *) __get_free_page(GFP_ATOMIC);
- if (!pr_bfr) {
- printk("NCR5380_print_status: no memory for print buffer\n");
- return;
- }
- len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0);
- pr_bfr[len] = 0;
- printk("\n%s\n", pr_bfr);
- free_page((unsigned long) pr_bfr);
+ char *pr_bfr;
+ char *start;
+ int len;
+
+ NCR_PRINT(NDEBUG_ANY);
+ NCR_PRINT_PHASE(NDEBUG_ANY);
+
+ pr_bfr = (char *)__get_free_page(GFP_ATOMIC);
+ if (!pr_bfr) {
+ printk("NCR5380_print_status: no memory for print buffer\n");
+ return;
+ }
+ len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0);
+ pr_bfr[len] = 0;
+ printk("\n%s\n", pr_bfr);
+ free_page((unsigned long)pr_bfr);
}
@@ -738,443 +756,478 @@ static void NCR5380_print_status (struct Scsi_Host *instance)
*/
#undef SPRINTF
-#define SPRINTF(fmt,args...) \
- do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
- pos += sprintf(pos, fmt , ## args); } while(0)
-static
-char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
-
-static
-int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset,
- int length, int inout)
+#define SPRINTF(fmt,args...) \
+ do { \
+ if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
+ pos += sprintf(pos, fmt , ## args); \
+ } while(0)
+static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
+
+static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer,
+ char **start, off_t offset, int length, int inout)
{
- char *pos = buffer;
- struct NCR5380_hostdata *hostdata;
- Scsi_Cmnd *ptr;
- unsigned long flags;
- off_t begin = 0;
-#define check_offset() \
- do { \
- if (pos - buffer < offset - begin) { \
- begin += pos - buffer; \
- pos = buffer; \
- } \
- } while (0)
-
- hostdata = (struct NCR5380_hostdata *)instance->hostdata;
-
- if (inout) { /* Has data been written to the file ? */
- return(-ENOSYS); /* Currently this is a no-op */
- }
- SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
- check_offset();
- local_irq_save(flags);
- SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
- check_offset();
- if (!hostdata->connected)
- SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
- else
- pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected,
- pos, buffer, length);
- SPRINTF("scsi%d: issue_queue\n", HOSTNO);
- check_offset();
- for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
- pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+ char *pos = buffer;
+ struct NCR5380_hostdata *hostdata;
+ Scsi_Cmnd *ptr;
+ unsigned long flags;
+ off_t begin = 0;
+#define check_offset() \
+ do { \
+ if (pos - buffer < offset - begin) { \
+ begin += pos - buffer; \
+ pos = buffer; \
+ } \
+ } while (0)
+
+ hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+ if (inout) /* Has data been written to the file ? */
+ return -ENOSYS; /* Currently this is a no-op */
+ SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
check_offset();
- }
+ local_irq_save(flags);
+ SPRINTF("NCR5380: coroutine is%s running.\n",
+ main_running ? "" : "n't");
+ check_offset();
+ if (!hostdata->connected)
+ SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
+ else
+ pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected,
+ pos, buffer, length);
+ SPRINTF("scsi%d: issue_queue\n", HOSTNO);
+ check_offset();
+ for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
+ pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
+ check_offset();
+ }
- SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
- check_offset();
- for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
- ptr = NEXT(ptr)) {
- pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+ SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
check_offset();
- }
+ for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+ ptr = NEXT(ptr)) {
+ pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
+ check_offset();
+ }
- local_irq_restore(flags);
- *start = buffer + (offset - begin);
- if (pos - buffer < offset - begin)
- return 0;
- else if (pos - buffer - (offset - begin) < length)
- return pos - buffer - (offset - begin);
- return length;
+ local_irq_restore(flags);
+ *start = buffer + (offset - begin);
+ if (pos - buffer < offset - begin)
+ return 0;
+ else if (pos - buffer - (offset - begin) < length)
+ return pos - buffer - (offset - begin);
+ return length;
}
-static char *
-lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
+static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
{
- int i, s;
- unsigned char *command;
- SPRINTF("scsi%d: destination target %d, lun %d\n",
- H_NO(cmd), cmd->device->id, cmd->device->lun);
- SPRINTF(" command = ");
- command = cmd->cmnd;
- SPRINTF("%2d (0x%02x)", command[0], command[0]);
- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- SPRINTF(" %02x", command[i]);
- SPRINTF("\n");
- return pos;
+ int i, s;
+ unsigned char *command;
+ SPRINTF("scsi%d: destination target %d, lun %d\n",
+ H_NO(cmd), cmd->device->id, cmd->device->lun);
+ SPRINTF(" command = ");
+ command = cmd->cmnd;
+ SPRINTF("%2d (0x%02x)", command[0], command[0]);
+ for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+ SPRINTF(" %02x", command[i]);
+ SPRINTF("\n");
+ return pos;
}
-/*
+/*
* Function : void NCR5380_init (struct Scsi_Host *instance)
*
* Purpose : initializes *instance and corresponding 5380 chip.
*
- * Inputs : instance - instantiation of the 5380 driver.
+ * Inputs : instance - instantiation of the 5380 driver.
*
* Notes : I assume that the host, hostno, and id bits have been
- * set correctly. I don't care about the irq and other fields.
- *
+ * set correctly. I don't care about the irq and other fields.
+ *
*/
-static int NCR5380_init (struct Scsi_Host *instance, int flags)
+static int NCR5380_init(struct Scsi_Host *instance, int flags)
{
- int i;
- SETUP_HOSTDATA(instance);
-
- NCR5380_all_init();
-
- hostdata->aborted = 0;
- hostdata->id_mask = 1 << instance->this_id;
- hostdata->id_higher_mask = 0;
- for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
- if (i > hostdata->id_mask)
- hostdata->id_higher_mask |= i;
- for (i = 0; i < 8; ++i)
- hostdata->busy[i] = 0;
+ int i;
+ SETUP_HOSTDATA(instance);
+
+ NCR5380_all_init();
+
+ hostdata->aborted = 0;
+ hostdata->id_mask = 1 << instance->this_id;
+ hostdata->id_higher_mask = 0;
+ for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
+ if (i > hostdata->id_mask)
+ hostdata->id_higher_mask |= i;
+ for (i = 0; i < 8; ++i)
+ hostdata->busy[i] = 0;
#ifdef SUPPORT_TAGS
- init_tags();
+ init_tags();
#endif
#if defined (REAL_DMA)
- hostdata->dma_len = 0;
+ hostdata->dma_len = 0;
#endif
- hostdata->targets_present = 0;
- hostdata->connected = NULL;
- hostdata->issue_queue = NULL;
- hostdata->disconnected_queue = NULL;
- hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
-
- if (!the_template) {
- the_template = instance->hostt;
- first_instance = instance;
- }
-
+ hostdata->targets_present = 0;
+ hostdata->connected = NULL;
+ hostdata->issue_queue = NULL;
+ hostdata->disconnected_queue = NULL;
+ hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
+
+ if (!the_template) {
+ the_template = instance->hostt;
+ first_instance = instance;
+ }
#ifndef AUTOSENSE
- if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
- printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
- " without AUTOSENSE option, contingent allegiance conditions may\n"
- " be incorrectly cleared.\n", HOSTNO);
+ if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
+ printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
+ " without AUTOSENSE option, contingent allegiance conditions may\n"
+ " be incorrectly cleared.\n", HOSTNO);
#endif /* def AUTOSENSE */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(TARGET_COMMAND_REG, 0);
- NCR5380_write(SELECT_ENABLE_REG, 0);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+ NCR5380_write(SELECT_ENABLE_REG, 0);
- return 0;
+ return 0;
}
-/*
- * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
- * void (*done)(Scsi_Cmnd *))
+/*
+ * our own old-style timeout update
+ */
+/*
+ * The strategy is to cause the timer code to call scsi_times_out()
+ * when the soonest timeout is pending.
+ * The arguments are used when we are queueing a new command, because
+ * we do not want to subtract the time used from this time, but when we
+ * set the timer, we want to take this value into account.
+ */
+
+int atari_scsi_update_timeout(Scsi_Cmnd * SCset, int timeout)
+{
+ int rtn;
+
+ /*
+ * We are using the new error handling code to actually register/deregister
+ * timers for timeout.
+ */
+
+ if (!timer_pending(&SCset->eh_timeout))
+ rtn = 0;
+ else
+ rtn = SCset->eh_timeout.expires - jiffies;
+
+ if (timeout == 0) {
+ del_timer(&SCset->eh_timeout);
+ SCset->eh_timeout.data = (unsigned long)NULL;
+ SCset->eh_timeout.expires = 0;
+ } else {
+ if (SCset->eh_timeout.data != (unsigned long)NULL)
+ del_timer(&SCset->eh_timeout);
+ SCset->eh_timeout.data = (unsigned long)SCset;
+ SCset->eh_timeout.expires = jiffies + timeout;
+ add_timer(&SCset->eh_timeout);
+ }
+ return rtn;
+}
+
+/*
+ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
+ * void (*done)(Scsi_Cmnd *))
*
* Purpose : enqueues a SCSI command
*
* Inputs : cmd - SCSI command, done - function called on completion, with
* a pointer to the command descriptor.
- *
+ *
* Returns : 0
*
- * Side effects :
- * cmd is added to the per instance issue_queue, with minor
- * twiddling done to the host specific fields of cmd. If the
+ * Side effects :
+ * cmd is added to the per instance issue_queue, with minor
+ * twiddling done to the host specific fields of cmd. If the
* main coroutine is not running, it is restarted.
*
*/
-static
-int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
- SETUP_HOSTDATA(cmd->device->host);
- Scsi_Cmnd *tmp;
- int oldto;
- unsigned long flags;
- extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
+ SETUP_HOSTDATA(cmd->device->host);
+ Scsi_Cmnd *tmp;
+ int oldto;
+ unsigned long flags;
+ // extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
#if (NDEBUG & NDEBUG_NO_WRITE)
- switch (cmd->cmnd[0]) {
- case WRITE_6:
- case WRITE_10:
- printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
- H_NO(cmd));
- cmd->result = (DID_ERROR << 16);
- done(cmd);
- return 0;
- }
+ switch (cmd->cmnd[0]) {
+ case WRITE_6:
+ case WRITE_10:
+ printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
+ H_NO(cmd));
+ cmd->result = (DID_ERROR << 16);
+ done(cmd);
+ return 0;
+ }
#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
-
#ifdef NCR5380_STATS
# if 0
- if (!hostdata->connected && !hostdata->issue_queue &&
- !hostdata->disconnected_queue) {
- hostdata->timebase = jiffies;
- }
+ if (!hostdata->connected && !hostdata->issue_queue &&
+ !hostdata->disconnected_queue) {
+ hostdata->timebase = jiffies;
+ }
# endif
# ifdef NCR5380_STAT_LIMIT
- if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+ if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
# endif
- switch (cmd->cmnd[0])
- {
- case WRITE:
- case WRITE_6:
- case WRITE_10:
- hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
- hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
- hostdata->pendingw++;
- break;
- case READ:
- case READ_6:
- case READ_10:
- hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
- hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
- hostdata->pendingr++;
- break;
- }
+ switch (cmd->cmnd[0]) {
+ case WRITE:
+ case WRITE_6:
+ case WRITE_10:
+ hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
+ hostdata->pendingw++;
+ break;
+ case READ:
+ case READ_6:
+ case READ_10:
+ hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
+ hostdata->pendingr++;
+ break;
+ }
#endif
- /*
- * We use the host_scribble field as a pointer to the next command
- * in a queue
- */
-
- NEXT(cmd) = NULL;
- cmd->scsi_done = done;
-
- cmd->result = 0;
-
-
- /*
- * Insert the cmd into the issue queue. Note that REQUEST SENSE
- * commands are added to the head of the queue since any command will
- * clear the contingent allegiance condition that exists and the
- * sense data is only guaranteed to be valid while the condition exists.
- */
-
- local_irq_save(flags);
- /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
- * Otherwise a running NCR5380_main may steal the lock.
- * Lock before actually inserting due to fairness reasons explained in
- * atari_scsi.c. If we insert first, then it's impossible for this driver
- * to release the lock.
- * Stop timer for this command while waiting for the lock, or timeouts
- * may happen (and they really do), and it's no good if the command doesn't
- * appear in any of the queues.
- * ++roman: Just disabling the NCR interrupt isn't sufficient here,
- * because also a timer int can trigger an abort or reset, which would
- * alter queues and touch the lock.
- */
- if (!IS_A_TT()) {
- oldto = update_timeout(cmd, 0);
- falcon_get_lock();
- update_timeout(cmd, oldto);
- }
- if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
- LIST(cmd, hostdata->issue_queue);
- NEXT(cmd) = hostdata->issue_queue;
- hostdata->issue_queue = cmd;
- } else {
- for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
- NEXT(tmp); tmp = NEXT(tmp))
- ;
- LIST(cmd, tmp);
- NEXT(tmp) = cmd;
- }
- local_irq_restore(flags);
-
- QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
- (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
-
- /* If queue_command() is called from an interrupt (real one or bottom
- * half), we let queue_main() do the job of taking care about main. If it
- * is already running, this is a no-op, else main will be queued.
- *
- * If we're not in an interrupt, we can call NCR5380_main()
- * unconditionally, because it cannot be already running.
- */
- if (in_interrupt() || ((flags >> 8) & 7) >= 6)
- queue_main();
- else
- NCR5380_main(NULL);
- return 0;
+ /*
+ * We use the host_scribble field as a pointer to the next command
+ * in a queue
+ */
+
+ SET_NEXT(cmd, NULL);
+ cmd->scsi_done = done;
+
+ cmd->result = 0;
+
+ /*
+ * Insert the cmd into the issue queue. Note that REQUEST SENSE
+ * commands are added to the head of the queue since any command will
+ * clear the contingent allegiance condition that exists and the
+ * sense data is only guaranteed to be valid while the condition exists.
+ */
+
+ local_irq_save(flags);
+ /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
+ * Otherwise a running NCR5380_main may steal the lock.
+ * Lock before actually inserting due to fairness reasons explained in
+ * atari_scsi.c. If we insert first, then it's impossible for this driver
+ * to release the lock.
+ * Stop timer for this command while waiting for the lock, or timeouts
+ * may happen (and they really do), and it's no good if the command doesn't
+ * appear in any of the queues.
+ * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+ * because also a timer int can trigger an abort or reset, which would
+ * alter queues and touch the lock.
+ */
+ if (!IS_A_TT()) {
+ oldto = atari_scsi_update_timeout(cmd, 0);
+ falcon_get_lock();
+ atari_scsi_update_timeout(cmd, oldto);
+ }
+ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+ LIST(cmd, hostdata->issue_queue);
+ SET_NEXT(cmd, hostdata->issue_queue);
+ hostdata->issue_queue = cmd;
+ } else {
+ for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+ NEXT(tmp); tmp = NEXT(tmp))
+ ;
+ LIST(cmd, tmp);
+ SET_NEXT(tmp, cmd);
+ }
+ local_irq_restore(flags);
+
+ QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
+ (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+
+ /* If queue_command() is called from an interrupt (real one or bottom
+ * half), we let queue_main() do the job of taking care about main. If it
+ * is already running, this is a no-op, else main will be queued.
+ *
+ * If we're not in an interrupt, we can call NCR5380_main()
+ * unconditionally, because it cannot be already running.
+ */
+ if (in_interrupt() || ((flags >> 8) & 7) >= 6)
+ queue_main();
+ else
+ NCR5380_main(NULL);
+ return 0;
}
/*
- * Function : NCR5380_main (void)
+ * Function : NCR5380_main (void)
*
- * Purpose : NCR5380_main is a coroutine that runs as long as more work can
- * be done on the NCR5380 host adapters in a system. Both
- * NCR5380_queue_command() and NCR5380_intr() will try to start it
+ * Purpose : NCR5380_main is a coroutine that runs as long as more work can
+ * be done on the NCR5380 host adapters in a system. Both
+ * NCR5380_queue_command() and NCR5380_intr() will try to start it
* in case it is not running.
- *
- * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should
+ *
+ * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should
* reenable them. This prevents reentrancy and kernel stack overflow.
- */
-
-static void NCR5380_main (void *bl)
+ */
+
+static void NCR5380_main(struct work_struct *work)
{
- Scsi_Cmnd *tmp, *prev;
- struct Scsi_Host *instance = first_instance;
- struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
- int done;
- unsigned long flags;
-
- /*
- * We run (with interrupts disabled) until we're sure that none of
- * the host adapters have anything that can be done, at which point
- * we set main_running to 0 and exit.
- *
- * Interrupts are enabled before doing various other internal
- * instructions, after we've decided that we need to run through
- * the loop again.
- *
- * this should prevent any race conditions.
- *
- * ++roman: Just disabling the NCR interrupt isn't sufficient here,
- * because also a timer int can trigger an abort or reset, which can
- * alter queues and touch the Falcon lock.
- */
-
- /* Tell int handlers main() is now already executing. Note that
- no races are possible here. If an int comes in before
- 'main_running' is set here, and queues/executes main via the
- task queue, it doesn't do any harm, just this instance of main
- won't find any work left to do. */
- if (main_running)
- return;
- main_running = 1;
-
- local_save_flags(flags);
- do {
- local_irq_disable(); /* Freeze request queues */
- done = 1;
-
- if (!hostdata->connected) {
- MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO );
- /*
- * Search through the issue_queue for a command destined
- * for a target that's not busy.
- */
+ Scsi_Cmnd *tmp, *prev;
+ struct Scsi_Host *instance = first_instance;
+ struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
+ int done;
+ unsigned long flags;
+
+ /*
+ * We run (with interrupts disabled) until we're sure that none of
+ * the host adapters have anything that can be done, at which point
+ * we set main_running to 0 and exit.
+ *
+ * Interrupts are enabled before doing various other internal
+ * instructions, after we've decided that we need to run through
+ * the loop again.
+ *
+ * this should prevent any race conditions.
+ *
+ * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+ * because also a timer int can trigger an abort or reset, which can
+ * alter queues and touch the Falcon lock.
+ */
+
+ /* Tell int handlers main() is now already executing. Note that
+ no races are possible here. If an int comes in before
+ 'main_running' is set here, and queues/executes main via the
+ task queue, it doesn't do any harm, just this instance of main
+ won't find any work left to do. */
+ if (main_running)
+ return;
+ main_running = 1;
+
+ local_save_flags(flags);
+ do {
+ local_irq_disable(); /* Freeze request queues */
+ done = 1;
+
+ if (!hostdata->connected) {
+ MAIN_PRINTK("scsi%d: not connected\n", HOSTNO);
+ /*
+ * Search through the issue_queue for a command destined
+ * for a target that's not busy.
+ */
#if (NDEBUG & NDEBUG_LISTS)
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
- tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
- ;
- /*printk("%p ", tmp);*/
- if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
+ tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
+ ;
+ /*printk("%p ", tmp);*/
+ if ((tmp == prev) && tmp)
+ printk(" LOOP\n");
+ /* else printk("\n"); */
#endif
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
- prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
+ prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) {
#if (NDEBUG & NDEBUG_LISTS)
- if (prev != tmp)
- printk("MAIN tmp=%p target=%d busy=%d lun=%d\n",
- tmp, tmp->device->id, hostdata->busy[tmp->device->id],
- tmp->device->lun);
+ if (prev != tmp)
+ printk("MAIN tmp=%p target=%d busy=%d lun=%d\n",
+ tmp, tmp->device->id, hostdata->busy[tmp->device->id],
+ tmp->device->lun);
#endif
- /* When we find one, remove it from the issue queue. */
- /* ++guenther: possible race with Falcon locking */
- if (
+ /* When we find one, remove it from the issue queue. */
+ /* ++guenther: possible race with Falcon locking */
+ if (
#ifdef SUPPORT_TAGS
- !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
+ !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
#else
- !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
+ !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
#endif
- ) {
- /* ++guenther: just to be sure, this must be atomic */
- local_irq_disable();
- if (prev) {
- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
- NEXT(prev) = NEXT(tmp);
- } else {
- REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
- hostdata->issue_queue = NEXT(tmp);
- }
- NEXT(tmp) = NULL;
- falcon_dont_release++;
-
- /* reenable interrupts after finding one */
- local_irq_restore(flags);
-
- /*
- * Attempt to establish an I_T_L nexus here.
- * On success, instance->hostdata->connected is set.
- * On failure, we must add the command back to the
- * issue queue so we can keep trying.
- */
- MAIN_PRINTK("scsi%d: main(): command for target %d "
- "lun %d removed from issue_queue\n",
- HOSTNO, tmp->device->id, tmp->device->lun);
- /*
- * REQUEST SENSE commands are issued without tagged
- * queueing, even on SCSI-II devices because the
- * contingent allegiance condition exists for the
- * entire unit.
- */
- /* ++roman: ...and the standard also requires that
- * REQUEST SENSE command are untagged.
- */
-
+ ) {
+ /* ++guenther: just to be sure, this must be atomic */
+ local_irq_disable();
+ if (prev) {
+ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+ SET_NEXT(prev, NEXT(tmp));
+ } else {
+ REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
+ hostdata->issue_queue = NEXT(tmp);
+ }
+ SET_NEXT(tmp, NULL);
+ falcon_dont_release++;
+
+ /* reenable interrupts after finding one */
+ local_irq_restore(flags);
+
+ /*
+ * Attempt to establish an I_T_L nexus here.
+ * On success, instance->hostdata->connected is set.
+ * On failure, we must add the command back to the
+ * issue queue so we can keep trying.
+ */
+ MAIN_PRINTK("scsi%d: main(): command for target %d "
+ "lun %d removed from issue_queue\n",
+ HOSTNO, tmp->device->id, tmp->device->lun);
+ /*
+ * REQUEST SENSE commands are issued without tagged
+ * queueing, even on SCSI-II devices because the
+ * contingent allegiance condition exists for the
+ * entire unit.
+ */
+ /* ++roman: ...and the standard also requires that
+ * REQUEST SENSE command are untagged.
+ */
+
#ifdef SUPPORT_TAGS
- cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE );
+ cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE);
#endif
- if (!NCR5380_select(instance, tmp,
- (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :
- TAG_NEXT)) {
- falcon_dont_release--;
- /* release if target did not response! */
- falcon_release_lock_if_possible( hostdata );
- break;
- } else {
- local_irq_disable();
- LIST(tmp, hostdata->issue_queue);
- NEXT(tmp) = hostdata->issue_queue;
- hostdata->issue_queue = tmp;
+ if (!NCR5380_select(instance, tmp,
+ (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :
+ TAG_NEXT)) {
+ falcon_dont_release--;
+ /* release if target did not response! */
+ falcon_release_lock_if_possible(hostdata);
+ break;
+ } else {
+ local_irq_disable();
+ LIST(tmp, hostdata->issue_queue);
+ SET_NEXT(tmp, hostdata->issue_queue);
+ hostdata->issue_queue = tmp;
#ifdef SUPPORT_TAGS
- cmd_free_tag( tmp );
+ cmd_free_tag(tmp);
#endif
- falcon_dont_release--;
- local_irq_restore(flags);
- MAIN_PRINTK("scsi%d: main(): select() failed, "
- "returned to issue_queue\n", HOSTNO);
- if (hostdata->connected)
- break;
- }
- } /* if target/lun/target queue is not busy */
- } /* for issue_queue */
- } /* if (!hostdata->connected) */
-
- if (hostdata->connected
+ falcon_dont_release--;
+ local_irq_restore(flags);
+ MAIN_PRINTK("scsi%d: main(): select() failed, "
+ "returned to issue_queue\n", HOSTNO);
+ if (hostdata->connected)
+ break;
+ }
+ } /* if target/lun/target queue is not busy */
+ } /* for issue_queue */
+ } /* if (!hostdata->connected) */
+
+ if (hostdata->connected
#ifdef REAL_DMA
- && !hostdata->dma_len
+ && !hostdata->dma_len
#endif
- ) {
- local_irq_restore(flags);
- MAIN_PRINTK("scsi%d: main: performing information transfer\n",
- HOSTNO);
- NCR5380_information_transfer(instance);
- MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
- done = 0;
- }
- } while (!done);
+ ) {
+ local_irq_restore(flags);
+ MAIN_PRINTK("scsi%d: main: performing information transfer\n",
+ HOSTNO);
+ NCR5380_information_transfer(instance);
+ MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
+ done = 0;
+ }
+ } while (!done);
- /* Better allow ints _after_ 'main_running' has been cleared, else
- an interrupt could believe we'll pick up the work it left for
- us, but we won't see it anymore here... */
- main_running = 0;
- local_irq_restore(flags);
+ /* Better allow ints _after_ 'main_running' has been cleared, else
+ an interrupt could believe we'll pick up the work it left for
+ us, but we won't see it anymore here... */
+ main_running = 0;
+ local_irq_restore(flags);
}
@@ -1183,1441 +1236,1439 @@ static void NCR5380_main (void *bl)
* Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
*
* Purpose : Called by interrupt handler when DMA finishes or a phase
- * mismatch occurs (which would finish the DMA transfer).
+ * mismatch occurs (which would finish the DMA transfer).
*
* Inputs : instance - this instance of the NCR5380.
*
*/
-static void NCR5380_dma_complete( struct Scsi_Host *instance )
+static void NCR5380_dma_complete(struct Scsi_Host *instance)
{
- SETUP_HOSTDATA(instance);
- int transfered, saved_data = 0, overrun = 0, cnt, toPIO;
- unsigned char **data, p;
- volatile int *count;
-
- if (!hostdata->connected) {
- printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
- "no connected cmd\n", HOSTNO);
- return;
- }
-
- if (atari_read_overruns) {
- p = hostdata->connected->SCp.phase;
- if (p & SR_IO) {
- udelay(10);
- if ((((NCR5380_read(BUS_AND_STATUS_REG)) &
- (BASR_PHASE_MATCH|BASR_ACK)) ==
- (BASR_PHASE_MATCH|BASR_ACK))) {
- saved_data = NCR5380_read(INPUT_DATA_REG);
- overrun = 1;
- DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO);
- }
+ SETUP_HOSTDATA(instance);
+ int transfered, saved_data = 0, overrun = 0, cnt, toPIO;
+ unsigned char **data, p;
+ volatile int *count;
+
+ if (!hostdata->connected) {
+ printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
+ "no connected cmd\n", HOSTNO);
+ return;
}
- }
-
- DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
- HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
- NCR5380_read(STATUS_REG));
-
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
- hostdata->dma_len = 0;
-
- data = (unsigned char **) &(hostdata->connected->SCp.ptr);
- count = &(hostdata->connected->SCp.this_residual);
- *data += transfered;
- *count -= transfered;
-
- if (atari_read_overruns) {
- if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
- cnt = toPIO = atari_read_overruns;
- if (overrun) {
- DMA_PRINTK("Got an input overrun, using saved byte\n");
- *(*data)++ = saved_data;
- (*count)--;
- cnt--;
- toPIO--;
- }
- DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data);
- NCR5380_transfer_pio(instance, &p, &cnt, data);
- *count -= toPIO - cnt;
+
+ if (atari_read_overruns) {
+ p = hostdata->connected->SCp.phase;
+ if (p & SR_IO) {
+ udelay(10);
+ if ((NCR5380_read(BUS_AND_STATUS_REG) &
+ (BASR_PHASE_MATCH|BASR_ACK)) ==
+ (BASR_PHASE_MATCH|BASR_ACK)) {
+ saved_data = NCR5380_read(INPUT_DATA_REG);
+ overrun = 1;
+ DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO);
+ }
+ }
+ }
+
+ DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
+ HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
+ NCR5380_read(STATUS_REG));
+
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
+ hostdata->dma_len = 0;
+
+ data = (unsigned char **)&hostdata->connected->SCp.ptr;
+ count = &hostdata->connected->SCp.this_residual;
+ *data += transfered;
+ *count -= transfered;
+
+ if (atari_read_overruns) {
+ if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
+ cnt = toPIO = atari_read_overruns;
+ if (overrun) {
+ DMA_PRINTK("Got an input overrun, using saved byte\n");
+ *(*data)++ = saved_data;
+ (*count)--;
+ cnt--;
+ toPIO--;
+ }
+ DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data);
+ NCR5380_transfer_pio(instance, &p, &cnt, data);
+ *count -= toPIO - cnt;
+ }
}
- }
}
#endif /* REAL_DMA */
/*
* Function : void NCR5380_intr (int irq)
- *
+ *
* Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
- * from the disconnected queue, and restarting NCR5380_main()
+ * from the disconnected queue, and restarting NCR5380_main()
* as required.
*
* Inputs : int irq, irq that caused this interrupt.
*
*/
-static irqreturn_t NCR5380_intr (int irq, void *dev_id)
+static irqreturn_t NCR5380_intr(int irq, void *dev_id)
{
- struct Scsi_Host *instance = first_instance;
- int done = 1, handled = 0;
- unsigned char basr;
-
- INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
-
- /* Look for pending interrupts */
- basr = NCR5380_read(BUS_AND_STATUS_REG);
- INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
- /* dispatch to appropriate routine if found and done=0 */
- if (basr & BASR_IRQ) {
- NCR_PRINT(NDEBUG_INTR);
- if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
- done = 0;
- ENABLE_IRQ();
- INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
- NCR5380_reselect(instance);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
- else if (basr & BASR_PARITY_ERROR) {
- INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
- else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
- INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
- else {
- /*
- * The rest of the interrupt conditions can occur only during a
- * DMA transfer
- */
+ struct Scsi_Host *instance = first_instance;
+ int done = 1, handled = 0;
+ unsigned char basr;
+
+ INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
+
+ /* Look for pending interrupts */
+ basr = NCR5380_read(BUS_AND_STATUS_REG);
+ INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
+ /* dispatch to appropriate routine if found and done=0 */
+ if (basr & BASR_IRQ) {
+ NCR_PRINT(NDEBUG_INTR);
+ if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
+ done = 0;
+ ENABLE_IRQ();
+ INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
+ NCR5380_reselect(instance);
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ } else if (basr & BASR_PARITY_ERROR) {
+ INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
+ INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ } else {
+ /*
+ * The rest of the interrupt conditions can occur only during a
+ * DMA transfer
+ */
#if defined(REAL_DMA)
- /*
- * We should only get PHASE MISMATCH and EOP interrupts if we have
- * DMA enabled, so do a sanity check based on the current setting
- * of the MODE register.
- */
-
- if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
- ((basr & BASR_END_DMA_TRANSFER) ||
- !(basr & BASR_PHASE_MATCH))) {
-
- INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
- NCR5380_dma_complete( instance );
- done = 0;
- ENABLE_IRQ();
- } else
+ /*
+ * We should only get PHASE MISMATCH and EOP interrupts if we have
+ * DMA enabled, so do a sanity check based on the current setting
+ * of the MODE register.
+ */
+
+ if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
+ ((basr & BASR_END_DMA_TRANSFER) ||
+ !(basr & BASR_PHASE_MATCH))) {
+
+ INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
+ NCR5380_dma_complete( instance );
+ done = 0;
+ ENABLE_IRQ();
+ } else
#endif /* REAL_DMA */
- {
+ {
/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
- if (basr & BASR_PHASE_MATCH)
- printk(KERN_NOTICE "scsi%d: unknown interrupt, "
- "BASR 0x%x, MR 0x%x, SR 0x%x\n",
- HOSTNO, basr, NCR5380_read(MODE_REG),
- NCR5380_read(STATUS_REG));
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
- } /* if !(SELECTION || PARITY) */
- handled = 1;
- } /* BASR & IRQ */
- else {
- printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
- "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
- NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
-
- if (!done) {
- INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
- /* Put a call to NCR5380_main() on the queue... */
- queue_main();
- }
- return IRQ_RETVAL(handled);
+ if (basr & BASR_PHASE_MATCH)
+ printk(KERN_NOTICE "scsi%d: unknown interrupt, "
+ "BASR 0x%x, MR 0x%x, SR 0x%x\n",
+ HOSTNO, basr, NCR5380_read(MODE_REG),
+ NCR5380_read(STATUS_REG));
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+ } /* if !(SELECTION || PARITY) */
+ handled = 1;
+ } /* BASR & IRQ */ else {
+ printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
+ "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
+ NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+
+ if (!done) {
+ INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
+ /* Put a call to NCR5380_main() on the queue... */
+ queue_main();
+ }
+ return IRQ_RETVAL(handled);
}
#ifdef NCR5380_STATS
-static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
+static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd)
{
# ifdef NCR5380_STAT_LIMIT
- if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+ if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
# endif
- switch (cmd->cmnd[0])
- {
- case WRITE:
- case WRITE_6:
- case WRITE_10:
- hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
- /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
- hostdata->pendingw--;
- break;
- case READ:
- case READ_6:
- case READ_10:
- hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
- /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
- hostdata->pendingr--;
- break;
- }
+ switch (cmd->cmnd[0]) {
+ case WRITE:
+ case WRITE_6:
+ case WRITE_10:
+ hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
+ hostdata->pendingw--;
+ break;
+ case READ:
+ case READ_6:
+ case READ_10:
+ hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
+ hostdata->pendingr--;
+ break;
+ }
}
#endif
-/*
- * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
+/*
+ * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
* int tag);
*
* Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
- * including ARBITRATION, SELECTION, and initial message out for
- * IDENTIFY and queue messages.
+ * including ARBITRATION, SELECTION, and initial message out for
+ * IDENTIFY and queue messages.
*
- * Inputs : instance - instantiation of the 5380 driver on which this
- * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
- * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
+ * Inputs : instance - instantiation of the 5380 driver on which this
+ * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
+ * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
* the command that is presently connected.
- *
+ *
* Returns : -1 if selection could not execute for some reason,
- * 0 if selection succeeded or failed because the target
- * did not respond.
+ * 0 if selection succeeded or failed because the target
+ * did not respond.
*
- * Side effects :
- * If bus busy, arbitration failed, etc, NCR5380_select() will exit
+ * Side effects :
+ * If bus busy, arbitration failed, etc, NCR5380_select() will exit
* with registers as they should have been on entry - ie
* SELECT_ENABLE will be set appropriately, the NCR5380
* will cease to drive any SCSI bus signals.
*
- * If successful : I_T_L or I_T_L_Q nexus will be established,
- * instance->connected will be set to cmd.
- * SELECT interrupt will be disabled.
+ * If successful : I_T_L or I_T_L_Q nexus will be established,
+ * instance->connected will be set to cmd.
+ * SELECT interrupt will be disabled.
*
- * If failed (no target) : cmd->scsi_done() will be called, and the
+ * If failed (no target) : cmd->scsi_done() will be called, and the
* cmd->result host byte set to DID_BAD_TARGET.
*/
-static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
+static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
{
- SETUP_HOSTDATA(instance);
- unsigned char tmp[3], phase;
- unsigned char *data;
- int len;
- unsigned long timeout;
- unsigned long flags;
-
- hostdata->restart_select = 0;
- NCR_PRINT(NDEBUG_ARBITRATION);
- ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
- instance->this_id);
-
- /*
- * Set the phase bits to 0, otherwise the NCR5380 won't drive the
- * data bus during SELECTION.
- */
-
- local_irq_save(flags);
- if (hostdata->connected) {
+ SETUP_HOSTDATA(instance);
+ unsigned char tmp[3], phase;
+ unsigned char *data;
+ int len;
+ unsigned long timeout;
+ unsigned long flags;
+
+ hostdata->restart_select = 0;
+ NCR_PRINT(NDEBUG_ARBITRATION);
+ ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
+ instance->this_id);
+
+ /*
+ * Set the phase bits to 0, otherwise the NCR5380 won't drive the
+ * data bus during SELECTION.
+ */
+
+ local_irq_save(flags);
+ if (hostdata->connected) {
+ local_irq_restore(flags);
+ return -1;
+ }
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+ /*
+ * Start arbitration.
+ */
+
+ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+ NCR5380_write(MODE_REG, MR_ARBITRATE);
+
local_irq_restore(flags);
- return -1;
- }
- NCR5380_write(TARGET_COMMAND_REG, 0);
-
-
- /*
- * Start arbitration.
- */
-
- NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
- NCR5380_write(MODE_REG, MR_ARBITRATE);
-
- local_irq_restore(flags);
-
- /* Wait for arbitration logic to complete */
-#if NCR_TIMEOUT
- {
- unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
-
- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
- && time_before(jiffies, timeout) && !hostdata->connected)
- ;
- if (time_after_eq(jiffies, timeout))
- {
- printk("scsi : arbitration timeout at %d\n", __LINE__);
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
- }
+
+ /* Wait for arbitration logic to complete */
+#if defined(NCR_TIMEOUT)
+ {
+ unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+
+ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
+ time_before(jiffies, timeout) && !hostdata->connected)
+ ;
+ if (time_after_eq(jiffies, timeout)) {
+ printk("scsi : arbitration timeout at %d\n", __LINE__);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return -1;
+ }
+ }
#else /* NCR_TIMEOUT */
- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
- && !hostdata->connected);
+ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
+ !hostdata->connected)
+ ;
#endif
- ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
-
- if (hostdata->connected) {
- NCR5380_write(MODE_REG, MR_BASE);
- return -1;
- }
- /*
- * The arbitration delay is 2.2us, but this is a minimum and there is
- * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
- * the integral nature of udelay().
- *
- */
-
- udelay(3);
-
- /* Check for lost arbitration */
- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
- (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- hostdata->connected) {
- NCR5380_write(MODE_REG, MR_BASE);
- ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
- HOSTNO);
- return -1;
- }
-
- /* after/during arbitration, BSY should be asserted.
- IBM DPES-31080 Version S31Q works now */
- /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL |
- ICR_ASSERT_BSY ) ;
-
- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- hostdata->connected) {
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
- HOSTNO);
- return -1;
- }
+ ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
- /*
- * Again, bus clear + bus settle time is 1.2us, however, this is
- * a minimum so we'll udelay ceil(1.2)
- */
+ if (hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ return -1;
+ }
+ /*
+ * The arbitration delay is 2.2us, but this is a minimum and there is
+ * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
+ * the integral nature of udelay().
+ *
+ */
+
+ udelay(3);
+
+ /* Check for lost arbitration */
+ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
+ (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
+ HOSTNO);
+ return -1;
+ }
+
+ /* after/during arbitration, BSY should be asserted.
+ IBM DPES-31080 Version S31Q works now */
+ /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+ NCR5380_write(INITIATOR_COMMAND_REG,
+ ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY);
+
+ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
+ HOSTNO);
+ return -1;
+ }
+
+ /*
+ * Again, bus clear + bus settle time is 1.2us, however, this is
+ * a minimum so we'll udelay ceil(1.2)
+ */
#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
- /* ++roman: But some targets (see above :-) seem to need a bit more... */
- udelay(15);
+ /* ++roman: But some targets (see above :-) seem to need a bit more... */
+ udelay(15);
#else
- udelay(2);
+ udelay(2);
#endif
-
- if (hostdata->connected) {
+
+ if (hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
+ }
+
+ ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
+
+ /*
+ * Now that we have won arbitration, start Selection process, asserting
+ * the host and target ID's on the SCSI bus.
+ */
+
+ NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
+
+ /*
+ * Raise ATN while SEL is true before BSY goes false from arbitration,
+ * since this is the only way to guarantee that we'll get a MESSAGE OUT
+ * phase immediately after selection.
+ */
+
+ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- return -1;
- }
- ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
+ /*
+ * Reselect interrupts must be turned off prior to the dropping of BSY,
+ * otherwise we will trigger an interrupt.
+ */
+
+ if (hostdata->connected) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
+ }
- /*
- * Now that we have won arbitration, start Selection process, asserting
- * the host and target ID's on the SCSI bus.
- */
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+
+ /*
+ * The initiator shall then wait at least two deskew delays and release
+ * the BSY signal.
+ */
+ udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
+
+ /* Reset BSY */
+ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
+ ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+
+ /*
+ * Something weird happens when we cease to drive BSY - looks
+ * like the board/chip is letting us do another read before the
+ * appropriate propagation delay has expired, and we're confusing
+ * a BSY signal from ourselves as the target's response to SELECTION.
+ *
+ * A small delay (the 'C++' frontend breaks the pipeline with an
+ * unnecessary jump, making it work on my 386-33/Trantor T128, the
+ * tighter 'C' code breaks and requires this) solves the problem -
+ * the 1 us delay is arbitrary, and only used because this delay will
+ * be the same on other platforms and since it works here, it should
+ * work there.
+ *
+ * wingel suggests that this could be due to failing to wait
+ * one deskew delay.
+ */
- NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
+ udelay(1);
- /*
- * Raise ATN while SEL is true before BSY goes false from arbitration,
- * since this is the only way to guarantee that we'll get a MESSAGE OUT
- * phase immediately after selection.
- */
+ SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
- NCR5380_write(MODE_REG, MR_BASE);
+ /*
+ * The SCSI specification calls for a 250 ms timeout for the actual
+ * selection.
+ */
- /*
- * Reselect interrupts must be turned off prior to the dropping of BSY,
- * otherwise we will trigger an interrupt.
- */
+ timeout = jiffies + 25;
- if (hostdata->connected) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- return -1;
- }
-
- NCR5380_write(SELECT_ENABLE_REG, 0);
-
- /*
- * The initiator shall then wait at least two deskew delays and release
- * the BSY signal.
- */
- udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
-
- /* Reset BSY */
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
- ICR_ASSERT_ATN | ICR_ASSERT_SEL));
-
- /*
- * Something weird happens when we cease to drive BSY - looks
- * like the board/chip is letting us do another read before the
- * appropriate propagation delay has expired, and we're confusing
- * a BSY signal from ourselves as the target's response to SELECTION.
- *
- * A small delay (the 'C++' frontend breaks the pipeline with an
- * unnecessary jump, making it work on my 386-33/Trantor T128, the
- * tighter 'C' code breaks and requires this) solves the problem -
- * the 1 us delay is arbitrary, and only used because this delay will
- * be the same on other platforms and since it works here, it should
- * work there.
- *
- * wingel suggests that this could be due to failing to wait
- * one deskew delay.
- */
-
- udelay(1);
-
- SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
-
- /*
- * The SCSI specification calls for a 250 ms timeout for the actual
- * selection.
- */
-
- timeout = jiffies + 25;
-
- /*
- * XXX very interesting - we're seeing a bounce where the BSY we
- * asserted is being reflected / still asserted (propagation delay?)
- * and it's detecting as true. Sigh.
- */
+ /*
+ * XXX very interesting - we're seeing a bounce where the BSY we
+ * asserted is being reflected / still asserted (propagation delay?)
+ * and it's detecting as true. Sigh.
+ */
#if 0
- /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
- * IO while SEL is true. But again, there are some disks out the in the
- * world that do that nevertheless. (Somebody claimed that this announces
- * reselection capability of the target.) So we better skip that test and
- * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
- */
-
- while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) &
- (SR_BSY | SR_IO)));
-
- if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) ==
- (SR_SEL | SR_IO)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_reselect(instance);
- printk (KERN_ERR "scsi%d: reselection after won arbitration?\n",
- HOSTNO);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
+ /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
+ * IO while SEL is true. But again, there are some disks out the in the
+ * world that do that nevertheless. (Somebody claimed that this announces
+ * reselection capability of the target.) So we better skip that test and
+ * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
+ */
+
+ while (time_before(jiffies, timeout) &&
+ !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO)))
+ ;
+
+ if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_reselect(instance);
+ printk(KERN_ERR "scsi%d: reselection after won arbitration?\n",
+ HOSTNO);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return -1;
+ }
#else
- while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));
+ while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY))
+ ;
#endif
- /*
- * No less than two deskew delays after the initiator detects the
- * BSY signal is true, it shall release the SEL signal and may
- * change the DATA BUS. -wingel
- */
+ /*
+ * No less than two deskew delays after the initiator detects the
+ * BSY signal is true, it shall release the SEL signal and may
+ * change the DATA BUS. -wingel
+ */
- udelay(1);
+ udelay(1);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- if (hostdata->targets_present & (1 << cmd->device->id)) {
- printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
- if (hostdata->restart_select)
- printk(KERN_NOTICE "\trestart select\n");
- NCR_PRINT(NDEBUG_ANY);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
- cmd->result = DID_BAD_TARGET << 16;
+ if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ if (hostdata->targets_present & (1 << cmd->device->id)) {
+ printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
+ if (hostdata->restart_select)
+ printk(KERN_NOTICE "\trestart select\n");
+ NCR_PRINT(NDEBUG_ANY);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return -1;
+ }
+ cmd->result = DID_BAD_TARGET << 16;
#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
+ collect_stats(hostdata, cmd);
#endif
#ifdef SUPPORT_TAGS
- cmd_free_tag( cmd );
+ cmd_free_tag(cmd);
#endif
- cmd->scsi_done(cmd);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return 0;
- }
-
- hostdata->targets_present |= (1 << cmd->device->id);
-
- /*
- * Since we followed the SCSI spec, and raised ATN while SEL
- * was true but before BSY was false during selection, the information
- * transfer phase should be a MESSAGE OUT phase so that we can send the
- * IDENTIFY message.
- *
- * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
- * message (2 bytes) with a tag ID that we increment with every command
- * until it wraps back to 0.
- *
- * XXX - it turns out that there are some broken SCSI-II devices,
- * which claim to support tagged queuing but fail when more than
- * some number of commands are issued at once.
- */
-
- /* Wait for start of REQ/ACK handshake */
- while (!(NCR5380_read(STATUS_REG) & SR_REQ));
-
- SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
- HOSTNO, cmd->device->id);
- tmp[0] = IDENTIFY(1, cmd->device->lun);
+ cmd->scsi_done(cmd);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return 0;
+ }
+
+ hostdata->targets_present |= (1 << cmd->device->id);
+
+ /*
+ * Since we followed the SCSI spec, and raised ATN while SEL
+ * was true but before BSY was false during selection, the information
+ * transfer phase should be a MESSAGE OUT phase so that we can send the
+ * IDENTIFY message.
+ *
+ * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
+ * message (2 bytes) with a tag ID that we increment with every command
+ * until it wraps back to 0.
+ *
+ * XXX - it turns out that there are some broken SCSI-II devices,
+ * which claim to support tagged queuing but fail when more than
+ * some number of commands are issued at once.
+ */
+
+ /* Wait for start of REQ/ACK handshake */
+ while (!(NCR5380_read(STATUS_REG) & SR_REQ))
+ ;
+
+ SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
+ HOSTNO, cmd->device->id);
+ tmp[0] = IDENTIFY(1, cmd->device->lun);
#ifdef SUPPORT_TAGS
- if (cmd->tag != TAG_NONE) {
- tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
- tmp[2] = cmd->tag;
- len = 3;
- } else
- len = 1;
+ if (cmd->tag != TAG_NONE) {
+ tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
+ tmp[2] = cmd->tag;
+ len = 3;
+ } else
+ len = 1;
#else
- len = 1;
- cmd->tag=0;
+ len = 1;
+ cmd->tag = 0;
#endif /* SUPPORT_TAGS */
- /* Send message(s) */
- data = tmp;
- phase = PHASE_MSGOUT;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
- /* XXX need to handle errors here */
- hostdata->connected = cmd;
+ /* Send message(s) */
+ data = tmp;
+ phase = PHASE_MSGOUT;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
+ /* XXX need to handle errors here */
+ hostdata->connected = cmd;
#ifndef SUPPORT_TAGS
- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
-#endif
-
- initialize_SCp(cmd);
+ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+#endif
+ initialize_SCp(cmd);
- return 0;
+ return 0;
}
-/*
- * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
+/*
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
* unsigned char *phase, int *count, unsigned char **data)
*
* Purpose : transfers data in given phase using polled I/O
*
- * Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
* bytes to transfer, **data - pointer to data pointer.
- *
+ *
* Returns : -1 when different phase is entered without transferring
* maximum number of bytes, 0 if all bytes are transfered or exit
* is in same phase.
*
- * Also, *phase, *count, *data are modified in place.
+ * Also, *phase, *count, *data are modified in place.
*
* XXX Note : handling for bus free may be useful.
*/
/*
- * Note : this code is not as quick as it could be, however it
+ * Note : this code is not as quick as it could be, however it
* IS 100% reliable, and for the actual data transfer where speed
* counts, we will always do a pseudo DMA or DMA transfer.
*/
-static int NCR5380_transfer_pio( struct Scsi_Host *instance,
- unsigned char *phase, int *count,
- unsigned char **data)
+static int NCR5380_transfer_pio(struct Scsi_Host *instance,
+ unsigned char *phase, int *count,
+ unsigned char **data)
{
- register unsigned char p = *phase, tmp;
- register int c = *count;
- register unsigned char *d = *data;
-
- /*
- * The NCR5380 chip will only drive the SCSI bus when the
- * phase specified in the appropriate bits of the TARGET COMMAND
- * REGISTER match the STATUS REGISTER
- */
-
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
-
- do {
- /*
- * Wait for assertion of REQ, after which the phase bits will be
- * valid
+ register unsigned char p = *phase, tmp;
+ register int c = *count;
+ register unsigned char *d = *data;
+
+ /*
+ * The NCR5380 chip will only drive the SCSI bus when the
+ * phase specified in the appropriate bits of the TARGET COMMAND
+ * REGISTER match the STATUS REGISTER
*/
- while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
- HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
- /* Check for phase mismatch */
- if ((tmp & PHASE_MASK) != p) {
- PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
- NCR_PRINT_PHASE(NDEBUG_PIO);
- break;
- }
+ do {
+ /*
+ * Wait for assertion of REQ, after which the phase bits will be
+ * valid
+ */
+ while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
+ ;
- /* Do actual transfer from SCSI bus to / from memory */
- if (!(p & SR_IO))
- NCR5380_write(OUTPUT_DATA_REG, *d);
- else
- *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+ HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
- ++d;
+ /* Check for phase mismatch */
+ if ((tmp & PHASE_MASK) != p) {
+ PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
+ NCR_PRINT_PHASE(NDEBUG_PIO);
+ break;
+ }
- /*
- * The SCSI standard suggests that in MSGOUT phase, the initiator
- * should drop ATN on the last byte of the message phase
- * after REQ has been asserted for the handshake but before
- * the initiator raises ACK.
- */
+ /* Do actual transfer from SCSI bus to / from memory */
+ if (!(p & SR_IO))
+ NCR5380_write(OUTPUT_DATA_REG, *d);
+ else
+ *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
- if (!(p & SR_IO)) {
- if (!((p & SR_MSG) && c > 1)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA);
- NCR_PRINT(NDEBUG_PIO);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ACK);
- } else {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN);
- NCR_PRINT(NDEBUG_PIO);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
- }
- } else {
- NCR_PRINT(NDEBUG_PIO);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
- }
+ ++d;
- while (NCR5380_read(STATUS_REG) & SR_REQ);
+ /*
+ * The SCSI standard suggests that in MSGOUT phase, the initiator
+ * should drop ATN on the last byte of the message phase
+ * after REQ has been asserted for the handshake but before
+ * the initiator raises ACK.
+ */
- HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
+ if (!(p & SR_IO)) {
+ if (!((p & SR_MSG) && c > 1)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+ NCR_PRINT(NDEBUG_PIO);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+ } else {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+ NCR_PRINT(NDEBUG_PIO);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+ }
+ } else {
+ NCR_PRINT(NDEBUG_PIO);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+ }
-/*
- * We have several special cases to consider during REQ/ACK handshaking :
- * 1. We were in MSGOUT phase, and we are on the last byte of the
- * message. ATN must be dropped as ACK is dropped.
- *
- * 2. We are in a MSGIN phase, and we are on the last byte of the
- * message. We must exit with ACK asserted, so that the calling
- * code may raise ATN before dropping ACK to reject the message.
- *
- * 3. ACK and ATN are clear and the target may proceed as normal.
- */
- if (!(p == PHASE_MSGIN && c == 1)) {
- if (p == PHASE_MSGOUT && c > 1)
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- else
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- }
- } while (--c);
-
- PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
-
- *count = c;
- *data = d;
- tmp = NCR5380_read(STATUS_REG);
- /* The phase read from the bus is valid if either REQ is (already)
- * asserted or if ACK hasn't been released yet. The latter is the case if
- * we're in MSGIN and all wanted bytes have been received. */
- if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
- *phase = tmp & PHASE_MASK;
- else
- *phase = PHASE_UNKNOWN;
-
- if (!c || (*phase == p))
- return 0;
- else
- return -1;
+ while (NCR5380_read(STATUS_REG) & SR_REQ)
+ ;
+
+ HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
+
+ /*
+ * We have several special cases to consider during REQ/ACK handshaking :
+ * 1. We were in MSGOUT phase, and we are on the last byte of the
+ * message. ATN must be dropped as ACK is dropped.
+ *
+ * 2. We are in a MSGIN phase, and we are on the last byte of the
+ * message. We must exit with ACK asserted, so that the calling
+ * code may raise ATN before dropping ACK to reject the message.
+ *
+ * 3. ACK and ATN are clear and the target may proceed as normal.
+ */
+ if (!(p == PHASE_MSGIN && c == 1)) {
+ if (p == PHASE_MSGOUT && c > 1)
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ else
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ }
+ } while (--c);
+
+ PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
+
+ *count = c;
+ *data = d;
+ tmp = NCR5380_read(STATUS_REG);
+ /* The phase read from the bus is valid if either REQ is (already)
+ * asserted or if ACK hasn't been released yet. The latter is the case if
+ * we're in MSGIN and all wanted bytes have been received.
+ */
+ if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+ *phase = tmp & PHASE_MASK;
+ else
+ *phase = PHASE_UNKNOWN;
+
+ if (!c || (*phase == p))
+ return 0;
+ else
+ return -1;
}
/*
* Function : do_abort (Scsi_Host *host)
- *
- * Purpose : abort the currently established nexus. Should only be
- * called from a routine which can drop into a
- *
+ *
+ * Purpose : abort the currently established nexus. Should only be
+ * called from a routine which can drop into a
+ *
* Returns : 0 on success, -1 on failure.
*/
-static int do_abort (struct Scsi_Host *host)
+static int do_abort(struct Scsi_Host *host)
{
- unsigned char tmp, *msgptr, phase;
- int len;
-
- /* Request message out phase */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
-
- /*
- * Wait for the target to indicate a valid phase by asserting
- * REQ. Once this happens, we'll have either a MSGOUT phase
- * and can immediately send the ABORT message, or we'll have some
- * other phase and will have to source/sink data.
- *
- * We really don't care what value was on the bus or what value
- * the target sees, so we just handshake.
- */
-
- while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
-
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
-
- if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
- ICR_ASSERT_ACK);
- while (NCR5380_read(STATUS_REG) & SR_REQ);
+ unsigned char tmp, *msgptr, phase;
+ int len;
+
+ /* Request message out phase */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- }
-
- tmp = ABORT;
- msgptr = &tmp;
- len = 1;
- phase = PHASE_MSGOUT;
- NCR5380_transfer_pio (host, &phase, &len, &msgptr);
-
- /*
- * If we got here, and the command completed successfully,
- * we're about to go into bus free state.
- */
-
- return len ? -1 : 0;
+
+ /*
+ * Wait for the target to indicate a valid phase by asserting
+ * REQ. Once this happens, we'll have either a MSGOUT phase
+ * and can immediately send the ABORT message, or we'll have some
+ * other phase and will have to source/sink data.
+ *
+ * We really don't care what value was on the bus or what value
+ * the target sees, so we just handshake.
+ */
+
+ while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ)
+ ;
+
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+ if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+ ICR_ASSERT_ACK);
+ while (NCR5380_read(STATUS_REG) & SR_REQ)
+ ;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ }
+
+ tmp = ABORT;
+ msgptr = &tmp;
+ len = 1;
+ phase = PHASE_MSGOUT;
+ NCR5380_transfer_pio(host, &phase, &len, &msgptr);
+
+ /*
+ * If we got here, and the command completed successfully,
+ * we're about to go into bus free state.
+ */
+
+ return len ? -1 : 0;
}
#if defined(REAL_DMA)
-/*
- * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
+/*
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
* unsigned char *phase, int *count, unsigned char **data)
*
* Purpose : transfers data in given phase using either real
* or pseudo DMA.
*
- * Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
* bytes to transfer, **data - pointer to data pointer.
- *
+ *
* Returns : -1 when different phase is entered without transferring
* maximum number of bytes, 0 if all bytes or transfered or exit
* is in same phase.
*
- * Also, *phase, *count, *data are modified in place.
+ * Also, *phase, *count, *data are modified in place.
*
*/
-static int NCR5380_transfer_dma( struct Scsi_Host *instance,
- unsigned char *phase, int *count,
- unsigned char **data)
+static int NCR5380_transfer_dma(struct Scsi_Host *instance,
+ unsigned char *phase, int *count,
+ unsigned char **data)
{
- SETUP_HOSTDATA(instance);
- register int c = *count;
- register unsigned char p = *phase;
- register unsigned char *d = *data;
- unsigned char tmp;
- unsigned long flags;
-
- if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
- *phase = tmp;
- return -1;
- }
+ SETUP_HOSTDATA(instance);
+ register int c = *count;
+ register unsigned char p = *phase;
+ register unsigned char *d = *data;
+ unsigned char tmp;
+ unsigned long flags;
+
+ if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
+ *phase = tmp;
+ return -1;
+ }
- if (atari_read_overruns && (p & SR_IO)) {
- c -= atari_read_overruns;
- }
+ if (atari_read_overruns && (p & SR_IO))
+ c -= atari_read_overruns;
- DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
- HOSTNO, (p & SR_IO) ? "reading" : "writing",
- c, (p & SR_IO) ? "to" : "from", d);
+ DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
+ HOSTNO, (p & SR_IO) ? "reading" : "writing",
+ c, (p & SR_IO) ? "to" : "from", d);
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
#ifdef REAL_DMA
- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
#endif /* def REAL_DMA */
- if (IS_A_TT()) {
- /* On the Medusa, it is a must to initialize the DMA before
- * starting the NCR. This is also the cleaner way for the TT.
- */
- local_irq_save(flags);
- hostdata->dma_len = (p & SR_IO) ?
- NCR5380_dma_read_setup(instance, d, c) :
- NCR5380_dma_write_setup(instance, d, c);
- local_irq_restore(flags);
- }
-
- if (p & SR_IO)
- NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
- else {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
- NCR5380_write(START_DMA_SEND_REG, 0);
- }
-
- if (!IS_A_TT()) {
- /* On the Falcon, the DMA setup must be done after the last */
- /* NCR access, else the DMA setup gets trashed!
- */
- local_irq_save(flags);
- hostdata->dma_len = (p & SR_IO) ?
- NCR5380_dma_read_setup(instance, d, c) :
- NCR5380_dma_write_setup(instance, d, c);
- local_irq_restore(flags);
- }
- return 0;
+ if (IS_A_TT()) {
+ /* On the Medusa, it is a must to initialize the DMA before
+ * starting the NCR. This is also the cleaner way for the TT.
+ */
+ local_irq_save(flags);
+ hostdata->dma_len = (p & SR_IO) ?
+ NCR5380_dma_read_setup(instance, d, c) :
+ NCR5380_dma_write_setup(instance, d, c);
+ local_irq_restore(flags);
+ }
+
+ if (p & SR_IO)
+ NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+ else {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+ NCR5380_write(START_DMA_SEND_REG, 0);
+ }
+
+ if (!IS_A_TT()) {
+ /* On the Falcon, the DMA setup must be done after the last */
+ /* NCR access, else the DMA setup gets trashed!
+ */
+ local_irq_save(flags);
+ hostdata->dma_len = (p & SR_IO) ?
+ NCR5380_dma_read_setup(instance, d, c) :
+ NCR5380_dma_write_setup(instance, d, c);
+ local_irq_restore(flags);
+ }
+ return 0;
}
#endif /* defined(REAL_DMA) */
/*
* Function : NCR5380_information_transfer (struct Scsi_Host *instance)
*
- * Purpose : run through the various SCSI phases and do as the target
- * directs us to. Operates on the currently connected command,
+ * Purpose : run through the various SCSI phases and do as the target
+ * directs us to. Operates on the currently connected command,
* instance->connected.
*
* Inputs : instance, instance for which we are doing commands
*
- * Side effects : SCSI things happen, the disconnected queue will be
+ * Side effects : SCSI things happen, the disconnected queue will be
* modified if a command disconnects, *instance->connected will
* change.
*
- * XXX Note : we need to watch for bus free or a reset condition here
- * to recover from an unexpected bus free condition.
+ * XXX Note : we need to watch for bus free or a reset condition here
+ * to recover from an unexpected bus free condition.
*/
-
-static void NCR5380_information_transfer (struct Scsi_Host *instance)
+
+static void NCR5380_information_transfer(struct Scsi_Host *instance)
{
- SETUP_HOSTDATA(instance);
- unsigned long flags;
- unsigned char msgout = NOP;
- int sink = 0;
- int len;
+ SETUP_HOSTDATA(instance);
+ unsigned long flags;
+ unsigned char msgout = NOP;
+ int sink = 0;
+ int len;
#if defined(REAL_DMA)
- int transfersize;
+ int transfersize;
#endif
- unsigned char *data;
- unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
- Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+ unsigned char *data;
+ unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
+ Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+
+ while (1) {
+ tmp = NCR5380_read(STATUS_REG);
+ /* We only have a valid SCSI phase when REQ is asserted */
+ if (tmp & SR_REQ) {
+ phase = (tmp & PHASE_MASK);
+ if (phase != old_phase) {
+ old_phase = phase;
+ NCR_PRINT_PHASE(NDEBUG_INFORMATION);
+ }
- while (1) {
- tmp = NCR5380_read(STATUS_REG);
- /* We only have a valid SCSI phase when REQ is asserted */
- if (tmp & SR_REQ) {
- phase = (tmp & PHASE_MASK);
- if (phase != old_phase) {
- old_phase = phase;
- NCR_PRINT_PHASE(NDEBUG_INFORMATION);
- }
-
- if (sink && (phase != PHASE_MSGOUT)) {
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
- ICR_ASSERT_ACK);
- while (NCR5380_read(STATUS_REG) & SR_REQ);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
- sink = 0;
- continue;
- }
-
- switch (phase) {
- case PHASE_DATAOUT:
+ if (sink && (phase != PHASE_MSGOUT)) {
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+ ICR_ASSERT_ACK);
+ while (NCR5380_read(STATUS_REG) & SR_REQ)
+ ;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
+ sink = 0;
+ continue;
+ }
+
+ switch (phase) {
+ case PHASE_DATAOUT:
#if (NDEBUG & NDEBUG_NO_DATAOUT)
- printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
- "aborted\n", HOSTNO);
- sink = 1;
- do_abort(instance);
- cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
- return;
+ printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
+ "aborted\n", HOSTNO);
+ sink = 1;
+ do_abort(instance);
+ cmd->result = DID_ERROR << 16;
+ cmd->done(cmd);
+ return;
#endif
- case PHASE_DATAIN:
- /*
- * If there is no room left in the current buffer in the
- * scatter-gather list, move onto the next one.
- */
-
- if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
- ++cmd->SCp.buffer;
- --cmd->SCp.buffers_residual;
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
- cmd->SCp.buffer->offset;
- /* ++roman: Try to merge some scatter-buffers if
- * they are at contiguous physical addresses.
- */
- merge_contiguous_buffers( cmd );
- INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
- HOSTNO, cmd->SCp.this_residual,
- cmd->SCp.buffers_residual);
- }
-
- /*
- * The preferred transfer method is going to be
- * PSEUDO-DMA for systems that are strictly PIO,
- * since we can let the hardware do the handshaking.
- *
- * For this to work, we need to know the transfersize
- * ahead of time, since the pseudo-DMA code will sit
- * in an unconditional loop.
- */
-
-/* ++roman: I suggest, this should be
- * #if def(REAL_DMA)
- * instead of leaving REAL_DMA out.
- */
+ case PHASE_DATAIN:
+ /*
+ * If there is no room left in the current buffer in the
+ * scatter-gather list, move onto the next one.
+ */
+
+ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+ ++cmd->SCp.buffer;
+ --cmd->SCp.buffers_residual;
+ cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
+ cmd->SCp.buffer->offset;
+ /* ++roman: Try to merge some scatter-buffers if
+ * they are at contiguous physical addresses.
+ */
+ merge_contiguous_buffers(cmd);
+ INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
+ HOSTNO, cmd->SCp.this_residual,
+ cmd->SCp.buffers_residual);
+ }
+
+ /*
+ * The preferred transfer method is going to be
+ * PSEUDO-DMA for systems that are strictly PIO,
+ * since we can let the hardware do the handshaking.
+ *
+ * For this to work, we need to know the transfersize
+ * ahead of time, since the pseudo-DMA code will sit
+ * in an unconditional loop.
+ */
+
+ /* ++roman: I suggest, this should be
+ * #if def(REAL_DMA)
+ * instead of leaving REAL_DMA out.
+ */
#if defined(REAL_DMA)
- if (!cmd->device->borken &&
- (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) {
- len = transfersize;
- cmd->SCp.phase = phase;
- if (NCR5380_transfer_dma(instance, &phase,
- &len, (unsigned char **) &cmd->SCp.ptr)) {
- /*
- * If the watchdog timer fires, all future
- * accesses to this device will use the
- * polled-IO. */
- printk(KERN_NOTICE "scsi%d: switching target %d "
- "lun %d to slow handshake\n", HOSTNO,
- cmd->device->id, cmd->device->lun);
- cmd->device->borken = 1;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
- sink = 1;
- do_abort(instance);
- cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
- /* XXX - need to source or sink data here, as appropriate */
- } else {
+ if (!cmd->device->borken &&
+ (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) {
+ len = transfersize;
+ cmd->SCp.phase = phase;
+ if (NCR5380_transfer_dma(instance, &phase,
+ &len, (unsigned char **)&cmd->SCp.ptr)) {
+ /*
+ * If the watchdog timer fires, all future
+ * accesses to this device will use the
+ * polled-IO. */
+ printk(KERN_NOTICE "scsi%d: switching target %d "
+ "lun %d to slow handshake\n", HOSTNO,
+ cmd->device->id, cmd->device->lun);
+ cmd->device->borken = 1;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
+ sink = 1;
+ do_abort(instance);
+ cmd->result = DID_ERROR << 16;
+ cmd->done(cmd);
+ /* XXX - need to source or sink data here, as appropriate */
+ } else {
#ifdef REAL_DMA
- /* ++roman: When using real DMA,
- * information_transfer() should return after
- * starting DMA since it has nothing more to
- * do.
- */
- return;
-#else
- cmd->SCp.this_residual -= transfersize - len;
+ /* ++roman: When using real DMA,
+ * information_transfer() should return after
+ * starting DMA since it has nothing more to
+ * do.
+ */
+ return;
+#else
+ cmd->SCp.this_residual -= transfersize - len;
#endif
- }
- } else
+ }
+ } else
#endif /* defined(REAL_DMA) */
- NCR5380_transfer_pio(instance, &phase,
- (int *) &cmd->SCp.this_residual, (unsigned char **)
- &cmd->SCp.ptr);
- break;
- case PHASE_MSGIN:
- len = 1;
- data = &tmp;
- NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- cmd->SCp.Message = tmp;
-
- switch (tmp) {
- /*
- * Linking lets us reduce the time required to get the
- * next command out to the device, hopefully this will
- * mean we don't waste another revolution due to the delays
- * required by ARBITRATION and another SELECTION.
- *
- * In the current implementation proposal, low level drivers
- * merely have to start the next command, pointed to by
- * next_link, done() is called as with unlinked commands.
- */
+ NCR5380_transfer_pio(instance, &phase,
+ (int *)&cmd->SCp.this_residual,
+ (unsigned char **)&cmd->SCp.ptr);
+ break;
+ case PHASE_MSGIN:
+ len = 1;
+ data = &tmp;
+ NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ cmd->SCp.Message = tmp;
+
+ switch (tmp) {
+ /*
+ * Linking lets us reduce the time required to get the
+ * next command out to the device, hopefully this will
+ * mean we don't waste another revolution due to the delays
+ * required by ARBITRATION and another SELECTION.
+ *
+ * In the current implementation proposal, low level drivers
+ * merely have to start the next command, pointed to by
+ * next_link, done() is called as with unlinked commands.
+ */
#ifdef LINKED
- case LINKED_CMD_COMPLETE:
- case LINKED_FLG_CMD_COMPLETE:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- LNK_PRINTK("scsi%d: target %d lun %d linked command "
- "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
-
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /*
- * Sanity check : A linked command should only terminate
- * with one of these messages if there are more linked
- * commands available.
- */
-
- if (!cmd->next_link) {
- printk(KERN_NOTICE "scsi%d: target %d lun %d "
- "linked command complete, no next_link\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
- sink = 1;
- do_abort (instance);
- return;
- }
-
- initialize_SCp(cmd->next_link);
- /* The next command is still part of this process; copy it
- * and don't free it! */
- cmd->next_link->tag = cmd->tag;
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- LNK_PRINTK("scsi%d: target %d lun %d linked request "
- "done, calling scsi_done().\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
+ case LINKED_CMD_COMPLETE:
+ case LINKED_FLG_CMD_COMPLETE:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ LNK_PRINTK("scsi%d: target %d lun %d linked command "
+ "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
+
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ /*
+ * Sanity check : A linked command should only terminate
+ * with one of these messages if there are more linked
+ * commands available.
+ */
+
+ if (!cmd->next_link) {
+ printk(KERN_NOTICE "scsi%d: target %d lun %d "
+ "linked command complete, no next_link\n",
+ HOSTNO, cmd->device->id, cmd->device->lun);
+ sink = 1;
+ do_abort(instance);
+ return;
+ }
+
+ initialize_SCp(cmd->next_link);
+ /* The next command is still part of this process; copy it
+ * and don't free it! */
+ cmd->next_link->tag = cmd->tag;
+ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+ LNK_PRINTK("scsi%d: target %d lun %d linked request "
+ "done, calling scsi_done().\n",
+ HOSTNO, cmd->device->id, cmd->device->lun);
#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
+ collect_stats(hostdata, cmd);
#endif
- cmd->scsi_done(cmd);
- cmd = hostdata->connected;
- break;
+ cmd->scsi_done(cmd);
+ cmd = hostdata->connected;
+ break;
#endif /* def LINKED */
- case ABORT:
- case COMMAND_COMPLETE:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* ++guenther: possible race with Falcon locking */
- falcon_dont_release++;
- hostdata->connected = NULL;
- QU_PRINTK("scsi%d: command for target %d, lun %d "
- "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
+ case ABORT:
+ case COMMAND_COMPLETE:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ /* ++guenther: possible race with Falcon locking */
+ falcon_dont_release++;
+ hostdata->connected = NULL;
+ QU_PRINTK("scsi%d: command for target %d, lun %d "
+ "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
#ifdef SUPPORT_TAGS
- cmd_free_tag( cmd );
- if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
- /* Turn a QUEUE FULL status into BUSY, I think the
- * mid level cannot handle QUEUE FULL :-( (The
- * command is retried after BUSY). Also update our
- * queue size to the number of currently issued
- * commands now.
- */
- /* ++Andreas: the mid level code knows about
- QUEUE_FULL now. */
- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
- TAG_PRINTK("scsi%d: target %d lun %d returned "
- "QUEUE_FULL after %d commands\n",
- HOSTNO, cmd->device->id, cmd->device->lun,
- ta->nr_allocated);
- if (ta->queue_size > ta->nr_allocated)
- ta->nr_allocated = ta->queue_size;
- }
+ cmd_free_tag(cmd);
+ if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
+ /* Turn a QUEUE FULL status into BUSY, I think the
+ * mid level cannot handle QUEUE FULL :-( (The
+ * command is retried after BUSY). Also update our
+ * queue size to the number of currently issued
+ * commands now.
+ */
+ /* ++Andreas: the mid level code knows about
+ QUEUE_FULL now. */
+ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+ TAG_PRINTK("scsi%d: target %d lun %d returned "
+ "QUEUE_FULL after %d commands\n",
+ HOSTNO, cmd->device->id, cmd->device->lun,
+ ta->nr_allocated);
+ if (ta->queue_size > ta->nr_allocated)
+ ta->nr_allocated = ta->queue_size;
+ }
#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-
- /*
- * I'm not sure what the correct thing to do here is :
- *
- * If the command that just executed is NOT a request
- * sense, the obvious thing to do is to set the result
- * code to the values of the stored parameters.
- *
- * If it was a REQUEST SENSE command, we need some way to
- * differentiate between the failure code of the original
- * and the failure code of the REQUEST sense - the obvious
- * case is success, where we fall through and leave the
- * result code unchanged.
- *
- * The non-obvious place is where the REQUEST SENSE failed
- */
-
- if (cmd->cmnd[0] != REQUEST_SENSE)
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- else if (status_byte(cmd->SCp.Status) != GOOD)
- cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-
-#ifdef AUTOSENSE
- if ((cmd->cmnd[0] != REQUEST_SENSE) &&
- (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
- ASEN_PRINTK("scsi%d: performing request sense\n",
- HOSTNO);
- cmd->cmnd[0] = REQUEST_SENSE;
- cmd->cmnd[1] &= 0xe0;
- cmd->cmnd[2] = 0;
- cmd->cmnd[3] = 0;
- cmd->cmnd[4] = sizeof(cmd->sense_buffer);
- cmd->cmnd[5] = 0;
- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
- cmd->use_sg = 0;
- /* this is initialized from initialize_SCp
- cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
- */
- cmd->request_buffer = (char *) cmd->sense_buffer;
- cmd->request_bufflen = sizeof(cmd->sense_buffer);
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+
+ /*
+ * I'm not sure what the correct thing to do here is :
+ *
+ * If the command that just executed is NOT a request
+ * sense, the obvious thing to do is to set the result
+ * code to the values of the stored parameters.
+ *
+ * If it was a REQUEST SENSE command, we need some way to
+ * differentiate between the failure code of the original
+ * and the failure code of the REQUEST sense - the obvious
+ * case is success, where we fall through and leave the
+ * result code unchanged.
+ *
+ * The non-obvious place is where the REQUEST SENSE failed
+ */
+
+ if (cmd->cmnd[0] != REQUEST_SENSE)
+ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+ else if (status_byte(cmd->SCp.Status) != GOOD)
+ cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
- local_irq_save(flags);
- LIST(cmd,hostdata->issue_queue);
- NEXT(cmd) = hostdata->issue_queue;
- hostdata->issue_queue = (Scsi_Cmnd *) cmd;
- local_irq_restore(flags);
- QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
- "issue queue\n", H_NO(cmd));
- } else
+#ifdef AUTOSENSE
+ if ((cmd->cmnd[0] != REQUEST_SENSE) &&
+ (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+ ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO);
+ cmd->cmnd[0] = REQUEST_SENSE;
+ cmd->cmnd[1] &= 0xe0;
+ cmd->cmnd[2] = 0;
+ cmd->cmnd[3] = 0;
+ cmd->cmnd[4] = sizeof(cmd->sense_buffer);
+ cmd->cmnd[5] = 0;
+ cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+
+ cmd->use_sg = 0;
+ /* this is initialized from initialize_SCp
+ cmd->SCp.buffer = NULL;
+ cmd->SCp.buffers_residual = 0;
+ */
+ cmd->request_buffer = (char *) cmd->sense_buffer;
+ cmd->request_bufflen = sizeof(cmd->sense_buffer);
+
+ local_irq_save(flags);
+ LIST(cmd,hostdata->issue_queue);
+ SET_NEXT(cmd, hostdata->issue_queue);
+ hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+ local_irq_restore(flags);
+ QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
+ "issue queue\n", H_NO(cmd));
+ } else
#endif /* def AUTOSENSE */
- {
+ {
#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
+ collect_stats(hostdata, cmd);
#endif
- cmd->scsi_done(cmd);
- }
-
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /*
- * Restore phase bits to 0 so an interrupted selection,
- * arbitration can resume.
- */
- NCR5380_write(TARGET_COMMAND_REG, 0);
-
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
-
- falcon_dont_release--;
- /* ++roman: For Falcon SCSI, release the lock on the
- * ST-DMA here if no other commands are waiting on the
- * disconnected queue.
- */
- falcon_release_lock_if_possible( hostdata );
- return;
- case MESSAGE_REJECT:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- switch (hostdata->last_message) {
- case HEAD_OF_QUEUE_TAG:
- case ORDERED_QUEUE_TAG:
- case SIMPLE_QUEUE_TAG:
- /* The target obviously doesn't support tagged
- * queuing, even though it announced this ability in
- * its INQUIRY data ?!? (maybe only this LUN?) Ok,
- * clear 'tagged_supported' and lock the LUN, since
- * the command is treated as untagged further on.
- */
- cmd->device->tagged_supported = 0;
- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
- cmd->tag = TAG_NONE;
- TAG_PRINTK("scsi%d: target %d lun %d rejected "
- "QUEUE_TAG message; tagged queuing "
- "disabled\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
- break;
- }
- break;
- case DISCONNECT:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- local_irq_save(flags);
- cmd->device->disconnect = 1;
- LIST(cmd,hostdata->disconnected_queue);
- NEXT(cmd) = hostdata->disconnected_queue;
- hostdata->connected = NULL;
- hostdata->disconnected_queue = cmd;
- local_irq_restore(flags);
- QU_PRINTK("scsi%d: command for target %d lun %d was "
- "moved from connected to the "
- "disconnected_queue\n", HOSTNO,
- cmd->device->id, cmd->device->lun);
- /*
- * Restore phase bits to 0 so an interrupted selection,
- * arbitration can resume.
- */
- NCR5380_write(TARGET_COMMAND_REG, 0);
-
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /* Wait for bus free to avoid nasty timeouts */
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
- return;
- /*
- * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
- * operation, in violation of the SCSI spec so we can safely
- * ignore SAVE/RESTORE pointers calls.
- *
- * Unfortunately, some disks violate the SCSI spec and
- * don't issue the required SAVE_POINTERS message before
- * disconnecting, and we have to break spec to remain
- * compatible.
- */
- case SAVE_POINTERS:
- case RESTORE_POINTERS:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- break;
- case EXTENDED_MESSAGE:
-/*
- * Extended messages are sent in the following format :
- * Byte
- * 0 EXTENDED_MESSAGE == 1
- * 1 length (includes one byte for code, doesn't
- * include first two bytes)
- * 2 code
- * 3..length+1 arguments
- *
- * Start the extended message buffer with the EXTENDED_MESSAGE
- * byte, since spi_print_msg() wants the whole thing.
- */
- extended_msg[0] = EXTENDED_MESSAGE;
- /* Accept first byte by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
-
- len = 2;
- data = extended_msg + 1;
- phase = PHASE_MSGIN;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
- (int)extended_msg[1], (int)extended_msg[2]);
-
- if (!len && extended_msg[1] <=
- (sizeof (extended_msg) - 1)) {
- /* Accept third byte by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- len = extended_msg[1] - 1;
- data = extended_msg + 3;
- phase = PHASE_MSGIN;
-
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- EXT_PRINTK("scsi%d: message received, residual %d\n",
- HOSTNO, len);
-
- switch (extended_msg[2]) {
- case EXTENDED_SDTR:
- case EXTENDED_WDTR:
- case EXTENDED_MODIFY_DATA_POINTER:
- case EXTENDED_EXTENDED_IDENTIFY:
- tmp = 0;
- }
- } else if (len) {
- printk(KERN_NOTICE "scsi%d: error receiving "
- "extended message\n", HOSTNO);
- tmp = 0;
- } else {
- printk(KERN_NOTICE "scsi%d: extended message "
- "code %02x length %d is too long\n",
- HOSTNO, extended_msg[2], extended_msg[1]);
- tmp = 0;
- }
- /* Fall through to reject message */
-
- /*
- * If we get something weird that we aren't expecting,
- * reject it.
- */
- default:
- if (!tmp) {
- printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
- spi_print_msg(extended_msg);
- printk("\n");
- } else if (tmp != EXTENDED_MESSAGE)
- printk(KERN_DEBUG "scsi%d: rejecting unknown "
- "message %02x from target %d, lun %d\n",
- HOSTNO, tmp, cmd->device->id, cmd->device->lun);
- else
- printk(KERN_DEBUG "scsi%d: rejecting unknown "
- "extended message "
- "code %02x, length %d from target %d, lun %d\n",
- HOSTNO, extended_msg[1], extended_msg[0],
- cmd->device->id, cmd->device->lun);
-
-
- msgout = MESSAGE_REJECT;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
- break;
- } /* switch (tmp) */
- break;
- case PHASE_MSGOUT:
- len = 1;
- data = &msgout;
- hostdata->last_message = msgout;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- if (msgout == ABORT) {
+ cmd->scsi_done(cmd);
+ }
+
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ /*
+ * Restore phase bits to 0 so an interrupted selection,
+ * arbitration can resume.
+ */
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+ barrier();
+
+ falcon_dont_release--;
+ /* ++roman: For Falcon SCSI, release the lock on the
+ * ST-DMA here if no other commands are waiting on the
+ * disconnected queue.
+ */
+ falcon_release_lock_if_possible(hostdata);
+ return;
+ case MESSAGE_REJECT:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ switch (hostdata->last_message) {
+ case HEAD_OF_QUEUE_TAG:
+ case ORDERED_QUEUE_TAG:
+ case SIMPLE_QUEUE_TAG:
+ /* The target obviously doesn't support tagged
+ * queuing, even though it announced this ability in
+ * its INQUIRY data ?!? (maybe only this LUN?) Ok,
+ * clear 'tagged_supported' and lock the LUN, since
+ * the command is treated as untagged further on.
+ */
+ cmd->device->tagged_supported = 0;
+ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+ cmd->tag = TAG_NONE;
+ TAG_PRINTK("scsi%d: target %d lun %d rejected "
+ "QUEUE_TAG message; tagged queuing "
+ "disabled\n",
+ HOSTNO, cmd->device->id, cmd->device->lun);
+ break;
+ }
+ break;
+ case DISCONNECT:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ local_irq_save(flags);
+ cmd->device->disconnect = 1;
+ LIST(cmd,hostdata->disconnected_queue);
+ SET_NEXT(cmd, hostdata->disconnected_queue);
+ hostdata->connected = NULL;
+ hostdata->disconnected_queue = cmd;
+ local_irq_restore(flags);
+ QU_PRINTK("scsi%d: command for target %d lun %d was "
+ "moved from connected to the "
+ "disconnected_queue\n", HOSTNO,
+ cmd->device->id, cmd->device->lun);
+ /*
+ * Restore phase bits to 0 so an interrupted selection,
+ * arbitration can resume.
+ */
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ /* Wait for bus free to avoid nasty timeouts */
+ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+ barrier();
+ return;
+ /*
+ * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
+ * operation, in violation of the SCSI spec so we can safely
+ * ignore SAVE/RESTORE pointers calls.
+ *
+ * Unfortunately, some disks violate the SCSI spec and
+ * don't issue the required SAVE_POINTERS message before
+ * disconnecting, and we have to break spec to remain
+ * compatible.
+ */
+ case SAVE_POINTERS:
+ case RESTORE_POINTERS:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ break;
+ case EXTENDED_MESSAGE:
+ /*
+ * Extended messages are sent in the following format :
+ * Byte
+ * 0 EXTENDED_MESSAGE == 1
+ * 1 length (includes one byte for code, doesn't
+ * include first two bytes)
+ * 2 code
+ * 3..length+1 arguments
+ *
+ * Start the extended message buffer with the EXTENDED_MESSAGE
+ * byte, since spi_print_msg() wants the whole thing.
+ */
+ extended_msg[0] = EXTENDED_MESSAGE;
+ /* Accept first byte by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
+
+ len = 2;
+ data = extended_msg + 1;
+ phase = PHASE_MSGIN;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
+ (int)extended_msg[1], (int)extended_msg[2]);
+
+ if (!len && extended_msg[1] <=
+ (sizeof(extended_msg) - 1)) {
+ /* Accept third byte by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ len = extended_msg[1] - 1;
+ data = extended_msg + 3;
+ phase = PHASE_MSGIN;
+
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ EXT_PRINTK("scsi%d: message received, residual %d\n",
+ HOSTNO, len);
+
+ switch (extended_msg[2]) {
+ case EXTENDED_SDTR:
+ case EXTENDED_WDTR:
+ case EXTENDED_MODIFY_DATA_POINTER:
+ case EXTENDED_EXTENDED_IDENTIFY:
+ tmp = 0;
+ }
+ } else if (len) {
+ printk(KERN_NOTICE "scsi%d: error receiving "
+ "extended message\n", HOSTNO);
+ tmp = 0;
+ } else {
+ printk(KERN_NOTICE "scsi%d: extended message "
+ "code %02x length %d is too long\n",
+ HOSTNO, extended_msg[2], extended_msg[1]);
+ tmp = 0;
+ }
+ /* Fall through to reject message */
+
+ /*
+ * If we get something weird that we aren't expecting,
+ * reject it.
+ */
+ default:
+ if (!tmp) {
+ printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
+ spi_print_msg(extended_msg);
+ printk("\n");
+ } else if (tmp != EXTENDED_MESSAGE)
+ printk(KERN_DEBUG "scsi%d: rejecting unknown "
+ "message %02x from target %d, lun %d\n",
+ HOSTNO, tmp, cmd->device->id, cmd->device->lun);
+ else
+ printk(KERN_DEBUG "scsi%d: rejecting unknown "
+ "extended message "
+ "code %02x, length %d from target %d, lun %d\n",
+ HOSTNO, extended_msg[1], extended_msg[0],
+ cmd->device->id, cmd->device->lun);
+
+
+ msgout = MESSAGE_REJECT;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ break;
+ } /* switch (tmp) */
+ break;
+ case PHASE_MSGOUT:
+ len = 1;
+ data = &msgout;
+ hostdata->last_message = msgout;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ if (msgout == ABORT) {
#ifdef SUPPORT_TAGS
- cmd_free_tag( cmd );
+ cmd_free_tag(cmd);
#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
- hostdata->connected = NULL;
- cmd->result = DID_ERROR << 16;
+ hostdata->connected = NULL;
+ cmd->result = DID_ERROR << 16;
#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
+ collect_stats(hostdata, cmd);
#endif
- cmd->scsi_done(cmd);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- falcon_release_lock_if_possible( hostdata );
- return;
- }
- msgout = NOP;
- break;
- case PHASE_CMDOUT:
- len = cmd->cmd_len;
- data = cmd->cmnd;
- /*
- * XXX for performance reasons, on machines with a
- * PSEUDO-DMA architecture we should probably
- * use the dma transfer function.
- */
- NCR5380_transfer_pio(instance, &phase, &len,
- &data);
- break;
- case PHASE_STATIN:
- len = 1;
- data = &tmp;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- cmd->SCp.Status = tmp;
- break;
- default:
- printk("scsi%d: unknown phase\n", HOSTNO);
- NCR_PRINT(NDEBUG_ANY);
- } /* switch(phase) */
- } /* if (tmp * SR_REQ) */
- } /* while (1) */
+ cmd->scsi_done(cmd);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ falcon_release_lock_if_possible(hostdata);
+ return;
+ }
+ msgout = NOP;
+ break;
+ case PHASE_CMDOUT:
+ len = cmd->cmd_len;
+ data = cmd->cmnd;
+ /*
+ * XXX for performance reasons, on machines with a
+ * PSEUDO-DMA architecture we should probably
+ * use the dma transfer function.
+ */
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ break;
+ case PHASE_STATIN:
+ len = 1;
+ data = &tmp;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ cmd->SCp.Status = tmp;
+ break;
+ default:
+ printk("scsi%d: unknown phase\n", HOSTNO);
+ NCR_PRINT(NDEBUG_ANY);
+ } /* switch(phase) */
+ } /* if (tmp * SR_REQ) */
+ } /* while (1) */
}
/*
* Function : void NCR5380_reselect (struct Scsi_Host *instance)
*
- * Purpose : does reselection, initializing the instance->connected
- * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
+ * Purpose : does reselection, initializing the instance->connected
+ * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
* nexus has been reestablished,
- *
+ *
* Inputs : instance - this instance of the NCR5380.
*
*/
-static void NCR5380_reselect (struct Scsi_Host *instance)
+static void NCR5380_reselect(struct Scsi_Host *instance)
{
- SETUP_HOSTDATA(instance);
- unsigned char target_mask;
- unsigned char lun, phase;
- int len;
+ SETUP_HOSTDATA(instance);
+ unsigned char target_mask;
+ unsigned char lun, phase;
+ int len;
#ifdef SUPPORT_TAGS
- unsigned char tag;
+ unsigned char tag;
#endif
- unsigned char msg[3];
- unsigned char *data;
- Scsi_Cmnd *tmp = NULL, *prev;
-/* unsigned long flags; */
-
- /*
- * Disable arbitration, etc. since the host adapter obviously
- * lost, and tell an interrupted NCR5380_select() to restart.
- */
-
- NCR5380_write(MODE_REG, MR_BASE);
- hostdata->restart_select = 1;
-
- target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
-
- RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
-
- /*
- * At this point, we have detected that our SCSI ID is on the bus,
- * SEL is true and BSY was false for at least one bus settle delay
- * (400 ns).
- *
- * We must assert BSY ourselves, until the target drops the SEL
- * signal.
- */
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
-
- while (NCR5380_read(STATUS_REG) & SR_SEL);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- /*
- * Wait for target to go into MSGIN.
- */
-
- while (!(NCR5380_read(STATUS_REG) & SR_REQ));
-
- len = 1;
- data = msg;
- phase = PHASE_MSGIN;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
-
- if (!(msg[0] & 0x80)) {
- printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
- spi_print_msg(msg);
- do_abort(instance);
- return;
- }
- lun = (msg[0] & 0x07);
+ unsigned char msg[3];
+ unsigned char *data;
+ Scsi_Cmnd *tmp = NULL, *prev;
+/* unsigned long flags; */
+
+ /*
+ * Disable arbitration, etc. since the host adapter obviously
+ * lost, and tell an interrupted NCR5380_select() to restart.
+ */
+
+ NCR5380_write(MODE_REG, MR_BASE);
+ hostdata->restart_select = 1;
+
+ target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+
+ RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
+
+ /*
+ * At this point, we have detected that our SCSI ID is on the bus,
+ * SEL is true and BSY was false for at least one bus settle delay
+ * (400 ns).
+ *
+ * We must assert BSY ourselves, until the target drops the SEL
+ * signal.
+ */
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+
+ while (NCR5380_read(STATUS_REG) & SR_SEL)
+ ;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ /*
+ * Wait for target to go into MSGIN.
+ */
+
+ while (!(NCR5380_read(STATUS_REG) & SR_REQ))
+ ;
+
+ len = 1;
+ data = msg;
+ phase = PHASE_MSGIN;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+ if (!(msg[0] & 0x80)) {
+ printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+ spi_print_msg(msg);
+ do_abort(instance);
+ return;
+ }
+ lun = (msg[0] & 0x07);
#ifdef SUPPORT_TAGS
- /* If the phase is still MSGIN, the target wants to send some more
- * messages. In case it supports tagged queuing, this is probably a
- * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
- */
- tag = TAG_NONE;
- if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
- /* Accept previous IDENTIFY message by clearing ACK */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
- len = 2;
- data = msg+1;
- if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
- msg[1] == SIMPLE_QUEUE_TAG)
- tag = msg[2];
- TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
- "reselection\n", HOSTNO, target_mask, lun, tag);
- }
+ /* If the phase is still MSGIN, the target wants to send some more
+ * messages. In case it supports tagged queuing, this is probably a
+ * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
+ */
+ tag = TAG_NONE;
+ if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
+ /* Accept previous IDENTIFY message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ len = 2;
+ data = msg + 1;
+ if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
+ msg[1] == SIMPLE_QUEUE_TAG)
+ tag = msg[2];
+ TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
+ "reselection\n", HOSTNO, target_mask, lun, tag);
+ }
#endif
-
- /*
- * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
- * just reestablished, and remove it from the disconnected queue.
- */
-
- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
- tmp; prev = tmp, tmp = NEXT(tmp) ) {
- if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
+
+ /*
+ * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
+ * just reestablished, and remove it from the disconnected queue.
+ */
+
+ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
+ tmp; prev = tmp, tmp = NEXT(tmp)) {
+ if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
#ifdef SUPPORT_TAGS
- && (tag == tmp->tag)
+ && (tag == tmp->tag)
#endif
- ) {
- /* ++guenther: prevent race with falcon_release_lock */
- falcon_dont_release++;
- if (prev) {
- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
- NEXT(prev) = NEXT(tmp);
- } else {
- REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
- hostdata->disconnected_queue = NEXT(tmp);
- }
- NEXT(tmp) = NULL;
- break;
+ ) {
+ /* ++guenther: prevent race with falcon_release_lock */
+ falcon_dont_release++;
+ if (prev) {
+ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+ SET_NEXT(prev, NEXT(tmp));
+ } else {
+ REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
+ hostdata->disconnected_queue = NEXT(tmp);
+ }
+ SET_NEXT(tmp, NULL);
+ break;
+ }
}
- }
-
- if (!tmp) {
- printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
+
+ if (!tmp) {
+ printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
#ifdef SUPPORT_TAGS
- "tag %d "
+ "tag %d "
#endif
- "not in disconnected_queue.\n",
- HOSTNO, target_mask, lun
+ "not in disconnected_queue.\n",
+ HOSTNO, target_mask, lun
#ifdef SUPPORT_TAGS
- , tag
+ , tag
#endif
- );
- /*
- * Since we have an established nexus that we can't do anything
- * with, we must abort it.
- */
- do_abort(instance);
- return;
- }
+ );
+ /*
+ * Since we have an established nexus that we can't do anything
+ * with, we must abort it.
+ */
+ do_abort(instance);
+ return;
+ }
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- hostdata->connected = tmp;
- RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
- HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
- falcon_dont_release--;
+ hostdata->connected = tmp;
+ RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
+ HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
+ falcon_dont_release--;
}
@@ -2626,362 +2677,361 @@ static void NCR5380_reselect (struct Scsi_Host *instance)
*
* Purpose : abort a command
*
- * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
- * host byte of the result field to, if zero DID_ABORTED is
+ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
+ * host byte of the result field to, if zero DID_ABORTED is
* used.
*
* Returns : 0 - success, -1 on failure.
*
- * XXX - there is no way to abort the command that is currently
- * connected, you have to wait for it to complete. If this is
+ * XXX - there is no way to abort the command that is currently
+ * connected, you have to wait for it to complete. If this is
* a problem, we could implement longjmp() / setjmp(), setjmp()
- * called where the loop started in NCR5380_main().
+ * called where the loop started in NCR5380_main().
*/
static
-int NCR5380_abort (Scsi_Cmnd *cmd)
+int NCR5380_abort(Scsi_Cmnd *cmd)
{
- struct Scsi_Host *instance = cmd->device->host;
- SETUP_HOSTDATA(instance);
- Scsi_Cmnd *tmp, **prev;
- unsigned long flags;
+ struct Scsi_Host *instance = cmd->device->host;
+ SETUP_HOSTDATA(instance);
+ Scsi_Cmnd *tmp, **prev;
+ unsigned long flags;
+
+ printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
+ scsi_print_command(cmd);
- printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
- scsi_print_command(cmd);
+ NCR5380_print_status(instance);
- NCR5380_print_status (instance);
+ local_irq_save(flags);
- local_irq_save(flags);
-
- if (!IS_A_TT() && !falcon_got_lock)
- printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
- HOSTNO);
+ if (!IS_A_TT() && !falcon_got_lock)
+ printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
+ HOSTNO);
- ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
- NCR5380_read(BUS_AND_STATUS_REG),
- NCR5380_read(STATUS_REG));
+ ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
+ NCR5380_read(BUS_AND_STATUS_REG),
+ NCR5380_read(STATUS_REG));
#if 1
-/*
- * Case 1 : If the command is the currently executing command,
- * we'll set the aborted flag and return control so that
- * information transfer routine can exit cleanly.
- */
+ /*
+ * Case 1 : If the command is the currently executing command,
+ * we'll set the aborted flag and return control so that
+ * information transfer routine can exit cleanly.
+ */
- if (hostdata->connected == cmd) {
+ if (hostdata->connected == cmd) {
- ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
-/*
- * We should perform BSY checking, and make sure we haven't slipped
- * into BUS FREE.
- */
+ ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
+ /*
+ * We should perform BSY checking, and make sure we haven't slipped
+ * into BUS FREE.
+ */
-/* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
-/*
- * Since we can't change phases until we've completed the current
- * handshake, we have to source or sink a byte of data if the current
- * phase is not MSGOUT.
- */
+ /* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
+ /*
+ * Since we can't change phases until we've completed the current
+ * handshake, we have to source or sink a byte of data if the current
+ * phase is not MSGOUT.
+ */
-/*
- * Return control to the executing NCR drive so we can clear the
- * aborted flag and get back into our main loop.
- */
+ /*
+ * Return control to the executing NCR drive so we can clear the
+ * aborted flag and get back into our main loop.
+ */
- if (do_abort(instance) == 0) {
- hostdata->aborted = 1;
- hostdata->connected = NULL;
- cmd->result = DID_ABORT << 16;
+ if (do_abort(instance) == 0) {
+ hostdata->aborted = 1;
+ hostdata->connected = NULL;
+ cmd->result = DID_ABORT << 16;
#ifdef SUPPORT_TAGS
- cmd_free_tag( cmd );
+ cmd_free_tag(cmd);
#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
- local_irq_restore(flags);
- cmd->scsi_done(cmd);
- falcon_release_lock_if_possible( hostdata );
- return SCSI_ABORT_SUCCESS;
- } else {
-/* local_irq_restore(flags); */
- printk("scsi%d: abort of connected command failed!\n", HOSTNO);
- return SCSI_ABORT_ERROR;
- }
- }
+ local_irq_restore(flags);
+ cmd->scsi_done(cmd);
+ falcon_release_lock_if_possible(hostdata);
+ return SCSI_ABORT_SUCCESS;
+ } else {
+/* local_irq_restore(flags); */
+ printk("scsi%d: abort of connected command failed!\n", HOSTNO);
+ return SCSI_ABORT_ERROR;
+ }
+ }
#endif
-/*
- * Case 2 : If the command hasn't been issued yet, we simply remove it
- * from the issue queue.
- */
- for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue),
- tmp = (Scsi_Cmnd *) hostdata->issue_queue;
- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, NEXT(tmp));
- (*prev) = NEXT(tmp);
- NEXT(tmp) = NULL;
- tmp->result = DID_ABORT << 16;
- local_irq_restore(flags);
- ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
- HOSTNO);
- /* Tagged queuing note: no tag to free here, hasn't been assigned
- * yet... */
- tmp->scsi_done(tmp);
- falcon_release_lock_if_possible( hostdata );
- return SCSI_ABORT_SUCCESS;
+ /*
+ * Case 2 : If the command hasn't been issued yet, we simply remove it
+ * from the issue queue.
+ */
+ for (prev = (Scsi_Cmnd **)&(hostdata->issue_queue),
+ tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
+ if (cmd == tmp) {
+ REMOVE(5, *prev, tmp, NEXT(tmp));
+ (*prev) = NEXT(tmp);
+ SET_NEXT(tmp, NULL);
+ tmp->result = DID_ABORT << 16;
+ local_irq_restore(flags);
+ ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
+ HOSTNO);
+ /* Tagged queuing note: no tag to free here, hasn't been assigned
+ * yet... */
+ tmp->scsi_done(tmp);
+ falcon_release_lock_if_possible(hostdata);
+ return SCSI_ABORT_SUCCESS;
+ }
}
-/*
- * Case 3 : If any commands are connected, we're going to fail the abort
- * and let the high level SCSI driver retry at a later time or
- * issue a reset.
- *
- * Timeouts, and therefore aborted commands, will be highly unlikely
- * and handling them cleanly in this situation would make the common
- * case of noresets less efficient, and would pollute our code. So,
- * we fail.
- */
+ /*
+ * Case 3 : If any commands are connected, we're going to fail the abort
+ * and let the high level SCSI driver retry at a later time or
+ * issue a reset.
+ *
+ * Timeouts, and therefore aborted commands, will be highly unlikely
+ * and handling them cleanly in this situation would make the common
+ * case of noresets less efficient, and would pollute our code. So,
+ * we fail.
+ */
- if (hostdata->connected) {
- local_irq_restore(flags);
- ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
- return SCSI_ABORT_SNOOZE;
- }
+ if (hostdata->connected) {
+ local_irq_restore(flags);
+ ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
+ return SCSI_ABORT_SNOOZE;
+ }
-/*
- * Case 4: If the command is currently disconnected from the bus, and
- * there are no connected commands, we reconnect the I_T_L or
- * I_T_L_Q nexus associated with it, go into message out, and send
- * an abort message.
- *
- * This case is especially ugly. In order to reestablish the nexus, we
- * need to call NCR5380_select(). The easiest way to implement this
- * function was to abort if the bus was busy, and let the interrupt
- * handler triggered on the SEL for reselect take care of lost arbitrations
- * where necessary, meaning interrupts need to be enabled.
- *
- * When interrupts are enabled, the queues may change - so we
- * can't remove it from the disconnected queue before selecting it
- * because that could cause a failure in hashing the nexus if that
- * device reselected.
- *
- * Since the queues may change, we can't use the pointers from when we
- * first locate it.
- *
- * So, we must first locate the command, and if NCR5380_select()
- * succeeds, then issue the abort, relocate the command and remove
- * it from the disconnected queue.
- */
+ /*
+ * Case 4: If the command is currently disconnected from the bus, and
+ * there are no connected commands, we reconnect the I_T_L or
+ * I_T_L_Q nexus associated with it, go into message out, and send
+ * an abort message.
+ *
+ * This case is especially ugly. In order to reestablish the nexus, we
+ * need to call NCR5380_select(). The easiest way to implement this
+ * function was to abort if the bus was busy, and let the interrupt
+ * handler triggered on the SEL for reselect take care of lost arbitrations
+ * where necessary, meaning interrupts need to be enabled.
+ *
+ * When interrupts are enabled, the queues may change - so we
+ * can't remove it from the disconnected queue before selecting it
+ * because that could cause a failure in hashing the nexus if that
+ * device reselected.
+ *
+ * Since the queues may change, we can't use the pointers from when we
+ * first locate it.
+ *
+ * So, we must first locate the command, and if NCR5380_select()
+ * succeeds, then issue the abort, relocate the command and remove
+ * it from the disconnected queue.
+ */
+
+ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+ tmp = NEXT(tmp)) {
+ if (cmd == tmp) {
+ local_irq_restore(flags);
+ ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
- tmp = NEXT(tmp))
- if (cmd == tmp) {
- local_irq_restore(flags);
- ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
-
- if (NCR5380_select (instance, cmd, (int) cmd->tag))
- return SCSI_ABORT_BUSY;
-
- ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
-
- do_abort (instance);
-
- local_irq_save(flags);
- for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue),
- tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, NEXT(tmp));
- *prev = NEXT(tmp);
- NEXT(tmp) = NULL;
- tmp->result = DID_ABORT << 16;
- /* We must unlock the tag/LUN immediately here, since the
- * target goes to BUS FREE and doesn't send us another
- * message (COMMAND_COMPLETE or the like)
- */
+ if (NCR5380_select(instance, cmd, (int)cmd->tag))
+ return SCSI_ABORT_BUSY;
+
+ ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
+
+ do_abort(instance);
+
+ local_irq_save(flags);
+ for (prev = (Scsi_Cmnd **)&(hostdata->disconnected_queue),
+ tmp = (Scsi_Cmnd *)hostdata->disconnected_queue;
+ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
+ if (cmd == tmp) {
+ REMOVE(5, *prev, tmp, NEXT(tmp));
+ *prev = NEXT(tmp);
+ SET_NEXT(tmp, NULL);
+ tmp->result = DID_ABORT << 16;
+ /* We must unlock the tag/LUN immediately here, since the
+ * target goes to BUS FREE and doesn't send us another
+ * message (COMMAND_COMPLETE or the like)
+ */
#ifdef SUPPORT_TAGS
- cmd_free_tag( tmp );
+ cmd_free_tag(tmp);
#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
- local_irq_restore(flags);
- tmp->scsi_done(tmp);
- falcon_release_lock_if_possible( hostdata );
- return SCSI_ABORT_SUCCESS;
+ local_irq_restore(flags);
+ tmp->scsi_done(tmp);
+ falcon_release_lock_if_possible(hostdata);
+ return SCSI_ABORT_SUCCESS;
+ }
+ }
}
}
-/*
- * Case 5 : If we reached this point, the command was not found in any of
- * the queues.
- *
- * We probably reached this point because of an unlikely race condition
- * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case something really
- * broke.
- */
+ /*
+ * Case 5 : If we reached this point, the command was not found in any of
+ * the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case something really
+ * broke.
+ */
- local_irq_restore(flags);
- printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
- KERN_INFO " before abortion\n", HOSTNO);
+ local_irq_restore(flags);
+ printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
+ KERN_INFO " before abortion\n", HOSTNO);
-/* Maybe it is sufficient just to release the ST-DMA lock... (if
- * possible at all) At least, we should check if the lock could be
- * released after the abort, in case it is kept due to some bug.
- */
- falcon_release_lock_if_possible( hostdata );
+ /* Maybe it is sufficient just to release the ST-DMA lock... (if
+ * possible at all) At least, we should check if the lock could be
+ * released after the abort, in case it is kept due to some bug.
+ */
+ falcon_release_lock_if_possible(hostdata);
- return SCSI_ABORT_NOT_RUNNING;
+ return SCSI_ABORT_NOT_RUNNING;
}
-/*
+/*
* Function : int NCR5380_reset (Scsi_Cmnd *cmd)
- *
+ *
* Purpose : reset the SCSI bus.
*
* Returns : SCSI_RESET_WAKEUP
*
- */
+ */
-static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
+static int NCR5380_bus_reset(Scsi_Cmnd *cmd)
{
- SETUP_HOSTDATA(cmd->device->host);
- int i;
- unsigned long flags;
+ SETUP_HOSTDATA(cmd->device->host);
+ int i;
+ unsigned long flags;
#if 1
- Scsi_Cmnd *connected, *disconnected_queue;
+ Scsi_Cmnd *connected, *disconnected_queue;
#endif
- if (!IS_A_TT() && !falcon_got_lock)
- printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
- H_NO(cmd) );
-
- NCR5380_print_status (cmd->device->host);
-
- /* get in phase */
- NCR5380_write( TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
- /* assert RST */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
- udelay (40);
- /* reset NCR registers */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
- NCR5380_write( MODE_REG, MR_BASE );
- NCR5380_write( TARGET_COMMAND_REG, 0 );
- NCR5380_write( SELECT_ENABLE_REG, 0 );
- /* ++roman: reset interrupt condition! otherwise no interrupts don't get
- * through anymore ... */
- (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG );
-
-#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
- /* XXX see below XXX */
-
- /* MSch: old-style reset: actually abort all command processing here */
-
- /* After the reset, there are no more connected or disconnected commands
- * and no busy units; to avoid problems with re-inserting the commands
- * into the issue_queue (via scsi_done()), the aborted commands are
- * remembered in local variables first.
- */
- local_irq_save(flags);
- connected = (Scsi_Cmnd *)hostdata->connected;
- hostdata->connected = NULL;
- disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
- hostdata->disconnected_queue = NULL;
+ if (!IS_A_TT() && !falcon_got_lock)
+ printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
+ H_NO(cmd));
+
+ NCR5380_print_status(cmd->device->host);
+
+ /* get in phase */
+ NCR5380_write(TARGET_COMMAND_REG,
+ PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
+ /* assert RST */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
+ udelay(40);
+ /* reset NCR registers */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+ /* ++roman: reset interrupt condition! otherwise no interrupts don't get
+ * through anymore ... */
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
+ /* XXX see below XXX */
+
+ /* MSch: old-style reset: actually abort all command processing here */
+
+ /* After the reset, there are no more connected or disconnected commands
+ * and no busy units; to avoid problems with re-inserting the commands
+ * into the issue_queue (via scsi_done()), the aborted commands are
+ * remembered in local variables first.
+ */
+ local_irq_save(flags);
+ connected = (Scsi_Cmnd *)hostdata->connected;
+ hostdata->connected = NULL;
+ disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
+ hostdata->disconnected_queue = NULL;
#ifdef SUPPORT_TAGS
- free_all_tags();
+ free_all_tags();
#endif
- for( i = 0; i < 8; ++i )
- hostdata->busy[i] = 0;
+ for (i = 0; i < 8; ++i)
+ hostdata->busy[i] = 0;
#ifdef REAL_DMA
- hostdata->dma_len = 0;
+ hostdata->dma_len = 0;
#endif
- local_irq_restore(flags);
-
- /* In order to tell the mid-level code which commands were aborted,
- * set the command status to DID_RESET and call scsi_done() !!!
- * This ultimately aborts processing of these commands in the mid-level.
- */
-
- if ((cmd = connected)) {
- ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
- cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
- cmd->scsi_done( cmd );
- }
-
- for (i = 0; (cmd = disconnected_queue); ++i) {
- disconnected_queue = NEXT(cmd);
- NEXT(cmd) = NULL;
- cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
- cmd->scsi_done( cmd );
- }
- if (i > 0)
- ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
-
-/* The Falcon lock should be released after a reset...
- */
-/* ++guenther: moved to atari_scsi_reset(), to prevent a race between
- * unlocking and enabling dma interrupt.
- */
-/* falcon_release_lock_if_possible( hostdata );*/
+ local_irq_restore(flags);
+
+ /* In order to tell the mid-level code which commands were aborted,
+ * set the command status to DID_RESET and call scsi_done() !!!
+ * This ultimately aborts processing of these commands in the mid-level.
+ */
+
+ if ((cmd = connected)) {
+ ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+ cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+ cmd->scsi_done(cmd);
+ }
- /* since all commands have been explicitly terminated, we need to tell
- * the midlevel code that the reset was SUCCESSFUL, and there is no
- * need to 'wake up' the commands by a request_sense
- */
- return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+ for (i = 0; (cmd = disconnected_queue); ++i) {
+ disconnected_queue = NEXT(cmd);
+ SET_NEXT(cmd, NULL);
+ cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+ cmd->scsi_done(cmd);
+ }
+ if (i > 0)
+ ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
+
+ /* The Falcon lock should be released after a reset...
+ */
+ /* ++guenther: moved to atari_scsi_reset(), to prevent a race between
+ * unlocking and enabling dma interrupt.
+ */
+/* falcon_release_lock_if_possible( hostdata );*/
+
+ /* since all commands have been explicitly terminated, we need to tell
+ * the midlevel code that the reset was SUCCESSFUL, and there is no
+ * need to 'wake up' the commands by a request_sense
+ */
+ return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
#else /* 1 */
- /* MSch: new-style reset handling: let the mid-level do what it can */
-
- /* ++guenther: MID-LEVEL IS STILL BROKEN.
- * Mid-level is supposed to requeue all commands that were active on the
- * various low-level queues. In fact it does this, but that's not enough
- * because all these commands are subject to timeout. And if a timeout
- * happens for any removed command, *_abort() is called but all queues
- * are now empty. Abort then gives up the falcon lock, which is fatal,
- * since the mid-level will queue more commands and must have the lock
- * (it's all happening inside timer interrupt handler!!).
- * Even worse, abort will return NOT_RUNNING for all those commands not
- * on any queue, so they won't be retried ...
- *
- * Conclusion: either scsi.c disables timeout for all resetted commands
- * immediately, or we lose! As of linux-2.0.20 it doesn't.
- */
-
- /* After the reset, there are no more connected or disconnected commands
- * and no busy units; so clear the low-level status here to avoid
- * conflicts when the mid-level code tries to wake up the affected
- * commands!
- */
-
- if (hostdata->issue_queue)
- ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
- if (hostdata->connected)
- ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
- if (hostdata->disconnected_queue)
- ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
-
- local_irq_save(flags);
- hostdata->issue_queue = NULL;
- hostdata->connected = NULL;
- hostdata->disconnected_queue = NULL;
+ /* MSch: new-style reset handling: let the mid-level do what it can */
+
+ /* ++guenther: MID-LEVEL IS STILL BROKEN.
+ * Mid-level is supposed to requeue all commands that were active on the
+ * various low-level queues. In fact it does this, but that's not enough
+ * because all these commands are subject to timeout. And if a timeout
+ * happens for any removed command, *_abort() is called but all queues
+ * are now empty. Abort then gives up the falcon lock, which is fatal,
+ * since the mid-level will queue more commands and must have the lock
+ * (it's all happening inside timer interrupt handler!!).
+ * Even worse, abort will return NOT_RUNNING for all those commands not
+ * on any queue, so they won't be retried ...
+ *
+ * Conclusion: either scsi.c disables timeout for all resetted commands
+ * immediately, or we lose! As of linux-2.0.20 it doesn't.
+ */
+
+ /* After the reset, there are no more connected or disconnected commands
+ * and no busy units; so clear the low-level status here to avoid
+ * conflicts when the mid-level code tries to wake up the affected
+ * commands!
+ */
+
+ if (hostdata->issue_queue)
+ ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
+ if (hostdata->connected)
+ ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+ if (hostdata->disconnected_queue)
+ ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+
+ local_irq_save(flags);
+ hostdata->issue_queue = NULL;
+ hostdata->connected = NULL;
+ hostdata->disconnected_queue = NULL;
#ifdef SUPPORT_TAGS
- free_all_tags();
+ free_all_tags();
#endif
- for( i = 0; i < 8; ++i )
- hostdata->busy[i] = 0;
+ for (i = 0; i < 8; ++i)
+ hostdata->busy[i] = 0;
#ifdef REAL_DMA
- hostdata->dma_len = 0;
+ hostdata->dma_len = 0;
#endif
- local_irq_restore(flags);
+ local_irq_restore(flags);
- /* we did no complete reset of all commands, so a wakeup is required */
- return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
+ /* we did no complete reset of all commands, so a wakeup is required */
+ return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
#endif /* 1 */
}
-
-/* Local Variables: */
-/* tab-width: 8 */
-/* End: */
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 642de7b2b7a..6f8403b82ba 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -69,9 +69,9 @@
#define NDEBUG (0)
-#define NDEBUG_ABORT 0x800000
-#define NDEBUG_TAGS 0x1000000
-#define NDEBUG_MERGING 0x2000000
+#define NDEBUG_ABORT 0x00100000
+#define NDEBUG_TAGS 0x00200000
+#define NDEBUG_MERGING 0x00400000
#define AUTOSENSE
/* For the Atari version, use only polled IO or REAL_DMA */
@@ -186,38 +186,37 @@ static inline void DISABLE_IRQ(void)
/***************************** Prototypes *****************************/
#ifdef REAL_DMA
-static int scsi_dma_is_ignored_buserr( unsigned char dma_stat );
-static void atari_scsi_fetch_restbytes( void );
-static long atari_scsi_dma_residual( struct Scsi_Host *instance );
-static int falcon_classify_cmd( Scsi_Cmnd *cmd );
-static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
- Scsi_Cmnd *cmd, int write_flag );
+static int scsi_dma_is_ignored_buserr(unsigned char dma_stat);
+static void atari_scsi_fetch_restbytes(void);
+static long atari_scsi_dma_residual(struct Scsi_Host *instance);
+static int falcon_classify_cmd(Scsi_Cmnd *cmd);
+static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
+ Scsi_Cmnd *cmd, int write_flag);
#endif
-static irqreturn_t scsi_tt_intr( int irq, void *dummy);
-static irqreturn_t scsi_falcon_intr( int irq, void *dummy);
-static void falcon_release_lock_if_possible( struct NCR5380_hostdata *
- hostdata );
-static void falcon_get_lock( void );
+static irqreturn_t scsi_tt_intr(int irq, void *dummy);
+static irqreturn_t scsi_falcon_intr(int irq, void *dummy);
+static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata);
+static void falcon_get_lock(void);
#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
-static void atari_scsi_reset_boot( void );
+static void atari_scsi_reset_boot(void);
#endif
-static unsigned char atari_scsi_tt_reg_read( unsigned char reg );
-static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value);
-static unsigned char atari_scsi_falcon_reg_read( unsigned char reg );
-static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value );
+static unsigned char atari_scsi_tt_reg_read(unsigned char reg);
+static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value);
+static unsigned char atari_scsi_falcon_reg_read(unsigned char reg);
+static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value);
/************************* End of Prototypes **************************/
-static struct Scsi_Host *atari_scsi_host = NULL;
-static unsigned char (*atari_scsi_reg_read)( unsigned char reg );
-static void (*atari_scsi_reg_write)( unsigned char reg, unsigned char value );
+static struct Scsi_Host *atari_scsi_host;
+static unsigned char (*atari_scsi_reg_read)(unsigned char reg);
+static void (*atari_scsi_reg_write)(unsigned char reg, unsigned char value);
#ifdef REAL_DMA
static unsigned long atari_dma_residual, atari_dma_startaddr;
static short atari_dma_active;
/* pointer to the dribble buffer */
-static char *atari_dma_buffer = NULL;
+static char *atari_dma_buffer;
/* precalculated physical address of the dribble buffer */
static unsigned long atari_dma_phys_buffer;
/* != 0 tells the Falcon int handler to copy data from the dribble buffer */
@@ -233,7 +232,7 @@ static char *atari_dma_orig_addr;
static unsigned long atari_dma_stram_mask;
#define STRAM_ADDR(a) (((a) & atari_dma_stram_mask) == 0)
/* number of bytes to cut from a transfer to handle NCR overruns */
-static int atari_read_overruns = 0;
+static int atari_read_overruns;
#endif
static int setup_can_queue = -1;
@@ -256,10 +255,10 @@ module_param(setup_hostid, int, 0);
#if defined(REAL_DMA)
-static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
+static int scsi_dma_is_ignored_buserr(unsigned char dma_stat)
{
int i;
- unsigned long addr = SCSI_DMA_READ_P( dma_addr ), end_addr;
+ unsigned long addr = SCSI_DMA_READ_P(dma_addr), end_addr;
if (dma_stat & 0x01) {
@@ -267,15 +266,14 @@ static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
* physical memory chunk (DMA prefetch!), but that doesn't hurt.
* Check for this case:
*/
-
- for( i = 0; i < m68k_num_memory; ++i ) {
- end_addr = m68k_memory[i].addr +
- m68k_memory[i].size;
+
+ for (i = 0; i < m68k_num_memory; ++i) {
+ end_addr = m68k_memory[i].addr + m68k_memory[i].size;
if (end_addr <= addr && addr <= end_addr + 4)
- return( 1 );
+ return 1;
}
}
- return( 0 );
+ return 0;
}
@@ -284,28 +282,27 @@ static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
* end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has
* to clear the DMA int pending bit before it allows other level 6 interrupts.
*/
-static void scsi_dma_buserr (int irq, void *dummy)
+static void scsi_dma_buserr(int irq, void *dummy)
{
- unsigned char dma_stat = tt_scsi_dma.dma_ctrl;
+ unsigned char dma_stat = tt_scsi_dma.dma_ctrl;
/* Don't do anything if a NCR interrupt is pending. Probably it's just
* masked... */
- if (atari_irq_pending( IRQ_TT_MFP_SCSI ))
+ if (atari_irq_pending(IRQ_TT_MFP_SCSI))
return;
-
+
printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n",
SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt));
if (dma_stat & 0x80) {
- if (!scsi_dma_is_ignored_buserr( dma_stat ))
- printk( "SCSI DMA bus error -- bad DMA programming!\n" );
- }
- else {
+ if (!scsi_dma_is_ignored_buserr(dma_stat))
+ printk("SCSI DMA bus error -- bad DMA programming!\n");
+ } else {
/* Under normal circumstances we never should get to this point,
* since both interrupts are triggered simultaneously and the 5380
* int has higher priority. When this irq is handled, that DMA
* interrupt is cleared. So a warning message is printed here.
*/
- printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" );
+ printk("SCSI DMA intr ?? -- this shouldn't happen!\n");
}
}
#endif
@@ -313,7 +310,7 @@ static void scsi_dma_buserr (int irq, void *dummy)
#endif
-static irqreturn_t scsi_tt_intr (int irq, void *dummy)
+static irqreturn_t scsi_tt_intr(int irq, void *dummy)
{
#ifdef REAL_DMA
int dma_stat;
@@ -327,7 +324,7 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy)
* is that a bus error occurred...
*/
if (dma_stat & 0x80) {
- if (!scsi_dma_is_ignored_buserr( dma_stat )) {
+ if (!scsi_dma_is_ignored_buserr(dma_stat)) {
printk(KERN_ERR "SCSI DMA caused bus error near 0x%08lx\n",
SCSI_DMA_READ_P(dma_addr));
printk(KERN_CRIT "SCSI DMA bus error -- bad DMA programming!");
@@ -344,8 +341,7 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy)
* data reg!
*/
if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
- atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P( dma_addr ) -
- atari_dma_startaddr);
+ atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr);
DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
atari_dma_residual);
@@ -353,28 +349,30 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy)
if ((signed int)atari_dma_residual < 0)
atari_dma_residual = 0;
if ((dma_stat & 1) == 0) {
- /* After read operations, we maybe have to
- transport some rest bytes */
+ /*
+ * After read operations, we maybe have to
+ * transport some rest bytes
+ */
atari_scsi_fetch_restbytes();
- }
- else {
- /* There seems to be a nasty bug in some SCSI-DMA/NCR
- combinations: If a target disconnects while a write
- operation is going on, the address register of the
- DMA may be a few bytes farer than it actually read.
- This is probably due to DMA prefetching and a delay
- between DMA and NCR. Experiments showed that the
- dma_addr is 9 bytes to high, but this could vary.
- The problem is, that the residual is thus calculated
- wrong and the next transfer will start behind where
- it should. So we round up the residual to the next
- multiple of a sector size, if it isn't already a
- multiple and the originally expected transfer size
- was. The latter condition is there to ensure that
- the correction is taken only for "real" data
- transfers and not for, e.g., the parameters of some
- other command. These shouldn't disconnect anyway.
- */
+ } else {
+ /*
+ * There seems to be a nasty bug in some SCSI-DMA/NCR
+ * combinations: If a target disconnects while a write
+ * operation is going on, the address register of the
+ * DMA may be a few bytes farer than it actually read.
+ * This is probably due to DMA prefetching and a delay
+ * between DMA and NCR. Experiments showed that the
+ * dma_addr is 9 bytes to high, but this could vary.
+ * The problem is, that the residual is thus calculated
+ * wrong and the next transfer will start behind where
+ * it should. So we round up the residual to the next
+ * multiple of a sector size, if it isn't already a
+ * multiple and the originally expected transfer size
+ * was. The latter condition is there to ensure that
+ * the correction is taken only for "real" data
+ * transfers and not for, e.g., the parameters of some
+ * other command. These shouldn't disconnect anyway.
+ */
if (atari_dma_residual & 0x1ff) {
DMA_PRINTK("SCSI DMA: DMA bug corrected, "
"difference %ld bytes\n",
@@ -394,18 +392,18 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy)
}
#endif /* REAL_DMA */
-
- NCR5380_intr (0, 0, 0);
+
+ NCR5380_intr(0, 0);
#if 0
/* To be sure the int is not masked */
- atari_enable_irq( IRQ_TT_MFP_SCSI );
+ atari_enable_irq(IRQ_TT_MFP_SCSI);
#endif
return IRQ_HANDLED;
}
-static irqreturn_t scsi_falcon_intr (int irq, void *dummy)
+static irqreturn_t scsi_falcon_intr(int irq, void *dummy)
{
#ifdef REAL_DMA
int dma_stat;
@@ -430,7 +428,7 @@ static irqreturn_t scsi_falcon_intr (int irq, void *dummy)
* bytes are stuck in the ST-DMA fifo (there's no way to reach them!)
*/
if (atari_dma_active && (dma_stat & 0x02)) {
- unsigned long transferred;
+ unsigned long transferred;
transferred = SCSI_DMA_GETADR() - atari_dma_startaddr;
/* The ST-DMA address is incremented in 2-byte steps, but the
@@ -445,8 +443,7 @@ static irqreturn_t scsi_falcon_intr (int irq, void *dummy)
atari_dma_residual = HOSTDATA_DMALEN - transferred;
DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
atari_dma_residual);
- }
- else
+ } else
atari_dma_residual = 0;
atari_dma_active = 0;
@@ -461,13 +458,13 @@ static irqreturn_t scsi_falcon_intr (int irq, void *dummy)
#endif /* REAL_DMA */
- NCR5380_intr (0, 0, 0);
+ NCR5380_intr(0, 0);
return IRQ_HANDLED;
}
#ifdef REAL_DMA
-static void atari_scsi_fetch_restbytes( void )
+static void atari_scsi_fetch_restbytes(void)
{
int nr;
char *src, *dst;
@@ -505,19 +502,17 @@ static int falcon_dont_release = 0;
* again (but others waiting longer more probably will win).
*/
-static void
-falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
+static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata)
{
unsigned long flags;
-
- if (IS_A_TT()) return;
-
+
+ if (IS_A_TT())
+ return;
+
local_irq_save(flags);
- if (falcon_got_lock &&
- !hostdata->disconnected_queue &&
- !hostdata->issue_queue &&
- !hostdata->connected) {
+ if (falcon_got_lock && !hostdata->disconnected_queue &&
+ !hostdata->issue_queue && !hostdata->connected) {
if (falcon_dont_release) {
#if 0
@@ -528,7 +523,7 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
}
falcon_got_lock = 0;
stdma_release();
- wake_up( &falcon_fairness_wait );
+ wake_up(&falcon_fairness_wait);
}
local_irq_restore(flags);
@@ -549,31 +544,31 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
* Complicated, complicated.... Sigh...
*/
-static void falcon_get_lock( void )
+static void falcon_get_lock(void)
{
unsigned long flags;
- if (IS_A_TT()) return;
+ if (IS_A_TT())
+ return;
local_irq_save(flags);
- while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() )
- sleep_on( &falcon_fairness_wait );
+ while (!in_irq() && falcon_got_lock && stdma_others_waiting())
+ sleep_on(&falcon_fairness_wait);
while (!falcon_got_lock) {
- if (in_interrupt())
- panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" );
+ if (in_irq())
+ panic("Falcon SCSI hasn't ST-DMA lock in interrupt");
if (!falcon_trying_lock) {
falcon_trying_lock = 1;
stdma_lock(scsi_falcon_intr, NULL);
falcon_got_lock = 1;
falcon_trying_lock = 0;
- wake_up( &falcon_try_wait );
- }
- else {
- sleep_on( &falcon_try_wait );
+ wake_up(&falcon_try_wait);
+ } else {
+ sleep_on(&falcon_try_wait);
}
- }
+ }
local_irq_restore(flags);
if (!falcon_got_lock)
@@ -587,18 +582,18 @@ static void falcon_get_lock( void )
*/
#if 0
-int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+int atari_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
/* falcon_get_lock();
* ++guenther: moved to NCR5380_queue_command() to prevent
* race condition, see there for an explanation.
*/
- return( NCR5380_queue_command( cmd, done ) );
+ return NCR5380_queue_command(cmd, done);
}
#endif
-int atari_scsi_detect (struct scsi_host_template *host)
+int atari_scsi_detect(struct scsi_host_template *host)
{
static int called = 0;
struct Scsi_Host *instance;
@@ -606,7 +601,7 @@ int atari_scsi_detect (struct scsi_host_template *host)
if (!MACH_IS_ATARI ||
(!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) ||
called)
- return( 0 );
+ return 0;
host->proc_name = "Atari";
@@ -655,32 +650,33 @@ int atari_scsi_detect (struct scsi_host_template *host)
!ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) {
atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI");
if (!atari_dma_buffer) {
- printk( KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "
- "double buffer\n" );
- return( 0 );
+ printk(KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "
+ "double buffer\n");
+ return 0;
}
- atari_dma_phys_buffer = virt_to_phys( atari_dma_buffer );
+ atari_dma_phys_buffer = virt_to_phys(atari_dma_buffer);
atari_dma_orig_addr = 0;
}
#endif
- instance = scsi_register (host, sizeof (struct NCR5380_hostdata));
- if(instance == NULL)
- {
+ instance = scsi_register(host, sizeof(struct NCR5380_hostdata));
+ if (instance == NULL) {
atari_stram_free(atari_dma_buffer);
atari_dma_buffer = 0;
return 0;
}
atari_scsi_host = instance;
- /* Set irq to 0, to avoid that the mid-level code disables our interrupt
- * during queue_command calls. This is completely unnecessary, and even
- * worse causes bad problems on the Falcon, where the int is shared with
- * IDE and floppy! */
+ /*
+ * Set irq to 0, to avoid that the mid-level code disables our interrupt
+ * during queue_command calls. This is completely unnecessary, and even
+ * worse causes bad problems on the Falcon, where the int is shared with
+ * IDE and floppy!
+ */
instance->irq = 0;
#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
atari_scsi_reset_boot();
#endif
- NCR5380_init (instance, 0);
+ NCR5380_init(instance, 0);
if (IS_A_TT()) {
@@ -727,11 +723,10 @@ int atari_scsi_detect (struct scsi_host_template *host)
* the rest data bug is fixed, this can be lowered to 1.
*/
atari_read_overruns = 4;
- }
+ }
#endif /*REAL_DMA*/
- }
- else { /* ! IS_A_TT */
-
+ } else { /* ! IS_A_TT */
+
/* Nothing to do for the interrupt: the ST-DMA is initialized
* already by atari_init_INTS()
*/
@@ -756,23 +751,21 @@ int atari_scsi_detect (struct scsi_host_template *host)
setup_use_tagged_queuing ? "yes" : "no",
#endif
instance->hostt->this_id );
- NCR5380_print_options (instance);
- printk ("\n");
+ NCR5380_print_options(instance);
+ printk("\n");
called = 1;
- return( 1 );
+ return 1;
}
-#ifdef MODULE
-int atari_scsi_release (struct Scsi_Host *sh)
+int atari_scsi_release(struct Scsi_Host *sh)
{
if (IS_A_TT())
free_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr);
if (atari_dma_buffer)
- atari_stram_free (atari_dma_buffer);
+ atari_stram_free(atari_dma_buffer);
return 1;
}
-#endif
void __init atari_scsi_setup(char *str, int *ints)
{
@@ -781,9 +774,9 @@ void __init atari_scsi_setup(char *str, int *ints)
* Defaults depend on TT or Falcon, hostid determined at run time.
* Negative values mean don't change.
*/
-
+
if (ints[0] < 1) {
- printk( "atari_scsi_setup: no arguments!\n" );
+ printk("atari_scsi_setup: no arguments!\n");
return;
}
@@ -809,7 +802,7 @@ void __init atari_scsi_setup(char *str, int *ints)
if (ints[4] >= 0 && ints[4] <= 7)
setup_hostid = ints[4];
else if (ints[4] > 7)
- printk( "atari_scsi_setup: invalid host ID %d !\n", ints[4] );
+ printk("atari_scsi_setup: invalid host ID %d !\n", ints[4]);
}
#ifdef SUPPORT_TAGS
if (ints[0] >= 5) {
@@ -821,7 +814,7 @@ void __init atari_scsi_setup(char *str, int *ints)
int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
{
- int rv;
+ int rv;
struct NCR5380_hostdata *hostdata =
(struct NCR5380_hostdata *)cmd->device->host->hostdata;
@@ -831,13 +824,12 @@ int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
*/
/* And abort a maybe active DMA transfer */
if (IS_A_TT()) {
- atari_turnoff_irq( IRQ_TT_MFP_SCSI );
+ atari_turnoff_irq(IRQ_TT_MFP_SCSI);
#ifdef REAL_DMA
tt_scsi_dma.dma_ctrl = 0;
#endif /* REAL_DMA */
- }
- else {
- atari_turnoff_irq( IRQ_MFP_FSCSI );
+ } else {
+ atari_turnoff_irq(IRQ_MFP_FSCSI);
#ifdef REAL_DMA
st_dma.dma_mode_status = 0x90;
atari_dma_active = 0;
@@ -849,52 +841,51 @@ int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
/* Re-enable ints */
if (IS_A_TT()) {
- atari_turnon_irq( IRQ_TT_MFP_SCSI );
- }
- else {
- atari_turnon_irq( IRQ_MFP_FSCSI );
+ atari_turnon_irq(IRQ_TT_MFP_SCSI);
+ } else {
+ atari_turnon_irq(IRQ_MFP_FSCSI);
}
if ((rv & SCSI_RESET_ACTION) == SCSI_RESET_SUCCESS)
falcon_release_lock_if_possible(hostdata);
- return( rv );
+ return rv;
}
-
+
#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
static void __init atari_scsi_reset_boot(void)
{
unsigned long end;
-
+
/*
* Do a SCSI reset to clean up the bus during initialization. No messing
* with the queues, interrupts, or locks necessary here.
*/
- printk( "Atari SCSI: resetting the SCSI bus..." );
+ printk("Atari SCSI: resetting the SCSI bus...");
/* get in phase */
- NCR5380_write( TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+ NCR5380_write(TARGET_COMMAND_REG,
+ PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
/* assert RST */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
/* The min. reset hold time is 25us, so 40us should be enough */
- udelay( 50 );
+ udelay(50);
/* reset RST and interrupt */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
- NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
end = jiffies + AFTER_RESET_DELAY;
while (time_before(jiffies, end))
barrier();
- printk( " done\n" );
+ printk(" done\n");
}
#endif
-const char * atari_scsi_info (struct Scsi_Host *host)
+const char *atari_scsi_info(struct Scsi_Host *host)
{
/* atari_scsi_detect() is verbose enough... */
static const char string[] = "Atari native SCSI";
@@ -904,10 +895,10 @@ const char * atari_scsi_info (struct Scsi_Host *host)
#if defined(REAL_DMA)
-unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
- unsigned long count, int dir )
+unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance, void *data,
+ unsigned long count, int dir)
{
- unsigned long addr = virt_to_phys( data );
+ unsigned long addr = virt_to_phys(data);
DMA_PRINTK("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, "
"dir = %d\n", instance->host_no, data, addr, count, dir);
@@ -919,38 +910,37 @@ unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
* wanted address.
*/
if (dir)
- memcpy( atari_dma_buffer, data, count );
+ memcpy(atari_dma_buffer, data, count);
else
atari_dma_orig_addr = data;
addr = atari_dma_phys_buffer;
}
-
+
atari_dma_startaddr = addr; /* Needed for calculating residual later. */
-
+
/* Cache cleanup stuff: On writes, push any dirty cache out before sending
* it to the peripheral. (Must be done before DMA setup, since at least
* the ST-DMA begins to fill internal buffers right after setup. For
* reads, invalidate any cache, may be altered after DMA without CPU
* knowledge.
- *
+ *
* ++roman: For the Medusa, there's no need at all for that cache stuff,
* because the hardware does bus snooping (fine!).
*/
- dma_cache_maintenance( addr, count, dir );
+ dma_cache_maintenance(addr, count, dir);
if (count == 0)
printk(KERN_NOTICE "SCSI warning: DMA programmed for 0 bytes !\n");
if (IS_A_TT()) {
tt_scsi_dma.dma_ctrl = dir;
- SCSI_DMA_WRITE_P( dma_addr, addr );
- SCSI_DMA_WRITE_P( dma_cnt, count );
+ SCSI_DMA_WRITE_P(dma_addr, addr);
+ SCSI_DMA_WRITE_P(dma_cnt, count);
tt_scsi_dma.dma_ctrl = dir | 2;
- }
- else { /* ! IS_A_TT */
-
+ } else { /* ! IS_A_TT */
+
/* set address */
- SCSI_DMA_SETADR( addr );
+ SCSI_DMA_SETADR(addr);
/* toggle direction bit to clear FIFO and set DMA direction */
dir <<= 8;
@@ -968,13 +958,13 @@ unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
atari_dma_active = 1;
}
- return( count );
+ return count;
}
-static long atari_scsi_dma_residual( struct Scsi_Host *instance )
+static long atari_scsi_dma_residual(struct Scsi_Host *instance)
{
- return( atari_dma_residual );
+ return atari_dma_residual;
}
@@ -982,13 +972,13 @@ static long atari_scsi_dma_residual( struct Scsi_Host *instance )
#define CMD_SURELY_BYTE_MODE 1
#define CMD_MODE_UNKNOWN 2
-static int falcon_classify_cmd( Scsi_Cmnd *cmd )
+static int falcon_classify_cmd(Scsi_Cmnd *cmd)
{
unsigned char opcode = cmd->cmnd[0];
-
+
if (opcode == READ_DEFECT_DATA || opcode == READ_LONG ||
- opcode == READ_BUFFER)
- return( CMD_SURELY_BYTE_MODE );
+ opcode == READ_BUFFER)
+ return CMD_SURELY_BYTE_MODE;
else if (opcode == READ_6 || opcode == READ_10 ||
opcode == 0xa8 /* READ_12 */ || opcode == READ_REVERSE ||
opcode == RECOVER_BUFFERED_DATA) {
@@ -996,12 +986,11 @@ static int falcon_classify_cmd( Scsi_Cmnd *cmd )
* needed here: The transfer is block-mode only if the 'fixed' bit is
* set! */
if (cmd->device->type == TYPE_TAPE && !(cmd->cmnd[1] & 1))
- return( CMD_SURELY_BYTE_MODE );
+ return CMD_SURELY_BYTE_MODE;
else
- return( CMD_SURELY_BLOCK_MODE );
- }
- else
- return( CMD_MODE_UNKNOWN );
+ return CMD_SURELY_BLOCK_MODE;
+ } else
+ return CMD_MODE_UNKNOWN;
}
@@ -1014,19 +1003,18 @@ static int falcon_classify_cmd( Scsi_Cmnd *cmd )
* the overrun problem, so this question is academic :-)
*/
-static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
- Scsi_Cmnd *cmd,
- int write_flag )
+static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
+ Scsi_Cmnd *cmd, int write_flag)
{
unsigned long possible_len, limit;
#ifndef CONFIG_TT_DMA_EMUL
if (MACH_IS_HADES)
/* Hades has no SCSI DMA at all :-( Always force use of PIO */
- return( 0 );
-#endif
+ return 0;
+#endif
if (IS_A_TT())
/* TT SCSI DMA can transfer arbitrary #bytes */
- return( wanted_len );
+ return wanted_len;
/* ST DMA chip is stupid -- only multiples of 512 bytes! (and max.
* 255*512 bytes, but this should be enough)
@@ -1062,8 +1050,7 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
* this).
*/
possible_len = wanted_len;
- }
- else {
+ } else {
/* Read operations: if the wanted transfer length is not a multiple of
* 512, we cannot use DMA, since the ST-DMA cannot split transfers
* (no interrupt on DMA finished!)
@@ -1073,15 +1060,15 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
else {
/* Now classify the command (see above) and decide whether it is
* allowed to do DMA at all */
- switch( falcon_classify_cmd( cmd )) {
- case CMD_SURELY_BLOCK_MODE:
+ switch (falcon_classify_cmd(cmd)) {
+ case CMD_SURELY_BLOCK_MODE:
possible_len = wanted_len;
break;
- case CMD_SURELY_BYTE_MODE:
+ case CMD_SURELY_BYTE_MODE:
possible_len = 0; /* DMA prohibited */
break;
- case CMD_MODE_UNKNOWN:
- default:
+ case CMD_MODE_UNKNOWN:
+ default:
/* For unknown commands assume block transfers if the transfer
* size/allocation length is >= 1024 */
possible_len = (wanted_len < 1024) ? 0 : wanted_len;
@@ -1089,9 +1076,9 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
}
}
}
-
+
/* Last step: apply the hard limit on DMA transfers */
- limit = (atari_dma_buffer && !STRAM_ADDR( virt_to_phys(cmd->SCp.ptr) )) ?
+ limit = (atari_dma_buffer && !STRAM_ADDR(virt_to_phys(cmd->SCp.ptr))) ?
STRAM_BUFFER_SIZE : 255*512;
if (possible_len > limit)
possible_len = limit;
@@ -1100,7 +1087,7 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
DMA_PRINTK("Sorry, must cut DMA transfer size to %ld bytes "
"instead of %ld\n", possible_len, wanted_len);
- return( possible_len );
+ return possible_len;
}
@@ -1114,23 +1101,23 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
* NCR5380_write call these functions via function pointers.
*/
-static unsigned char atari_scsi_tt_reg_read( unsigned char reg )
+static unsigned char atari_scsi_tt_reg_read(unsigned char reg)
{
- return( tt_scsi_regp[reg * 2] );
+ return tt_scsi_regp[reg * 2];
}
-static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value )
+static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value)
{
tt_scsi_regp[reg * 2] = value;
}
-static unsigned char atari_scsi_falcon_reg_read( unsigned char reg )
+static unsigned char atari_scsi_falcon_reg_read(unsigned char reg)
{
dma_wd.dma_mode_status= (u_short)(0x88 + reg);
- return( (u_char)dma_wd.fdc_acces_seccount );
+ return (u_char)dma_wd.fdc_acces_seccount;
}
-static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value )
+static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value)
{
dma_wd.dma_mode_status = (u_short)(0x88 + reg);
dma_wd.fdc_acces_seccount = (u_short)value;
diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h
index f917bdd09b4..efadb8d567c 100644
--- a/drivers/scsi/atari_scsi.h
+++ b/drivers/scsi/atari_scsi.h
@@ -21,11 +21,7 @@
int atari_scsi_detect (struct scsi_host_template *);
const char *atari_scsi_info (struct Scsi_Host *);
int atari_scsi_reset (Scsi_Cmnd *, unsigned int);
-#ifdef MODULE
int atari_scsi_release (struct Scsi_Host *);
-#else
-#define atari_scsi_release NULL
-#endif
/* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher
* values should work, too; try it! (but cmd_per_lun costs memory!) */
@@ -63,6 +59,32 @@ int atari_scsi_release (struct Scsi_Host *);
#define NCR5380_dma_xfer_len(i,cmd,phase) \
atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
+/* former generic SCSI error handling stuff */
+
+#define SCSI_ABORT_SNOOZE 0
+#define SCSI_ABORT_SUCCESS 1
+#define SCSI_ABORT_PENDING 2
+#define SCSI_ABORT_BUSY 3
+#define SCSI_ABORT_NOT_RUNNING 4
+#define SCSI_ABORT_ERROR 5
+
+#define SCSI_RESET_SNOOZE 0
+#define SCSI_RESET_PUNT 1
+#define SCSI_RESET_SUCCESS 2
+#define SCSI_RESET_PENDING 3
+#define SCSI_RESET_WAKEUP 4
+#define SCSI_RESET_NOT_RUNNING 5
+#define SCSI_RESET_ERROR 6
+
+#define SCSI_RESET_SYNCHRONOUS 0x01
+#define SCSI_RESET_ASYNCHRONOUS 0x02
+#define SCSI_RESET_SUGGEST_BUS_RESET 0x04
+#define SCSI_RESET_SUGGEST_HOST_RESET 0x08
+
+#define SCSI_RESET_BUS_RESET 0x100
+#define SCSI_RESET_HOST_RESET 0x200
+#define SCSI_RESET_ACTION 0xff
+
/* Debugging printk definitions:
*
* ARB -> arbitration
@@ -91,144 +113,58 @@ int atari_scsi_release (struct Scsi_Host *);
*
*/
-#if NDEBUG & NDEBUG_ARBITRATION
+#define dprint(flg, format...) \
+({ \
+ if (NDEBUG & (flg)) \
+ printk(KERN_DEBUG format); \
+})
+
#define ARB_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define ARB_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_AUTOSENSE
+ dprint(NDEBUG_ARBITRATION, format , ## args)
#define ASEN_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define ASEN_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_DMA
+ dprint(NDEBUG_AUTOSENSE, format , ## args)
#define DMA_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define DMA_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_HANDSHAKE
+ dprint(NDEBUG_DMA, format , ## args)
#define HSH_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define HSH_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_INFORMATION
+ dprint(NDEBUG_HANDSHAKE, format , ## args)
#define INF_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define INF_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_INIT
+ dprint(NDEBUG_INFORMATION, format , ## args)
#define INI_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define INI_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_INTR
+ dprint(NDEBUG_INIT, format , ## args)
#define INT_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define INT_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_LINKED
+ dprint(NDEBUG_INTR, format , ## args)
#define LNK_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define LNK_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_MAIN
+ dprint(NDEBUG_LINKED, format , ## args)
#define MAIN_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define MAIN_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_NO_DATAOUT
+ dprint(NDEBUG_MAIN, format , ## args)
#define NDAT_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define NDAT_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_NO_WRITE
+ dprint(NDEBUG_NO_DATAOUT, format , ## args)
#define NWR_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define NWR_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_PIO
+ dprint(NDEBUG_NO_WRITE, format , ## args)
#define PIO_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define PIO_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_PSEUDO_DMA
+ dprint(NDEBUG_PIO, format , ## args)
#define PDMA_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define PDMA_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_QUEUES
+ dprint(NDEBUG_PSEUDO_DMA, format , ## args)
#define QU_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define QU_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_RESELECTION
+ dprint(NDEBUG_QUEUES, format , ## args)
#define RSL_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define RSL_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_SELECTION
+ dprint(NDEBUG_RESELECTION, format , ## args)
#define SEL_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define SEL_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_USLEEP
+ dprint(NDEBUG_SELECTION, format , ## args)
#define USL_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define USL_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_LAST_BYTE_SENT
+ dprint(NDEBUG_USLEEP, format , ## args)
#define LBS_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define LBS_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_RESTART_SELECT
+ dprint(NDEBUG_LAST_BYTE_SENT, format , ## args)
#define RSS_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define RSS_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_EXTENDED
+ dprint(NDEBUG_RESTART_SELECT, format , ## args)
#define EXT_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define EXT_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_ABORT
+ dprint(NDEBUG_EXTENDED, format , ## args)
#define ABRT_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define ABRT_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_TAGS
+ dprint(NDEBUG_ABORT, format , ## args)
#define TAG_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define TAG_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_MERGING
+ dprint(NDEBUG_TAGS, format , ## args)
#define MER_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define MER_PRINTK(format, args...)
-#endif
+ dprint(NDEBUG_MERGING, format , ## args)
/* conditional macros for NCR5380_print_{,phase,status} */
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 61f6024b61b..2a458d66b6f 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -202,31 +202,29 @@ static const char * get_sa_name(const struct value_name_pair * arr,
}
/* attempt to guess cdb length if cdb_len==0 . No trailing linefeed. */
-static void print_opcode_name(unsigned char * cdbp, int cdb_len,
- int start_of_line)
+static void print_opcode_name(unsigned char * cdbp, int cdb_len)
{
int sa, len, cdb0;
const char * name;
- const char * leadin = start_of_line ? KERN_INFO : "";
cdb0 = cdbp[0];
switch(cdb0) {
case VARIABLE_LENGTH_CMD:
len = cdbp[7] + 8;
if (len < 10) {
- printk("%sshort variable length command, "
- "len=%d ext_len=%d", leadin, len, cdb_len);
+ printk("short variable length command, "
+ "len=%d ext_len=%d", len, cdb_len);
break;
}
sa = (cdbp[8] << 8) + cdbp[9];
name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
if (name) {
- printk("%s%s", leadin, name);
+ printk("%s", name);
if ((cdb_len > 0) && (len != cdb_len))
printk(", in_cdb_len=%d, ext_len=%d",
len, cdb_len);
} else {
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
if ((cdb_len > 0) && (len != cdb_len))
printk(", in_cdb_len=%d, ext_len=%d",
len, cdb_len);
@@ -236,83 +234,80 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len,
sa = cdbp[1] & 0x1f;
name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
case MAINTENANCE_OUT:
sa = cdbp[1] & 0x1f;
name = get_sa_name(maint_out_arr, MAINT_OUT_SZ, sa);
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
case SERVICE_ACTION_IN_12:
sa = cdbp[1] & 0x1f;
name = get_sa_name(serv_in12_arr, SERV_IN12_SZ, sa);
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
case SERVICE_ACTION_OUT_12:
sa = cdbp[1] & 0x1f;
name = get_sa_name(serv_out12_arr, SERV_OUT12_SZ, sa);
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
case SERVICE_ACTION_IN_16:
sa = cdbp[1] & 0x1f;
name = get_sa_name(serv_in16_arr, SERV_IN16_SZ, sa);
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
case SERVICE_ACTION_OUT_16:
sa = cdbp[1] & 0x1f;
name = get_sa_name(serv_out16_arr, SERV_OUT16_SZ, sa);
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
default:
if (cdb0 < 0xc0) {
name = cdb_byte0_names[cdb0];
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x (reserved)",
- leadin, cdb0);
+ printk("cdb[0]=0x%x (reserved)", cdb0);
} else
- printk("%scdb[0]=0x%x (vendor)", leadin, cdb0);
+ printk("cdb[0]=0x%x (vendor)", cdb0);
break;
}
}
#else /* ifndef CONFIG_SCSI_CONSTANTS */
-static void print_opcode_name(unsigned char * cdbp, int cdb_len,
- int start_of_line)
+static void print_opcode_name(unsigned char * cdbp, int cdb_len)
{
int sa, len, cdb0;
- const char * leadin = start_of_line ? KERN_INFO : "";
cdb0 = cdbp[0];
switch(cdb0) {
case VARIABLE_LENGTH_CMD:
len = cdbp[7] + 8;
if (len < 10) {
- printk("%sshort opcode=0x%x command, len=%d "
- "ext_len=%d", leadin, cdb0, len, cdb_len);
+ printk("short opcode=0x%x command, len=%d "
+ "ext_len=%d", cdb0, len, cdb_len);
break;
}
sa = (cdbp[8] << 8) + cdbp[9];
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
if (len != cdb_len)
printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len);
break;
@@ -323,49 +318,48 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len,
case SERVICE_ACTION_IN_16:
case SERVICE_ACTION_OUT_16:
sa = cdbp[1] & 0x1f;
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
default:
if (cdb0 < 0xc0)
- printk("%scdb[0]=0x%x", leadin, cdb0);
+ printk("cdb[0]=0x%x", cdb0);
else
- printk("%scdb[0]=0x%x (vendor)", leadin, cdb0);
+ printk("cdb[0]=0x%x (vendor)", cdb0);
break;
}
}
#endif
-void __scsi_print_command(unsigned char *command)
+void __scsi_print_command(unsigned char *cdb)
{
int k, len;
- print_opcode_name(command, 0, 1);
- if (VARIABLE_LENGTH_CMD == command[0])
- len = command[7] + 8;
+ print_opcode_name(cdb, 0);
+ if (VARIABLE_LENGTH_CMD == cdb[0])
+ len = cdb[7] + 8;
else
- len = COMMAND_SIZE(command[0]);
+ len = COMMAND_SIZE(cdb[0]);
/* print out all bytes in cdb */
for (k = 0; k < len; ++k)
- printk(" %02x", command[k]);
+ printk(" %02x", cdb[k]);
printk("\n");
}
EXPORT_SYMBOL(__scsi_print_command);
-/* This function (perhaps with the addition of peripheral device type)
- * is more approriate than __scsi_print_command(). Perhaps that static
- * can be dropped later if it replaces the __scsi_print_command version.
- */
-static void scsi_print_cdb(unsigned char *cdb, int cdb_len, int start_of_line)
+void scsi_print_command(struct scsi_cmnd *cmd)
{
int k;
- print_opcode_name(cdb, cdb_len, start_of_line);
+ scmd_printk(KERN_INFO, cmd, "CDB: ");
+ print_opcode_name(cmd->cmnd, cmd->cmd_len);
+
/* print out all bytes in cdb */
printk(":");
- for (k = 0; k < cdb_len; ++k)
- printk(" %02x", cdb[k]);
+ for (k = 0; k < cmd->cmd_len; ++k)
+ printk(" %02x", cmd->cmnd[k]);
printk("\n");
}
+EXPORT_SYMBOL(scsi_print_command);
/**
*
@@ -410,7 +404,11 @@ struct error_info {
const char * text;
};
-static struct error_info additional[] =
+/*
+ * The canonical list of T10 Additional Sense Codes is available at:
+ * http://www.t10.org/lists/asc-num.txt
+ */
+static const struct error_info additional[] =
{
{0x0000, "No additional sense information"},
{0x0001, "Filemark detected"},
@@ -714,6 +712,7 @@ static struct error_info additional[] =
{0x2F00, "Commands cleared by another initiator"},
{0x2F01, "Commands cleared by power loss notification"},
+ {0x2F02, "Commands cleared by device server"},
{0x3000, "Incompatible medium installed"},
{0x3001, "Cannot read medium - unknown format"},
@@ -1176,67 +1175,77 @@ scsi_extd_sense_format(unsigned char asc, unsigned char ascq) {
}
EXPORT_SYMBOL(scsi_extd_sense_format);
-/* Print extended sense information; no leadin, no linefeed */
-static void
+void
scsi_show_extd_sense(unsigned char asc, unsigned char ascq)
{
- const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq);
+ const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq);
if (extd_sense_fmt) {
if (strstr(extd_sense_fmt, "%x")) {
- printk("Additional sense: ");
+ printk("Add. Sense: ");
printk(extd_sense_fmt, ascq);
} else
- printk("Additional sense: %s", extd_sense_fmt);
+ printk("Add. Sense: %s", extd_sense_fmt);
} else {
if (asc >= 0x80)
- printk("<<vendor>> ASC=0x%x ASCQ=0x%x", asc, ascq);
+ printk("<<vendor>> ASC=0x%x ASCQ=0x%x", asc,
+ ascq);
if (ascq >= 0x80)
- printk("ASC=0x%x <<vendor>> ASCQ=0x%x", asc, ascq);
+ printk("ASC=0x%x <<vendor>> ASCQ=0x%x", asc,
+ ascq);
else
printk("ASC=0x%x ASCQ=0x%x", asc, ascq);
}
+
+ printk("\n");
}
+EXPORT_SYMBOL(scsi_show_extd_sense);
void
-scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr)
+scsi_show_sense_hdr(struct scsi_sense_hdr *sshdr)
{
const char *sense_txt;
- /* An example of deferred is when an earlier write to disk cache
- * succeeded, but now the disk discovers that it cannot write the
- * data to the magnetic media.
- */
- const char *error = scsi_sense_is_deferred(sshdr) ?
- "<<DEFERRED>>" : "Current";
- printk(KERN_INFO "%s: %s", name, error);
- if (sshdr->response_code >= 0x72)
- printk(" [descriptor]");
sense_txt = scsi_sense_key_string(sshdr->sense_key);
if (sense_txt)
- printk(": sense key: %s\n", sense_txt);
+ printk("Sense Key : %s ", sense_txt);
else
- printk(": sense key=0x%x\n", sshdr->sense_key);
- printk(KERN_INFO " ");
- scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+ printk("Sense Key : 0x%x ", sshdr->sense_key);
+
+ printk("%s", scsi_sense_is_deferred(sshdr) ? "[deferred] " :
+ "[current] ");
+
+ if (sshdr->response_code >= 0x72)
+ printk("[descriptor]");
+
printk("\n");
}
+EXPORT_SYMBOL(scsi_show_sense_hdr);
+
+/*
+ * Print normalized SCSI sense header with a prefix.
+ */
+void
+scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr)
+{
+ printk(KERN_INFO "%s: ", name);
+ scsi_show_sense_hdr(sshdr);
+ printk(KERN_INFO "%s: ", name);
+ scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+}
EXPORT_SYMBOL(scsi_print_sense_hdr);
-/* Print sense information */
void
-__scsi_print_sense(const char *name, const unsigned char *sense_buffer,
- int sense_len)
+scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
+ struct scsi_sense_hdr *sshdr)
{
int k, num, res;
- unsigned int info;
- struct scsi_sense_hdr ssh;
- res = scsi_normalize_sense(sense_buffer, sense_len, &ssh);
+ res = scsi_normalize_sense(sense_buffer, sense_len, sshdr);
if (0 == res) {
/* this may be SCSI-1 sense data */
num = (sense_len < 32) ? sense_len : 32;
- printk(KERN_INFO "Unrecognized sense data (in hex):");
+ printk("Unrecognized sense data (in hex):");
for (k = 0; k < num; ++k) {
if (0 == (k % 16)) {
printk("\n");
@@ -1247,11 +1256,20 @@ __scsi_print_sense(const char *name, const unsigned char *sense_buffer,
printk("\n");
return;
}
- scsi_print_sense_hdr(name, &ssh);
- if (ssh.response_code < 0x72) {
+}
+
+void
+scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len,
+ struct scsi_sense_hdr *sshdr)
+{
+ int k, num, res;
+
+ if (sshdr->response_code < 0x72)
+ {
/* only decode extras for "fixed" format now */
char buff[80];
int blen, fixed_valid;
+ unsigned int info;
fixed_valid = sense_buffer[0] & 0x80;
info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) |
@@ -1281,13 +1299,13 @@ __scsi_print_sense(const char *name, const unsigned char *sense_buffer,
res += snprintf(buff + res, blen - res, "ILI");
}
if (res > 0)
- printk(KERN_INFO "%s\n", buff);
- } else if (ssh.additional_length > 0) {
+ printk("%s\n", buff);
+ } else if (sshdr->additional_length > 0) {
/* descriptor format with sense descriptors */
- num = 8 + ssh.additional_length;
+ num = 8 + sshdr->additional_length;
num = (sense_len < num) ? sense_len : num;
- printk(KERN_INFO "Descriptor sense data with sense "
- "descriptors (in hex):");
+ printk("Descriptor sense data with sense descriptors "
+ "(in hex):");
for (k = 0; k < num; ++k) {
if (0 == (k % 16)) {
printk("\n");
@@ -1295,29 +1313,42 @@ __scsi_print_sense(const char *name, const unsigned char *sense_buffer,
}
printk("%02x ", sense_buffer[k]);
}
+
printk("\n");
}
+
}
-EXPORT_SYMBOL(__scsi_print_sense);
-void scsi_print_sense(const char *devclass, struct scsi_cmnd *cmd)
+/* Normalize and print sense buffer with name prefix */
+void __scsi_print_sense(const char *name, const unsigned char *sense_buffer,
+ int sense_len)
{
- const char *name = devclass;
-
- if (cmd->request->rq_disk)
- name = cmd->request->rq_disk->disk_name;
- __scsi_print_sense(name, cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+ struct scsi_sense_hdr sshdr;
+
+ printk(KERN_INFO "%s: ", name);
+ scsi_decode_sense_buffer(sense_buffer, sense_len, &sshdr);
+ scsi_show_sense_hdr(&sshdr);
+ scsi_decode_sense_extras(sense_buffer, sense_len, &sshdr);
+ printk(KERN_INFO "%s: ", name);
+ scsi_show_extd_sense(sshdr.asc, sshdr.ascq);
}
-EXPORT_SYMBOL(scsi_print_sense);
+EXPORT_SYMBOL(__scsi_print_sense);
-void scsi_print_command(struct scsi_cmnd *cmd)
+/* Normalize and print sense buffer in SCSI command */
+void scsi_print_sense(char *name, struct scsi_cmnd *cmd)
{
- /* Assume appended output (i.e. not at start of line) */
- sdev_printk("", cmd->device, "\n");
- printk(KERN_INFO " command: ");
- scsi_print_cdb(cmd->cmnd, cmd->cmd_len, 0);
+ struct scsi_sense_hdr sshdr;
+
+ scmd_printk(KERN_INFO, cmd, "");
+ scsi_decode_sense_buffer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+ &sshdr);
+ scsi_show_sense_hdr(&sshdr);
+ scsi_decode_sense_extras(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+ &sshdr);
+ scmd_printk(KERN_INFO, cmd, "");
+ scsi_show_extd_sense(sshdr.asc, sshdr.ascq);
}
-EXPORT_SYMBOL(scsi_print_command);
+EXPORT_SYMBOL(scsi_print_sense);
#ifdef CONFIG_SCSI_CONSTANTS
@@ -1327,25 +1358,6 @@ static const char * const hostbyte_table[]={
"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY"};
#define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table)
-void scsi_print_hostbyte(int scsiresult)
-{
- int hb = host_byte(scsiresult);
-
- printk("Hostbyte=0x%02x", hb);
- if (hb < NUM_HOSTBYTE_STRS)
- printk("(%s) ", hostbyte_table[hb]);
- else
- printk("is invalid ");
-}
-#else
-void scsi_print_hostbyte(int scsiresult)
-{
- printk("Hostbyte=0x%02x ", host_byte(scsiresult));
-}
-#endif
-
-#ifdef CONFIG_SCSI_CONSTANTS
-
static const char * const driverbyte_table[]={
"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR",
"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"};
@@ -1356,19 +1368,35 @@ static const char * const driversuggest_table[]={"SUGGEST_OK",
"SUGGEST_5", "SUGGEST_6", "SUGGEST_7", "SUGGEST_SENSE"};
#define NUM_SUGGEST_STRS ARRAY_SIZE(driversuggest_table)
-void scsi_print_driverbyte(int scsiresult)
+void scsi_show_result(int result)
{
- int dr = (driver_byte(scsiresult) & DRIVER_MASK);
- int su = ((driver_byte(scsiresult) & SUGGEST_MASK) >> 4);
+ int hb = host_byte(result);
+ int db = (driver_byte(result) & DRIVER_MASK);
+ int su = ((driver_byte(result) & SUGGEST_MASK) >> 4);
- printk("Driverbyte=0x%02x ", driver_byte(scsiresult));
- printk("(%s,%s) ",
- (dr < NUM_DRIVERBYTE_STRS ? driverbyte_table[dr] : "invalid"),
+ printk("Result: hostbyte=%s driverbyte=%s,%s\n",
+ (hb < NUM_HOSTBYTE_STRS ? hostbyte_table[hb] : "invalid"),
+ (db < NUM_DRIVERBYTE_STRS ? driverbyte_table[db] : "invalid"),
(su < NUM_SUGGEST_STRS ? driversuggest_table[su] : "invalid"));
}
+
#else
-void scsi_print_driverbyte(int scsiresult)
+
+void scsi_show_result(int result)
{
- printk("Driverbyte=0x%02x ", driver_byte(scsiresult));
+ printk("Result: hostbyte=0x%02x driverbyte=0x%02x\n",
+ host_byte(result), driver_byte(result));
}
+
#endif
+EXPORT_SYMBOL(scsi_show_result);
+
+
+void scsi_print_result(struct scsi_cmnd *cmd)
+{
+ scmd_printk(KERN_INFO, cmd, "");
+ scsi_show_result(cmd->result);
+}
+EXPORT_SYMBOL(scsi_print_result);
+
+
diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h
index 5a49216fe4c..100b49baca7 100644
--- a/drivers/scsi/dpt/dpti_i2o.h
+++ b/drivers/scsi/dpt/dpti_i2o.h
@@ -31,7 +31,7 @@
* Tunable parameters first
*/
-/* How many different OSM's are we allowing */
+/* How many different OSM's are we allowing */
#define MAX_I2O_MODULES 64
#define I2O_EVT_CAPABILITY_OTHER 0x01
@@ -63,7 +63,7 @@ struct i2o_message
u16 size;
u32 target_tid:12;
u32 init_tid:12;
- u32 function:8;
+ u32 function:8;
u32 initiator_context;
/* List follows */
};
@@ -77,7 +77,7 @@ struct i2o_device
char dev_name[8]; /* linux /dev name if available */
i2o_lct_entry lct_data;/* Device LCT information */
- u32 flags;
+ u32 flags;
struct proc_dir_entry* proc_entry; /* /proc dir */
struct adpt_device *owner;
struct _adpt_hba *controller; /* Controlling IOP */
@@ -86,7 +86,7 @@ struct i2o_device
/*
* Each I2O controller has one of these objects
*/
-
+
struct i2o_controller
{
char name[16];
@@ -111,9 +111,9 @@ struct i2o_sys_tbl_entry
u32 iop_id:12;
u32 reserved2:20;
u16 seg_num:12;
- u16 i2o_version:4;
- u8 iop_state;
- u8 msg_type;
+ u16 i2o_version:4;
+ u8 iop_state;
+ u8 msg_type;
u16 frame_size;
u16 reserved3;
u32 last_changed;
@@ -124,14 +124,14 @@ struct i2o_sys_tbl_entry
struct i2o_sys_tbl
{
- u8 num_entries;
- u8 version;
- u16 reserved1;
+ u8 num_entries;
+ u8 version;
+ u16 reserved1;
u32 change_ind;
u32 reserved2;
u32 reserved3;
struct i2o_sys_tbl_entry iops[0];
-};
+};
/*
* I2O classes / subclasses
@@ -146,7 +146,7 @@ struct i2o_sys_tbl
/* Class code names
* (from v1.5 Table 6-1 Class Code Assignments.)
*/
-
+
#define I2O_CLASS_EXECUTIVE 0x000
#define I2O_CLASS_DDM 0x001
#define I2O_CLASS_RANDOM_BLOCK_STORAGE 0x010
@@ -166,7 +166,7 @@ struct i2o_sys_tbl
/* Rest of 0x092 - 0x09f reserved for peer-to-peer classes
*/
-
+
#define I2O_CLASS_MATCH_ANYCLASS 0xffffffff
/* Subclasses
@@ -175,7 +175,7 @@ struct i2o_sys_tbl
#define I2O_SUBCLASS_i960 0x001
#define I2O_SUBCLASS_HDM 0x020
#define I2O_SUBCLASS_ISM 0x021
-
+
/* Operation functions */
#define I2O_PARAMS_FIELD_GET 0x0001
@@ -219,7 +219,7 @@ struct i2o_sys_tbl
/*
* Messaging API values
*/
-
+
#define I2O_CMD_ADAPTER_ASSIGN 0xB3
#define I2O_CMD_ADAPTER_READ 0xB2
#define I2O_CMD_ADAPTER_RELEASE 0xB5
@@ -284,16 +284,16 @@ struct i2o_sys_tbl
#define I2O_PRIVATE_MSG 0xFF
/*
- * Init Outbound Q status
+ * Init Outbound Q status
*/
-
+
#define I2O_CMD_OUTBOUND_INIT_IN_PROGRESS 0x01
#define I2O_CMD_OUTBOUND_INIT_REJECTED 0x02
#define I2O_CMD_OUTBOUND_INIT_FAILED 0x03
#define I2O_CMD_OUTBOUND_INIT_COMPLETE 0x04
/*
- * I2O Get Status State values
+ * I2O Get Status State values
*/
#define ADAPTER_STATE_INITIALIZING 0x01
@@ -303,7 +303,7 @@ struct i2o_sys_tbl
#define ADAPTER_STATE_OPERATIONAL 0x08
#define ADAPTER_STATE_FAILED 0x10
#define ADAPTER_STATE_FAULTED 0x11
-
+
/* I2O API function return values */
#define I2O_RTN_NO_ERROR 0
@@ -321,9 +321,9 @@ struct i2o_sys_tbl
/* Reply message status defines for all messages */
-#define I2O_REPLY_STATUS_SUCCESS 0x00
-#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01
-#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
+#define I2O_REPLY_STATUS_SUCCESS 0x00
+#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01
+#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
#define I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03
#define I2O_REPLY_STATUS_ERROR_DIRTY 0x04
#define I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05
@@ -338,7 +338,7 @@ struct i2o_sys_tbl
#define I2O_PARAMS_STATUS_SUCCESS 0x00
#define I2O_PARAMS_STATUS_BAD_KEY_ABORT 0x01
-#define I2O_PARAMS_STATUS_BAD_KEY_CONTINUE 0x02
+#define I2O_PARAMS_STATUS_BAD_KEY_CONTINUE 0x02
#define I2O_PARAMS_STATUS_BUFFER_FULL 0x03
#define I2O_PARAMS_STATUS_BUFFER_TOO_SMALL 0x04
#define I2O_PARAMS_STATUS_FIELD_UNREADABLE 0x05
@@ -390,7 +390,7 @@ struct i2o_sys_tbl
#define I2O_CLAIM_MANAGEMENT 0x02000000
#define I2O_CLAIM_AUTHORIZED 0x03000000
#define I2O_CLAIM_SECONDARY 0x04000000
-
+
/* Message header defines for VersionOffset */
#define I2OVER15 0x0001
#define I2OVER20 0x0002
diff --git a/drivers/scsi/dpt/dpti_ioctl.h b/drivers/scsi/dpt/dpti_ioctl.h
index 82d24864be0..cc784e8f6e9 100644
--- a/drivers/scsi/dpt/dpti_ioctl.h
+++ b/drivers/scsi/dpt/dpti_ioctl.h
@@ -99,7 +99,7 @@ typedef struct {
uCHAR eataVersion; /* EATA Version */
uLONG cpLength; /* EATA Command Packet Length */
uLONG spLength; /* EATA Status Packet Length */
- uCHAR drqNum; /* DRQ Index (0,5,6,7) */
+ uCHAR drqNum; /* DRQ Index (0,5,6,7) */
uCHAR flag1; /* EATA Flags 1 (Byte 9) */
uCHAR flag2; /* EATA Flags 2 (Byte 30) */
} CtrlInfo;
diff --git a/drivers/scsi/dpt/dptsig.h b/drivers/scsi/dpt/dptsig.h
index 4bf44779212..94bc894d120 100644
--- a/drivers/scsi/dpt/dptsig.h
+++ b/drivers/scsi/dpt/dptsig.h
@@ -145,8 +145,8 @@ typedef unsigned long sigLONG;
#define FT_LOGGER 12 /* Event Logger */
#define FT_INSTALL 13 /* An Install Program */
#define FT_LIBRARY 14 /* Storage Manager Real-Mode Calls */
-#define FT_RESOURCE 15 /* Storage Manager Resource File */
-#define FT_MODEM_DB 16 /* Storage Manager Modem Database */
+#define FT_RESOURCE 15 /* Storage Manager Resource File */
+#define FT_MODEM_DB 16 /* Storage Manager Modem Database */
/* Filetype flags - sigBYTE dsFiletypeFlags; FLAG BITS */
/* ------------------------------------------------------------------ */
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index cd36e81b2d9..f7b9dbd64a9 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -195,8 +195,6 @@ static int adpt_detect(struct scsi_host_template* sht)
pci_dev_get(pDev);
}
}
- if (pDev)
- pci_dev_put(pDev);
/* In INIT state, Activate IOPs */
for (pHba = hba_chain; pHba; pHba = pHba->next) {
diff --git a/drivers/scsi/eata_generic.h b/drivers/scsi/eata_generic.h
index 635c14861f8..5016af5cf86 100644
--- a/drivers/scsi/eata_generic.h
+++ b/drivers/scsi/eata_generic.h
@@ -18,13 +18,6 @@
* Misc. definitions *
*********************************************/
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
#define R_LIMIT 0x20000
#define MAXISA 4
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
deleted file mode 100644
index 2c2fe80bc42..00000000000
--- a/drivers/scsi/esp.c
+++ /dev/null
@@ -1,4394 +0,0 @@
-/* esp.c: ESP Sun SCSI driver.
- *
- * Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net)
- */
-
-/* TODO:
- *
- * 1) Maybe disable parity checking in config register one for SCSI1
- * targets. (Gilmore says parity error on the SBus can lock up
- * old sun4c's)
- * 2) Add support for DMA2 pipelining.
- * 3) Add tagged queueing.
- */
-
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-
-#include "esp.h"
-
-#include <asm/sbus.h>
-#include <asm/dma.h>
-#include <asm/system.h>
-#include <asm/ptrace.h>
-#include <asm/pgtable.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#ifndef __sparc_v9__
-#include <asm/machines.h>
-#include <asm/idprom.h>
-#endif
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_eh.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_tcq.h>
-
-#define DRV_VERSION "1.101"
-
-#define DEBUG_ESP
-/* #define DEBUG_ESP_HME */
-/* #define DEBUG_ESP_DATA */
-/* #define DEBUG_ESP_QUEUE */
-/* #define DEBUG_ESP_DISCONNECT */
-/* #define DEBUG_ESP_STATUS */
-/* #define DEBUG_ESP_PHASES */
-/* #define DEBUG_ESP_WORKBUS */
-/* #define DEBUG_STATE_MACHINE */
-/* #define DEBUG_ESP_CMDS */
-/* #define DEBUG_ESP_IRQS */
-/* #define DEBUG_SDTR */
-/* #define DEBUG_ESP_SG */
-
-/* Use the following to sprinkle debugging messages in a way which
- * suits you if combinations of the above become too verbose when
- * trying to track down a specific problem.
- */
-/* #define DEBUG_ESP_MISC */
-
-#if defined(DEBUG_ESP)
-#define ESPLOG(foo) printk foo
-#else
-#define ESPLOG(foo)
-#endif /* (DEBUG_ESP) */
-
-#if defined(DEBUG_ESP_HME)
-#define ESPHME(foo) printk foo
-#else
-#define ESPHME(foo)
-#endif
-
-#if defined(DEBUG_ESP_DATA)
-#define ESPDATA(foo) printk foo
-#else
-#define ESPDATA(foo)
-#endif
-
-#if defined(DEBUG_ESP_QUEUE)
-#define ESPQUEUE(foo) printk foo
-#else
-#define ESPQUEUE(foo)
-#endif
-
-#if defined(DEBUG_ESP_DISCONNECT)
-#define ESPDISC(foo) printk foo
-#else
-#define ESPDISC(foo)
-#endif
-
-#if defined(DEBUG_ESP_STATUS)
-#define ESPSTAT(foo) printk foo
-#else
-#define ESPSTAT(foo)
-#endif
-
-#if defined(DEBUG_ESP_PHASES)
-#define ESPPHASE(foo) printk foo
-#else
-#define ESPPHASE(foo)
-#endif
-
-#if defined(DEBUG_ESP_WORKBUS)
-#define ESPBUS(foo) printk foo
-#else
-#define ESPBUS(foo)
-#endif
-
-#if defined(DEBUG_ESP_IRQS)
-#define ESPIRQ(foo) printk foo
-#else
-#define ESPIRQ(foo)
-#endif
-
-#if defined(DEBUG_SDTR)
-#define ESPSDTR(foo) printk foo
-#else
-#define ESPSDTR(foo)
-#endif
-
-#if defined(DEBUG_ESP_MISC)
-#define ESPMISC(foo) printk foo
-#else
-#define ESPMISC(foo)
-#endif
-
-/* Command phase enumeration. */
-enum {
- not_issued = 0x00, /* Still in the issue_SC queue. */
-
- /* Various forms of selecting a target. */
-#define in_slct_mask 0x10
- in_slct_norm = 0x10, /* ESP is arbitrating, normal selection */
- in_slct_stop = 0x11, /* ESP will select, then stop with IRQ */
- in_slct_msg = 0x12, /* select, then send a message */
- in_slct_tag = 0x13, /* select and send tagged queue msg */
- in_slct_sneg = 0x14, /* select and acquire sync capabilities */
-
- /* Any post selection activity. */
-#define in_phases_mask 0x20
- in_datain = 0x20, /* Data is transferring from the bus */
- in_dataout = 0x21, /* Data is transferring to the bus */
- in_data_done = 0x22, /* Last DMA data operation done (maybe) */
- in_msgin = 0x23, /* Eating message from target */
- in_msgincont = 0x24, /* Eating more msg bytes from target */
- in_msgindone = 0x25, /* Decide what to do with what we got */
- in_msgout = 0x26, /* Sending message to target */
- in_msgoutdone = 0x27, /* Done sending msg out */
- in_cmdbegin = 0x28, /* Sending cmd after abnormal selection */
- in_cmdend = 0x29, /* Done sending slow cmd */
- in_status = 0x2a, /* Was in status phase, finishing cmd */
- in_freeing = 0x2b, /* freeing the bus for cmd cmplt or disc */
- in_the_dark = 0x2c, /* Don't know what bus phase we are in */
-
- /* Special states, ie. not normal bus transitions... */
-#define in_spec_mask 0x80
- in_abortone = 0x80, /* Aborting one command currently */
- in_abortall = 0x81, /* Blowing away all commands we have */
- in_resetdev = 0x82, /* SCSI target reset in progress */
- in_resetbus = 0x83, /* SCSI bus reset in progress */
- in_tgterror = 0x84, /* Target did something stupid */
-};
-
-enum {
- /* Zero has special meaning, see skipahead[12]. */
-/*0*/ do_never,
-
-/*1*/ do_phase_determine,
-/*2*/ do_reset_bus,
-/*3*/ do_reset_complete,
-/*4*/ do_work_bus,
-/*5*/ do_intr_end
-};
-
-/* Forward declarations. */
-static irqreturn_t esp_intr(int irq, void *dev_id);
-
-/* Debugging routines */
-struct esp_cmdstrings {
- u8 cmdchar;
- char *text;
-} esp_cmd_strings[] = {
- /* Miscellaneous */
- { ESP_CMD_NULL, "ESP_NOP", },
- { ESP_CMD_FLUSH, "FIFO_FLUSH", },
- { ESP_CMD_RC, "RSTESP", },
- { ESP_CMD_RS, "RSTSCSI", },
- /* Disconnected State Group */
- { ESP_CMD_RSEL, "RESLCTSEQ", },
- { ESP_CMD_SEL, "SLCTNATN", },
- { ESP_CMD_SELA, "SLCTATN", },
- { ESP_CMD_SELAS, "SLCTATNSTOP", },
- { ESP_CMD_ESEL, "ENSLCTRESEL", },
- { ESP_CMD_DSEL, "DISSELRESEL", },
- { ESP_CMD_SA3, "SLCTATN3", },
- { ESP_CMD_RSEL3, "RESLCTSEQ", },
- /* Target State Group */
- { ESP_CMD_SMSG, "SNDMSG", },
- { ESP_CMD_SSTAT, "SNDSTATUS", },
- { ESP_CMD_SDATA, "SNDDATA", },
- { ESP_CMD_DSEQ, "DISCSEQ", },
- { ESP_CMD_TSEQ, "TERMSEQ", },
- { ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", },
- { ESP_CMD_DCNCT, "DISC", },
- { ESP_CMD_RMSG, "RCVMSG", },
- { ESP_CMD_RCMD, "RCVCMD", },
- { ESP_CMD_RDATA, "RCVDATA", },
- { ESP_CMD_RCSEQ, "RCVCMDSEQ", },
- /* Initiator State Group */
- { ESP_CMD_TI, "TRANSINFO", },
- { ESP_CMD_ICCSEQ, "INICMDSEQCOMP", },
- { ESP_CMD_MOK, "MSGACCEPTED", },
- { ESP_CMD_TPAD, "TPAD", },
- { ESP_CMD_SATN, "SATN", },
- { ESP_CMD_RATN, "RATN", },
-};
-#define NUM_ESP_COMMANDS ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings)))
-
-/* Print textual representation of an ESP command */
-static inline void esp_print_cmd(u8 espcmd)
-{
- u8 dma_bit = espcmd & ESP_CMD_DMA;
- int i;
-
- espcmd &= ~dma_bit;
- for (i = 0; i < NUM_ESP_COMMANDS; i++)
- if (esp_cmd_strings[i].cmdchar == espcmd)
- break;
- if (i == NUM_ESP_COMMANDS)
- printk("ESP_Unknown");
- else
- printk("%s%s", esp_cmd_strings[i].text,
- ((dma_bit) ? "+DMA" : ""));
-}
-
-/* Print the status register's value */
-static inline void esp_print_statreg(u8 statreg)
-{
- u8 phase;
-
- printk("STATUS<");
- phase = statreg & ESP_STAT_PMASK;
- printk("%s,", (phase == ESP_DOP ? "DATA-OUT" :
- (phase == ESP_DIP ? "DATA-IN" :
- (phase == ESP_CMDP ? "COMMAND" :
- (phase == ESP_STATP ? "STATUS" :
- (phase == ESP_MOP ? "MSG-OUT" :
- (phase == ESP_MIP ? "MSG_IN" :
- "unknown")))))));
- if (statreg & ESP_STAT_TDONE)
- printk("TRANS_DONE,");
- if (statreg & ESP_STAT_TCNT)
- printk("TCOUNT_ZERO,");
- if (statreg & ESP_STAT_PERR)
- printk("P_ERROR,");
- if (statreg & ESP_STAT_SPAM)
- printk("SPAM,");
- if (statreg & ESP_STAT_INTR)
- printk("IRQ,");
- printk(">");
-}
-
-/* Print the interrupt register's value */
-static inline void esp_print_ireg(u8 intreg)
-{
- printk("INTREG< ");
- if (intreg & ESP_INTR_S)
- printk("SLCT_NATN ");
- if (intreg & ESP_INTR_SATN)
- printk("SLCT_ATN ");
- if (intreg & ESP_INTR_RSEL)
- printk("RSLCT ");
- if (intreg & ESP_INTR_FDONE)
- printk("FDONE ");
- if (intreg & ESP_INTR_BSERV)
- printk("BSERV ");
- if (intreg & ESP_INTR_DC)
- printk("DISCNCT ");
- if (intreg & ESP_INTR_IC)
- printk("ILL_CMD ");
- if (intreg & ESP_INTR_SR)
- printk("SCSI_BUS_RESET ");
- printk(">");
-}
-
-/* Print the sequence step registers contents */
-static inline void esp_print_seqreg(u8 stepreg)
-{
- stepreg &= ESP_STEP_VBITS;
- printk("STEP<%s>",
- (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" :
- (stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" :
- (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" :
- (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" :
- (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" :
- "UNKNOWN"))))));
-}
-
-static char *phase_string(int phase)
-{
- switch (phase) {
- case not_issued:
- return "UNISSUED";
- case in_slct_norm:
- return "SLCTNORM";
- case in_slct_stop:
- return "SLCTSTOP";
- case in_slct_msg:
- return "SLCTMSG";
- case in_slct_tag:
- return "SLCTTAG";
- case in_slct_sneg:
- return "SLCTSNEG";
- case in_datain:
- return "DATAIN";
- case in_dataout:
- return "DATAOUT";
- case in_data_done:
- return "DATADONE";
- case in_msgin:
- return "MSGIN";
- case in_msgincont:
- return "MSGINCONT";
- case in_msgindone:
- return "MSGINDONE";
- case in_msgout:
- return "MSGOUT";
- case in_msgoutdone:
- return "MSGOUTDONE";
- case in_cmdbegin:
- return "CMDBEGIN";
- case in_cmdend:
- return "CMDEND";
- case in_status:
- return "STATUS";
- case in_freeing:
- return "FREEING";
- case in_the_dark:
- return "CLUELESS";
- case in_abortone:
- return "ABORTONE";
- case in_abortall:
- return "ABORTALL";
- case in_resetdev:
- return "RESETDEV";
- case in_resetbus:
- return "RESETBUS";
- case in_tgterror:
- return "TGTERROR";
- default:
- return "UNKNOWN";
- };
-}
-
-#ifdef DEBUG_STATE_MACHINE
-static inline void esp_advance_phase(struct scsi_cmnd *s, int newphase)
-{
- ESPLOG(("<%s>", phase_string(newphase)));
- s->SCp.sent_command = s->SCp.phase;
- s->SCp.phase = newphase;
-}
-#else
-#define esp_advance_phase(__s, __newphase) \
- (__s)->SCp.sent_command = (__s)->SCp.phase; \
- (__s)->SCp.phase = (__newphase);
-#endif
-
-#ifdef DEBUG_ESP_CMDS
-static inline void esp_cmd(struct esp *esp, u8 cmd)
-{
- esp->espcmdlog[esp->espcmdent] = cmd;
- esp->espcmdent = (esp->espcmdent + 1) & 31;
- sbus_writeb(cmd, esp->eregs + ESP_CMD);
-}
-#else
-#define esp_cmd(__esp, __cmd) \
- sbus_writeb((__cmd), ((__esp)->eregs) + ESP_CMD)
-#endif
-
-#define ESP_INTSOFF(__dregs) \
- sbus_writel(sbus_readl((__dregs)+DMA_CSR)&~(DMA_INT_ENAB), (__dregs)+DMA_CSR)
-#define ESP_INTSON(__dregs) \
- sbus_writel(sbus_readl((__dregs)+DMA_CSR)|DMA_INT_ENAB, (__dregs)+DMA_CSR)
-#define ESP_IRQ_P(__dregs) \
- (sbus_readl((__dregs)+DMA_CSR) & (DMA_HNDL_INTR|DMA_HNDL_ERROR))
-
-/* How we use the various Linux SCSI data structures for operation.
- *
- * struct scsi_cmnd:
- *
- * We keep track of the synchronous capabilities of a target
- * in the device member, using sync_min_period and
- * sync_max_offset. These are the values we directly write
- * into the ESP registers while running a command. If offset
- * is zero the ESP will use asynchronous transfers.
- * If the borken flag is set we assume we shouldn't even bother
- * trying to negotiate for synchronous transfer as this target
- * is really stupid. If we notice the target is dropping the
- * bus, and we have been allowing it to disconnect, we clear
- * the disconnect flag.
- */
-
-
-/* Manipulation of the ESP command queues. Thanks to the aha152x driver
- * and its author, Juergen E. Fischer, for the methods used here.
- * Note that these are per-ESP queues, not global queues like
- * the aha152x driver uses.
- */
-static inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
-{
- struct scsi_cmnd *end;
-
- new_SC->host_scribble = (unsigned char *) NULL;
- if (!*SC)
- *SC = new_SC;
- else {
- for (end=*SC;end->host_scribble;end=(struct scsi_cmnd *)end->host_scribble)
- ;
- end->host_scribble = (unsigned char *) new_SC;
- }
-}
-
-static inline void prepend_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
-{
- new_SC->host_scribble = (unsigned char *) *SC;
- *SC = new_SC;
-}
-
-static inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd **SC)
-{
- struct scsi_cmnd *ptr;
- ptr = *SC;
- if (ptr)
- *SC = (struct scsi_cmnd *) (*SC)->host_scribble;
- return ptr;
-}
-
-static inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC, int target, int lun)
-{
- struct scsi_cmnd *ptr, *prev;
-
- for (ptr = *SC, prev = NULL;
- ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
- prev = ptr, ptr = (struct scsi_cmnd *) ptr->host_scribble)
- ;
- if (ptr) {
- if (prev)
- prev->host_scribble=ptr->host_scribble;
- else
- *SC=(struct scsi_cmnd *)ptr->host_scribble;
- }
- return ptr;
-}
-
-/* Resetting various pieces of the ESP scsi driver chipset/buses. */
-static void esp_reset_dma(struct esp *esp)
-{
- int can_do_burst16, can_do_burst32, can_do_burst64;
- int can_do_sbus64;
- u32 tmp;
-
- can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
- can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;
- can_do_burst64 = 0;
- can_do_sbus64 = 0;
- if (sbus_can_dma_64bit(esp->sdev))
- can_do_sbus64 = 1;
- if (sbus_can_burst64(esp->sdev))
- can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;
-
- /* Punt the DVMA into a known state. */
- if (esp->dma->revision != dvmahme) {
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- sbus_writel(tmp | DMA_RST_SCSI, esp->dregs + DMA_CSR);
- sbus_writel(tmp & ~DMA_RST_SCSI, esp->dregs + DMA_CSR);
- }
- switch (esp->dma->revision) {
- case dvmahme:
- /* This is the HME DVMA gate array. */
-
- sbus_writel(DMA_RESET_FAS366, esp->dregs + DMA_CSR);
- sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR);
-
- esp->prev_hme_dmacsr = (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB);
- esp->prev_hme_dmacsr &= ~(DMA_ENABLE|DMA_ST_WRITE|DMA_BRST_SZ);
-
- if (can_do_burst64)
- esp->prev_hme_dmacsr |= DMA_BRST64;
- else if (can_do_burst32)
- esp->prev_hme_dmacsr |= DMA_BRST32;
-
- if (can_do_sbus64) {
- esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
- sbus_set_sbus64(esp->sdev, esp->bursts);
- }
-
- /* This chip is horrible. */
- while (sbus_readl(esp->dregs + DMA_CSR) & DMA_PEND_READ)
- udelay(1);
-
- sbus_writel(0, esp->dregs + DMA_CSR);
- sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
-
- /* This is necessary to avoid having the SCSI channel
- * engine lock up on us.
- */
- sbus_writel(0, esp->dregs + DMA_ADDR);
-
- break;
- case dvmarev2:
- /* This is the gate array found in the sun4m
- * NCR SBUS I/O subsystem.
- */
- if (esp->erev != esp100) {
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- sbus_writel(tmp | DMA_3CLKS, esp->dregs + DMA_CSR);
- }
- break;
- case dvmarev3:
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- tmp &= ~DMA_3CLKS;
- tmp |= DMA_2CLKS;
- if (can_do_burst32) {
- tmp &= ~DMA_BRST_SZ;
- tmp |= DMA_BRST32;
- }
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- break;
- case dvmaesc1:
- /* This is the DMA unit found on SCSI/Ether cards. */
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- tmp |= DMA_ADD_ENABLE;
- tmp &= ~DMA_BCNT_ENAB;
- if (!can_do_burst32 && can_do_burst16) {
- tmp |= DMA_ESC_BURST;
- } else {
- tmp &= ~(DMA_ESC_BURST);
- }
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- break;
- default:
- break;
- };
- ESP_INTSON(esp->dregs);
-}
-
-/* Reset the ESP chip, _not_ the SCSI bus. */
-static void __init esp_reset_esp(struct esp *esp)
-{
- u8 family_code, version;
- int i;
-
- /* Now reset the ESP chip */
- esp_cmd(esp, ESP_CMD_RC);
- esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
- esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
-
- /* Reload the configuration registers */
- sbus_writeb(esp->cfact, esp->eregs + ESP_CFACT);
- esp->prev_stp = 0;
- sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
- esp->prev_soff = 0;
- sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
- sbus_writeb(esp->neg_defp, esp->eregs + ESP_TIMEO);
-
- /* This is the only point at which it is reliable to read
- * the ID-code for a fast ESP chip variants.
- */
- esp->max_period = ((35 * esp->ccycle) / 1000);
- if (esp->erev == fast) {
- version = sbus_readb(esp->eregs + ESP_UID);
- family_code = (version & 0xf8) >> 3;
- if (family_code == 0x02)
- esp->erev = fas236;
- else if (family_code == 0x0a)
- esp->erev = fashme; /* Version is usually '5'. */
- else
- esp->erev = fas100a;
- ESPMISC(("esp%d: FAST chip is %s (family=%d, version=%d)\n",
- esp->esp_id,
- (esp->erev == fas236) ? "fas236" :
- ((esp->erev == fas100a) ? "fas100a" :
- "fasHME"), family_code, (version & 7)));
-
- esp->min_period = ((4 * esp->ccycle) / 1000);
- } else {
- esp->min_period = ((5 * esp->ccycle) / 1000);
- }
- esp->max_period = (esp->max_period + 3)>>2;
- esp->min_period = (esp->min_period + 3)>>2;
-
- sbus_writeb(esp->config1, esp->eregs + ESP_CFG1);
- switch (esp->erev) {
- case esp100:
- /* nothing to do */
- break;
- case esp100a:
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- break;
- case esp236:
- /* Slow 236 */
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- esp->prev_cfg3 = esp->config3[0];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- break;
- case fashme:
- esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
- /* fallthrough... */
- case fas236:
- /* Fast 236 or HME */
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- for (i = 0; i < 16; i++) {
- if (esp->erev == fashme) {
- u8 cfg3;
-
- cfg3 = ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH;
- if (esp->scsi_id >= 8)
- cfg3 |= ESP_CONFIG3_IDBIT3;
- esp->config3[i] |= cfg3;
- } else {
- esp->config3[i] |= ESP_CONFIG3_FCLK;
- }
- }
- esp->prev_cfg3 = esp->config3[0];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- if (esp->erev == fashme) {
- esp->radelay = 80;
- } else {
- if (esp->diff)
- esp->radelay = 0;
- else
- esp->radelay = 96;
- }
- break;
- case fas100a:
- /* Fast 100a */
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- for (i = 0; i < 16; i++)
- esp->config3[i] |= ESP_CONFIG3_FCLOCK;
- esp->prev_cfg3 = esp->config3[0];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- esp->radelay = 32;
- break;
- default:
- panic("esp: what could it be... I wonder...");
- break;
- };
-
- /* Eat any bitrot in the chip */
- sbus_readb(esp->eregs + ESP_INTRPT);
- udelay(100);
-}
-
-/* This places the ESP into a known state at boot time. */
-static void __init esp_bootup_reset(struct esp *esp)
-{
- u8 tmp;
-
- /* Reset the DMA */
- esp_reset_dma(esp);
-
- /* Reset the ESP */
- esp_reset_esp(esp);
-
- /* Reset the SCSI bus, but tell ESP not to generate an irq */
- tmp = sbus_readb(esp->eregs + ESP_CFG1);
- tmp |= ESP_CONFIG1_SRRDISAB;
- sbus_writeb(tmp, esp->eregs + ESP_CFG1);
-
- esp_cmd(esp, ESP_CMD_RS);
- udelay(400);
-
- sbus_writeb(esp->config1, esp->eregs + ESP_CFG1);
-
- /* Eat any bitrot in the chip and we are done... */
- sbus_readb(esp->eregs + ESP_INTRPT);
-}
-
-static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev)
-{
- struct sbus_dev *sdev = esp->sdev;
- struct sbus_dma *dma;
-
- if (dma_sdev != NULL) {
- for_each_dvma(dma) {
- if (dma->sdev == dma_sdev)
- break;
- }
- } else {
- for_each_dvma(dma) {
- /* If allocated already, can't use it. */
- if (dma->allocated)
- continue;
-
- if (dma->sdev == NULL)
- break;
-
- /* If bus + slot are the same and it has the
- * correct OBP name, it's ours.
- */
- if (sdev->bus == dma->sdev->bus &&
- sdev->slot == dma->sdev->slot &&
- (!strcmp(dma->sdev->prom_name, "dma") ||
- !strcmp(dma->sdev->prom_name, "espdma")))
- break;
- }
- }
-
- /* If we don't know how to handle the dvma,
- * do not use this device.
- */
- if (dma == NULL) {
- printk("Cannot find dvma for ESP%d's SCSI\n", esp->esp_id);
- return -1;
- }
- if (dma->allocated) {
- printk("esp%d: can't use my espdma\n", esp->esp_id);
- return -1;
- }
- dma->allocated = 1;
- esp->dma = dma;
- esp->dregs = dma->regs;
-
- return 0;
-}
-
-static int __init esp_map_regs(struct esp *esp, int hme)
-{
- struct sbus_dev *sdev = esp->sdev;
- struct resource *res;
-
- /* On HME, two reg sets exist, first is DVMA,
- * second is ESP registers.
- */
- if (hme)
- res = &sdev->resource[1];
- else
- res = &sdev->resource[0];
-
- esp->eregs = sbus_ioremap(res, 0, ESP_REG_SIZE, "ESP Registers");
-
- if (esp->eregs == 0)
- return -1;
- return 0;
-}
-
-static int __init esp_map_cmdarea(struct esp *esp)
-{
- struct sbus_dev *sdev = esp->sdev;
-
- esp->esp_command = sbus_alloc_consistent(sdev, 16,
- &esp->esp_command_dvma);
- if (esp->esp_command == NULL ||
- esp->esp_command_dvma == 0)
- return -1;
- return 0;
-}
-
-static int __init esp_register_irq(struct esp *esp)
-{
- esp->ehost->irq = esp->irq = esp->sdev->irqs[0];
-
- /* We used to try various overly-clever things to
- * reduce the interrupt processing overhead on
- * sun4c/sun4m when multiple ESP's shared the
- * same IRQ. It was too complex and messy to
- * sanely maintain.
- */
- if (request_irq(esp->ehost->irq, esp_intr,
- IRQF_SHARED, "ESP SCSI", esp)) {
- printk("esp%d: Cannot acquire irq line\n",
- esp->esp_id);
- return -1;
- }
-
- printk("esp%d: IRQ %d ", esp->esp_id,
- esp->ehost->irq);
-
- return 0;
-}
-
-static void __init esp_get_scsi_id(struct esp *esp)
-{
- struct sbus_dev *sdev = esp->sdev;
- struct device_node *dp = sdev->ofdev.node;
-
- esp->scsi_id = of_getintprop_default(dp,
- "initiator-id",
- -1);
- if (esp->scsi_id == -1)
- esp->scsi_id = of_getintprop_default(dp,
- "scsi-initiator-id",
- -1);
- if (esp->scsi_id == -1)
- esp->scsi_id = (sdev->bus == NULL) ? 7 :
- of_getintprop_default(sdev->bus->ofdev.node,
- "scsi-initiator-id",
- 7);
- esp->ehost->this_id = esp->scsi_id;
- esp->scsi_id_mask = (1 << esp->scsi_id);
-
-}
-
-static void __init esp_get_clock_params(struct esp *esp)
-{
- struct sbus_dev *sdev = esp->sdev;
- int prom_node = esp->prom_node;
- int sbus_prom_node;
- unsigned int fmhz;
- u8 ccf;
-
- if (sdev != NULL && sdev->bus != NULL)
- sbus_prom_node = sdev->bus->prom_node;
- else
- sbus_prom_node = 0;
-
- /* This is getting messy but it has to be done
- * correctly or else you get weird behavior all
- * over the place. We are trying to basically
- * figure out three pieces of information.
- *
- * a) Clock Conversion Factor
- *
- * This is a representation of the input
- * crystal clock frequency going into the
- * ESP on this machine. Any operation whose
- * timing is longer than 400ns depends on this
- * value being correct. For example, you'll
- * get blips for arbitration/selection during
- * high load or with multiple targets if this
- * is not set correctly.
- *
- * b) Selection Time-Out
- *
- * The ESP isn't very bright and will arbitrate
- * for the bus and try to select a target
- * forever if you let it. This value tells
- * the ESP when it has taken too long to
- * negotiate and that it should interrupt
- * the CPU so we can see what happened.
- * The value is computed as follows (from
- * NCR/Symbios chip docs).
- *
- * (Time Out Period) * (Input Clock)
- * STO = ----------------------------------
- * (8192) * (Clock Conversion Factor)
- *
- * You usually want the time out period to be
- * around 250ms, I think we'll set it a little
- * bit higher to account for fully loaded SCSI
- * bus's and slow devices that don't respond so
- * quickly to selection attempts. (yeah, I know
- * this is out of spec. but there is a lot of
- * buggy pieces of firmware out there so bite me)
- *
- * c) Imperical constants for synchronous offset
- * and transfer period register values
- *
- * This entails the smallest and largest sync
- * period we could ever handle on this ESP.
- */
-
- fmhz = prom_getintdefault(prom_node, "clock-frequency", -1);
- if (fmhz == -1)
- fmhz = (!sbus_prom_node) ? 0 :
- prom_getintdefault(sbus_prom_node, "clock-frequency", -1);
-
- if (fmhz <= (5000000))
- ccf = 0;
- else
- ccf = (((5000000 - 1) + (fmhz))/(5000000));
-
- if (!ccf || ccf > 8) {
- /* If we can't find anything reasonable,
- * just assume 20MHZ. This is the clock
- * frequency of the older sun4c's where I've
- * been unable to find the clock-frequency
- * PROM property. All other machines provide
- * useful values it seems.
- */
- ccf = ESP_CCF_F4;
- fmhz = (20000000);
- }
-
- if (ccf == (ESP_CCF_F7 + 1))
- esp->cfact = ESP_CCF_F0;
- else if (ccf == ESP_CCF_NEVER)
- esp->cfact = ESP_CCF_F2;
- else
- esp->cfact = ccf;
- esp->raw_cfact = ccf;
-
- esp->cfreq = fmhz;
- esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
- esp->ctick = ESP_TICK(ccf, esp->ccycle);
- esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
- esp->sync_defp = SYNC_DEFP_SLOW;
-
- printk("SCSI ID %d Clk %dMHz CCYC=%d CCF=%d TOut %d ",
- esp->scsi_id, (fmhz / 1000000),
- (int)esp->ccycle, (int)ccf, (int) esp->neg_defp);
-}
-
-static void __init esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
-{
- struct sbus_dev *sdev = esp->sdev;
- u8 bursts;
-
- bursts = prom_getintdefault(esp->prom_node, "burst-sizes", 0xff);
-
- if (dma) {
- u8 tmp = prom_getintdefault(dma->prom_node,
- "burst-sizes", 0xff);
- if (tmp != 0xff)
- bursts &= tmp;
- }
-
- if (sdev->bus) {
- u8 tmp = prom_getintdefault(sdev->bus->prom_node,
- "burst-sizes", 0xff);
- if (tmp != 0xff)
- bursts &= tmp;
- }
-
- if (bursts == 0xff ||
- (bursts & DMA_BURST16) == 0 ||
- (bursts & DMA_BURST32) == 0)
- bursts = (DMA_BURST32 - 1);
-
- esp->bursts = bursts;
-}
-
-static void __init esp_get_revision(struct esp *esp)
-{
- u8 tmp;
-
- esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
- esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
-
- tmp = sbus_readb(esp->eregs + ESP_CFG2);
- tmp &= ~ESP_CONFIG2_MAGIC;
- if (tmp != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
- /* If what we write to cfg2 does not come back, cfg2
- * is not implemented, therefore this must be a plain
- * esp100.
- */
- esp->erev = esp100;
- printk("NCR53C90(esp100)\n");
- } else {
- esp->config2 = 0;
- esp->prev_cfg3 = esp->config3[0] = 5;
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- sbus_writeb(0, esp->eregs + ESP_CFG3);
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-
- tmp = sbus_readb(esp->eregs + ESP_CFG3);
- if (tmp != 5) {
- /* The cfg2 register is implemented, however
- * cfg3 is not, must be esp100a.
- */
- esp->erev = esp100a;
- printk("NCR53C90A(esp100a)\n");
- } else {
- int target;
-
- for (target = 0; target < 16; target++)
- esp->config3[target] = 0;
- esp->prev_cfg3 = 0;
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-
- /* All of cfg{1,2,3} implemented, must be one of
- * the fas variants, figure out which one.
- */
- if (esp->raw_cfact > ESP_CCF_F5) {
- esp->erev = fast;
- esp->sync_defp = SYNC_DEFP_FAST;
- printk("NCR53C9XF(espfast)\n");
- } else {
- esp->erev = esp236;
- printk("NCR53C9x(esp236)\n");
- }
- esp->config2 = 0;
- sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
- }
- }
-}
-
-static void __init esp_init_swstate(struct esp *esp)
-{
- int i;
-
- /* Command queues... */
- esp->current_SC = NULL;
- esp->disconnected_SC = NULL;
- esp->issue_SC = NULL;
-
- /* Target and current command state... */
- esp->targets_present = 0;
- esp->resetting_bus = 0;
- esp->snip = 0;
-
- init_waitqueue_head(&esp->reset_queue);
-
- /* Debugging... */
- for(i = 0; i < 32; i++)
- esp->espcmdlog[i] = 0;
- esp->espcmdent = 0;
-
- /* MSG phase state... */
- for(i = 0; i < 16; i++) {
- esp->cur_msgout[i] = 0;
- esp->cur_msgin[i] = 0;
- }
- esp->prevmsgout = esp->prevmsgin = 0;
- esp->msgout_len = esp->msgin_len = 0;
-
- /* Clear the one behind caches to hold unmatchable values. */
- esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff;
- esp->prev_hme_dmacsr = 0xffffffff;
-}
-
-static int __init detect_one_esp(struct scsi_host_template *tpnt,
- struct device *dev,
- struct sbus_dev *esp_dev,
- struct sbus_dev *espdma,
- struct sbus_bus *sbus,
- int hme)
-{
- static int instance;
- struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp));
- struct esp *esp;
-
- if (!esp_host)
- return -ENOMEM;
-
- if (hme)
- esp_host->max_id = 16;
- esp = (struct esp *) esp_host->hostdata;
- esp->ehost = esp_host;
- esp->sdev = esp_dev;
- esp->esp_id = instance;
- esp->prom_node = esp_dev->prom_node;
- prom_getstring(esp->prom_node, "name", esp->prom_name,
- sizeof(esp->prom_name));
-
- if (esp_find_dvma(esp, espdma) < 0)
- goto fail_unlink;
- if (esp_map_regs(esp, hme) < 0) {
- printk("ESP registers unmappable");
- goto fail_dvma_release;
- }
- if (esp_map_cmdarea(esp) < 0) {
- printk("ESP DVMA transport area unmappable");
- goto fail_unmap_regs;
- }
- if (esp_register_irq(esp) < 0)
- goto fail_unmap_cmdarea;
-
- esp_get_scsi_id(esp);
-
- esp->diff = prom_getbool(esp->prom_node, "differential");
- if (esp->diff)
- printk("Differential ");
-
- esp_get_clock_params(esp);
- esp_get_bursts(esp, espdma);
- esp_get_revision(esp);
- esp_init_swstate(esp);
-
- esp_bootup_reset(esp);
-
- if (scsi_add_host(esp_host, dev))
- goto fail_free_irq;
-
- dev_set_drvdata(&esp_dev->ofdev.dev, esp);
-
- scsi_scan_host(esp_host);
- instance++;
-
- return 0;
-
-fail_free_irq:
- free_irq(esp->ehost->irq, esp);
-
-fail_unmap_cmdarea:
- sbus_free_consistent(esp->sdev, 16,
- (void *) esp->esp_command,
- esp->esp_command_dvma);
-
-fail_unmap_regs:
- sbus_iounmap(esp->eregs, ESP_REG_SIZE);
-
-fail_dvma_release:
- esp->dma->allocated = 0;
-
-fail_unlink:
- scsi_host_put(esp_host);
- return -1;
-}
-
-/* Detecting ESP chips on the machine. This is the simple and easy
- * version.
- */
-static int __devexit esp_remove_common(struct esp *esp)
-{
- unsigned int irq = esp->ehost->irq;
-
- scsi_remove_host(esp->ehost);
-
- ESP_INTSOFF(esp->dregs);
-#if 0
- esp_reset_dma(esp);
- esp_reset_esp(esp);
-#endif
-
- free_irq(irq, esp);
- sbus_free_consistent(esp->sdev, 16,
- (void *) esp->esp_command, esp->esp_command_dvma);
- sbus_iounmap(esp->eregs, ESP_REG_SIZE);
- esp->dma->allocated = 0;
-
- scsi_host_put(esp->ehost);
-
- return 0;
-}
-
-
-#ifdef CONFIG_SUN4
-
-#include <asm/sun4paddr.h>
-
-static struct sbus_dev sun4_esp_dev;
-
-static int __init esp_sun4_probe(struct scsi_host_template *tpnt)
-{
- if (sun4_esp_physaddr) {
- memset(&sun4_esp_dev, 0, sizeof(sun4_esp_dev));
- sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
- sun4_esp_dev.irqs[0] = 4;
- sun4_esp_dev.resource[0].start = sun4_esp_physaddr;
- sun4_esp_dev.resource[0].end =
- sun4_esp_physaddr + ESP_REG_SIZE - 1;
- sun4_esp_dev.resource[0].flags = IORESOURCE_IO;
-
- return detect_one_esp(tpnt, NULL,
- &sun4_esp_dev, NULL, NULL, 0);
- }
- return 0;
-}
-
-static int __devexit esp_sun4_remove(void)
-{
- struct of_device *dev = &sun4_esp_dev.ofdev;
- struct esp *esp = dev_get_drvdata(&dev->dev);
-
- return esp_remove_common(esp);
-}
-
-#else /* !CONFIG_SUN4 */
-
-static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- struct device_node *dp = dev->node;
- struct sbus_dev *dma_sdev = NULL;
- int hme = 0;
-
- if (dp->parent &&
- (!strcmp(dp->parent->name, "espdma") ||
- !strcmp(dp->parent->name, "dma")))
- dma_sdev = sdev->parent;
- else if (!strcmp(dp->name, "SUNW,fas")) {
- dma_sdev = sdev;
- hme = 1;
- }
-
- return detect_one_esp(match->data, &dev->dev,
- sdev, dma_sdev, sdev->bus, hme);
-}
-
-static int __devexit esp_sbus_remove(struct of_device *dev)
-{
- struct esp *esp = dev_get_drvdata(&dev->dev);
-
- return esp_remove_common(esp);
-}
-
-#endif /* !CONFIG_SUN4 */
-
-/* The info function will return whatever useful
- * information the developer sees fit. If not provided, then
- * the name field will be used instead.
- */
-static const char *esp_info(struct Scsi_Host *host)
-{
- struct esp *esp;
-
- esp = (struct esp *) host->hostdata;
- switch (esp->erev) {
- case esp100:
- return "Sparc ESP100 (NCR53C90)";
- case esp100a:
- return "Sparc ESP100A (NCR53C90A)";
- case esp236:
- return "Sparc ESP236";
- case fas236:
- return "Sparc ESP236-FAST";
- case fashme:
- return "Sparc ESP366-HME";
- case fas100a:
- return "Sparc ESP100A-FAST";
- default:
- return "Bogon ESP revision";
- };
-}
-
-/* From Wolfgang Stanglmeier's NCR scsi driver. */
-struct info_str
-{
- char *buffer;
- int length;
- int offset;
- int pos;
-};
-
-static void copy_mem_info(struct info_str *info, char *data, int len)
-{
- if (info->pos + len > info->length)
- len = info->length - info->pos;
-
- if (info->pos + len < info->offset) {
- info->pos += len;
- return;
- }
- if (info->pos < info->offset) {
- data += (info->offset - info->pos);
- len -= (info->offset - info->pos);
- }
-
- if (len > 0) {
- memcpy(info->buffer + info->pos, data, len);
- info->pos += len;
- }
-}
-
-static int copy_info(struct info_str *info, char *fmt, ...)
-{
- va_list args;
- char buf[81];
- int len;
-
- va_start(args, fmt);
- len = vsprintf(buf, fmt, args);
- va_end(args);
-
- copy_mem_info(info, buf, len);
- return len;
-}
-
-static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len)
-{
- struct scsi_device *sdev;
- struct info_str info;
- int i;
-
- info.buffer = ptr;
- info.length = len;
- info.offset = offset;
- info.pos = 0;
-
- copy_info(&info, "Sparc ESP Host Adapter:\n");
- copy_info(&info, "\tPROM node\t\t%08x\n", (unsigned int) esp->prom_node);
- copy_info(&info, "\tPROM name\t\t%s\n", esp->prom_name);
- copy_info(&info, "\tESP Model\t\t");
- switch (esp->erev) {
- case esp100:
- copy_info(&info, "ESP100\n");
- break;
- case esp100a:
- copy_info(&info, "ESP100A\n");
- break;
- case esp236:
- copy_info(&info, "ESP236\n");
- break;
- case fas236:
- copy_info(&info, "FAS236\n");
- break;
- case fas100a:
- copy_info(&info, "FAS100A\n");
- break;
- case fast:
- copy_info(&info, "FAST\n");
- break;
- case fashme:
- copy_info(&info, "Happy Meal FAS\n");
- break;
- case espunknown:
- default:
- copy_info(&info, "Unknown!\n");
- break;
- };
- copy_info(&info, "\tDMA Revision\t\t");
- switch (esp->dma->revision) {
- case dvmarev0:
- copy_info(&info, "Rev 0\n");
- break;
- case dvmaesc1:
- copy_info(&info, "ESC Rev 1\n");
- break;
- case dvmarev1:
- copy_info(&info, "Rev 1\n");
- break;
- case dvmarev2:
- copy_info(&info, "Rev 2\n");
- break;
- case dvmarev3:
- copy_info(&info, "Rev 3\n");
- break;
- case dvmarevplus:
- copy_info(&info, "Rev 1+\n");
- break;
- case dvmahme:
- copy_info(&info, "Rev HME/FAS\n");
- break;
- default:
- copy_info(&info, "Unknown!\n");
- break;
- };
- copy_info(&info, "\tLive Targets\t\t[ ");
- for (i = 0; i < 15; i++) {
- if (esp->targets_present & (1 << i))
- copy_info(&info, "%d ", i);
- }
- copy_info(&info, "]\n\n");
-
- /* Now describe the state of each existing target. */
- copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\tWide\n");
-
- shost_for_each_device(sdev, esp->ehost) {
- struct esp_device *esp_dev = sdev->hostdata;
- uint id = sdev->id;
-
- if (!(esp->targets_present & (1 << id)))
- continue;
-
- copy_info(&info, "%d\t\t", id);
- copy_info(&info, "%08lx\t", esp->config3[id]);
- copy_info(&info, "[%02lx,%02lx]\t\t\t",
- esp_dev->sync_max_offset,
- esp_dev->sync_min_period);
- copy_info(&info, "%s\t\t",
- esp_dev->disconnect ? "yes" : "no");
- copy_info(&info, "%s\n",
- (esp->config3[id] & ESP_CONFIG3_EWIDE) ? "yes" : "no");
- }
- return info.pos > info.offset? info.pos - info.offset : 0;
-}
-
-/* ESP proc filesystem code. */
-static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
- int length, int inout)
-{
- struct esp *esp = (struct esp *) host->hostdata;
-
- if (inout)
- return -EINVAL; /* not yet */
-
- if (start)
- *start = buffer;
-
- return esp_host_info(esp, buffer, offset, length);
-}
-
-static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
-{
- if (sp->use_sg == 0) {
- sp->SCp.this_residual = sp->request_bufflen;
- sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
- sp->SCp.buffers_residual = 0;
- if (sp->request_bufflen) {
- sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer,
- sp->SCp.this_residual,
- sp->sc_data_direction);
- sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in);
- } else {
- sp->SCp.ptr = NULL;
- }
- } else {
- sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
- sp->SCp.buffers_residual = sbus_map_sg(esp->sdev,
- sp->SCp.buffer,
- sp->use_sg,
- sp->sc_data_direction);
- sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer);
- sp->SCp.ptr = (char *) ((unsigned long)sg_dma_address(sp->SCp.buffer));
- }
-}
-
-static void esp_release_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
-{
- if (sp->use_sg) {
- sbus_unmap_sg(esp->sdev, sp->request_buffer, sp->use_sg,
- sp->sc_data_direction);
- } else if (sp->request_bufflen) {
- sbus_unmap_single(esp->sdev,
- sp->SCp.have_data_in,
- sp->request_bufflen,
- sp->sc_data_direction);
- }
-}
-
-static void esp_restore_pointers(struct esp *esp, struct scsi_cmnd *sp)
-{
- struct esp_pointers *ep = &esp->data_pointers[sp->device->id];
-
- sp->SCp.ptr = ep->saved_ptr;
- sp->SCp.buffer = ep->saved_buffer;
- sp->SCp.this_residual = ep->saved_this_residual;
- sp->SCp.buffers_residual = ep->saved_buffers_residual;
-}
-
-static void esp_save_pointers(struct esp *esp, struct scsi_cmnd *sp)
-{
- struct esp_pointers *ep = &esp->data_pointers[sp->device->id];
-
- ep->saved_ptr = sp->SCp.ptr;
- ep->saved_buffer = sp->SCp.buffer;
- ep->saved_this_residual = sp->SCp.this_residual;
- ep->saved_buffers_residual = sp->SCp.buffers_residual;
-}
-
-/* Some rules:
- *
- * 1) Never ever panic while something is live on the bus.
- * If there is to be any chance of syncing the disks this
- * rule is to be obeyed.
- *
- * 2) Any target that causes a foul condition will no longer
- * have synchronous transfers done to it, no questions
- * asked.
- *
- * 3) Keep register accesses to a minimum. Think about some
- * day when we have Xbus machines this is running on and
- * the ESP chip is on the other end of the machine on a
- * different board from the cpu where this is running.
- */
-
-/* Fire off a command. We assume the bus is free and that the only
- * case where we could see an interrupt is where we have disconnected
- * commands active and they are trying to reselect us.
- */
-static inline void esp_check_cmd(struct esp *esp, struct scsi_cmnd *sp)
-{
- switch (sp->cmd_len) {
- case 6:
- case 10:
- case 12:
- esp->esp_slowcmd = 0;
- break;
-
- default:
- esp->esp_slowcmd = 1;
- esp->esp_scmdleft = sp->cmd_len;
- esp->esp_scmdp = &sp->cmnd[0];
- break;
- };
-}
-
-static inline void build_sync_nego_msg(struct esp *esp, int period, int offset)
-{
- esp->cur_msgout[0] = EXTENDED_MESSAGE;
- esp->cur_msgout[1] = 3;
- esp->cur_msgout[2] = EXTENDED_SDTR;
- esp->cur_msgout[3] = period;
- esp->cur_msgout[4] = offset;
- esp->msgout_len = 5;
-}
-
-/* SIZE is in bits, currently HME only supports 16 bit wide transfers. */
-static inline void build_wide_nego_msg(struct esp *esp, int size)
-{
- esp->cur_msgout[0] = EXTENDED_MESSAGE;
- esp->cur_msgout[1] = 2;
- esp->cur_msgout[2] = EXTENDED_WDTR;
- switch (size) {
- case 32:
- esp->cur_msgout[3] = 2;
- break;
- case 16:
- esp->cur_msgout[3] = 1;
- break;
- case 8:
- default:
- esp->cur_msgout[3] = 0;
- break;
- };
-
- esp->msgout_len = 4;
-}
-
-static void esp_exec_cmd(struct esp *esp)
-{
- struct scsi_cmnd *SCptr;
- struct scsi_device *SDptr;
- struct esp_device *esp_dev;
- volatile u8 *cmdp = esp->esp_command;
- u8 the_esp_command;
- int lun, target;
- int i;
-
- /* Hold off if we have disconnected commands and
- * an IRQ is showing...
- */
- if (esp->disconnected_SC && ESP_IRQ_P(esp->dregs))
- return;
-
- /* Grab first member of the issue queue. */
- SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);
-
- /* Safe to panic here because current_SC is null. */
- if (!SCptr)
- panic("esp: esp_exec_cmd and issue queue is NULL");
-
- SDptr = SCptr->device;
- esp_dev = SDptr->hostdata;
- lun = SCptr->device->lun;
- target = SCptr->device->id;
-
- esp->snip = 0;
- esp->msgout_len = 0;
-
- /* Send it out whole, or piece by piece? The ESP
- * only knows how to automatically send out 6, 10,
- * and 12 byte commands. I used to think that the
- * Linux SCSI code would never throw anything other
- * than that to us, but then again there is the
- * SCSI generic driver which can send us anything.
- */
- esp_check_cmd(esp, SCptr);
-
- /* If arbitration/selection is successful, the ESP will leave
- * ATN asserted, causing the target to go into message out
- * phase. The ESP will feed the target the identify and then
- * the target can only legally go to one of command,
- * datain/out, status, or message in phase, or stay in message
- * out phase (should we be trying to send a sync negotiation
- * message after the identify). It is not allowed to drop
- * BSY, but some buggy targets do and we check for this
- * condition in the selection complete code. Most of the time
- * we'll make the command bytes available to the ESP and it
- * will not interrupt us until it finishes command phase, we
- * cannot do this for command sizes the ESP does not
- * understand and in this case we'll get interrupted right
- * when the target goes into command phase.
- *
- * It is absolutely _illegal_ in the presence of SCSI-2 devices
- * to use the ESP select w/o ATN command. When SCSI-2 devices are
- * present on the bus we _must_ always go straight to message out
- * phase with an identify message for the target. Being that
- * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2
- * selections should not confuse SCSI-1 we hope.
- */
-
- if (esp_dev->sync) {
- /* this targets sync is known */
-#ifndef __sparc_v9__
-do_sync_known:
-#endif
- if (esp_dev->disconnect)
- *cmdp++ = IDENTIFY(1, lun);
- else
- *cmdp++ = IDENTIFY(0, lun);
-
- if (esp->esp_slowcmd) {
- the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
- esp_advance_phase(SCptr, in_slct_stop);
- } else {
- the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
- esp_advance_phase(SCptr, in_slct_norm);
- }
- } else if (!(esp->targets_present & (1<<target)) || !(esp_dev->disconnect)) {
- /* After the bootup SCSI code sends both the
- * TEST_UNIT_READY and INQUIRY commands we want
- * to at least attempt allowing the device to
- * disconnect.
- */
- ESPMISC(("esp: Selecting device for first time. target=%d "
- "lun=%d\n", target, SCptr->device->lun));
- if (!SDptr->borken && !esp_dev->disconnect)
- esp_dev->disconnect = 1;
-
- *cmdp++ = IDENTIFY(0, lun);
- esp->prevmsgout = NOP;
- esp_advance_phase(SCptr, in_slct_norm);
- the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
-
- /* Take no chances... */
- esp_dev->sync_max_offset = 0;
- esp_dev->sync_min_period = 0;
- } else {
- /* Sorry, I have had way too many problems with
- * various CDROM devices on ESP. -DaveM
- */
- int cdrom_hwbug_wkaround = 0;
-
-#ifndef __sparc_v9__
- /* Never allow disconnects or synchronous transfers on
- * SparcStation1 and SparcStation1+. Allowing those
- * to be enabled seems to lockup the machine completely.
- */
- if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
- (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
- /* But we are nice and allow tapes and removable
- * disks (but not CDROMs) to disconnect.
- */
- if(SDptr->type == TYPE_TAPE ||
- (SDptr->type != TYPE_ROM && SDptr->removable))
- esp_dev->disconnect = 1;
- else
- esp_dev->disconnect = 0;
- esp_dev->sync_max_offset = 0;
- esp_dev->sync_min_period = 0;
- esp_dev->sync = 1;
- esp->snip = 0;
- goto do_sync_known;
- }
-#endif /* !(__sparc_v9__) */
-
- /* We've talked to this guy before,
- * but never negotiated. Let's try,
- * need to attempt WIDE first, before
- * sync nego, as per SCSI 2 standard.
- */
- if (esp->erev == fashme && !esp_dev->wide) {
- if (!SDptr->borken &&
- SDptr->type != TYPE_ROM &&
- SDptr->removable == 0) {
- build_wide_nego_msg(esp, 16);
- esp_dev->wide = 1;
- esp->wnip = 1;
- goto after_nego_msg_built;
- } else {
- esp_dev->wide = 1;
- /* Fall through and try sync. */
- }
- }
-
- if (!SDptr->borken) {
- if ((SDptr->type == TYPE_ROM)) {
- /* Nice try sucker... */
- ESPMISC(("esp%d: Disabling sync for buggy "
- "CDROM.\n", esp->esp_id));
- cdrom_hwbug_wkaround = 1;
- build_sync_nego_msg(esp, 0, 0);
- } else if (SDptr->removable != 0) {
- ESPMISC(("esp%d: Not negotiating sync/wide but "
- "allowing disconnect for removable media.\n",
- esp->esp_id));
- build_sync_nego_msg(esp, 0, 0);
- } else {
- build_sync_nego_msg(esp, esp->sync_defp, 15);
- }
- } else {
- build_sync_nego_msg(esp, 0, 0);
- }
- esp_dev->sync = 1;
- esp->snip = 1;
-
-after_nego_msg_built:
- /* A fix for broken SCSI1 targets, when they disconnect
- * they lock up the bus and confuse ESP. So disallow
- * disconnects for SCSI1 targets for now until we
- * find a better fix.
- *
- * Addendum: This is funny, I figured out what was going
- * on. The blotzed SCSI1 target would disconnect,
- * one of the other SCSI2 targets or both would be
- * disconnected as well. The SCSI1 target would
- * stay disconnected long enough that we start
- * up a command on one of the SCSI2 targets. As
- * the ESP is arbitrating for the bus the SCSI1
- * target begins to arbitrate as well to reselect
- * the ESP. The SCSI1 target refuses to drop it's
- * ID bit on the data bus even though the ESP is
- * at ID 7 and is the obvious winner for any
- * arbitration. The ESP is a poor sport and refuses
- * to lose arbitration, it will continue indefinitely
- * trying to arbitrate for the bus and can only be
- * stopped via a chip reset or SCSI bus reset.
- * Therefore _no_ disconnects for SCSI1 targets
- * thank you very much. ;-)
- */
- if(((SDptr->scsi_level < 3) &&
- (SDptr->type != TYPE_TAPE) &&
- SDptr->removable == 0) ||
- cdrom_hwbug_wkaround || SDptr->borken) {
- ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
- "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
- esp_dev->disconnect = 0;
- *cmdp++ = IDENTIFY(0, lun);
- } else {
- *cmdp++ = IDENTIFY(1, lun);
- }
-
- /* ESP fifo is only so big...
- * Make this look like a slow command.
- */
- esp->esp_slowcmd = 1;
- esp->esp_scmdleft = SCptr->cmd_len;
- esp->esp_scmdp = &SCptr->cmnd[0];
-
- the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
- esp_advance_phase(SCptr, in_slct_msg);
- }
-
- if (!esp->esp_slowcmd)
- for (i = 0; i < SCptr->cmd_len; i++)
- *cmdp++ = SCptr->cmnd[i];
-
- /* HME sucks... */
- if (esp->erev == fashme)
- sbus_writeb((target & 0xf) | (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT),
- esp->eregs + ESP_BUSID);
- else
- sbus_writeb(target & 7, esp->eregs + ESP_BUSID);
- if (esp->prev_soff != esp_dev->sync_max_offset ||
- esp->prev_stp != esp_dev->sync_min_period ||
- (esp->erev > esp100a &&
- esp->prev_cfg3 != esp->config3[target])) {
- esp->prev_soff = esp_dev->sync_max_offset;
- esp->prev_stp = esp_dev->sync_min_period;
- sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
- sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
- if (esp->erev > esp100a) {
- esp->prev_cfg3 = esp->config3[target];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- }
- }
- i = (cmdp - esp->esp_command);
-
- if (esp->erev == fashme) {
- esp_cmd(esp, ESP_CMD_FLUSH); /* Grrr! */
-
- /* Set up the DMA and HME counters */
- sbus_writeb(i, esp->eregs + ESP_TCLOW);
- sbus_writeb(0, esp->eregs + ESP_TCMED);
- sbus_writeb(0, esp->eregs + FAS_RLO);
- sbus_writeb(0, esp->eregs + FAS_RHI);
- esp_cmd(esp, the_esp_command);
-
- /* Talk about touchy hardware... */
- esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
- (DMA_SCSI_DISAB | DMA_ENABLE)) &
- ~(DMA_ST_WRITE));
- sbus_writel(16, esp->dregs + DMA_COUNT);
- sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
- sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
- } else {
- u32 tmp;
-
- /* Set up the DMA and ESP counters */
- sbus_writeb(i, esp->eregs + ESP_TCLOW);
- sbus_writeb(0, esp->eregs + ESP_TCMED);
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- tmp &= ~DMA_ST_WRITE;
- tmp |= DMA_ENABLE;
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- if (esp->dma->revision == dvmaesc1) {
- if (i) /* Workaround ESC gate array SBUS rerun bug. */
- sbus_writel(PAGE_SIZE, esp->dregs + DMA_COUNT);
- }
- sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
-
- /* Tell ESP to "go". */
- esp_cmd(esp, the_esp_command);
- }
-}
-
-/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */
-static int esp_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
-{
- struct esp *esp;
-
- /* Set up func ptr and initial driver cmd-phase. */
- SCpnt->scsi_done = done;
- SCpnt->SCp.phase = not_issued;
-
- /* We use the scratch area. */
- ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->device->lun));
- ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->device->lun));
-
- esp = (struct esp *) SCpnt->device->host->hostdata;
- esp_get_dmabufs(esp, SCpnt);
- esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */
-
- SCpnt->SCp.Status = CHECK_CONDITION;
- SCpnt->SCp.Message = 0xff;
- SCpnt->SCp.sent_command = 0;
-
- /* Place into our queue. */
- if (SCpnt->cmnd[0] == REQUEST_SENSE) {
- ESPQUEUE(("RQSENSE\n"));
- prepend_SC(&esp->issue_SC, SCpnt);
- } else {
- ESPQUEUE(("\n"));
- append_SC(&esp->issue_SC, SCpnt);
- }
-
- /* Run it now if we can. */
- if (!esp->current_SC && !esp->resetting_bus)
- esp_exec_cmd(esp);
-
- return 0;
-}
-
-/* Dump driver state. */
-static void esp_dump_cmd(struct scsi_cmnd *SCptr)
-{
- ESPLOG(("[tgt<%02x> lun<%02x> "
- "pphase<%s> cphase<%s>]",
- SCptr->device->id, SCptr->device->lun,
- phase_string(SCptr->SCp.sent_command),
- phase_string(SCptr->SCp.phase)));
-}
-
-static void esp_dump_state(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
-#ifdef DEBUG_ESP_CMDS
- int i;
-#endif
-
- ESPLOG(("esp%d: dumping state\n", esp->esp_id));
- ESPLOG(("esp%d: dma -- cond_reg<%08x> addr<%08x>\n",
- esp->esp_id,
- sbus_readl(esp->dregs + DMA_CSR),
- sbus_readl(esp->dregs + DMA_ADDR)));
- ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
- esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));
- ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
- esp->esp_id,
- sbus_readb(esp->eregs + ESP_STATUS),
- sbus_readb(esp->eregs + ESP_SSTEP),
- sbus_readb(esp->eregs + ESP_INTRPT)));
-#ifdef DEBUG_ESP_CMDS
- printk("esp%d: last ESP cmds [", esp->esp_id);
- i = (esp->espcmdent - 1) & 31;
- printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
- i = (i - 1) & 31;
- printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
- i = (i - 1) & 31;
- printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
- i = (i - 1) & 31;
- printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
- printk("]\n");
-#endif /* (DEBUG_ESP_CMDS) */
-
- if (SCptr) {
- ESPLOG(("esp%d: current command ", esp->esp_id));
- esp_dump_cmd(SCptr);
- }
- ESPLOG(("\n"));
- SCptr = esp->disconnected_SC;
- ESPLOG(("esp%d: disconnected ", esp->esp_id));
- while (SCptr) {
- esp_dump_cmd(SCptr);
- SCptr = (struct scsi_cmnd *) SCptr->host_scribble;
- }
- ESPLOG(("\n"));
-}
-
-/* Abort a command. The host_lock is acquired by caller. */
-static int esp_abort(struct scsi_cmnd *SCptr)
-{
- struct esp *esp = (struct esp *) SCptr->device->host->hostdata;
- int don;
-
- ESPLOG(("esp%d: Aborting command\n", esp->esp_id));
- esp_dump_state(esp);
-
- /* Wheee, if this is the current command on the bus, the
- * best we can do is assert ATN and wait for msgout phase.
- * This should even fix a hung SCSI bus when we lose state
- * in the driver and timeout because the eventual phase change
- * will cause the ESP to (eventually) give an interrupt.
- */
- if (esp->current_SC == SCptr) {
- esp->cur_msgout[0] = ABORT;
- esp->msgout_len = 1;
- esp->msgout_ctr = 0;
- esp_cmd(esp, ESP_CMD_SATN);
- return SUCCESS;
- }
-
- /* If it is still in the issue queue then we can safely
- * call the completion routine and report abort success.
- */
- don = (sbus_readl(esp->dregs + DMA_CSR) & DMA_INT_ENAB);
- if (don) {
- ESP_INTSOFF(esp->dregs);
- }
- if (esp->issue_SC) {
- struct scsi_cmnd **prev, *this;
- for (prev = (&esp->issue_SC), this = esp->issue_SC;
- this != NULL;
- prev = (struct scsi_cmnd **) &(this->host_scribble),
- this = (struct scsi_cmnd *) this->host_scribble) {
-
- if (this == SCptr) {
- *prev = (struct scsi_cmnd *) this->host_scribble;
- this->host_scribble = NULL;
-
- esp_release_dmabufs(esp, this);
- this->result = DID_ABORT << 16;
- this->scsi_done(this);
-
- if (don)
- ESP_INTSON(esp->dregs);
-
- return SUCCESS;
- }
- }
- }
-
- /* Yuck, the command to abort is disconnected, it is not
- * worth trying to abort it now if something else is live
- * on the bus at this time. So, we let the SCSI code wait
- * a little bit and try again later.
- */
- if (esp->current_SC) {
- if (don)
- ESP_INTSON(esp->dregs);
- return FAILED;
- }
-
- /* It's disconnected, we have to reconnect to re-establish
- * the nexus and tell the device to abort. However, we really
- * cannot 'reconnect' per se. Don't try to be fancy, just
- * indicate failure, which causes our caller to reset the whole
- * bus.
- */
-
- if (don)
- ESP_INTSON(esp->dregs);
-
- return FAILED;
-}
-
-/* We've sent ESP_CMD_RS to the ESP, the interrupt had just
- * arrived indicating the end of the SCSI bus reset. Our job
- * is to clean out the command queues and begin re-execution
- * of SCSI commands once more.
- */
-static int esp_finish_reset(struct esp *esp)
-{
- struct scsi_cmnd *sp = esp->current_SC;
-
- /* Clean up currently executing command, if any. */
- if (sp != NULL) {
- esp->current_SC = NULL;
-
- esp_release_dmabufs(esp, sp);
- sp->result = (DID_RESET << 16);
-
- sp->scsi_done(sp);
- }
-
- /* Clean up disconnected queue, they have been invalidated
- * by the bus reset.
- */
- if (esp->disconnected_SC) {
- while ((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) {
- esp_release_dmabufs(esp, sp);
- sp->result = (DID_RESET << 16);
-
- sp->scsi_done(sp);
- }
- }
-
- /* SCSI bus reset is complete. */
- esp->resetting_bus = 0;
- wake_up(&esp->reset_queue);
-
- /* Ok, now it is safe to get commands going once more. */
- if (esp->issue_SC)
- esp_exec_cmd(esp);
-
- return do_intr_end;
-}
-
-static int esp_do_resetbus(struct esp *esp)
-{
- ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));
- esp->resetting_bus = 1;
- esp_cmd(esp, ESP_CMD_RS);
-
- return do_intr_end;
-}
-
-/* Reset ESP chip, reset hanging bus, then kill active and
- * disconnected commands for targets without soft reset.
- *
- * The host_lock is acquired by caller.
- */
-static int esp_reset(struct scsi_cmnd *SCptr)
-{
- struct esp *esp = (struct esp *) SCptr->device->host->hostdata;
-
- spin_lock_irq(esp->ehost->host_lock);
- (void) esp_do_resetbus(esp);
- spin_unlock_irq(esp->ehost->host_lock);
-
- wait_event(esp->reset_queue, (esp->resetting_bus == 0));
-
- return SUCCESS;
-}
-
-/* Internal ESP done function. */
-static void esp_done(struct esp *esp, int error)
-{
- struct scsi_cmnd *done_SC = esp->current_SC;
-
- esp->current_SC = NULL;
-
- esp_release_dmabufs(esp, done_SC);
- done_SC->result = error;
-
- done_SC->scsi_done(done_SC);
-
- /* Bus is free, issue any commands in the queue. */
- if (esp->issue_SC && !esp->current_SC)
- esp_exec_cmd(esp);
-
-}
-
-/* Wheee, ESP interrupt engine. */
-
-/* Forward declarations. */
-static int esp_do_phase_determine(struct esp *esp);
-static int esp_do_data_finale(struct esp *esp);
-static int esp_select_complete(struct esp *esp);
-static int esp_do_status(struct esp *esp);
-static int esp_do_msgin(struct esp *esp);
-static int esp_do_msgindone(struct esp *esp);
-static int esp_do_msgout(struct esp *esp);
-static int esp_do_cmdbegin(struct esp *esp);
-
-#define sreg_datainp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)
-#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP)
-
-/* Read any bytes found in the FAS366 fifo, storing them into
- * the ESP driver software state structure.
- */
-static void hme_fifo_read(struct esp *esp)
-{
- u8 count = 0;
- u8 status = esp->sreg;
-
- /* Cannot safely frob the fifo for these following cases, but
- * we must always read the fifo when the reselect interrupt
- * is pending.
- */
- if (((esp->ireg & ESP_INTR_RSEL) == 0) &&
- (sreg_datainp(status) ||
- sreg_dataoutp(status) ||
- (esp->current_SC &&
- esp->current_SC->SCp.phase == in_data_done))) {
- ESPHME(("<wkaround_skipped>"));
- } else {
- unsigned long fcnt = sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES;
-
- /* The HME stores bytes in multiples of 2 in the fifo. */
- ESPHME(("hme_fifo[fcnt=%d", (int)fcnt));
- while (fcnt) {
- esp->hme_fifo_workaround_buffer[count++] =
- sbus_readb(esp->eregs + ESP_FDATA);
- esp->hme_fifo_workaround_buffer[count++] =
- sbus_readb(esp->eregs + ESP_FDATA);
- ESPHME(("<%02x,%02x>", esp->hme_fifo_workaround_buffer[count-2], esp->hme_fifo_workaround_buffer[count-1]));
- fcnt--;
- }
- if (sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_F1BYTE) {
- ESPHME(("<poke_byte>"));
- sbus_writeb(0, esp->eregs + ESP_FDATA);
- esp->hme_fifo_workaround_buffer[count++] =
- sbus_readb(esp->eregs + ESP_FDATA);
- ESPHME(("<%02x,0x00>", esp->hme_fifo_workaround_buffer[count-1]));
- ESPHME(("CMD_FLUSH"));
- esp_cmd(esp, ESP_CMD_FLUSH);
- } else {
- ESPHME(("no_xtra_byte"));
- }
- }
- ESPHME(("wkarnd_cnt=%d]", (int)count));
- esp->hme_fifo_workaround_count = count;
-}
-
-static inline void hme_fifo_push(struct esp *esp, u8 *bytes, u8 count)
-{
- esp_cmd(esp, ESP_CMD_FLUSH);
- while (count) {
- u8 tmp = *bytes++;
- sbus_writeb(tmp, esp->eregs + ESP_FDATA);
- sbus_writeb(0, esp->eregs + ESP_FDATA);
- count--;
- }
-}
-
-/* We try to avoid some interrupts by jumping ahead and see if the ESP
- * has gotten far enough yet. Hence the following.
- */
-static inline int skipahead1(struct esp *esp, struct scsi_cmnd *scp,
- int prev_phase, int new_phase)
-{
- if (scp->SCp.sent_command != prev_phase)
- return 0;
- if (ESP_IRQ_P(esp->dregs)) {
- /* Yes, we are able to save an interrupt. */
- if (esp->erev == fashme)
- esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);
- esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR));
- esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);
- if (esp->erev == fashme) {
- /* This chip is really losing. */
- ESPHME(("HME["));
- /* Must latch fifo before reading the interrupt
- * register else garbage ends up in the FIFO
- * which confuses the driver utterly.
- * Happy Meal indeed....
- */
- ESPHME(("fifo_workaround]"));
- if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
- (esp->sreg2 & ESP_STAT2_F1BYTE))
- hme_fifo_read(esp);
- }
- if (!(esp->ireg & ESP_INTR_SR))
- return 0;
- else
- return do_reset_complete;
- }
- /* Ho hum, target is taking forever... */
- scp->SCp.sent_command = new_phase; /* so we don't recurse... */
- return do_intr_end;
-}
-
-static inline int skipahead2(struct esp *esp, struct scsi_cmnd *scp,
- int prev_phase1, int prev_phase2, int new_phase)
-{
- if (scp->SCp.sent_command != prev_phase1 &&
- scp->SCp.sent_command != prev_phase2)
- return 0;
- if (ESP_IRQ_P(esp->dregs)) {
- /* Yes, we are able to save an interrupt. */
- if (esp->erev == fashme)
- esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);
- esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR));
- esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);
- if (esp->erev == fashme) {
- /* This chip is really losing. */
- ESPHME(("HME["));
-
- /* Must latch fifo before reading the interrupt
- * register else garbage ends up in the FIFO
- * which confuses the driver utterly.
- * Happy Meal indeed....
- */
- ESPHME(("fifo_workaround]"));
- if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
- (esp->sreg2 & ESP_STAT2_F1BYTE))
- hme_fifo_read(esp);
- }
- if (!(esp->ireg & ESP_INTR_SR))
- return 0;
- else
- return do_reset_complete;
- }
- /* Ho hum, target is taking forever... */
- scp->SCp.sent_command = new_phase; /* so we don't recurse... */
- return do_intr_end;
-}
-
-/* Now some dma helpers. */
-static void dma_setup(struct esp *esp, __u32 addr, int count, int write)
-{
- u32 nreg = sbus_readl(esp->dregs + DMA_CSR);
-
- if (write)
- nreg |= DMA_ST_WRITE;
- else
- nreg &= ~(DMA_ST_WRITE);
- nreg |= DMA_ENABLE;
- sbus_writel(nreg, esp->dregs + DMA_CSR);
- if (esp->dma->revision == dvmaesc1) {
- /* This ESC gate array sucks! */
- __u32 src = addr;
- __u32 dest = src + count;
-
- if (dest & (PAGE_SIZE - 1))
- count = PAGE_ALIGN(count);
- sbus_writel(count, esp->dregs + DMA_COUNT);
- }
- sbus_writel(addr, esp->dregs + DMA_ADDR);
-}
-
-static void dma_drain(struct esp *esp)
-{
- u32 tmp;
-
- if (esp->dma->revision == dvmahme)
- return;
- if ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_FIFO_ISDRAIN) {
- switch (esp->dma->revision) {
- default:
- tmp |= DMA_FIFO_STDRAIN;
- sbus_writel(tmp, esp->dregs + DMA_CSR);
-
- case dvmarev3:
- case dvmaesc1:
- while (sbus_readl(esp->dregs + DMA_CSR) & DMA_FIFO_ISDRAIN)
- udelay(1);
- };
- }
-}
-
-static void dma_invalidate(struct esp *esp)
-{
- u32 tmp;
-
- if (esp->dma->revision == dvmahme) {
- sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR);
-
- esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
- (DMA_PARITY_OFF | DMA_2CLKS |
- DMA_SCSI_DISAB | DMA_INT_ENAB)) &
- ~(DMA_ST_WRITE | DMA_ENABLE));
-
- sbus_writel(0, esp->dregs + DMA_CSR);
- sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
-
- /* This is necessary to avoid having the SCSI channel
- * engine lock up on us.
- */
- sbus_writel(0, esp->dregs + DMA_ADDR);
- } else {
- while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ)
- udelay(1);
-
- tmp &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);
- tmp |= DMA_FIFO_INV;
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- tmp &= ~DMA_FIFO_INV;
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- }
-}
-
-static inline void dma_flashclear(struct esp *esp)
-{
- dma_drain(esp);
- dma_invalidate(esp);
-}
-
-static int dma_can_transfer(struct esp *esp, struct scsi_cmnd *sp)
-{
- __u32 base, end, sz;
-
- if (esp->dma->revision == dvmarev3) {
- sz = sp->SCp.this_residual;
- if (sz > 0x1000000)
- sz = 0x1000000;
- } else {
- base = ((__u32)((unsigned long)sp->SCp.ptr));
- base &= (0x1000000 - 1);
- end = (base + sp->SCp.this_residual);
- if (end > 0x1000000)
- end = 0x1000000;
- sz = (end - base);
- }
- return sz;
-}
-
-/* Misc. esp helper macros. */
-#define esp_setcount(__eregs, __cnt, __hme) \
- sbus_writeb(((__cnt)&0xff), (__eregs) + ESP_TCLOW); \
- sbus_writeb((((__cnt)>>8)&0xff), (__eregs) + ESP_TCMED); \
- if (__hme) { \
- sbus_writeb((((__cnt)>>16)&0xff), (__eregs) + FAS_RLO); \
- sbus_writeb(0, (__eregs) + FAS_RHI); \
- }
-
-#define esp_getcount(__eregs, __hme) \
- ((sbus_readb((__eregs) + ESP_TCLOW)&0xff) | \
- ((sbus_readb((__eregs) + ESP_TCMED)&0xff) << 8) | \
- ((__hme) ? sbus_readb((__eregs) + FAS_RLO) << 16 : 0))
-
-#define fcount(__esp) \
- (((__esp)->erev == fashme) ? \
- (__esp)->hme_fifo_workaround_count : \
- sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_FBYTES)
-
-#define fnzero(__esp) \
- (((__esp)->erev == fashme) ? 0 : \
- sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_ONOTZERO)
-
-/* XXX speculative nops unnecessary when continuing amidst a data phase
- * XXX even on esp100!!! another case of flooding the bus with I/O reg
- * XXX writes...
- */
-#define esp_maybe_nop(__esp) \
- if ((__esp)->erev == esp100) \
- esp_cmd((__esp), ESP_CMD_NULL)
-
-#define sreg_to_dataphase(__sreg) \
- ((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain)
-
-/* The ESP100 when in synchronous data phase, can mistake a long final
- * REQ pulse from the target as an extra byte, it places whatever is on
- * the data lines into the fifo. For now, we will assume when this
- * happens that the target is a bit quirky and we don't want to
- * be talking synchronously to it anyways. Regardless, we need to
- * tell the ESP to eat the extraneous byte so that we can proceed
- * to the next phase.
- */
-static int esp100_sync_hwbug(struct esp *esp, struct scsi_cmnd *sp, int fifocnt)
-{
- /* Do not touch this piece of code. */
- if ((!(esp->erev == esp100)) ||
- (!(sreg_datainp((esp->sreg = sbus_readb(esp->eregs + ESP_STATUS))) &&
- !fifocnt) &&
- !(sreg_dataoutp(esp->sreg) && !fnzero(esp)))) {
- if (sp->SCp.phase == in_dataout)
- esp_cmd(esp, ESP_CMD_FLUSH);
- return 0;
- } else {
- /* Async mode for this guy. */
- build_sync_nego_msg(esp, 0, 0);
-
- /* Ack the bogus byte, but set ATN first. */
- esp_cmd(esp, ESP_CMD_SATN);
- esp_cmd(esp, ESP_CMD_MOK);
- return 1;
- }
-}
-
-/* This closes the window during a selection with a reselect pending, because
- * we use DMA for the selection process the FIFO should hold the correct
- * contents if we get reselected during this process. So we just need to
- * ack the possible illegal cmd interrupt pending on the esp100.
- */
-static inline int esp100_reconnect_hwbug(struct esp *esp)
-{
- u8 tmp;
-
- if (esp->erev != esp100)
- return 0;
- tmp = sbus_readb(esp->eregs + ESP_INTRPT);
- if (tmp & ESP_INTR_SR)
- return 1;
- return 0;
-}
-
-/* This verifies the BUSID bits during a reselection so that we know which
- * target is talking to us.
- */
-static inline int reconnect_target(struct esp *esp)
-{
- int it, me = esp->scsi_id_mask, targ = 0;
-
- if (2 != fcount(esp))
- return -1;
- if (esp->erev == fashme) {
- /* HME does not latch it's own BUS ID bits during
- * a reselection. Also the target number is given
- * as an unsigned char, not as a sole bit number
- * like the other ESP's do.
- * Happy Meal indeed....
- */
- targ = esp->hme_fifo_workaround_buffer[0];
- } else {
- it = sbus_readb(esp->eregs + ESP_FDATA);
- if (!(it & me))
- return -1;
- it &= ~me;
- if (it & (it - 1))
- return -1;
- while (!(it & 1))
- targ++, it >>= 1;
- }
- return targ;
-}
-
-/* This verifies the identify from the target so that we know which lun is
- * being reconnected.
- */
-static inline int reconnect_lun(struct esp *esp)
-{
- int lun;
-
- if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)
- return -1;
- if (esp->erev == fashme)
- lun = esp->hme_fifo_workaround_buffer[1];
- else
- lun = sbus_readb(esp->eregs + ESP_FDATA);
-
- /* Yes, you read this correctly. We report lun of zero
- * if we see parity error. ESP reports parity error for
- * the lun byte, and this is the only way to hope to recover
- * because the target is connected.
- */
- if (esp->sreg & ESP_STAT_PERR)
- return 0;
-
- /* Check for illegal bits being set in the lun. */
- if ((lun & 0x40) || !(lun & 0x80))
- return -1;
-
- return lun & 7;
-}
-
-/* This puts the driver in a state where it can revitalize a command that
- * is being continued due to reselection.
- */
-static inline void esp_connect(struct esp *esp, struct scsi_cmnd *sp)
-{
- struct esp_device *esp_dev = sp->device->hostdata;
-
- if (esp->prev_soff != esp_dev->sync_max_offset ||
- esp->prev_stp != esp_dev->sync_min_period ||
- (esp->erev > esp100a &&
- esp->prev_cfg3 != esp->config3[sp->device->id])) {
- esp->prev_soff = esp_dev->sync_max_offset;
- esp->prev_stp = esp_dev->sync_min_period;
- sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
- sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
- if (esp->erev > esp100a) {
- esp->prev_cfg3 = esp->config3[sp->device->id];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- }
- }
- esp->current_SC = sp;
-}
-
-/* This will place the current working command back into the issue queue
- * if we are to receive a reselection amidst a selection attempt.
- */
-static inline void esp_reconnect(struct esp *esp, struct scsi_cmnd *sp)
-{
- if (!esp->disconnected_SC)
- ESPLOG(("esp%d: Weird, being reselected but disconnected "
- "command queue is empty.\n", esp->esp_id));
- esp->snip = 0;
- esp->current_SC = NULL;
- sp->SCp.phase = not_issued;
- append_SC(&esp->issue_SC, sp);
-}
-
-/* Begin message in phase. */
-static int esp_do_msgin(struct esp *esp)
-{
- /* Must be very careful with the fifo on the HME */
- if ((esp->erev != fashme) ||
- !(sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_FEMPTY))
- esp_cmd(esp, ESP_CMD_FLUSH);
- esp_maybe_nop(esp);
- esp_cmd(esp, ESP_CMD_TI);
- esp->msgin_len = 1;
- esp->msgin_ctr = 0;
- esp_advance_phase(esp->current_SC, in_msgindone);
- return do_work_bus;
-}
-
-/* This uses various DMA csr fields and the fifo flags count value to
- * determine how many bytes were successfully sent/received by the ESP.
- */
-static inline int esp_bytes_sent(struct esp *esp, int fifo_count)
-{
- int rval = sbus_readl(esp->dregs + DMA_ADDR) - esp->esp_command_dvma;
-
- if (esp->dma->revision == dvmarev1)
- rval -= (4 - ((sbus_readl(esp->dregs + DMA_CSR) & DMA_READ_AHEAD)>>11));
- return rval - fifo_count;
-}
-
-static inline void advance_sg(struct scsi_cmnd *sp)
-{
- ++sp->SCp.buffer;
- --sp->SCp.buffers_residual;
- sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer);
- sp->SCp.ptr = (char *)((unsigned long)sg_dma_address(sp->SCp.buffer));
-}
-
-/* Please note that the way I've coded these routines is that I _always_
- * check for a disconnect during any and all information transfer
- * phases. The SCSI standard states that the target _can_ cause a BUS
- * FREE condition by dropping all MSG/CD/IO/BSY signals. Also note
- * that during information transfer phases the target controls every
- * change in phase, the only thing the initiator can do is "ask" for
- * a message out phase by driving ATN true. The target can, and sometimes
- * will, completely ignore this request so we cannot assume anything when
- * we try to force a message out phase to abort/reset a target. Most of
- * the time the target will eventually be nice and go to message out, so
- * we may have to hold on to our state about what we want to tell the target
- * for some period of time.
- */
-
-/* I think I have things working here correctly. Even partial transfers
- * within a buffer or sub-buffer should not upset us at all no matter
- * how bad the target and/or ESP fucks things up.
- */
-static int esp_do_data(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- int thisphase, hmuch;
-
- ESPDATA(("esp_do_data: "));
- esp_maybe_nop(esp);
- thisphase = sreg_to_dataphase(esp->sreg);
- esp_advance_phase(SCptr, thisphase);
- ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT"));
- hmuch = dma_can_transfer(esp, SCptr);
- if (hmuch > (64 * 1024) && (esp->erev != fashme))
- hmuch = (64 * 1024);
- ESPDATA(("hmuch<%d> ", hmuch));
- esp->current_transfer_size = hmuch;
-
- if (esp->erev == fashme) {
- u32 tmp = esp->prev_hme_dmacsr;
-
- /* Always set the ESP count registers first. */
- esp_setcount(esp->eregs, hmuch, 1);
-
- /* Get the DMA csr computed. */
- tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
- if (thisphase == in_datain)
- tmp |= DMA_ST_WRITE;
- else
- tmp &= ~(DMA_ST_WRITE);
- esp->prev_hme_dmacsr = tmp;
-
- ESPDATA(("DMA|TI --> do_intr_end\n"));
- if (thisphase == in_datain) {
- sbus_writel(hmuch, esp->dregs + DMA_COUNT);
- esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
- } else {
- esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
- sbus_writel(hmuch, esp->dregs + DMA_COUNT);
- }
- sbus_writel((__u32)((unsigned long)SCptr->SCp.ptr), esp->dregs+DMA_ADDR);
- sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
- } else {
- esp_setcount(esp->eregs, hmuch, 0);
- dma_setup(esp, ((__u32)((unsigned long)SCptr->SCp.ptr)),
- hmuch, (thisphase == in_datain));
- ESPDATA(("DMA|TI --> do_intr_end\n"));
- esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
- }
- return do_intr_end;
-}
-
-/* See how successful the data transfer was. */
-static int esp_do_data_finale(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- struct esp_device *esp_dev = SCptr->device->hostdata;
- int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0;
-
- ESPDATA(("esp_do_data_finale: "));
-
- if (SCptr->SCp.phase == in_datain) {
- if (esp->sreg & ESP_STAT_PERR) {
- /* Yuck, parity error. The ESP asserts ATN
- * so that we can go to message out phase
- * immediately and inform the target that
- * something bad happened.
- */
- ESPLOG(("esp%d: data bad parity detected.\n",
- esp->esp_id));
- esp->cur_msgout[0] = INITIATOR_ERROR;
- esp->msgout_len = 1;
- }
- dma_drain(esp);
- }
- dma_invalidate(esp);
-
- /* This could happen for the above parity error case. */
- if (esp->ireg != ESP_INTR_BSERV) {
- /* Please go to msgout phase, please please please... */
- ESPLOG(("esp%d: !BSERV after data, probably to msgout\n",
- esp->esp_id));
- return esp_do_phase_determine(esp);
- }
-
- /* Check for partial transfers and other horrible events.
- * Note, here we read the real fifo flags register even
- * on HME broken adapters because we skip the HME fifo
- * workaround code in esp_handle() if we are doing data
- * phase things. We don't want to fuck directly with
- * the fifo like that, especially if doing synchronous
- * transfers! Also, will need to double the count on
- * HME if we are doing wide transfers, as the HME fifo
- * will move and count 16-bit quantities during wide data.
- * SMCC _and_ Qlogic can both bite me.
- */
- fifocnt = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES);
- if (esp->erev != fashme)
- ecount = esp_getcount(esp->eregs, 0);
- bytes_sent = esp->current_transfer_size;
-
- ESPDATA(("trans_sz(%d), ", bytes_sent));
- if (esp->erev == fashme) {
- if (!(esp->sreg & ESP_STAT_TCNT)) {
- ecount = esp_getcount(esp->eregs, 1);
- bytes_sent -= ecount;
- }
-
- /* Always subtract any cruft remaining in the FIFO. */
- if (esp->prev_cfg3 & ESP_CONFIG3_EWIDE)
- fifocnt <<= 1;
- if (SCptr->SCp.phase == in_dataout)
- bytes_sent -= fifocnt;
-
- /* I have an IBM disk which exhibits the following
- * behavior during writes to it. It disconnects in
- * the middle of a partial transfer, the current sglist
- * buffer is 1024 bytes, the disk stops data transfer
- * at 512 bytes.
- *
- * However the FAS366 reports that 32 more bytes were
- * transferred than really were. This is precisely
- * the size of a fully loaded FIFO in wide scsi mode.
- * The FIFO state recorded indicates that it is empty.
- *
- * I have no idea if this is a bug in the FAS366 chip
- * or a bug in the firmware on this IBM disk. In any
- * event the following seems to be a good workaround. -DaveM
- */
- if (bytes_sent != esp->current_transfer_size &&
- SCptr->SCp.phase == in_dataout) {
- int mask = (64 - 1);
-
- if ((esp->prev_cfg3 & ESP_CONFIG3_EWIDE) == 0)
- mask >>= 1;
-
- if (bytes_sent & mask)
- bytes_sent -= (bytes_sent & mask);
- }
- } else {
- if (!(esp->sreg & ESP_STAT_TCNT))
- bytes_sent -= ecount;
- if (SCptr->SCp.phase == in_dataout)
- bytes_sent -= fifocnt;
- }
-
- ESPDATA(("bytes_sent(%d), ", bytes_sent));
-
- /* If we were in synchronous mode, check for peculiarities. */
- if (esp->erev == fashme) {
- if (esp_dev->sync_max_offset) {
- if (SCptr->SCp.phase == in_dataout)
- esp_cmd(esp, ESP_CMD_FLUSH);
- } else {
- esp_cmd(esp, ESP_CMD_FLUSH);
- }
- } else {
- if (esp_dev->sync_max_offset)
- bogus_data = esp100_sync_hwbug(esp, SCptr, fifocnt);
- else
- esp_cmd(esp, ESP_CMD_FLUSH);
- }
-
- /* Until we are sure of what has happened, we are certainly
- * in the dark.
- */
- esp_advance_phase(SCptr, in_the_dark);
-
- if (bytes_sent < 0) {
- /* I've seen this happen due to lost state in this
- * driver. No idea why it happened, but allowing
- * this value to be negative caused things to
- * lock up. This allows greater chance of recovery.
- * In fact every time I've seen this, it has been
- * a driver bug without question.
- */
- ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id));
- ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n",
- esp->esp_id,
- esp->current_transfer_size, fifocnt, ecount));
- ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n",
- esp->esp_id,
- SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual));
- ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id,
- SCptr->device->id));
- SCptr->device->borken = 1;
- esp_dev->sync = 0;
- bytes_sent = 0;
- }
-
- /* Update the state of our transfer. */
- SCptr->SCp.ptr += bytes_sent;
- SCptr->SCp.this_residual -= bytes_sent;
- if (SCptr->SCp.this_residual < 0) {
- /* shit */
- ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id));
- SCptr->SCp.this_residual = 0;
- }
-
- /* Maybe continue. */
- if (!bogus_data) {
- ESPDATA(("!bogus_data, "));
-
- /* NO MATTER WHAT, we advance the scatterlist,
- * if the target should decide to disconnect
- * in between scatter chunks (which is common)
- * we could die horribly! I used to have the sg
- * advance occur only if we are going back into
- * (or are staying in) a data phase, you can
- * imagine the hell I went through trying to
- * figure this out.
- */
- if (SCptr->use_sg && !SCptr->SCp.this_residual)
- advance_sg(SCptr);
- if (sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) {
- ESPDATA(("to more data\n"));
- return esp_do_data(esp);
- }
- ESPDATA(("to new phase\n"));
- return esp_do_phase_determine(esp);
- }
- /* Bogus data, just wait for next interrupt. */
- ESPLOG(("esp%d: bogus_data during end of data phase\n",
- esp->esp_id));
- return do_intr_end;
-}
-
-/* We received a non-good status return at the end of
- * running a SCSI command. This is used to decide if
- * we should clear our synchronous transfer state for
- * such a device when that happens.
- *
- * The idea is that when spinning up a disk or rewinding
- * a tape, we don't want to go into a loop re-negotiating
- * synchronous capabilities over and over.
- */
-static int esp_should_clear_sync(struct scsi_cmnd *sp)
-{
- u8 cmd = sp->cmnd[0];
-
- /* These cases are for spinning up a disk and
- * waiting for that spinup to complete.
- */
- if (cmd == START_STOP)
- return 0;
-
- if (cmd == TEST_UNIT_READY)
- return 0;
-
- /* One more special case for SCSI tape drives,
- * this is what is used to probe the device for
- * completion of a rewind or tape load operation.
- */
- if (sp->device->type == TYPE_TAPE) {
- if (cmd == MODE_SENSE)
- return 0;
- }
-
- return 1;
-}
-
-/* Either a command is completing or a target is dropping off the bus
- * to continue the command in the background so we can do other work.
- */
-static int esp_do_freebus(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- struct esp_device *esp_dev = SCptr->device->hostdata;
- int rval;
-
- rval = skipahead2(esp, SCptr, in_status, in_msgindone, in_freeing);
- if (rval)
- return rval;
- if (esp->ireg != ESP_INTR_DC) {
- ESPLOG(("esp%d: Target will not disconnect\n", esp->esp_id));
- return do_reset_bus; /* target will not drop BSY... */
- }
- esp->msgout_len = 0;
- esp->prevmsgout = NOP;
- if (esp->prevmsgin == COMMAND_COMPLETE) {
- /* Normal end of nexus. */
- if (esp->disconnected_SC || (esp->erev == fashme))
- esp_cmd(esp, ESP_CMD_ESEL);
-
- if (SCptr->SCp.Status != GOOD &&
- SCptr->SCp.Status != CONDITION_GOOD &&
- ((1<<SCptr->device->id) & esp->targets_present) &&
- esp_dev->sync &&
- esp_dev->sync_max_offset) {
- /* SCSI standard says that the synchronous capabilities
- * should be renegotiated at this point. Most likely
- * we are about to request sense from this target
- * in which case we want to avoid using sync
- * transfers until we are sure of the current target
- * state.
- */
- ESPMISC(("esp: Status <%d> for target %d lun %d\n",
- SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun));
-
- /* But don't do this when spinning up a disk at
- * boot time while we poll for completion as it
- * fills up the console with messages. Also, tapes
- * can report not ready many times right after
- * loading up a tape.
- */
- if (esp_should_clear_sync(SCptr) != 0)
- esp_dev->sync = 0;
- }
- ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
- esp_done(esp, ((SCptr->SCp.Status & 0xff) |
- ((SCptr->SCp.Message & 0xff)<<8) |
- (DID_OK << 16)));
- } else if (esp->prevmsgin == DISCONNECT) {
- /* Normal disconnect. */
- esp_cmd(esp, ESP_CMD_ESEL);
- ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
- append_SC(&esp->disconnected_SC, SCptr);
- esp->current_SC = NULL;
- if (esp->issue_SC)
- esp_exec_cmd(esp);
- } else {
- /* Driver bug, we do not expect a disconnect here
- * and should not have advanced the state engine
- * to in_freeing.
- */
- ESPLOG(("esp%d: last msg not disc and not cmd cmplt.\n",
- esp->esp_id));
- return do_reset_bus;
- }
- return do_intr_end;
-}
-
-/* When a reselect occurs, and we cannot find the command to
- * reconnect to in our queues, we do this.
- */
-static int esp_bad_reconnect(struct esp *esp)
-{
- struct scsi_cmnd *sp;
-
- ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n",
- esp->esp_id));
- ESPLOG(("QUEUE DUMP\n"));
- sp = esp->issue_SC;
- ESPLOG(("esp%d: issue_SC[", esp->esp_id));
- while (sp) {
- ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
- sp = (struct scsi_cmnd *) sp->host_scribble;
- }
- ESPLOG(("]\n"));
- sp = esp->current_SC;
- ESPLOG(("esp%d: current_SC[", esp->esp_id));
- if (sp)
- ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
- else
- ESPLOG(("<NULL>"));
- ESPLOG(("]\n"));
- sp = esp->disconnected_SC;
- ESPLOG(("esp%d: disconnected_SC[", esp->esp_id));
- while (sp) {
- ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
- sp = (struct scsi_cmnd *) sp->host_scribble;
- }
- ESPLOG(("]\n"));
- return do_reset_bus;
-}
-
-/* Do the needy when a target tries to reconnect to us. */
-static int esp_do_reconnect(struct esp *esp)
-{
- int lun, target;
- struct scsi_cmnd *SCptr;
-
- /* Check for all bogus conditions first. */
- target = reconnect_target(esp);
- if (target < 0) {
- ESPDISC(("bad bus bits\n"));
- return do_reset_bus;
- }
- lun = reconnect_lun(esp);
- if (lun < 0) {
- ESPDISC(("target=%2x, bad identify msg\n", target));
- return do_reset_bus;
- }
-
- /* Things look ok... */
- ESPDISC(("R<%02x,%02x>", target, lun));
-
- /* Must not flush FIFO or DVMA on HME. */
- if (esp->erev != fashme) {
- esp_cmd(esp, ESP_CMD_FLUSH);
- if (esp100_reconnect_hwbug(esp))
- return do_reset_bus;
- esp_cmd(esp, ESP_CMD_NULL);
- }
-
- SCptr = remove_SC(&esp->disconnected_SC, (u8) target, (u8) lun);
- if (!SCptr)
- return esp_bad_reconnect(esp);
-
- esp_connect(esp, SCptr);
- esp_cmd(esp, ESP_CMD_MOK);
-
- if (esp->erev == fashme)
- sbus_writeb(((SCptr->device->id & 0xf) |
- (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT)),
- esp->eregs + ESP_BUSID);
-
- /* Reconnect implies a restore pointers operation. */
- esp_restore_pointers(esp, SCptr);
-
- esp->snip = 0;
- esp_advance_phase(SCptr, in_the_dark);
- return do_intr_end;
-}
-
-/* End of NEXUS (hopefully), pick up status + message byte then leave if
- * all goes well.
- */
-static int esp_do_status(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- int intr, rval;
-
- rval = skipahead1(esp, SCptr, in_the_dark, in_status);
- if (rval)
- return rval;
- intr = esp->ireg;
- ESPSTAT(("esp_do_status: "));
- if (intr != ESP_INTR_DC) {
- int message_out = 0; /* for parity problems */
-
- /* Ack the message. */
- ESPSTAT(("ack msg, "));
- esp_cmd(esp, ESP_CMD_MOK);
-
- if (esp->erev != fashme) {
- dma_flashclear(esp);
-
- /* Wait till the first bits settle. */
- while (esp->esp_command[0] == 0xff)
- udelay(1);
- } else {
- esp->esp_command[0] = esp->hme_fifo_workaround_buffer[0];
- esp->esp_command[1] = esp->hme_fifo_workaround_buffer[1];
- }
-
- ESPSTAT(("got something, "));
- /* ESP chimes in with one of
- *
- * 1) function done interrupt:
- * both status and message in bytes
- * are available
- *
- * 2) bus service interrupt:
- * only status byte was acquired
- *
- * 3) Anything else:
- * can't happen, but we test for it
- * anyways
- *
- * ALSO: If bad parity was detected on either
- * the status _or_ the message byte then
- * the ESP has asserted ATN on the bus
- * and we must therefore wait for the
- * next phase change.
- */
- if (intr & ESP_INTR_FDONE) {
- /* We got it all, hallejulia. */
- ESPSTAT(("got both, "));
- SCptr->SCp.Status = esp->esp_command[0];
- SCptr->SCp.Message = esp->esp_command[1];
- esp->prevmsgin = SCptr->SCp.Message;
- esp->cur_msgin[0] = SCptr->SCp.Message;
- if (esp->sreg & ESP_STAT_PERR) {
- /* There was bad parity for the
- * message byte, the status byte
- * was ok.
- */
- message_out = MSG_PARITY_ERROR;
- }
- } else if (intr == ESP_INTR_BSERV) {
- /* Only got status byte. */
- ESPLOG(("esp%d: got status only, ", esp->esp_id));
- if (!(esp->sreg & ESP_STAT_PERR)) {
- SCptr->SCp.Status = esp->esp_command[0];
- SCptr->SCp.Message = 0xff;
- } else {
- /* The status byte had bad parity.
- * we leave the scsi_pointer Status
- * field alone as we set it to a default
- * of CHECK_CONDITION in esp_queue.
- */
- message_out = INITIATOR_ERROR;
- }
- } else {
- /* This shouldn't happen ever. */
- ESPSTAT(("got bolixed\n"));
- esp_advance_phase(SCptr, in_the_dark);
- return esp_do_phase_determine(esp);
- }
-
- if (!message_out) {
- ESPSTAT(("status=%2x msg=%2x, ", SCptr->SCp.Status,
- SCptr->SCp.Message));
- if (SCptr->SCp.Message == COMMAND_COMPLETE) {
- ESPSTAT(("and was COMMAND_COMPLETE\n"));
- esp_advance_phase(SCptr, in_freeing);
- return esp_do_freebus(esp);
- } else {
- ESPLOG(("esp%d: and _not_ COMMAND_COMPLETE\n",
- esp->esp_id));
- esp->msgin_len = esp->msgin_ctr = 1;
- esp_advance_phase(SCptr, in_msgindone);
- return esp_do_msgindone(esp);
- }
- } else {
- /* With luck we'll be able to let the target
- * know that bad parity happened, it will know
- * which byte caused the problems and send it
- * again. For the case where the status byte
- * receives bad parity, I do not believe most
- * targets recover very well. We'll see.
- */
- ESPLOG(("esp%d: bad parity somewhere mout=%2x\n",
- esp->esp_id, message_out));
- esp->cur_msgout[0] = message_out;
- esp->msgout_len = esp->msgout_ctr = 1;
- esp_advance_phase(SCptr, in_the_dark);
- return esp_do_phase_determine(esp);
- }
- } else {
- /* If we disconnect now, all hell breaks loose. */
- ESPLOG(("esp%d: whoops, disconnect\n", esp->esp_id));
- esp_advance_phase(SCptr, in_the_dark);
- return esp_do_phase_determine(esp);
- }
-}
-
-static int esp_enter_status(struct esp *esp)
-{
- u8 thecmd = ESP_CMD_ICCSEQ;
-
- esp_cmd(esp, ESP_CMD_FLUSH);
- if (esp->erev != fashme) {
- u32 tmp;
-
- esp->esp_command[0] = esp->esp_command[1] = 0xff;
- sbus_writeb(2, esp->eregs + ESP_TCLOW);
- sbus_writeb(0, esp->eregs + ESP_TCMED);
- tmp = sbus_readl(esp->dregs + DMA_CSR);
- tmp |= (DMA_ST_WRITE | DMA_ENABLE);
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- if (esp->dma->revision == dvmaesc1)
- sbus_writel(0x100, esp->dregs + DMA_COUNT);
- sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
- thecmd |= ESP_CMD_DMA;
- }
- esp_cmd(esp, thecmd);
- esp_advance_phase(esp->current_SC, in_status);
-
- return esp_do_status(esp);
-}
-
-static int esp_disconnect_amidst_phases(struct esp *esp)
-{
- struct scsi_cmnd *sp = esp->current_SC;
- struct esp_device *esp_dev = sp->device->hostdata;
-
- /* This means real problems if we see this
- * here. Unless we were actually trying
- * to force the device to abort/reset.
- */
- ESPLOG(("esp%d Disconnect amidst phases, ", esp->esp_id));
- ESPLOG(("pphase<%s> cphase<%s>, ",
- phase_string(sp->SCp.phase),
- phase_string(sp->SCp.sent_command)));
-
- if (esp->disconnected_SC != NULL || (esp->erev == fashme))
- esp_cmd(esp, ESP_CMD_ESEL);
-
- switch (esp->cur_msgout[0]) {
- default:
- /* We didn't expect this to happen at all. */
- ESPLOG(("device is bolixed\n"));
- esp_advance_phase(sp, in_tgterror);
- esp_done(esp, (DID_ERROR << 16));
- break;
-
- case BUS_DEVICE_RESET:
- ESPLOG(("device reset successful\n"));
- esp_dev->sync_max_offset = 0;
- esp_dev->sync_min_period = 0;
- esp_dev->sync = 0;
- esp_advance_phase(sp, in_resetdev);
- esp_done(esp, (DID_RESET << 16));
- break;
-
- case ABORT:
- ESPLOG(("device abort successful\n"));
- esp_advance_phase(sp, in_abortone);
- esp_done(esp, (DID_ABORT << 16));
- break;
-
- };
- return do_intr_end;
-}
-
-static int esp_enter_msgout(struct esp *esp)
-{
- esp_advance_phase(esp->current_SC, in_msgout);
- return esp_do_msgout(esp);
-}
-
-static int esp_enter_msgin(struct esp *esp)
-{
- esp_advance_phase(esp->current_SC, in_msgin);
- return esp_do_msgin(esp);
-}
-
-static int esp_enter_cmd(struct esp *esp)
-{
- esp_advance_phase(esp->current_SC, in_cmdbegin);
- return esp_do_cmdbegin(esp);
-}
-
-static int esp_enter_badphase(struct esp *esp)
-{
- ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id,
- esp->sreg & ESP_STAT_PMASK));
- return do_reset_bus;
-}
-
-typedef int (*espfunc_t)(struct esp *);
-
-static espfunc_t phase_vector[] = {
- esp_do_data, /* ESP_DOP */
- esp_do_data, /* ESP_DIP */
- esp_enter_cmd, /* ESP_CMDP */
- esp_enter_status, /* ESP_STATP */
- esp_enter_badphase, /* ESP_STAT_PMSG */
- esp_enter_badphase, /* ESP_STAT_PMSG | ESP_STAT_PIO */
- esp_enter_msgout, /* ESP_MOP */
- esp_enter_msgin, /* ESP_MIP */
-};
-
-/* The target has control of the bus and we have to see where it has
- * taken us.
- */
-static int esp_do_phase_determine(struct esp *esp)
-{
- if ((esp->ireg & ESP_INTR_DC) != 0)
- return esp_disconnect_amidst_phases(esp);
- return phase_vector[esp->sreg & ESP_STAT_PMASK](esp);
-}
-
-/* First interrupt after exec'ing a cmd comes here. */
-static int esp_select_complete(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- struct esp_device *esp_dev = SCptr->device->hostdata;
- int cmd_bytes_sent, fcnt;
-
- if (esp->erev != fashme)
- esp->seqreg = (sbus_readb(esp->eregs + ESP_SSTEP) & ESP_STEP_VBITS);
-
- if (esp->erev == fashme)
- fcnt = esp->hme_fifo_workaround_count;
- else
- fcnt = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES);
-
- cmd_bytes_sent = esp_bytes_sent(esp, fcnt);
- dma_invalidate(esp);
-
- /* Let's check to see if a reselect happened
- * while we we're trying to select. This must
- * be checked first.
- */
- if (esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) {
- esp_reconnect(esp, SCptr);
- return esp_do_reconnect(esp);
- }
-
- /* Looks like things worked, we should see a bus service &
- * a function complete interrupt at this point. Note we
- * are doing a direct comparison because we don't want to
- * be fooled into thinking selection was successful if
- * ESP_INTR_DC is set, see below.
- */
- if (esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) {
- /* target speaks... */
- esp->targets_present |= (1<<SCptr->device->id);
-
- /* What if the target ignores the sdtr? */
- if (esp->snip)
- esp_dev->sync = 1;
-
- /* See how far, if at all, we got in getting
- * the information out to the target.
- */
- switch (esp->seqreg) {
- default:
-
- case ESP_STEP_ASEL:
- /* Arbitration won, target selected, but
- * we are in some phase which is not command
- * phase nor is it message out phase.
- *
- * XXX We've confused the target, obviously.
- * XXX So clear it's state, but we also end
- * XXX up clearing everyone elses. That isn't
- * XXX so nice. I'd like to just reset this
- * XXX target, but if I cannot even get it's
- * XXX attention and finish selection to talk
- * XXX to it, there is not much more I can do.
- * XXX If we have a loaded bus we're going to
- * XXX spend the next second or so renegotiating
- * XXX for synchronous transfers.
- */
- ESPLOG(("esp%d: STEP_ASEL for tgt %d\n",
- esp->esp_id, SCptr->device->id));
-
- case ESP_STEP_SID:
- /* Arbitration won, target selected, went
- * to message out phase, sent one message
- * byte, then we stopped. ATN is asserted
- * on the SCSI bus and the target is still
- * there hanging on. This is a legal
- * sequence step if we gave the ESP a select
- * and stop command.
- *
- * XXX See above, I could set the borken flag
- * XXX in the device struct and retry the
- * XXX command. But would that help for
- * XXX tagged capable targets?
- */
-
- case ESP_STEP_NCMD:
- /* Arbitration won, target selected, maybe
- * sent the one message byte in message out
- * phase, but we did not go to command phase
- * in the end. Actually, we could have sent
- * only some of the message bytes if we tried
- * to send out the entire identify and tag
- * message using ESP_CMD_SA3.
- */
- cmd_bytes_sent = 0;
- break;
-
- case ESP_STEP_PPC:
- /* No, not the powerPC pinhead. Arbitration
- * won, all message bytes sent if we went to
- * message out phase, went to command phase
- * but only part of the command was sent.
- *
- * XXX I've seen this, but usually in conjunction
- * XXX with a gross error which appears to have
- * XXX occurred between the time I told the
- * XXX ESP to arbitrate and when I got the
- * XXX interrupt. Could I have misloaded the
- * XXX command bytes into the fifo? Actually,
- * XXX I most likely missed a phase, and therefore
- * XXX went into never never land and didn't even
- * XXX know it. That was the old driver though.
- * XXX What is even more peculiar is that the ESP
- * XXX showed the proper function complete and
- * XXX bus service bits in the interrupt register.
- */
-
- case ESP_STEP_FINI4:
- case ESP_STEP_FINI5:
- case ESP_STEP_FINI6:
- case ESP_STEP_FINI7:
- /* Account for the identify message */
- if (SCptr->SCp.phase == in_slct_norm)
- cmd_bytes_sent -= 1;
- };
-
- if (esp->erev != fashme)
- esp_cmd(esp, ESP_CMD_NULL);
-
- /* Be careful, we could really get fucked during synchronous
- * data transfers if we try to flush the fifo now.
- */
- if ((esp->erev != fashme) && /* not a Happy Meal and... */
- !fcnt && /* Fifo is empty and... */
- /* either we are not doing synchronous transfers or... */
- (!esp_dev->sync_max_offset ||
- /* We are not going into data in phase. */
- ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP)))
- esp_cmd(esp, ESP_CMD_FLUSH); /* flush is safe */
-
- /* See how far we got if this is not a slow command. */
- if (!esp->esp_slowcmd) {
- if (cmd_bytes_sent < 0)
- cmd_bytes_sent = 0;
- if (cmd_bytes_sent != SCptr->cmd_len) {
- /* Crapola, mark it as a slowcmd
- * so that we have some chance of
- * keeping the command alive with
- * good luck.
- *
- * XXX Actually, if we didn't send it all
- * XXX this means either we didn't set things
- * XXX up properly (driver bug) or the target
- * XXX or the ESP detected parity on one of
- * XXX the command bytes. This makes much
- * XXX more sense, and therefore this code
- * XXX should be changed to send out a
- * XXX parity error message or if the status
- * XXX register shows no parity error then
- * XXX just expect the target to bring the
- * XXX bus into message in phase so that it
- * XXX can send us the parity error message.
- * XXX SCSI sucks...
- */
- esp->esp_slowcmd = 1;
- esp->esp_scmdp = &(SCptr->cmnd[cmd_bytes_sent]);
- esp->esp_scmdleft = (SCptr->cmd_len - cmd_bytes_sent);
- }
- }
-
- /* Now figure out where we went. */
- esp_advance_phase(SCptr, in_the_dark);
- return esp_do_phase_determine(esp);
- }
-
- /* Did the target even make it? */
- if (esp->ireg == ESP_INTR_DC) {
- /* wheee... nobody there or they didn't like
- * what we told it to do, clean up.
- */
-
- /* If anyone is off the bus, but working on
- * a command in the background for us, tell
- * the ESP to listen for them.
- */
- if (esp->disconnected_SC)
- esp_cmd(esp, ESP_CMD_ESEL);
-
- if (((1<<SCptr->device->id) & esp->targets_present) &&
- esp->seqreg != 0 &&
- (esp->cur_msgout[0] == EXTENDED_MESSAGE) &&
- (SCptr->SCp.phase == in_slct_msg ||
- SCptr->SCp.phase == in_slct_stop)) {
- /* shit */
- esp->snip = 0;
- ESPLOG(("esp%d: Failed synchronous negotiation for target %d "
- "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
- esp_dev->sync_max_offset = 0;
- esp_dev->sync_min_period = 0;
- esp_dev->sync = 1; /* so we don't negotiate again */
-
- /* Run the command again, this time though we
- * won't try to negotiate for synchronous transfers.
- *
- * XXX I'd like to do something like send an
- * XXX INITIATOR_ERROR or ABORT message to the
- * XXX target to tell it, "Sorry I confused you,
- * XXX please come back and I will be nicer next
- * XXX time". But that requires having the target
- * XXX on the bus, and it has dropped BSY on us.
- */
- esp->current_SC = NULL;
- esp_advance_phase(SCptr, not_issued);
- prepend_SC(&esp->issue_SC, SCptr);
- esp_exec_cmd(esp);
- return do_intr_end;
- }
-
- /* Ok, this is normal, this is what we see during boot
- * or whenever when we are scanning the bus for targets.
- * But first make sure that is really what is happening.
- */
- if (((1<<SCptr->device->id) & esp->targets_present)) {
- ESPLOG(("esp%d: Warning, live target %d not responding to "
- "selection.\n", esp->esp_id, SCptr->device->id));
-
- /* This _CAN_ happen. The SCSI standard states that
- * the target is to _not_ respond to selection if
- * _it_ detects bad parity on the bus for any reason.
- * Therefore, we assume that if we've talked successfully
- * to this target before, bad parity is the problem.
- */
- esp_done(esp, (DID_PARITY << 16));
- } else {
- /* Else, there really isn't anyone there. */
- ESPMISC(("esp: selection failure, maybe nobody there?\n"));
- ESPMISC(("esp: target %d lun %d\n",
- SCptr->device->id, SCptr->device->lun));
- esp_done(esp, (DID_BAD_TARGET << 16));
- }
- return do_intr_end;
- }
-
- ESPLOG(("esp%d: Selection failure.\n", esp->esp_id));
- printk("esp%d: Currently -- ", esp->esp_id);
- esp_print_ireg(esp->ireg); printk(" ");
- esp_print_statreg(esp->sreg); printk(" ");
- esp_print_seqreg(esp->seqreg); printk("\n");
- printk("esp%d: New -- ", esp->esp_id);
- esp->sreg = sbus_readb(esp->eregs + ESP_STATUS);
- esp->seqreg = sbus_readb(esp->eregs + ESP_SSTEP);
- esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);
- esp_print_ireg(esp->ireg); printk(" ");
- esp_print_statreg(esp->sreg); printk(" ");
- esp_print_seqreg(esp->seqreg); printk("\n");
- ESPLOG(("esp%d: resetting bus\n", esp->esp_id));
- return do_reset_bus; /* ugh... */
-}
-
-/* Continue reading bytes for msgin phase. */
-static int esp_do_msgincont(struct esp *esp)
-{
- if (esp->ireg & ESP_INTR_BSERV) {
- /* in the right phase too? */
- if ((esp->sreg & ESP_STAT_PMASK) == ESP_MIP) {
- /* phew... */
- esp_cmd(esp, ESP_CMD_TI);
- esp_advance_phase(esp->current_SC, in_msgindone);
- return do_intr_end;
- }
-
- /* We changed phase but ESP shows bus service,
- * in this case it is most likely that we, the
- * hacker who has been up for 20hrs straight
- * staring at the screen, drowned in coffee
- * smelling like retched cigarette ashes
- * have miscoded something..... so, try to
- * recover as best we can.
- */
- ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id));
- }
- esp_advance_phase(esp->current_SC, in_the_dark);
- return do_phase_determine;
-}
-
-static int check_singlebyte_msg(struct esp *esp)
-{
- esp->prevmsgin = esp->cur_msgin[0];
- if (esp->cur_msgin[0] & 0x80) {
- /* wheee... */
- ESPLOG(("esp%d: target sends identify amidst phases\n",
- esp->esp_id));
- esp_advance_phase(esp->current_SC, in_the_dark);
- return 0;
- } else if (((esp->cur_msgin[0] & 0xf0) == 0x20) ||
- (esp->cur_msgin[0] == EXTENDED_MESSAGE)) {
- esp->msgin_len = 2;
- esp_advance_phase(esp->current_SC, in_msgincont);
- return 0;
- }
- esp_advance_phase(esp->current_SC, in_the_dark);
- switch (esp->cur_msgin[0]) {
- default:
- /* We don't want to hear about it. */
- ESPLOG(("esp%d: msg %02x which we don't know about\n", esp->esp_id,
- esp->cur_msgin[0]));
- return MESSAGE_REJECT;
-
- case NOP:
- ESPLOG(("esp%d: target %d sends a nop\n", esp->esp_id,
- esp->current_SC->device->id));
- return 0;
-
- case RESTORE_POINTERS:
- /* In this case we might also have to backup the
- * "slow command" pointer. It is rare to get such
- * a save/restore pointer sequence so early in the
- * bus transition sequences, but cover it.
- */
- if (esp->esp_slowcmd) {
- esp->esp_scmdleft = esp->current_SC->cmd_len;
- esp->esp_scmdp = &esp->current_SC->cmnd[0];
- }
- esp_restore_pointers(esp, esp->current_SC);
- return 0;
-
- case SAVE_POINTERS:
- esp_save_pointers(esp, esp->current_SC);
- return 0;
-
- case COMMAND_COMPLETE:
- case DISCONNECT:
- /* Freeing the bus, let it go. */
- esp->current_SC->SCp.phase = in_freeing;
- return 0;
-
- case MESSAGE_REJECT:
- ESPMISC(("msg reject, "));
- if (esp->prevmsgout == EXTENDED_MESSAGE) {
- struct esp_device *esp_dev = esp->current_SC->device->hostdata;
-
- /* Doesn't look like this target can
- * do synchronous or WIDE transfers.
- */
- ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n"));
- esp_dev->sync = 1;
- esp_dev->wide = 1;
- esp_dev->sync_min_period = 0;
- esp_dev->sync_max_offset = 0;
- return 0;
- } else {
- ESPMISC(("not sync nego, sending ABORT\n"));
- return ABORT;
- }
- };
-}
-
-/* Target negotiates for synchronous transfers before we do, this
- * is legal although very strange. What is even funnier is that
- * the SCSI2 standard specifically recommends against targets doing
- * this because so many initiators cannot cope with this occurring.
- */
-static int target_with_ants_in_pants(struct esp *esp,
- struct scsi_cmnd *SCptr,
- struct esp_device *esp_dev)
-{
- if (esp_dev->sync || SCptr->device->borken) {
- /* sorry, no can do */
- ESPSDTR(("forcing to async, "));
- build_sync_nego_msg(esp, 0, 0);
- esp_dev->sync = 1;
- esp->snip = 1;
- ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id));
- esp_advance_phase(SCptr, in_the_dark);
- return EXTENDED_MESSAGE;
- }
-
- /* Ok, we'll check them out... */
- return 0;
-}
-
-static void sync_report(struct esp *esp)
-{
- int msg3, msg4;
- char *type;
-
- msg3 = esp->cur_msgin[3];
- msg4 = esp->cur_msgin[4];
- if (msg4) {
- int hz = 1000000000 / (msg3 * 4);
- int integer = hz / 1000000;
- int fraction = (hz - (integer * 1000000)) / 10000;
- if ((esp->erev == fashme) &&
- (esp->config3[esp->current_SC->device->id] & ESP_CONFIG3_EWIDE)) {
- type = "FAST-WIDE";
- integer <<= 1;
- fraction <<= 1;
- } else if ((msg3 * 4) < 200) {
- type = "FAST";
- } else {
- type = "synchronous";
- }
-
- /* Do not transform this back into one big printk
- * again, it triggers a bug in our sparc64-gcc272
- * sibling call optimization. -DaveM
- */
- ESPLOG((KERN_INFO "esp%d: target %d ",
- esp->esp_id, esp->current_SC->device->id));
- ESPLOG(("[period %dns offset %d %d.%02dMHz ",
- (int) msg3 * 4, (int) msg4,
- integer, fraction));
- ESPLOG(("%s SCSI%s]\n", type,
- (((msg3 * 4) < 200) ? "-II" : "")));
- } else {
- ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n",
- esp->esp_id, esp->current_SC->device->id));
- }
-}
-
-static int check_multibyte_msg(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- struct esp_device *esp_dev = SCptr->device->hostdata;
- u8 regval = 0;
- int message_out = 0;
-
- ESPSDTR(("chk multibyte msg: "));
- if (esp->cur_msgin[2] == EXTENDED_SDTR) {
- int period = esp->cur_msgin[3];
- int offset = esp->cur_msgin[4];
-
- ESPSDTR(("is sync nego response, "));
- if (!esp->snip) {
- int rval;
-
- /* Target negotiates first! */
- ESPSDTR(("target jumps the gun, "));
- message_out = EXTENDED_MESSAGE; /* we must respond */
- rval = target_with_ants_in_pants(esp, SCptr, esp_dev);
- if (rval)
- return rval;
- }
-
- ESPSDTR(("examining sdtr, "));
-
- /* Offset cannot be larger than ESP fifo size. */
- if (offset > 15) {
- ESPSDTR(("offset too big %2x, ", offset));
- offset = 15;
- ESPSDTR(("sending back new offset\n"));
- build_sync_nego_msg(esp, period, offset);
- return EXTENDED_MESSAGE;
- }
-
- if (offset && period > esp->max_period) {
- /* Yeee, async for this slow device. */
- ESPSDTR(("period too long %2x, ", period));
- build_sync_nego_msg(esp, 0, 0);
- ESPSDTR(("hoping for msgout\n"));
- esp_advance_phase(esp->current_SC, in_the_dark);
- return EXTENDED_MESSAGE;
- } else if (offset && period < esp->min_period) {
- ESPSDTR(("period too short %2x, ", period));
- period = esp->min_period;
- if (esp->erev > esp236)
- regval = 4;
- else
- regval = 5;
- } else if (offset) {
- int tmp;
-
- ESPSDTR(("period is ok, "));
- tmp = esp->ccycle / 1000;
- regval = (((period << 2) + tmp - 1) / tmp);
- if (regval && ((esp->erev == fas100a ||
- esp->erev == fas236 ||
- esp->erev == fashme))) {
- if (period >= 50)
- regval--;
- }
- }
-
- if (offset) {
- u8 bit;
-
- esp_dev->sync_min_period = (regval & 0x1f);
- esp_dev->sync_max_offset = (offset | esp->radelay);
- if (esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme) {
- if ((esp->erev == fas100a) || (esp->erev == fashme))
- bit = ESP_CONFIG3_FAST;
- else
- bit = ESP_CONFIG3_FSCSI;
- if (period < 50) {
- /* On FAS366, if using fast-20 synchronous transfers
- * we need to make sure the REQ/ACK assert/deassert
- * control bits are clear.
- */
- if (esp->erev == fashme)
- esp_dev->sync_max_offset &= ~esp->radelay;
- esp->config3[SCptr->device->id] |= bit;
- } else {
- esp->config3[SCptr->device->id] &= ~bit;
- }
- esp->prev_cfg3 = esp->config3[SCptr->device->id];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- }
- esp->prev_soff = esp_dev->sync_max_offset;
- esp->prev_stp = esp_dev->sync_min_period;
- sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
- sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
- ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
- esp_dev->sync_max_offset,
- esp_dev->sync_min_period,
- esp->config3[SCptr->device->id]));
-
- esp->snip = 0;
- } else if (esp_dev->sync_max_offset) {
- u8 bit;
-
- /* back to async mode */
- ESPSDTR(("unaccaptable sync nego, forcing async\n"));
- esp_dev->sync_max_offset = 0;
- esp_dev->sync_min_period = 0;
- esp->prev_soff = 0;
- esp->prev_stp = 0;
- sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
- sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
- if (esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme) {
- if ((esp->erev == fas100a) || (esp->erev == fashme))
- bit = ESP_CONFIG3_FAST;
- else
- bit = ESP_CONFIG3_FSCSI;
- esp->config3[SCptr->device->id] &= ~bit;
- esp->prev_cfg3 = esp->config3[SCptr->device->id];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
- }
- }
-
- sync_report(esp);
-
- ESPSDTR(("chk multibyte msg: sync is known, "));
- esp_dev->sync = 1;
-
- if (message_out) {
- ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n",
- esp->esp_id));
- build_sync_nego_msg(esp, period, offset);
- esp_advance_phase(SCptr, in_the_dark);
- return EXTENDED_MESSAGE;
- }
-
- ESPSDTR(("returning zero\n"));
- esp_advance_phase(SCptr, in_the_dark); /* ...or else! */
- return 0;
- } else if (esp->cur_msgin[2] == EXTENDED_WDTR) {
- int size = 8 << esp->cur_msgin[3];
-
- esp->wnip = 0;
- if (esp->erev != fashme) {
- ESPLOG(("esp%d: AIEEE wide msg received and not HME.\n",
- esp->esp_id));
- message_out = MESSAGE_REJECT;
- } else if (size > 16) {
- ESPLOG(("esp%d: AIEEE wide transfer for %d size "
- "not supported.\n", esp->esp_id, size));
- message_out = MESSAGE_REJECT;
- } else {
- /* Things look good; let's see what we got. */
- if (size == 16) {
- /* Set config 3 register for this target. */
- esp->config3[SCptr->device->id] |= ESP_CONFIG3_EWIDE;
- } else {
- /* Just make sure it was one byte sized. */
- if (size != 8) {
- ESPLOG(("esp%d: Aieee, wide nego of %d size.\n",
- esp->esp_id, size));
- message_out = MESSAGE_REJECT;
- goto finish;
- }
- /* Pure paranoia. */
- esp->config3[SCptr->device->id] &= ~(ESP_CONFIG3_EWIDE);
- }
- esp->prev_cfg3 = esp->config3[SCptr->device->id];
- sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
-
- /* Regardless, next try for sync transfers. */
- build_sync_nego_msg(esp, esp->sync_defp, 15);
- esp_dev->sync = 1;
- esp->snip = 1;
- message_out = EXTENDED_MESSAGE;
- }
- } else if (esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) {
- ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id));
- message_out = MESSAGE_REJECT;
- }
-finish:
- esp_advance_phase(SCptr, in_the_dark);
- return message_out;
-}
-
-static int esp_do_msgindone(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- int message_out = 0, it = 0, rval;
-
- rval = skipahead1(esp, SCptr, in_msgin, in_msgindone);
- if (rval)
- return rval;
- if (SCptr->SCp.sent_command != in_status) {
- if (!(esp->ireg & ESP_INTR_DC)) {
- if (esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) {
- message_out = MSG_PARITY_ERROR;
- esp_cmd(esp, ESP_CMD_FLUSH);
- } else if (esp->erev != fashme &&
- (it = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES)) != 1) {
- /* We certainly dropped the ball somewhere. */
- message_out = INITIATOR_ERROR;
- esp_cmd(esp, ESP_CMD_FLUSH);
- } else if (!esp->msgin_len) {
- if (esp->erev == fashme)
- it = esp->hme_fifo_workaround_buffer[0];
- else
- it = sbus_readb(esp->eregs + ESP_FDATA);
- esp_advance_phase(SCptr, in_msgincont);
- } else {
- /* it is ok and we want it */
- if (esp->erev == fashme)
- it = esp->cur_msgin[esp->msgin_ctr] =
- esp->hme_fifo_workaround_buffer[0];
- else
- it = esp->cur_msgin[esp->msgin_ctr] =
- sbus_readb(esp->eregs + ESP_FDATA);
- esp->msgin_ctr++;
- }
- } else {
- esp_advance_phase(SCptr, in_the_dark);
- return do_work_bus;
- }
- } else {
- it = esp->cur_msgin[0];
- }
- if (!message_out && esp->msgin_len) {
- if (esp->msgin_ctr < esp->msgin_len) {
- esp_advance_phase(SCptr, in_msgincont);
- } else if (esp->msgin_len == 1) {
- message_out = check_singlebyte_msg(esp);
- } else if (esp->msgin_len == 2) {
- if (esp->cur_msgin[0] == EXTENDED_MESSAGE) {
- if ((it + 2) >= 15) {
- message_out = MESSAGE_REJECT;
- } else {
- esp->msgin_len = (it + 2);
- esp_advance_phase(SCptr, in_msgincont);
- }
- } else {
- message_out = MESSAGE_REJECT; /* foo on you */
- }
- } else {
- message_out = check_multibyte_msg(esp);
- }
- }
- if (message_out < 0) {
- return -message_out;
- } else if (message_out) {
- if (((message_out != 1) &&
- ((message_out < 0x20) || (message_out & 0x80))))
- esp->msgout_len = 1;
- esp->cur_msgout[0] = message_out;
- esp_cmd(esp, ESP_CMD_SATN);
- esp_advance_phase(SCptr, in_the_dark);
- esp->msgin_len = 0;
- }
- esp->sreg = sbus_readb(esp->eregs + ESP_STATUS);
- esp->sreg &= ~(ESP_STAT_INTR);
- if ((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD))
- esp_cmd(esp, ESP_CMD_MOK);
- if ((SCptr->SCp.sent_command == in_msgindone) &&
- (SCptr->SCp.phase == in_freeing))
- return esp_do_freebus(esp);
- return do_intr_end;
-}
-
-static int esp_do_cmdbegin(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
-
- esp_advance_phase(SCptr, in_cmdend);
- if (esp->erev == fashme) {
- u32 tmp = sbus_readl(esp->dregs + DMA_CSR);
- int i;
-
- for (i = 0; i < esp->esp_scmdleft; i++)
- esp->esp_command[i] = *esp->esp_scmdp++;
- esp->esp_scmdleft = 0;
- esp_cmd(esp, ESP_CMD_FLUSH);
- esp_setcount(esp->eregs, i, 1);
- esp_cmd(esp, (ESP_CMD_DMA | ESP_CMD_TI));
- tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
- tmp &= ~(DMA_ST_WRITE);
- sbus_writel(i, esp->dregs + DMA_COUNT);
- sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- } else {
- u8 tmp;
-
- esp_cmd(esp, ESP_CMD_FLUSH);
- tmp = *esp->esp_scmdp++;
- esp->esp_scmdleft--;
- sbus_writeb(tmp, esp->eregs + ESP_FDATA);
- esp_cmd(esp, ESP_CMD_TI);
- }
- return do_intr_end;
-}
-
-static int esp_do_cmddone(struct esp *esp)
-{
- if (esp->erev == fashme)
- dma_invalidate(esp);
- else
- esp_cmd(esp, ESP_CMD_NULL);
-
- if (esp->ireg & ESP_INTR_BSERV) {
- esp_advance_phase(esp->current_SC, in_the_dark);
- return esp_do_phase_determine(esp);
- }
-
- ESPLOG(("esp%d: in do_cmddone() but didn't get BSERV interrupt.\n",
- esp->esp_id));
- return do_reset_bus;
-}
-
-static int esp_do_msgout(struct esp *esp)
-{
- esp_cmd(esp, ESP_CMD_FLUSH);
- switch (esp->msgout_len) {
- case 1:
- if (esp->erev == fashme)
- hme_fifo_push(esp, &esp->cur_msgout[0], 1);
- else
- sbus_writeb(esp->cur_msgout[0], esp->eregs + ESP_FDATA);
-
- esp_cmd(esp, ESP_CMD_TI);
- break;
-
- case 2:
- esp->esp_command[0] = esp->cur_msgout[0];
- esp->esp_command[1] = esp->cur_msgout[1];
-
- if (esp->erev == fashme) {
- hme_fifo_push(esp, &esp->cur_msgout[0], 2);
- esp_cmd(esp, ESP_CMD_TI);
- } else {
- dma_setup(esp, esp->esp_command_dvma, 2, 0);
- esp_setcount(esp->eregs, 2, 0);
- esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
- }
- break;
-
- case 4:
- esp->esp_command[0] = esp->cur_msgout[0];
- esp->esp_command[1] = esp->cur_msgout[1];
- esp->esp_command[2] = esp->cur_msgout[2];
- esp->esp_command[3] = esp->cur_msgout[3];
- esp->snip = 1;
-
- if (esp->erev == fashme) {
- hme_fifo_push(esp, &esp->cur_msgout[0], 4);
- esp_cmd(esp, ESP_CMD_TI);
- } else {
- dma_setup(esp, esp->esp_command_dvma, 4, 0);
- esp_setcount(esp->eregs, 4, 0);
- esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
- }
- break;
-
- case 5:
- esp->esp_command[0] = esp->cur_msgout[0];
- esp->esp_command[1] = esp->cur_msgout[1];
- esp->esp_command[2] = esp->cur_msgout[2];
- esp->esp_command[3] = esp->cur_msgout[3];
- esp->esp_command[4] = esp->cur_msgout[4];
- esp->snip = 1;
-
- if (esp->erev == fashme) {
- hme_fifo_push(esp, &esp->cur_msgout[0], 5);
- esp_cmd(esp, ESP_CMD_TI);
- } else {
- dma_setup(esp, esp->esp_command_dvma, 5, 0);
- esp_setcount(esp->eregs, 5, 0);
- esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
- }
- break;
-
- default:
- /* whoops */
- ESPMISC(("bogus msgout sending NOP\n"));
- esp->cur_msgout[0] = NOP;
-
- if (esp->erev == fashme) {
- hme_fifo_push(esp, &esp->cur_msgout[0], 1);
- } else {
- sbus_writeb(esp->cur_msgout[0], esp->eregs + ESP_FDATA);
- }
-
- esp->msgout_len = 1;
- esp_cmd(esp, ESP_CMD_TI);
- break;
- };
-
- esp_advance_phase(esp->current_SC, in_msgoutdone);
- return do_intr_end;
-}
-
-static int esp_do_msgoutdone(struct esp *esp)
-{
- if (esp->msgout_len > 1) {
- /* XXX HME/FAS ATN deassert workaround required,
- * XXX no DMA flushing, only possible ESP_CMD_FLUSH
- * XXX to kill the fifo.
- */
- if (esp->erev != fashme) {
- u32 tmp;
-
- while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ)
- udelay(1);
- tmp &= ~DMA_ENABLE;
- sbus_writel(tmp, esp->dregs + DMA_CSR);
- dma_invalidate(esp);
- } else {
- esp_cmd(esp, ESP_CMD_FLUSH);
- }
- }
- if (!(esp->ireg & ESP_INTR_DC)) {
- if (esp->erev != fashme)
- esp_cmd(esp, ESP_CMD_NULL);
- switch (esp->sreg & ESP_STAT_PMASK) {
- case ESP_MOP:
- /* whoops, parity error */
- ESPLOG(("esp%d: still in msgout, parity error assumed\n",
- esp->esp_id));
- if (esp->msgout_len > 1)
- esp_cmd(esp, ESP_CMD_SATN);
- esp_advance_phase(esp->current_SC, in_msgout);
- return do_work_bus;
-
- case ESP_DIP:
- break;
-
- default:
- /* Happy Meal fifo is touchy... */
- if ((esp->erev != fashme) &&
- !fcount(esp) &&
- !(((struct esp_device *)esp->current_SC->device->hostdata)->sync_max_offset))
- esp_cmd(esp, ESP_CMD_FLUSH);
- break;
-
- };
- } else {
- ESPLOG(("esp%d: disconnect, resetting bus\n", esp->esp_id));
- return do_reset_bus;
- }
-
- /* If we sent out a synchronous negotiation message, update
- * our state.
- */
- if (esp->cur_msgout[2] == EXTENDED_MESSAGE &&
- esp->cur_msgout[4] == EXTENDED_SDTR) {
- esp->snip = 1; /* anal retentiveness... */
- }
-
- esp->prevmsgout = esp->cur_msgout[0];
- esp->msgout_len = 0;
- esp_advance_phase(esp->current_SC, in_the_dark);
- return esp_do_phase_determine(esp);
-}
-
-static int esp_bus_unexpected(struct esp *esp)
-{
- ESPLOG(("esp%d: command in weird state %2x\n",
- esp->esp_id, esp->current_SC->SCp.phase));
- return do_reset_bus;
-}
-
-static espfunc_t bus_vector[] = {
- esp_do_data_finale,
- esp_do_data_finale,
- esp_bus_unexpected,
- esp_do_msgin,
- esp_do_msgincont,
- esp_do_msgindone,
- esp_do_msgout,
- esp_do_msgoutdone,
- esp_do_cmdbegin,
- esp_do_cmddone,
- esp_do_status,
- esp_do_freebus,
- esp_do_phase_determine,
- esp_bus_unexpected,
- esp_bus_unexpected,
- esp_bus_unexpected,
-};
-
-/* This is the second tier in our dual-level SCSI state machine. */
-static int esp_work_bus(struct esp *esp)
-{
- struct scsi_cmnd *SCptr = esp->current_SC;
- unsigned int phase;
-
- ESPBUS(("esp_work_bus: "));
- if (!SCptr) {
- ESPBUS(("reconnect\n"));
- return esp_do_reconnect(esp);
- }
- phase = SCptr->SCp.phase;
- if ((phase & 0xf0) == in_phases_mask)
- return bus_vector[(phase & 0x0f)](esp);
- else if ((phase & 0xf0) == in_slct_mask)
- return esp_select_complete(esp);
- else
- return esp_bus_unexpected(esp);
-}
-
-static espfunc_t isvc_vector[] = {
- NULL,
- esp_do_phase_determine,
- esp_do_resetbus,
- esp_finish_reset,
- esp_work_bus
-};
-
-/* Main interrupt handler for an esp adapter. */
-static void esp_handle(struct esp *esp)
-{
- struct scsi_cmnd *SCptr;
- int what_next = do_intr_end;
-
- SCptr = esp->current_SC;
-
- /* Check for errors. */
- esp->sreg = sbus_readb(esp->eregs + ESP_STATUS);
- esp->sreg &= (~ESP_STAT_INTR);
- if (esp->erev == fashme) {
- esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);
- esp->seqreg = (sbus_readb(esp->eregs + ESP_SSTEP) & ESP_STEP_VBITS);
- }
-
- if (esp->sreg & (ESP_STAT_SPAM)) {
- /* Gross error, could be due to one of:
- *
- * - top of fifo overwritten, could be because
- * we tried to do a synchronous transfer with
- * an offset greater than ESP fifo size
- *
- * - top of command register overwritten
- *
- * - DMA setup to go in one direction, SCSI
- * bus points in the other, whoops
- *
- * - weird phase change during asynchronous
- * data phase while we are initiator
- */
- ESPLOG(("esp%d: Gross error sreg=%2x\n", esp->esp_id, esp->sreg));
-
- /* If a command is live on the bus we cannot safely
- * reset the bus, so we'll just let the pieces fall
- * where they may. Here we are hoping that the
- * target will be able to cleanly go away soon
- * so we can safely reset things.
- */
- if (!SCptr) {
- ESPLOG(("esp%d: No current cmd during gross error, "
- "resetting bus\n", esp->esp_id));
- what_next = do_reset_bus;
- goto state_machine;
- }
- }
-
- if (sbus_readl(esp->dregs + DMA_CSR) & DMA_HNDL_ERROR) {
- /* A DMA gate array error. Here we must
- * be seeing one of two things. Either the
- * virtual to physical address translation
- * on the SBUS could not occur, else the
- * translation it did get pointed to a bogus
- * page. Ho hum...
- */
- ESPLOG(("esp%d: DMA error %08x\n", esp->esp_id,
- sbus_readl(esp->dregs + DMA_CSR)));
-
- /* DMA gate array itself must be reset to clear the
- * error condition.
- */
- esp_reset_dma(esp);
-
- what_next = do_reset_bus;
- goto state_machine;
- }
-
- esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT); /* Unlatch intr reg */
-
- if (esp->erev == fashme) {
- /* This chip is really losing. */
- ESPHME(("HME["));
-
- ESPHME(("sreg2=%02x,", esp->sreg2));
- /* Must latch fifo before reading the interrupt
- * register else garbage ends up in the FIFO
- * which confuses the driver utterly.
- */
- if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
- (esp->sreg2 & ESP_STAT2_F1BYTE)) {
- ESPHME(("fifo_workaround]"));
- hme_fifo_read(esp);
- } else {
- ESPHME(("no_fifo_workaround]"));
- }
- }
-
- /* No current cmd is only valid at this point when there are
- * commands off the bus or we are trying a reset.
- */
- if (!SCptr && !esp->disconnected_SC && !(esp->ireg & ESP_INTR_SR)) {
- /* Panic is safe, since current_SC is null. */
- ESPLOG(("esp%d: no command in esp_handle()\n", esp->esp_id));
- panic("esp_handle: current_SC == penguin within interrupt!");
- }
-
- if (esp->ireg & (ESP_INTR_IC)) {
- /* Illegal command fed to ESP. Outside of obvious
- * software bugs that could cause this, there is
- * a condition with esp100 where we can confuse the
- * ESP into an erroneous illegal command interrupt
- * because it does not scrape the FIFO properly
- * for reselection. See esp100_reconnect_hwbug()
- * to see how we try very hard to avoid this.
- */
- ESPLOG(("esp%d: invalid command\n", esp->esp_id));
-
- esp_dump_state(esp);
-
- if (SCptr != NULL) {
- /* Devices with very buggy firmware can drop BSY
- * during a scatter list interrupt when using sync
- * mode transfers. We continue the transfer as
- * expected, the target drops the bus, the ESP
- * gets confused, and we get a illegal command
- * interrupt because the bus is in the disconnected
- * state now and ESP_CMD_TI is only allowed when
- * a nexus is alive on the bus.
- */
- ESPLOG(("esp%d: Forcing async and disabling disconnect for "
- "target %d\n", esp->esp_id, SCptr->device->id));
- SCptr->device->borken = 1; /* foo on you */
- }
-
- what_next = do_reset_bus;
- } else if (!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) {
- if (SCptr) {
- unsigned int phase = SCptr->SCp.phase;
-
- if (phase & in_phases_mask) {
- what_next = esp_work_bus(esp);
- } else if (phase & in_slct_mask) {
- what_next = esp_select_complete(esp);
- } else {
- ESPLOG(("esp%d: interrupt for no good reason...\n",
- esp->esp_id));
- what_next = do_intr_end;
- }
- } else {
- ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n",
- esp->esp_id));
- what_next = do_reset_bus;
- }
- } else if (esp->ireg & ESP_INTR_SR) {
- ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id));
- what_next = do_reset_complete;
- } else if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN)) {
- ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n",
- esp->esp_id));
- what_next = do_reset_bus;
- } else if (esp->ireg & ESP_INTR_RSEL) {
- if (SCptr == NULL) {
- /* This is ok. */
- what_next = esp_do_reconnect(esp);
- } else if (SCptr->SCp.phase & in_slct_mask) {
- /* Only selection code knows how to clean
- * up properly.
- */
- ESPDISC(("Reselected during selection attempt\n"));
- what_next = esp_select_complete(esp);
- } else {
- ESPLOG(("esp%d: Reselected while bus is busy\n",
- esp->esp_id));
- what_next = do_reset_bus;
- }
- }
-
- /* This is tier-one in our dual level SCSI state machine. */
-state_machine:
- while (what_next != do_intr_end) {
- if (what_next >= do_phase_determine &&
- what_next < do_intr_end) {
- what_next = isvc_vector[what_next](esp);
- } else {
- /* state is completely lost ;-( */
- ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n",
- esp->esp_id));
- what_next = do_reset_bus;
- }
- }
-}
-
-/* Service only the ESP described by dev_id. */
-static irqreturn_t esp_intr(int irq, void *dev_id)
-{
- struct esp *esp = dev_id;
- unsigned long flags;
-
- spin_lock_irqsave(esp->ehost->host_lock, flags);
- if (ESP_IRQ_P(esp->dregs)) {
- ESP_INTSOFF(esp->dregs);
-
- ESPIRQ(("I[%d:%d](", smp_processor_id(), esp->esp_id));
- esp_handle(esp);
- ESPIRQ((")"));
-
- ESP_INTSON(esp->dregs);
- }
- spin_unlock_irqrestore(esp->ehost->host_lock, flags);
-
- return IRQ_HANDLED;
-}
-
-static int esp_slave_alloc(struct scsi_device *SDptr)
-{
- struct esp_device *esp_dev =
- kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
-
- if (!esp_dev)
- return -ENOMEM;
- memset(esp_dev, 0, sizeof(struct esp_device));
- SDptr->hostdata = esp_dev;
- return 0;
-}
-
-static void esp_slave_destroy(struct scsi_device *SDptr)
-{
- struct esp *esp = (struct esp *) SDptr->host->hostdata;
-
- esp->targets_present &= ~(1 << SDptr->id);
- kfree(SDptr->hostdata);
- SDptr->hostdata = NULL;
-}
-
-static struct scsi_host_template esp_template = {
- .module = THIS_MODULE,
- .name = "esp",
- .info = esp_info,
- .slave_alloc = esp_slave_alloc,
- .slave_destroy = esp_slave_destroy,
- .queuecommand = esp_queue,
- .eh_abort_handler = esp_abort,
- .eh_bus_reset_handler = esp_reset,
- .can_queue = 7,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = 1,
- .use_clustering = ENABLE_CLUSTERING,
- .proc_name = "esp",
- .proc_info = esp_proc_info,
-};
-
-#ifndef CONFIG_SUN4
-static struct of_device_id esp_match[] = {
- {
- .name = "SUNW,esp",
- .data = &esp_template,
- },
- {
- .name = "SUNW,fas",
- .data = &esp_template,
- },
- {
- .name = "esp",
- .data = &esp_template,
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, esp_match);
-
-static struct of_platform_driver esp_sbus_driver = {
- .name = "esp",
- .match_table = esp_match,
- .probe = esp_sbus_probe,
- .remove = __devexit_p(esp_sbus_remove),
-};
-#endif
-
-static int __init esp_init(void)
-{
-#ifdef CONFIG_SUN4
- return esp_sun4_probe(&esp_template);
-#else
- return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
-#endif
-}
-
-static void __exit esp_exit(void)
-{
-#ifdef CONFIG_SUN4
- esp_sun4_remove();
-#else
- of_unregister_driver(&esp_sbus_driver);
-#endif
-}
-
-MODULE_DESCRIPTION("ESP Sun SCSI driver");
-MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
-module_init(esp_init);
-module_exit(esp_exit);
diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h
deleted file mode 100644
index a98cda9121f..00000000000
--- a/drivers/scsi/esp.h
+++ /dev/null
@@ -1,406 +0,0 @@
-/* $Id: esp.h,v 1.29 2001/12/11 04:55:47 davem Exp $
- * esp.h: Defines and structures for the Sparc ESP (Enhanced SCSI
- * Processor) driver under Linux.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _SPARC_ESP_H
-#define _SPARC_ESP_H
-
-/* For dvma controller register definitions. */
-#include <asm/dma.h>
-
-/* The ESP SCSI controllers have their register sets in three
- * "classes":
- *
- * 1) Registers which are both read and write.
- * 2) Registers which are read only.
- * 3) Registers which are write only.
- *
- * Yet, they all live within the same IO space.
- */
-
-/* All the ESP registers are one byte each and are accessed longwords
- * apart with a big-endian ordering to the bytes.
- */
- /* Access Description Offset */
-#define ESP_TCLOW 0x00UL /* rw Low bits of the transfer count 0x00 */
-#define ESP_TCMED 0x04UL /* rw Mid bits of the transfer count 0x04 */
-#define ESP_FDATA 0x08UL /* rw FIFO data bits 0x08 */
-#define ESP_CMD 0x0cUL /* rw SCSI command bits 0x0c */
-#define ESP_STATUS 0x10UL /* ro ESP status register 0x10 */
-#define ESP_BUSID ESP_STATUS /* wo Bus ID for select/reselect 0x10 */
-#define ESP_INTRPT 0x14UL /* ro Kind of interrupt 0x14 */
-#define ESP_TIMEO ESP_INTRPT /* wo Timeout value for select/resel 0x14 */
-#define ESP_SSTEP 0x18UL /* ro Sequence step register 0x18 */
-#define ESP_STP ESP_SSTEP /* wo Transfer period per sync 0x18 */
-#define ESP_FFLAGS 0x1cUL /* ro Bits of current FIFO info 0x1c */
-#define ESP_SOFF ESP_FFLAGS /* wo Sync offset 0x1c */
-#define ESP_CFG1 0x20UL /* rw First configuration register 0x20 */
-#define ESP_CFACT 0x24UL /* wo Clock conversion factor 0x24 */
-#define ESP_STATUS2 ESP_CFACT /* ro HME status2 register 0x24 */
-#define ESP_CTEST 0x28UL /* wo Chip test register 0x28 */
-#define ESP_CFG2 0x2cUL /* rw Second configuration register 0x2c */
-#define ESP_CFG3 0x30UL /* rw Third configuration register 0x30 */
-#define ESP_TCHI 0x38UL /* rw High bits of transfer count 0x38 */
-#define ESP_UID ESP_TCHI /* ro Unique ID code 0x38 */
-#define FAS_RLO ESP_TCHI /* rw HME extended counter 0x38 */
-#define ESP_FGRND 0x3cUL /* rw Data base for fifo 0x3c */
-#define FAS_RHI ESP_FGRND /* rw HME extended counter 0x3c */
-#define ESP_REG_SIZE 0x40UL
-
-/* Various revisions of the ESP board. */
-enum esp_rev {
- esp100 = 0x00, /* NCR53C90 - very broken */
- esp100a = 0x01, /* NCR53C90A */
- esp236 = 0x02,
- fas236 = 0x03,
- fas100a = 0x04,
- fast = 0x05,
- fashme = 0x06,
- espunknown = 0x07
-};
-
-/* We allocate one of these for each scsi device and attach it to
- * SDptr->hostdata for use in the driver
- */
-struct esp_device {
- unsigned char sync_min_period;
- unsigned char sync_max_offset;
- unsigned sync:1;
- unsigned wide:1;
- unsigned disconnect:1;
-};
-
-struct scsi_cmnd;
-
-/* We get one of these for each ESP probed. */
-struct esp {
- void __iomem *eregs; /* ESP controller registers */
- void __iomem *dregs; /* DMA controller registers */
- struct sbus_dma *dma; /* DMA controller sw state */
- struct Scsi_Host *ehost; /* Backpointer to SCSI Host */
- struct sbus_dev *sdev; /* Pointer to SBus entry */
-
- /* ESP Configuration Registers */
- u8 config1; /* Copy of the 1st config register */
- u8 config2; /* Copy of the 2nd config register */
- u8 config3[16]; /* Copy of the 3rd config register */
-
- /* The current command we are sending to the ESP chip. This esp_command
- * ptr needs to be mapped in DVMA area so we can send commands and read
- * from the ESP fifo without burning precious CPU cycles. Programmed I/O
- * sucks when we have the DVMA to do it for us. The ESP is stupid and will
- * only send out 6, 10, and 12 byte SCSI commands, others we need to send
- * one byte at a time. esp_slowcmd being set says that we are doing one
- * of the command types ESP doesn't understand, esp_scmdp keeps track of
- * which byte we are sending, esp_scmdleft says how many bytes to go.
- */
- volatile u8 *esp_command; /* Location of command (CPU view) */
- __u32 esp_command_dvma;/* Location of command (DVMA view) */
- unsigned char esp_clen; /* Length of this command */
- unsigned char esp_slowcmd;
- unsigned char *esp_scmdp;
- unsigned char esp_scmdleft;
-
- /* The following are used to determine the cause of an IRQ. Upon every
- * IRQ entry we synchronize these with the hardware registers.
- */
- u8 ireg; /* Copy of ESP interrupt register */
- u8 sreg; /* Copy of ESP status register */
- u8 seqreg; /* Copy of ESP sequence step register */
- u8 sreg2; /* Copy of HME status2 register */
-
- /* To save register writes to the ESP, which can be expensive, we
- * keep track of the previous value that various registers had for
- * the last target we connected to. If they are the same for the
- * current target, we skip the register writes as they are not needed.
- */
- u8 prev_soff, prev_stp;
- u8 prev_cfg3, __cache_pad;
-
- /* We also keep a cache of the previous FAS/HME DMA CSR register value. */
- u32 prev_hme_dmacsr;
-
- /* The HME is the biggest piece of shit I have ever seen. */
- u8 hme_fifo_workaround_buffer[16 * 2];
- u8 hme_fifo_workaround_count;
-
- /* For each target we keep track of save/restore data
- * pointer information. This needs to be updated majorly
- * when we add support for tagged queueing. -DaveM
- */
- struct esp_pointers {
- char *saved_ptr;
- struct scatterlist *saved_buffer;
- int saved_this_residual;
- int saved_buffers_residual;
- } data_pointers[16] /*XXX [MAX_TAGS_PER_TARGET]*/;
-
- /* Clock periods, frequencies, synchronization, etc. */
- unsigned int cfreq; /* Clock frequency in HZ */
- unsigned int cfact; /* Clock conversion factor */
- unsigned int raw_cfact; /* Raw copy from probing */
- unsigned int ccycle; /* One ESP clock cycle */
- unsigned int ctick; /* One ESP clock time */
- unsigned int radelay; /* FAST chip req/ack delay */
- unsigned int neg_defp; /* Default negotiation period */
- unsigned int sync_defp; /* Default sync transfer period */
- unsigned int max_period; /* longest our period can be */
- unsigned int min_period; /* shortest period we can withstand */
-
- struct esp *next; /* Next ESP we probed or NULL */
- char prom_name[64]; /* Name of ESP device from prom */
- int prom_node; /* Prom node where ESP found */
- int esp_id; /* Unique per-ESP ID number */
-
- /* For slow to medium speed input clock rates we shoot for 5mb/s,
- * but for high input clock rates we try to do 10mb/s although I
- * don't think a transfer can even run that fast with an ESP even
- * with DMA2 scatter gather pipelining.
- */
-#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */
-#define SYNC_DEFP_FAST 0x19 /* 10mb/s */
-
- unsigned int snip; /* Sync. negotiation in progress */
- unsigned int wnip; /* WIDE negotiation in progress */
- unsigned int targets_present;/* targets spoken to before */
-
- int current_transfer_size; /* Set at beginning of data dma */
-
- u8 espcmdlog[32]; /* Log of current esp cmds sent. */
- u8 espcmdent; /* Current entry in esp cmd log. */
-
- /* Misc. info about this ESP */
- enum esp_rev erev; /* ESP revision */
- int irq; /* SBus IRQ for this ESP */
- int scsi_id; /* Who am I as initiator? */
- int scsi_id_mask; /* Bitmask of 'me'. */
- int diff; /* Differential SCSI bus? */
- int bursts; /* Burst sizes our DVMA supports */
-
- /* Our command queues, only one cmd lives in the current_SC queue. */
- struct scsi_cmnd *issue_SC; /* Commands to be issued */
- struct scsi_cmnd *current_SC; /* Who is currently working the bus */
- struct scsi_cmnd *disconnected_SC;/* Commands disconnected from the bus */
-
- /* Message goo */
- u8 cur_msgout[16];
- u8 cur_msgin[16];
- u8 prevmsgout, prevmsgin;
- u8 msgout_len, msgin_len;
- u8 msgout_ctr, msgin_ctr;
-
- /* States that we cannot keep in the per cmd structure because they
- * cannot be assosciated with any specific command.
- */
- u8 resetting_bus;
- wait_queue_head_t reset_queue;
-};
-
-/* Bitfield meanings for the above registers. */
-
-/* ESP config reg 1, read-write, found on all ESP chips */
-#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */
-#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */
-#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */
-#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */
-#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */
-#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */
-
-/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */
-#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236) */
-#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236) */
-#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */
-#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tmode only) */
-#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */
-#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */
-#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236) */
-#define ESP_CONFIG2_DISPINT 0x20 /* Disable pause irq (hme) */
-#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,esp216) */
-#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (esp236) */
-#define ESP_CONFIG2_MKDONE 0x40 /* HME magic feature */
-#define ESP_CONFIG2_HME32 0x80 /* HME 32 extended */
-#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */
-
-/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */
-#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/hme) */
-#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236) */
-#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a/hme) */
-#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236) */
-#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a/hme) */
-#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236) */
-#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a/hme) */
-#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236) */
-#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a/hme) */
-#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236) */
-#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236) */
-#define ESP_CONFIG3_IDBIT3 0x20 /* Bit 3 of HME SCSI-ID (hme) */
-#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236) */
-#define ESP_CONFIG3_EWIDE 0x40 /* Enable Wide-SCSI (hme) */
-#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */
-#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */
-
-/* ESP command register read-write */
-/* Group 1 commands: These may be sent at any point in time to the ESP
- * chip. None of them can generate interrupts 'cept
- * the "SCSI bus reset" command if you have not disabled
- * SCSI reset interrupts in the config1 ESP register.
- */
-#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */
-#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */
-#define ESP_CMD_RC 0x02 /* Chip reset */
-#define ESP_CMD_RS 0x03 /* SCSI bus reset */
-
-/* Group 2 commands: ESP must be an initiator and connected to a target
- * for these commands to work.
- */
-#define ESP_CMD_TI 0x10 /* Transfer Information */
-#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */
-#define ESP_CMD_MOK 0x12 /* Message okie-dokie */
-#define ESP_CMD_TPAD 0x18 /* Transfer Pad */
-#define ESP_CMD_SATN 0x1a /* Set ATN */
-#define ESP_CMD_RATN 0x1b /* De-assert ATN */
-
-/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected
- * to a target as the initiator for these commands to work.
- */
-#define ESP_CMD_SMSG 0x20 /* Send message */
-#define ESP_CMD_SSTAT 0x21 /* Send status */
-#define ESP_CMD_SDATA 0x22 /* Send data */
-#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */
-#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */
-#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */
-#define ESP_CMD_DCNCT 0x27 /* Disconnect */
-#define ESP_CMD_RMSG 0x28 /* Receive Message */
-#define ESP_CMD_RCMD 0x29 /* Receive Command */
-#define ESP_CMD_RDATA 0x2a /* Receive Data */
-#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */
-
-/* Group 4 commands: The ESP must be in the disconnected state and must
- * not be connected to any targets as initiator for
- * these commands to work.
- */
-#define ESP_CMD_RSEL 0x40 /* Reselect */
-#define ESP_CMD_SEL 0x41 /* Select w/o ATN */
-#define ESP_CMD_SELA 0x42 /* Select w/ATN */
-#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */
-#define ESP_CMD_ESEL 0x44 /* Enable selection */
-#define ESP_CMD_DSEL 0x45 /* Disable selections */
-#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */
-#define ESP_CMD_RSEL3 0x47 /* Reselect3 */
-
-/* This bit enables the ESP's DMA on the SBus */
-#define ESP_CMD_DMA 0x80 /* Do DMA? */
-
-
-/* ESP status register read-only */
-#define ESP_STAT_PIO 0x01 /* IO phase bit */
-#define ESP_STAT_PCD 0x02 /* CD phase bit */
-#define ESP_STAT_PMSG 0x04 /* MSG phase bit */
-#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */
-#define ESP_STAT_TDONE 0x08 /* Transfer Completed */
-#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */
-#define ESP_STAT_PERR 0x20 /* Parity error */
-#define ESP_STAT_SPAM 0x40 /* Real bad error */
-/* This indicates the 'interrupt pending' condition on esp236, it is a reserved
- * bit on other revs of the ESP.
- */
-#define ESP_STAT_INTR 0x80 /* Interrupt */
-
-/* HME only: status 2 register */
-#define ESP_STAT2_SCHBIT 0x01 /* Upper bits 3-7 of sstep enabled */
-#define ESP_STAT2_FFLAGS 0x02 /* The fifo flags are now latched */
-#define ESP_STAT2_XCNT 0x04 /* The transfer counter is latched */
-#define ESP_STAT2_CREGA 0x08 /* The command reg is active now */
-#define ESP_STAT2_WIDE 0x10 /* Interface on this adapter is wide */
-#define ESP_STAT2_F1BYTE 0x20 /* There is one byte at top of fifo */
-#define ESP_STAT2_FMSB 0x40 /* Next byte in fifo is most significant */
-#define ESP_STAT2_FEMPTY 0x80 /* FIFO is empty */
-
-/* The status register can be masked with ESP_STAT_PMASK and compared
- * with the following values to determine the current phase the ESP
- * (at least thinks it) is in. For our purposes we also add our own
- * software 'done' bit for our phase management engine.
- */
-#define ESP_DOP (0) /* Data Out */
-#define ESP_DIP (ESP_STAT_PIO) /* Data In */
-#define ESP_CMDP (ESP_STAT_PCD) /* Command */
-#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */
-#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */
-#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */
-
-/* ESP interrupt register read-only */
-#define ESP_INTR_S 0x01 /* Select w/o ATN */
-#define ESP_INTR_SATN 0x02 /* Select w/ATN */
-#define ESP_INTR_RSEL 0x04 /* Reselected */
-#define ESP_INTR_FDONE 0x08 /* Function done */
-#define ESP_INTR_BSERV 0x10 /* Bus service */
-#define ESP_INTR_DC 0x20 /* Disconnect */
-#define ESP_INTR_IC 0x40 /* Illegal command given */
-#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */
-
-/* Interrupt status macros */
-#define ESP_SRESET_IRQ(esp) ((esp)->intreg & (ESP_INTR_SR))
-#define ESP_ILLCMD_IRQ(esp) ((esp)->intreg & (ESP_INTR_IC))
-#define ESP_SELECT_WITH_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_SATN))
-#define ESP_SELECT_WITHOUT_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_S))
-#define ESP_SELECTION_IRQ(esp) ((ESP_SELECT_WITH_ATN_IRQ(esp)) || \
- (ESP_SELECT_WITHOUT_ATN_IRQ(esp)))
-#define ESP_RESELECTION_IRQ(esp) ((esp)->intreg & (ESP_INTR_RSEL))
-
-/* ESP sequence step register read-only */
-#define ESP_STEP_VBITS 0x07 /* Valid bits */
-#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */
-#define ESP_STEP_SID 0x01 /* One msg byte sent */
-#define ESP_STEP_NCMD 0x02 /* Was not in command phase */
-#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd
- * bytes to be lost
- */
-#define ESP_STEP_FINI4 0x04 /* Command was sent ok */
-
-/* Ho hum, some ESP's set the step register to this as well... */
-#define ESP_STEP_FINI5 0x05
-#define ESP_STEP_FINI6 0x06
-#define ESP_STEP_FINI7 0x07
-
-/* ESP chip-test register read-write */
-#define ESP_TEST_TARG 0x01 /* Target test mode */
-#define ESP_TEST_INI 0x02 /* Initiator test mode */
-#define ESP_TEST_TS 0x04 /* Tristate test mode */
-
-/* ESP unique ID register read-only, found on fas236+fas100a only */
-#define ESP_UID_F100A 0x00 /* ESP FAS100A */
-#define ESP_UID_F236 0x02 /* ESP FAS236 */
-#define ESP_UID_REV 0x07 /* ESP revision */
-#define ESP_UID_FAM 0xf8 /* ESP family */
-
-/* ESP fifo flags register read-only */
-/* Note that the following implies a 16 byte FIFO on the ESP. */
-#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */
-#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100) */
-#define ESP_FF_SSTEP 0xe0 /* Sequence step */
-
-/* ESP clock conversion factor register write-only */
-#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */
-#define ESP_CCF_NEVER 0x01 /* Set it to this and die */
-#define ESP_CCF_F2 0x02 /* 10MHz */
-#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */
-#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */
-#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */
-#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */
-#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */
-
-/* HME only... */
-#define ESP_BUSID_RESELID 0x10
-#define ESP_BUSID_CTR32BIT 0x40
-
-#define ESP_BUS_TIMEOUT 275 /* In milli-seconds */
-#define ESP_TIMEO_CONST 8192
-#define ESP_NEG_DEFP(mhz, cfact) \
- ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
-#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
-#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
-
-#endif /* !(_SPARC_ESP_H) */
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
new file mode 100644
index 00000000000..99ce03331b6
--- /dev/null
+++ b/drivers/scsi/esp_scsi.c
@@ -0,0 +1,2711 @@
+/* esp_scsi.c: ESP SCSI driver.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/completion.h>
+#include <linux/kallsyms.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/irqreturn.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "esp_scsi.h"
+
+#define DRV_MODULE_NAME "esp"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_VERSION "2.000"
+#define DRV_MODULE_RELDATE "April 19, 2007"
+
+/* SCSI bus reset settle time in seconds. */
+static int esp_bus_reset_settle = 3;
+
+static u32 esp_debug;
+#define ESP_DEBUG_INTR 0x00000001
+#define ESP_DEBUG_SCSICMD 0x00000002
+#define ESP_DEBUG_RESET 0x00000004
+#define ESP_DEBUG_MSGIN 0x00000008
+#define ESP_DEBUG_MSGOUT 0x00000010
+#define ESP_DEBUG_CMDDONE 0x00000020
+#define ESP_DEBUG_DISCONNECT 0x00000040
+#define ESP_DEBUG_DATASTART 0x00000080
+#define ESP_DEBUG_DATADONE 0x00000100
+#define ESP_DEBUG_RECONNECT 0x00000200
+#define ESP_DEBUG_AUTOSENSE 0x00000400
+
+#define esp_log_intr(f, a...) \
+do { if (esp_debug & ESP_DEBUG_INTR) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_reset(f, a...) \
+do { if (esp_debug & ESP_DEBUG_RESET) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_msgin(f, a...) \
+do { if (esp_debug & ESP_DEBUG_MSGIN) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_msgout(f, a...) \
+do { if (esp_debug & ESP_DEBUG_MSGOUT) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_cmddone(f, a...) \
+do { if (esp_debug & ESP_DEBUG_CMDDONE) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_disconnect(f, a...) \
+do { if (esp_debug & ESP_DEBUG_DISCONNECT) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_datastart(f, a...) \
+do { if (esp_debug & ESP_DEBUG_DATASTART) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_datadone(f, a...) \
+do { if (esp_debug & ESP_DEBUG_DATADONE) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_reconnect(f, a...) \
+do { if (esp_debug & ESP_DEBUG_RECONNECT) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_log_autosense(f, a...) \
+do { if (esp_debug & ESP_DEBUG_AUTOSENSE) \
+ printk(f, ## a); \
+} while (0)
+
+#define esp_read8(REG) esp->ops->esp_read8(esp, REG)
+#define esp_write8(VAL,REG) esp->ops->esp_write8(esp, VAL, REG)
+
+static void esp_log_fill_regs(struct esp *esp,
+ struct esp_event_ent *p)
+{
+ p->sreg = esp->sreg;
+ p->seqreg = esp->seqreg;
+ p->sreg2 = esp->sreg2;
+ p->ireg = esp->ireg;
+ p->select_state = esp->select_state;
+ p->event = esp->event;
+}
+
+void scsi_esp_cmd(struct esp *esp, u8 val)
+{
+ struct esp_event_ent *p;
+ int idx = esp->esp_event_cur;
+
+ p = &esp->esp_event_log[idx];
+ p->type = ESP_EVENT_TYPE_CMD;
+ p->val = val;
+ esp_log_fill_regs(esp, p);
+
+ esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);
+
+ esp_write8(val, ESP_CMD);
+}
+EXPORT_SYMBOL(scsi_esp_cmd);
+
+static void esp_event(struct esp *esp, u8 val)
+{
+ struct esp_event_ent *p;
+ int idx = esp->esp_event_cur;
+
+ p = &esp->esp_event_log[idx];
+ p->type = ESP_EVENT_TYPE_EVENT;
+ p->val = val;
+ esp_log_fill_regs(esp, p);
+
+ esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);
+
+ esp->event = val;
+}
+
+static void esp_dump_cmd_log(struct esp *esp)
+{
+ int idx = esp->esp_event_cur;
+ int stop = idx;
+
+ printk(KERN_INFO PFX "esp%d: Dumping command log\n",
+ esp->host->unique_id);
+ do {
+ struct esp_event_ent *p = &esp->esp_event_log[idx];
+
+ printk(KERN_INFO PFX "esp%d: ent[%d] %s ",
+ esp->host->unique_id, idx,
+ p->type == ESP_EVENT_TYPE_CMD ? "CMD" : "EVENT");
+
+ printk("val[%02x] sreg[%02x] seqreg[%02x] "
+ "sreg2[%02x] ireg[%02x] ss[%02x] event[%02x]\n",
+ p->val, p->sreg, p->seqreg,
+ p->sreg2, p->ireg, p->select_state, p->event);
+
+ idx = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);
+ } while (idx != stop);
+}
+
+static void esp_flush_fifo(struct esp *esp)
+{
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ if (esp->rev == ESP236) {
+ int lim = 1000;
+
+ while (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES) {
+ if (--lim == 0) {
+ printk(KERN_ALERT PFX "esp%d: ESP_FF_BYTES "
+ "will not clear!\n",
+ esp->host->unique_id);
+ break;
+ }
+ udelay(1);
+ }
+ }
+}
+
+static void hme_read_fifo(struct esp *esp)
+{
+ int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
+ int idx = 0;
+
+ while (fcnt--) {
+ esp->fifo[idx++] = esp_read8(ESP_FDATA);
+ esp->fifo[idx++] = esp_read8(ESP_FDATA);
+ }
+ if (esp->sreg2 & ESP_STAT2_F1BYTE) {
+ esp_write8(0, ESP_FDATA);
+ esp->fifo[idx++] = esp_read8(ESP_FDATA);
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ }
+ esp->fifo_cnt = idx;
+}
+
+static void esp_set_all_config3(struct esp *esp, u8 val)
+{
+ int i;
+
+ for (i = 0; i < ESP_MAX_TARGET; i++)
+ esp->target[i].esp_config3 = val;
+}
+
+/* Reset the ESP chip, _not_ the SCSI bus. */
+static void esp_reset_esp(struct esp *esp)
+{
+ u8 family_code, version;
+
+ /* Now reset the ESP chip */
+ scsi_esp_cmd(esp, ESP_CMD_RC);
+ scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
+ scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
+
+ /* Reload the configuration registers */
+ esp_write8(esp->cfact, ESP_CFACT);
+
+ esp->prev_stp = 0;
+ esp_write8(esp->prev_stp, ESP_STP);
+
+ esp->prev_soff = 0;
+ esp_write8(esp->prev_soff, ESP_SOFF);
+
+ esp_write8(esp->neg_defp, ESP_TIMEO);
+
+ /* This is the only point at which it is reliable to read
+ * the ID-code for a fast ESP chip variants.
+ */
+ esp->max_period = ((35 * esp->ccycle) / 1000);
+ if (esp->rev == FAST) {
+ version = esp_read8(ESP_UID);
+ family_code = (version & 0xf8) >> 3;
+ if (family_code == 0x02)
+ esp->rev = FAS236;
+ else if (family_code == 0x0a)
+ esp->rev = FASHME; /* Version is usually '5'. */
+ else
+ esp->rev = FAS100A;
+ esp->min_period = ((4 * esp->ccycle) / 1000);
+ } else {
+ esp->min_period = ((5 * esp->ccycle) / 1000);
+ }
+ esp->max_period = (esp->max_period + 3)>>2;
+ esp->min_period = (esp->min_period + 3)>>2;
+
+ esp_write8(esp->config1, ESP_CFG1);
+ switch (esp->rev) {
+ case ESP100:
+ /* nothing to do */
+ break;
+
+ case ESP100A:
+ esp_write8(esp->config2, ESP_CFG2);
+ break;
+
+ case ESP236:
+ /* Slow 236 */
+ esp_write8(esp->config2, ESP_CFG2);
+ esp->prev_cfg3 = esp->target[0].esp_config3;
+ esp_write8(esp->prev_cfg3, ESP_CFG3);
+ break;
+
+ case FASHME:
+ esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
+ /* fallthrough... */
+
+ case FAS236:
+ /* Fast 236 or HME */
+ esp_write8(esp->config2, ESP_CFG2);
+ if (esp->rev == FASHME) {
+ u8 cfg3 = esp->target[0].esp_config3;
+
+ cfg3 |= ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH;
+ if (esp->scsi_id >= 8)
+ cfg3 |= ESP_CONFIG3_IDBIT3;
+ esp_set_all_config3(esp, cfg3);
+ } else {
+ u32 cfg3 = esp->target[0].esp_config3;
+
+ cfg3 |= ESP_CONFIG3_FCLK;
+ esp_set_all_config3(esp, cfg3);
+ }
+ esp->prev_cfg3 = esp->target[0].esp_config3;
+ esp_write8(esp->prev_cfg3, ESP_CFG3);
+ if (esp->rev == FASHME) {
+ esp->radelay = 80;
+ } else {
+ if (esp->flags & ESP_FLAG_DIFFERENTIAL)
+ esp->radelay = 0;
+ else
+ esp->radelay = 96;
+ }
+ break;
+
+ case FAS100A:
+ /* Fast 100a */
+ esp_write8(esp->config2, ESP_CFG2);
+ esp_set_all_config3(esp,
+ (esp->target[0].esp_config3 |
+ ESP_CONFIG3_FCLOCK));
+ esp->prev_cfg3 = esp->target[0].esp_config3;
+ esp_write8(esp->prev_cfg3, ESP_CFG3);
+ esp->radelay = 32;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Eat any bitrot in the chip */
+ esp_read8(ESP_INTRPT);
+ udelay(100);
+}
+
+static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd)
+{
+ struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
+ struct scatterlist *sg = cmd->request_buffer;
+ int dir = cmd->sc_data_direction;
+ int total, i;
+
+ if (dir == DMA_NONE)
+ return;
+
+ BUG_ON(cmd->use_sg == 0);
+
+ spriv->u.num_sg = esp->ops->map_sg(esp, sg,
+ cmd->use_sg, dir);
+ spriv->cur_residue = sg_dma_len(sg);
+ spriv->cur_sg = sg;
+
+ total = 0;
+ for (i = 0; i < spriv->u.num_sg; i++)
+ total += sg_dma_len(&sg[i]);
+ spriv->tot_residue = total;
+}
+
+static dma_addr_t esp_cur_dma_addr(struct esp_cmd_entry *ent,
+ struct scsi_cmnd *cmd)
+{
+ struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ return ent->sense_dma +
+ (ent->sense_ptr - cmd->sense_buffer);
+ }
+
+ return sg_dma_address(p->cur_sg) +
+ (sg_dma_len(p->cur_sg) -
+ p->cur_residue);
+}
+
+static unsigned int esp_cur_dma_len(struct esp_cmd_entry *ent,
+ struct scsi_cmnd *cmd)
+{
+ struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ return SCSI_SENSE_BUFFERSIZE -
+ (ent->sense_ptr - cmd->sense_buffer);
+ }
+ return p->cur_residue;
+}
+
+static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent,
+ struct scsi_cmnd *cmd, unsigned int len)
+{
+ struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ ent->sense_ptr += len;
+ return;
+ }
+
+ p->cur_residue -= len;
+ p->tot_residue -= len;
+ if (p->cur_residue < 0 || p->tot_residue < 0) {
+ printk(KERN_ERR PFX "esp%d: Data transfer overflow.\n",
+ esp->host->unique_id);
+ printk(KERN_ERR PFX "esp%d: cur_residue[%d] tot_residue[%d] "
+ "len[%u]\n",
+ esp->host->unique_id,
+ p->cur_residue, p->tot_residue, len);
+ p->cur_residue = 0;
+ p->tot_residue = 0;
+ }
+ if (!p->cur_residue && p->tot_residue) {
+ p->cur_sg++;
+ p->cur_residue = sg_dma_len(p->cur_sg);
+ }
+}
+
+static void esp_unmap_dma(struct esp *esp, struct scsi_cmnd *cmd)
+{
+ struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
+ int dir = cmd->sc_data_direction;
+
+ if (dir == DMA_NONE)
+ return;
+
+ esp->ops->unmap_sg(esp, cmd->request_buffer,
+ spriv->u.num_sg, dir);
+}
+
+static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ struct scsi_cmnd *cmd = ent->cmd;
+ struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ ent->saved_sense_ptr = ent->sense_ptr;
+ return;
+ }
+ ent->saved_cur_residue = spriv->cur_residue;
+ ent->saved_cur_sg = spriv->cur_sg;
+ ent->saved_tot_residue = spriv->tot_residue;
+}
+
+static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ struct scsi_cmnd *cmd = ent->cmd;
+ struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ ent->sense_ptr = ent->saved_sense_ptr;
+ return;
+ }
+ spriv->cur_residue = ent->saved_cur_residue;
+ spriv->cur_sg = ent->saved_cur_sg;
+ spriv->tot_residue = ent->saved_tot_residue;
+}
+
+static void esp_check_command_len(struct esp *esp, struct scsi_cmnd *cmd)
+{
+ if (cmd->cmd_len == 6 ||
+ cmd->cmd_len == 10 ||
+ cmd->cmd_len == 12) {
+ esp->flags &= ~ESP_FLAG_DOING_SLOWCMD;
+ } else {
+ esp->flags |= ESP_FLAG_DOING_SLOWCMD;
+ }
+}
+
+static void esp_write_tgt_config3(struct esp *esp, int tgt)
+{
+ if (esp->rev > ESP100A) {
+ u8 val = esp->target[tgt].esp_config3;
+
+ if (val != esp->prev_cfg3) {
+ esp->prev_cfg3 = val;
+ esp_write8(val, ESP_CFG3);
+ }
+ }
+}
+
+static void esp_write_tgt_sync(struct esp *esp, int tgt)
+{
+ u8 off = esp->target[tgt].esp_offset;
+ u8 per = esp->target[tgt].esp_period;
+
+ if (off != esp->prev_soff) {
+ esp->prev_soff = off;
+ esp_write8(off, ESP_SOFF);
+ }
+ if (per != esp->prev_stp) {
+ esp->prev_stp = per;
+ esp_write8(per, ESP_STP);
+ }
+}
+
+static u32 esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len)
+{
+ if (esp->rev == FASHME) {
+ /* Arbitrary segment boundaries, 24-bit counts. */
+ if (dma_len > (1U << 24))
+ dma_len = (1U << 24);
+ } else {
+ u32 base, end;
+
+ /* ESP chip limits other variants by 16-bits of transfer
+ * count. Actually on FAS100A and FAS236 we could get
+ * 24-bits of transfer count by enabling ESP_CONFIG2_FENAB
+ * in the ESP_CFG2 register but that causes other unwanted
+ * changes so we don't use it currently.
+ */
+ if (dma_len > (1U << 16))
+ dma_len = (1U << 16);
+
+ /* All of the DMA variants hooked up to these chips
+ * cannot handle crossing a 24-bit address boundary.
+ */
+ base = dma_addr & ((1U << 24) - 1U);
+ end = base + dma_len;
+ if (end > (1U << 24))
+ end = (1U <<24);
+ dma_len = end - base;
+ }
+ return dma_len;
+}
+
+static int esp_need_to_nego_wide(struct esp_target_data *tp)
+{
+ struct scsi_target *target = tp->starget;
+
+ return spi_width(target) != tp->nego_goal_width;
+}
+
+static int esp_need_to_nego_sync(struct esp_target_data *tp)
+{
+ struct scsi_target *target = tp->starget;
+
+ /* When offset is zero, period is "don't care". */
+ if (!spi_offset(target) && !tp->nego_goal_offset)
+ return 0;
+
+ if (spi_offset(target) == tp->nego_goal_offset &&
+ spi_period(target) == tp->nego_goal_period)
+ return 0;
+
+ return 1;
+}
+
+static int esp_alloc_lun_tag(struct esp_cmd_entry *ent,
+ struct esp_lun_data *lp)
+{
+ if (!ent->tag[0]) {
+ /* Non-tagged, slot already taken? */
+ if (lp->non_tagged_cmd)
+ return -EBUSY;
+
+ if (lp->hold) {
+ /* We are being held by active tagged
+ * commands.
+ */
+ if (lp->num_tagged)
+ return -EBUSY;
+
+ /* Tagged commands completed, we can unplug
+ * the queue and run this untagged command.
+ */
+ lp->hold = 0;
+ } else if (lp->num_tagged) {
+ /* Plug the queue until num_tagged decreases
+ * to zero in esp_free_lun_tag.
+ */
+ lp->hold = 1;
+ return -EBUSY;
+ }
+
+ lp->non_tagged_cmd = ent;
+ return 0;
+ } else {
+ /* Tagged command, see if blocked by a
+ * non-tagged one.
+ */
+ if (lp->non_tagged_cmd || lp->hold)
+ return -EBUSY;
+ }
+
+ BUG_ON(lp->tagged_cmds[ent->tag[1]]);
+
+ lp->tagged_cmds[ent->tag[1]] = ent;
+ lp->num_tagged++;
+
+ return 0;
+}
+
+static void esp_free_lun_tag(struct esp_cmd_entry *ent,
+ struct esp_lun_data *lp)
+{
+ if (ent->tag[0]) {
+ BUG_ON(lp->tagged_cmds[ent->tag[1]] != ent);
+ lp->tagged_cmds[ent->tag[1]] = NULL;
+ lp->num_tagged--;
+ } else {
+ BUG_ON(lp->non_tagged_cmd != ent);
+ lp->non_tagged_cmd = NULL;
+ }
+}
+
+/* When a contingent allegiance conditon is created, we force feed a
+ * REQUEST_SENSE command to the device to fetch the sense data. I
+ * tried many other schemes, relying on the scsi error handling layer
+ * to send out the REQUEST_SENSE automatically, but this was difficult
+ * to get right especially in the presence of applications like smartd
+ * which use SG_IO to send out their own REQUEST_SENSE commands.
+ */
+static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ struct scsi_cmnd *cmd = ent->cmd;
+ struct scsi_device *dev = cmd->device;
+ int tgt, lun;
+ u8 *p, val;
+
+ tgt = dev->id;
+ lun = dev->lun;
+
+
+ if (!ent->sense_ptr) {
+ esp_log_autosense("esp%d: Doing auto-sense for "
+ "tgt[%d] lun[%d]\n",
+ esp->host->unique_id, tgt, lun);
+
+ ent->sense_ptr = cmd->sense_buffer;
+ ent->sense_dma = esp->ops->map_single(esp,
+ ent->sense_ptr,
+ SCSI_SENSE_BUFFERSIZE,
+ DMA_FROM_DEVICE);
+ }
+ ent->saved_sense_ptr = ent->sense_ptr;
+
+ esp->active_cmd = ent;
+
+ p = esp->command_block;
+ esp->msg_out_len = 0;
+
+ *p++ = IDENTIFY(0, lun);
+ *p++ = REQUEST_SENSE;
+ *p++ = ((dev->scsi_level <= SCSI_2) ?
+ (lun << 5) : 0);
+ *p++ = 0;
+ *p++ = 0;
+ *p++ = SCSI_SENSE_BUFFERSIZE;
+ *p++ = 0;
+
+ esp->select_state = ESP_SELECT_BASIC;
+
+ val = tgt;
+ if (esp->rev == FASHME)
+ val |= ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT;
+ esp_write8(val, ESP_BUSID);
+
+ esp_write_tgt_sync(esp, tgt);
+ esp_write_tgt_config3(esp, tgt);
+
+ val = (p - esp->command_block);
+
+ if (esp->rev == FASHME)
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ esp->ops->send_dma_cmd(esp, esp->command_block_dma,
+ val, 16, 0, ESP_CMD_DMA | ESP_CMD_SELA);
+}
+
+static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp)
+{
+ struct esp_cmd_entry *ent;
+
+ list_for_each_entry(ent, &esp->queued_cmds, list) {
+ struct scsi_cmnd *cmd = ent->cmd;
+ struct scsi_device *dev = cmd->device;
+ struct esp_lun_data *lp = dev->hostdata;
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ ent->tag[0] = 0;
+ ent->tag[1] = 0;
+ return ent;
+ }
+
+ if (!scsi_populate_tag_msg(cmd, &ent->tag[0])) {
+ ent->tag[0] = 0;
+ ent->tag[1] = 0;
+ }
+
+ if (esp_alloc_lun_tag(ent, lp) < 0)
+ continue;
+
+ return ent;
+ }
+
+ return NULL;
+}
+
+static void esp_maybe_execute_command(struct esp *esp)
+{
+ struct esp_target_data *tp;
+ struct esp_lun_data *lp;
+ struct scsi_device *dev;
+ struct scsi_cmnd *cmd;
+ struct esp_cmd_entry *ent;
+ int tgt, lun, i;
+ u32 val, start_cmd;
+ u8 *p;
+
+ if (esp->active_cmd ||
+ (esp->flags & ESP_FLAG_RESETTING))
+ return;
+
+ ent = find_and_prep_issuable_command(esp);
+ if (!ent)
+ return;
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ esp_autosense(esp, ent);
+ return;
+ }
+
+ cmd = ent->cmd;
+ dev = cmd->device;
+ tgt = dev->id;
+ lun = dev->lun;
+ tp = &esp->target[tgt];
+ lp = dev->hostdata;
+
+ list_del(&ent->list);
+ list_add(&ent->list, &esp->active_cmds);
+
+ esp->active_cmd = ent;
+
+ esp_map_dma(esp, cmd);
+ esp_save_pointers(esp, ent);
+
+ esp_check_command_len(esp, cmd);
+
+ p = esp->command_block;
+
+ esp->msg_out_len = 0;
+ if (tp->flags & ESP_TGT_CHECK_NEGO) {
+ /* Need to negotiate. If the target is broken
+ * go for synchronous transfers and non-wide.
+ */
+ if (tp->flags & ESP_TGT_BROKEN) {
+ tp->flags &= ~ESP_TGT_DISCONNECT;
+ tp->nego_goal_period = 0;
+ tp->nego_goal_offset = 0;
+ tp->nego_goal_width = 0;
+ tp->nego_goal_tags = 0;
+ }
+
+ /* If the settings are not changing, skip this. */
+ if (spi_width(tp->starget) == tp->nego_goal_width &&
+ spi_period(tp->starget) == tp->nego_goal_period &&
+ spi_offset(tp->starget) == tp->nego_goal_offset) {
+ tp->flags &= ~ESP_TGT_CHECK_NEGO;
+ goto build_identify;
+ }
+
+ if (esp->rev == FASHME && esp_need_to_nego_wide(tp)) {
+ esp->msg_out_len =
+ spi_populate_width_msg(&esp->msg_out[0],
+ (tp->nego_goal_width ?
+ 1 : 0));
+ tp->flags |= ESP_TGT_NEGO_WIDE;
+ } else if (esp_need_to_nego_sync(tp)) {
+ esp->msg_out_len =
+ spi_populate_sync_msg(&esp->msg_out[0],
+ tp->nego_goal_period,
+ tp->nego_goal_offset);
+ tp->flags |= ESP_TGT_NEGO_SYNC;
+ } else {
+ tp->flags &= ~ESP_TGT_CHECK_NEGO;
+ }
+
+ /* Process it like a slow command. */
+ if (tp->flags & (ESP_TGT_NEGO_WIDE | ESP_TGT_NEGO_SYNC))
+ esp->flags |= ESP_FLAG_DOING_SLOWCMD;
+ }
+
+build_identify:
+ /* If we don't have a lun-data struct yet, we're probing
+ * so do not disconnect. Also, do not disconnect unless
+ * we have a tag on this command.
+ */
+ if (lp && (tp->flags & ESP_TGT_DISCONNECT) && ent->tag[0])
+ *p++ = IDENTIFY(1, lun);
+ else
+ *p++ = IDENTIFY(0, lun);
+
+ if (ent->tag[0] && esp->rev == ESP100) {
+ /* ESP100 lacks select w/atn3 command, use select
+ * and stop instead.
+ */
+ esp->flags |= ESP_FLAG_DOING_SLOWCMD;
+ }
+
+ if (!(esp->flags & ESP_FLAG_DOING_SLOWCMD)) {
+ start_cmd = ESP_CMD_DMA | ESP_CMD_SELA;
+ if (ent->tag[0]) {
+ *p++ = ent->tag[0];
+ *p++ = ent->tag[1];
+
+ start_cmd = ESP_CMD_DMA | ESP_CMD_SA3;
+ }
+
+ for (i = 0; i < cmd->cmd_len; i++)
+ *p++ = cmd->cmnd[i];
+
+ esp->select_state = ESP_SELECT_BASIC;
+ } else {
+ esp->cmd_bytes_left = cmd->cmd_len;
+ esp->cmd_bytes_ptr = &cmd->cmnd[0];
+
+ if (ent->tag[0]) {
+ for (i = esp->msg_out_len - 1;
+ i >= 0; i--)
+ esp->msg_out[i + 2] = esp->msg_out[i];
+ esp->msg_out[0] = ent->tag[0];
+ esp->msg_out[1] = ent->tag[1];
+ esp->msg_out_len += 2;
+ }
+
+ start_cmd = ESP_CMD_DMA | ESP_CMD_SELAS;
+ esp->select_state = ESP_SELECT_MSGOUT;
+ }
+ val = tgt;
+ if (esp->rev == FASHME)
+ val |= ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT;
+ esp_write8(val, ESP_BUSID);
+
+ esp_write_tgt_sync(esp, tgt);
+ esp_write_tgt_config3(esp, tgt);
+
+ val = (p - esp->command_block);
+
+ if (esp_debug & ESP_DEBUG_SCSICMD) {
+ printk("ESP: tgt[%d] lun[%d] scsi_cmd [ ", tgt, lun);
+ for (i = 0; i < cmd->cmd_len; i++)
+ printk("%02x ", cmd->cmnd[i]);
+ printk("]\n");
+ }
+
+ if (esp->rev == FASHME)
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ esp->ops->send_dma_cmd(esp, esp->command_block_dma,
+ val, 16, 0, start_cmd);
+}
+
+static struct esp_cmd_entry *esp_get_ent(struct esp *esp)
+{
+ struct list_head *head = &esp->esp_cmd_pool;
+ struct esp_cmd_entry *ret;
+
+ if (list_empty(head)) {
+ ret = kzalloc(sizeof(struct esp_cmd_entry), GFP_ATOMIC);
+ } else {
+ ret = list_entry(head->next, struct esp_cmd_entry, list);
+ list_del(&ret->list);
+ memset(ret, 0, sizeof(*ret));
+ }
+ return ret;
+}
+
+static void esp_put_ent(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ list_add(&ent->list, &esp->esp_cmd_pool);
+}
+
+static void esp_cmd_is_done(struct esp *esp, struct esp_cmd_entry *ent,
+ struct scsi_cmnd *cmd, unsigned int result)
+{
+ struct scsi_device *dev = cmd->device;
+ int tgt = dev->id;
+ int lun = dev->lun;
+
+ esp->active_cmd = NULL;
+ esp_unmap_dma(esp, cmd);
+ esp_free_lun_tag(ent, dev->hostdata);
+ cmd->result = result;
+
+ if (ent->eh_done) {
+ complete(ent->eh_done);
+ ent->eh_done = NULL;
+ }
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ esp->ops->unmap_single(esp, ent->sense_dma,
+ SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+ ent->sense_ptr = NULL;
+
+ /* Restore the message/status bytes to what we actually
+ * saw originally. Also, report that we are providing
+ * the sense data.
+ */
+ cmd->result = ((DRIVER_SENSE << 24) |
+ (DID_OK << 16) |
+ (COMMAND_COMPLETE << 8) |
+ (SAM_STAT_CHECK_CONDITION << 0));
+
+ ent->flags &= ~ESP_CMD_FLAG_AUTOSENSE;
+ if (esp_debug & ESP_DEBUG_AUTOSENSE) {
+ int i;
+
+ printk("esp%d: tgt[%d] lun[%d] AUTO SENSE[ ",
+ esp->host->unique_id, tgt, lun);
+ for (i = 0; i < 18; i++)
+ printk("%02x ", cmd->sense_buffer[i]);
+ printk("]\n");
+ }
+ }
+
+ cmd->scsi_done(cmd);
+
+ list_del(&ent->list);
+ esp_put_ent(esp, ent);
+
+ esp_maybe_execute_command(esp);
+}
+
+static unsigned int compose_result(unsigned int status, unsigned int message,
+ unsigned int driver_code)
+{
+ return (status | (message << 8) | (driver_code << 16));
+}
+
+static void esp_event_queue_full(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ struct scsi_device *dev = ent->cmd->device;
+ struct esp_lun_data *lp = dev->hostdata;
+
+ scsi_track_queue_full(dev, lp->num_tagged - 1);
+}
+
+static int esp_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+ struct scsi_device *dev = cmd->device;
+ struct esp *esp = host_to_esp(dev->host);
+ struct esp_cmd_priv *spriv;
+ struct esp_cmd_entry *ent;
+
+ ent = esp_get_ent(esp);
+ if (!ent)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ ent->cmd = cmd;
+
+ cmd->scsi_done = done;
+
+ spriv = ESP_CMD_PRIV(cmd);
+ spriv->u.dma_addr = ~(dma_addr_t)0x0;
+
+ list_add_tail(&ent->list, &esp->queued_cmds);
+
+ esp_maybe_execute_command(esp);
+
+ return 0;
+}
+
+static int esp_check_gross_error(struct esp *esp)
+{
+ if (esp->sreg & ESP_STAT_SPAM) {
+ /* Gross Error, could be one of:
+ * - top of fifo overwritten
+ * - top of command register overwritten
+ * - DMA programmed with wrong direction
+ * - improper phase change
+ */
+ printk(KERN_ERR PFX "esp%d: Gross error sreg[%02x]\n",
+ esp->host->unique_id, esp->sreg);
+ /* XXX Reset the chip. XXX */
+ return 1;
+ }
+ return 0;
+}
+
+static int esp_check_spur_intr(struct esp *esp)
+{
+ switch (esp->rev) {
+ case ESP100:
+ case ESP100A:
+ /* The interrupt pending bit of the status register cannot
+ * be trusted on these revisions.
+ */
+ esp->sreg &= ~ESP_STAT_INTR;
+ break;
+
+ default:
+ if (!(esp->sreg & ESP_STAT_INTR)) {
+ esp->ireg = esp_read8(ESP_INTRPT);
+ if (esp->ireg & ESP_INTR_SR)
+ return 1;
+
+ /* If the DMA is indicating interrupt pending and the
+ * ESP is not, the only possibility is a DMA error.
+ */
+ if (!esp->ops->dma_error(esp)) {
+ printk(KERN_ERR PFX "esp%d: Spurious irq, "
+ "sreg=%x.\n",
+ esp->host->unique_id, esp->sreg);
+ return -1;
+ }
+
+ printk(KERN_ERR PFX "esp%d: DMA error\n",
+ esp->host->unique_id);
+
+ /* XXX Reset the chip. XXX */
+ return -1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static void esp_schedule_reset(struct esp *esp)
+{
+ esp_log_reset("ESP: esp_schedule_reset() from %p\n",
+ __builtin_return_address(0));
+ esp->flags |= ESP_FLAG_RESETTING;
+ esp_event(esp, ESP_EVENT_RESET);
+}
+
+/* In order to avoid having to add a special half-reconnected state
+ * into the driver we just sit here and poll through the rest of
+ * the reselection process to get the tag message bytes.
+ */
+static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp,
+ struct esp_lun_data *lp)
+{
+ struct esp_cmd_entry *ent;
+ int i;
+
+ if (!lp->num_tagged) {
+ printk(KERN_ERR PFX "esp%d: Reconnect w/num_tagged==0\n",
+ esp->host->unique_id);
+ return NULL;
+ }
+
+ esp_log_reconnect("ESP: reconnect tag, ");
+
+ for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) {
+ if (esp->ops->irq_pending(esp))
+ break;
+ }
+ if (i == ESP_QUICKIRQ_LIMIT) {
+ printk(KERN_ERR PFX "esp%d: Reconnect IRQ1 timeout\n",
+ esp->host->unique_id);
+ return NULL;
+ }
+
+ esp->sreg = esp_read8(ESP_STATUS);
+ esp->ireg = esp_read8(ESP_INTRPT);
+
+ esp_log_reconnect("IRQ(%d:%x:%x), ",
+ i, esp->ireg, esp->sreg);
+
+ if (esp->ireg & ESP_INTR_DC) {
+ printk(KERN_ERR PFX "esp%d: Reconnect, got disconnect.\n",
+ esp->host->unique_id);
+ return NULL;
+ }
+
+ if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) {
+ printk(KERN_ERR PFX "esp%d: Reconnect, not MIP sreg[%02x].\n",
+ esp->host->unique_id, esp->sreg);
+ return NULL;
+ }
+
+ /* DMA in the tag bytes... */
+ esp->command_block[0] = 0xff;
+ esp->command_block[1] = 0xff;
+ esp->ops->send_dma_cmd(esp, esp->command_block_dma,
+ 2, 2, 1, ESP_CMD_DMA | ESP_CMD_TI);
+
+ /* ACK the msssage. */
+ scsi_esp_cmd(esp, ESP_CMD_MOK);
+
+ for (i = 0; i < ESP_RESELECT_TAG_LIMIT; i++) {
+ if (esp->ops->irq_pending(esp)) {
+ esp->sreg = esp_read8(ESP_STATUS);
+ esp->ireg = esp_read8(ESP_INTRPT);
+ if (esp->ireg & ESP_INTR_FDONE)
+ break;
+ }
+ udelay(1);
+ }
+ if (i == ESP_RESELECT_TAG_LIMIT) {
+ printk(KERN_ERR PFX "esp%d: Reconnect IRQ2 timeout\n",
+ esp->host->unique_id);
+ return NULL;
+ }
+ esp->ops->dma_drain(esp);
+ esp->ops->dma_invalidate(esp);
+
+ esp_log_reconnect("IRQ2(%d:%x:%x) tag[%x:%x]\n",
+ i, esp->ireg, esp->sreg,
+ esp->command_block[0],
+ esp->command_block[1]);
+
+ if (esp->command_block[0] < SIMPLE_QUEUE_TAG ||
+ esp->command_block[0] > ORDERED_QUEUE_TAG) {
+ printk(KERN_ERR PFX "esp%d: Reconnect, bad tag "
+ "type %02x.\n",
+ esp->host->unique_id, esp->command_block[0]);
+ return NULL;
+ }
+
+ ent = lp->tagged_cmds[esp->command_block[1]];
+ if (!ent) {
+ printk(KERN_ERR PFX "esp%d: Reconnect, no entry for "
+ "tag %02x.\n",
+ esp->host->unique_id, esp->command_block[1]);
+ return NULL;
+ }
+
+ return ent;
+}
+
+static int esp_reconnect(struct esp *esp)
+{
+ struct esp_cmd_entry *ent;
+ struct esp_target_data *tp;
+ struct esp_lun_data *lp;
+ struct scsi_device *dev;
+ int target, lun;
+
+ BUG_ON(esp->active_cmd);
+ if (esp->rev == FASHME) {
+ /* FASHME puts the target and lun numbers directly
+ * into the fifo.
+ */
+ target = esp->fifo[0];
+ lun = esp->fifo[1] & 0x7;
+ } else {
+ u8 bits = esp_read8(ESP_FDATA);
+
+ /* Older chips put the lun directly into the fifo, but
+ * the target is given as a sample of the arbitration
+ * lines on the bus at reselection time. So we should
+ * see the ID of the ESP and the one reconnecting target
+ * set in the bitmap.
+ */
+ if (!(bits & esp->scsi_id_mask))
+ goto do_reset;
+ bits &= ~esp->scsi_id_mask;
+ if (!bits || (bits & (bits - 1)))
+ goto do_reset;
+
+ target = ffs(bits) - 1;
+ lun = (esp_read8(ESP_FDATA) & 0x7);
+
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ if (esp->rev == ESP100) {
+ u8 ireg = esp_read8(ESP_INTRPT);
+ /* This chip has a bug during reselection that can
+ * cause a spurious illegal-command interrupt, which
+ * we simply ACK here. Another possibility is a bus
+ * reset so we must check for that.
+ */
+ if (ireg & ESP_INTR_SR)
+ goto do_reset;
+ }
+ scsi_esp_cmd(esp, ESP_CMD_NULL);
+ }
+
+ esp_write_tgt_sync(esp, target);
+ esp_write_tgt_config3(esp, target);
+
+ scsi_esp_cmd(esp, ESP_CMD_MOK);
+
+ if (esp->rev == FASHME)
+ esp_write8(target | ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT,
+ ESP_BUSID);
+
+ tp = &esp->target[target];
+ dev = __scsi_device_lookup_by_target(tp->starget, lun);
+ if (!dev) {
+ printk(KERN_ERR PFX "esp%d: Reconnect, no lp "
+ "tgt[%u] lun[%u]\n",
+ esp->host->unique_id, target, lun);
+ goto do_reset;
+ }
+ lp = dev->hostdata;
+
+ ent = lp->non_tagged_cmd;
+ if (!ent) {
+ ent = esp_reconnect_with_tag(esp, lp);
+ if (!ent)
+ goto do_reset;
+ }
+
+ esp->active_cmd = ent;
+
+ if (ent->flags & ESP_CMD_FLAG_ABORT) {
+ esp->msg_out[0] = ABORT_TASK_SET;
+ esp->msg_out_len = 1;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+ }
+
+ esp_event(esp, ESP_EVENT_CHECK_PHASE);
+ esp_restore_pointers(esp, ent);
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ return 1;
+
+do_reset:
+ esp_schedule_reset(esp);
+ return 0;
+}
+
+static int esp_finish_select(struct esp *esp)
+{
+ struct esp_cmd_entry *ent;
+ struct scsi_cmnd *cmd;
+ u8 orig_select_state;
+
+ orig_select_state = esp->select_state;
+
+ /* No longer selecting. */
+ esp->select_state = ESP_SELECT_NONE;
+
+ esp->seqreg = esp_read8(ESP_SSTEP) & ESP_STEP_VBITS;
+ ent = esp->active_cmd;
+ cmd = ent->cmd;
+
+ if (esp->ops->dma_error(esp)) {
+ /* If we see a DMA error during or as a result of selection,
+ * all bets are off.
+ */
+ esp_schedule_reset(esp);
+ esp_cmd_is_done(esp, ent, cmd, (DID_ERROR << 16));
+ return 0;
+ }
+
+ esp->ops->dma_invalidate(esp);
+
+ if (esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) {
+ struct esp_target_data *tp = &esp->target[cmd->device->id];
+
+ /* Carefully back out of the selection attempt. Release
+ * resources (such as DMA mapping & TAG) and reset state (such
+ * as message out and command delivery variables).
+ */
+ if (!(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) {
+ esp_unmap_dma(esp, cmd);
+ esp_free_lun_tag(ent, cmd->device->hostdata);
+ tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_NEGO_WIDE);
+ esp->flags &= ~ESP_FLAG_DOING_SLOWCMD;
+ esp->cmd_bytes_ptr = NULL;
+ esp->cmd_bytes_left = 0;
+ } else {
+ esp->ops->unmap_single(esp, ent->sense_dma,
+ SCSI_SENSE_BUFFERSIZE,
+ DMA_FROM_DEVICE);
+ ent->sense_ptr = NULL;
+ }
+
+ /* Now that the state is unwound properly, put back onto
+ * the issue queue. This command is no longer active.
+ */
+ list_del(&ent->list);
+ list_add(&ent->list, &esp->queued_cmds);
+ esp->active_cmd = NULL;
+
+ /* Return value ignored by caller, it directly invokes
+ * esp_reconnect().
+ */
+ return 0;
+ }
+
+ if (esp->ireg == ESP_INTR_DC) {
+ struct scsi_device *dev = cmd->device;
+
+ /* Disconnect. Make sure we re-negotiate sync and
+ * wide parameters if this target starts responding
+ * again in the future.
+ */
+ esp->target[dev->id].flags |= ESP_TGT_CHECK_NEGO;
+
+ scsi_esp_cmd(esp, ESP_CMD_ESEL);
+ esp_cmd_is_done(esp, ent, cmd, (DID_BAD_TARGET << 16));
+ return 1;
+ }
+
+ if (esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) {
+ /* Selection successful. On pre-FAST chips we have
+ * to do a NOP and possibly clean out the FIFO.
+ */
+ if (esp->rev <= ESP236) {
+ int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
+
+ scsi_esp_cmd(esp, ESP_CMD_NULL);
+
+ if (!fcnt &&
+ (!esp->prev_soff ||
+ ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP)))
+ esp_flush_fifo(esp);
+ }
+
+ /* If we are doing a slow command, negotiation, etc.
+ * we'll do the right thing as we transition to the
+ * next phase.
+ */
+ esp_event(esp, ESP_EVENT_CHECK_PHASE);
+ return 0;
+ }
+
+ printk("ESP: Unexpected selection completion ireg[%x].\n",
+ esp->ireg);
+ esp_schedule_reset(esp);
+ return 0;
+}
+
+static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent,
+ struct scsi_cmnd *cmd)
+{
+ int fifo_cnt, ecount, bytes_sent, flush_fifo;
+
+ fifo_cnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES;
+ if (esp->prev_cfg3 & ESP_CONFIG3_EWIDE)
+ fifo_cnt <<= 1;
+
+ ecount = 0;
+ if (!(esp->sreg & ESP_STAT_TCNT)) {
+ ecount = ((unsigned int)esp_read8(ESP_TCLOW) |
+ (((unsigned int)esp_read8(ESP_TCMED)) << 8));
+ if (esp->rev == FASHME)
+ ecount |= ((unsigned int)esp_read8(FAS_RLO)) << 16;
+ }
+
+ bytes_sent = esp->data_dma_len;
+ bytes_sent -= ecount;
+
+ if (!(ent->flags & ESP_CMD_FLAG_WRITE))
+ bytes_sent -= fifo_cnt;
+
+ flush_fifo = 0;
+ if (!esp->prev_soff) {
+ /* Synchronous data transfer, always flush fifo. */
+ flush_fifo = 1;
+ } else {
+ if (esp->rev == ESP100) {
+ u32 fflags, phase;
+
+ /* ESP100 has a chip bug where in the synchronous data
+ * phase it can mistake a final long REQ pulse from the
+ * target as an extra data byte. Fun.
+ *
+ * To detect this case we resample the status register
+ * and fifo flags. If we're still in a data phase and
+ * we see spurious chunks in the fifo, we return error
+ * to the caller which should reset and set things up
+ * such that we only try future transfers to this
+ * target in synchronous mode.
+ */
+ esp->sreg = esp_read8(ESP_STATUS);
+ phase = esp->sreg & ESP_STAT_PMASK;
+ fflags = esp_read8(ESP_FFLAGS);
+
+ if ((phase == ESP_DOP &&
+ (fflags & ESP_FF_ONOTZERO)) ||
+ (phase == ESP_DIP &&
+ (fflags & ESP_FF_FBYTES)))
+ return -1;
+ }
+ if (!(ent->flags & ESP_CMD_FLAG_WRITE))
+ flush_fifo = 1;
+ }
+
+ if (flush_fifo)
+ esp_flush_fifo(esp);
+
+ return bytes_sent;
+}
+
+static void esp_setsync(struct esp *esp, struct esp_target_data *tp,
+ u8 scsi_period, u8 scsi_offset,
+ u8 esp_stp, u8 esp_soff)
+{
+ spi_period(tp->starget) = scsi_period;
+ spi_offset(tp->starget) = scsi_offset;
+ spi_width(tp->starget) = (tp->flags & ESP_TGT_WIDE) ? 1 : 0;
+
+ if (esp_soff) {
+ esp_stp &= 0x1f;
+ esp_soff |= esp->radelay;
+ if (esp->rev >= FAS236) {
+ u8 bit = ESP_CONFIG3_FSCSI;
+ if (esp->rev >= FAS100A)
+ bit = ESP_CONFIG3_FAST;
+
+ if (scsi_period < 50) {
+ if (esp->rev == FASHME)
+ esp_soff &= ~esp->radelay;
+ tp->esp_config3 |= bit;
+ } else {
+ tp->esp_config3 &= ~bit;
+ }
+ esp->prev_cfg3 = tp->esp_config3;
+ esp_write8(esp->prev_cfg3, ESP_CFG3);
+ }
+ }
+
+ tp->esp_period = esp->prev_stp = esp_stp;
+ tp->esp_offset = esp->prev_soff = esp_soff;
+
+ esp_write8(esp_soff, ESP_SOFF);
+ esp_write8(esp_stp, ESP_STP);
+
+ tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_CHECK_NEGO);
+
+ spi_display_xfer_agreement(tp->starget);
+}
+
+static void esp_msgin_reject(struct esp *esp)
+{
+ struct esp_cmd_entry *ent = esp->active_cmd;
+ struct scsi_cmnd *cmd = ent->cmd;
+ struct esp_target_data *tp;
+ int tgt;
+
+ tgt = cmd->device->id;
+ tp = &esp->target[tgt];
+
+ if (tp->flags & ESP_TGT_NEGO_WIDE) {
+ tp->flags &= ~(ESP_TGT_NEGO_WIDE | ESP_TGT_WIDE);
+
+ if (!esp_need_to_nego_sync(tp)) {
+ tp->flags &= ~ESP_TGT_CHECK_NEGO;
+ scsi_esp_cmd(esp, ESP_CMD_RATN);
+ } else {
+ esp->msg_out_len =
+ spi_populate_sync_msg(&esp->msg_out[0],
+ tp->nego_goal_period,
+ tp->nego_goal_offset);
+ tp->flags |= ESP_TGT_NEGO_SYNC;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+ }
+ return;
+ }
+
+ if (tp->flags & ESP_TGT_NEGO_SYNC) {
+ tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_CHECK_NEGO);
+ tp->esp_period = 0;
+ tp->esp_offset = 0;
+ esp_setsync(esp, tp, 0, 0, 0, 0);
+ scsi_esp_cmd(esp, ESP_CMD_RATN);
+ return;
+ }
+
+ esp->msg_out[0] = ABORT_TASK_SET;
+ esp->msg_out_len = 1;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+}
+
+static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp)
+{
+ u8 period = esp->msg_in[3];
+ u8 offset = esp->msg_in[4];
+ u8 stp;
+
+ if (!(tp->flags & ESP_TGT_NEGO_SYNC))
+ goto do_reject;
+
+ if (offset > 15)
+ goto do_reject;
+
+ if (offset) {
+ int rounded_up, one_clock;
+
+ if (period > esp->max_period) {
+ period = offset = 0;
+ goto do_sdtr;
+ }
+ if (period < esp->min_period)
+ goto do_reject;
+
+ one_clock = esp->ccycle / 1000;
+ rounded_up = (period << 2);
+ rounded_up = (rounded_up + one_clock - 1) / one_clock;
+ stp = rounded_up;
+ if (stp && esp->rev >= FAS236) {
+ if (stp >= 50)
+ stp--;
+ }
+ } else {
+ stp = 0;
+ }
+
+ esp_setsync(esp, tp, period, offset, stp, offset);
+ return;
+
+do_reject:
+ esp->msg_out[0] = MESSAGE_REJECT;
+ esp->msg_out_len = 1;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+ return;
+
+do_sdtr:
+ tp->nego_goal_period = period;
+ tp->nego_goal_offset = offset;
+ esp->msg_out_len =
+ spi_populate_sync_msg(&esp->msg_out[0],
+ tp->nego_goal_period,
+ tp->nego_goal_offset);
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+}
+
+static void esp_msgin_wdtr(struct esp *esp, struct esp_target_data *tp)
+{
+ int size = 8 << esp->msg_in[3];
+ u8 cfg3;
+
+ if (esp->rev != FASHME)
+ goto do_reject;
+
+ if (size != 8 && size != 16)
+ goto do_reject;
+
+ if (!(tp->flags & ESP_TGT_NEGO_WIDE))
+ goto do_reject;
+
+ cfg3 = tp->esp_config3;
+ if (size == 16) {
+ tp->flags |= ESP_TGT_WIDE;
+ cfg3 |= ESP_CONFIG3_EWIDE;
+ } else {
+ tp->flags &= ~ESP_TGT_WIDE;
+ cfg3 &= ~ESP_CONFIG3_EWIDE;
+ }
+ tp->esp_config3 = cfg3;
+ esp->prev_cfg3 = cfg3;
+ esp_write8(cfg3, ESP_CFG3);
+
+ tp->flags &= ~ESP_TGT_NEGO_WIDE;
+
+ spi_period(tp->starget) = 0;
+ spi_offset(tp->starget) = 0;
+ if (!esp_need_to_nego_sync(tp)) {
+ tp->flags &= ~ESP_TGT_CHECK_NEGO;
+ scsi_esp_cmd(esp, ESP_CMD_RATN);
+ } else {
+ esp->msg_out_len =
+ spi_populate_sync_msg(&esp->msg_out[0],
+ tp->nego_goal_period,
+ tp->nego_goal_offset);
+ tp->flags |= ESP_TGT_NEGO_SYNC;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+ }
+ return;
+
+do_reject:
+ esp->msg_out[0] = MESSAGE_REJECT;
+ esp->msg_out_len = 1;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+}
+
+static void esp_msgin_extended(struct esp *esp)
+{
+ struct esp_cmd_entry *ent = esp->active_cmd;
+ struct scsi_cmnd *cmd = ent->cmd;
+ struct esp_target_data *tp;
+ int tgt = cmd->device->id;
+
+ tp = &esp->target[tgt];
+ if (esp->msg_in[2] == EXTENDED_SDTR) {
+ esp_msgin_sdtr(esp, tp);
+ return;
+ }
+ if (esp->msg_in[2] == EXTENDED_WDTR) {
+ esp_msgin_wdtr(esp, tp);
+ return;
+ }
+
+ printk("ESP: Unexpected extended msg type %x\n",
+ esp->msg_in[2]);
+
+ esp->msg_out[0] = ABORT_TASK_SET;
+ esp->msg_out_len = 1;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+}
+
+/* Analyze msgin bytes received from target so far. Return non-zero
+ * if there are more bytes needed to complete the message.
+ */
+static int esp_msgin_process(struct esp *esp)
+{
+ u8 msg0 = esp->msg_in[0];
+ int len = esp->msg_in_len;
+
+ if (msg0 & 0x80) {
+ /* Identify */
+ printk("ESP: Unexpected msgin identify\n");
+ return 0;
+ }
+
+ switch (msg0) {
+ case EXTENDED_MESSAGE:
+ if (len == 1)
+ return 1;
+ if (len < esp->msg_in[1] + 2)
+ return 1;
+ esp_msgin_extended(esp);
+ return 0;
+
+ case IGNORE_WIDE_RESIDUE: {
+ struct esp_cmd_entry *ent;
+ struct esp_cmd_priv *spriv;
+ if (len == 1)
+ return 1;
+
+ if (esp->msg_in[1] != 1)
+ goto do_reject;
+
+ ent = esp->active_cmd;
+ spriv = ESP_CMD_PRIV(ent->cmd);
+
+ if (spriv->cur_residue == sg_dma_len(spriv->cur_sg)) {
+ spriv->cur_sg--;
+ spriv->cur_residue = 1;
+ } else
+ spriv->cur_residue++;
+ spriv->tot_residue++;
+ return 0;
+ }
+ case NOP:
+ return 0;
+ case RESTORE_POINTERS:
+ esp_restore_pointers(esp, esp->active_cmd);
+ return 0;
+ case SAVE_POINTERS:
+ esp_save_pointers(esp, esp->active_cmd);
+ return 0;
+
+ case COMMAND_COMPLETE:
+ case DISCONNECT: {
+ struct esp_cmd_entry *ent = esp->active_cmd;
+
+ ent->message = msg0;
+ esp_event(esp, ESP_EVENT_FREE_BUS);
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ return 0;
+ }
+ case MESSAGE_REJECT:
+ esp_msgin_reject(esp);
+ return 0;
+
+ default:
+ do_reject:
+ esp->msg_out[0] = MESSAGE_REJECT;
+ esp->msg_out_len = 1;
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+ return 0;
+ }
+}
+
+static int esp_process_event(struct esp *esp)
+{
+ int write;
+
+again:
+ write = 0;
+ switch (esp->event) {
+ case ESP_EVENT_CHECK_PHASE:
+ switch (esp->sreg & ESP_STAT_PMASK) {
+ case ESP_DOP:
+ esp_event(esp, ESP_EVENT_DATA_OUT);
+ break;
+ case ESP_DIP:
+ esp_event(esp, ESP_EVENT_DATA_IN);
+ break;
+ case ESP_STATP:
+ esp_flush_fifo(esp);
+ scsi_esp_cmd(esp, ESP_CMD_ICCSEQ);
+ esp_event(esp, ESP_EVENT_STATUS);
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ return 1;
+
+ case ESP_MOP:
+ esp_event(esp, ESP_EVENT_MSGOUT);
+ break;
+
+ case ESP_MIP:
+ esp_event(esp, ESP_EVENT_MSGIN);
+ break;
+
+ case ESP_CMDP:
+ esp_event(esp, ESP_EVENT_CMD_START);
+ break;
+
+ default:
+ printk("ESP: Unexpected phase, sreg=%02x\n",
+ esp->sreg);
+ esp_schedule_reset(esp);
+ return 0;
+ }
+ goto again;
+ break;
+
+ case ESP_EVENT_DATA_IN:
+ write = 1;
+ /* fallthru */
+
+ case ESP_EVENT_DATA_OUT: {
+ struct esp_cmd_entry *ent = esp->active_cmd;
+ struct scsi_cmnd *cmd = ent->cmd;
+ dma_addr_t dma_addr = esp_cur_dma_addr(ent, cmd);
+ unsigned int dma_len = esp_cur_dma_len(ent, cmd);
+
+ if (esp->rev == ESP100)
+ scsi_esp_cmd(esp, ESP_CMD_NULL);
+
+ if (write)
+ ent->flags |= ESP_CMD_FLAG_WRITE;
+ else
+ ent->flags &= ~ESP_CMD_FLAG_WRITE;
+
+ dma_len = esp_dma_length_limit(esp, dma_addr, dma_len);
+ esp->data_dma_len = dma_len;
+
+ if (!dma_len) {
+ printk(KERN_ERR PFX "esp%d: DMA length is zero!\n",
+ esp->host->unique_id);
+ printk(KERN_ERR PFX "esp%d: cur adr[%08llx] len[%08x]\n",
+ esp->host->unique_id,
+ (unsigned long long)esp_cur_dma_addr(ent, cmd),
+ esp_cur_dma_len(ent, cmd));
+ esp_schedule_reset(esp);
+ return 0;
+ }
+
+ esp_log_datastart("ESP: start data addr[%08llx] len[%u] "
+ "write(%d)\n",
+ (unsigned long long)dma_addr, dma_len, write);
+
+ esp->ops->send_dma_cmd(esp, dma_addr, dma_len, dma_len,
+ write, ESP_CMD_DMA | ESP_CMD_TI);
+ esp_event(esp, ESP_EVENT_DATA_DONE);
+ break;
+ }
+ case ESP_EVENT_DATA_DONE: {
+ struct esp_cmd_entry *ent = esp->active_cmd;
+ struct scsi_cmnd *cmd = ent->cmd;
+ int bytes_sent;
+
+ if (esp->ops->dma_error(esp)) {
+ printk("ESP: data done, DMA error, resetting\n");
+ esp_schedule_reset(esp);
+ return 0;
+ }
+
+ if (ent->flags & ESP_CMD_FLAG_WRITE) {
+ /* XXX parity errors, etc. XXX */
+
+ esp->ops->dma_drain(esp);
+ }
+ esp->ops->dma_invalidate(esp);
+
+ if (esp->ireg != ESP_INTR_BSERV) {
+ /* We should always see exactly a bus-service
+ * interrupt at the end of a successful transfer.
+ */
+ printk("ESP: data done, not BSERV, resetting\n");
+ esp_schedule_reset(esp);
+ return 0;
+ }
+
+ bytes_sent = esp_data_bytes_sent(esp, ent, cmd);
+
+ esp_log_datadone("ESP: data done flgs[%x] sent[%d]\n",
+ ent->flags, bytes_sent);
+
+ if (bytes_sent < 0) {
+ /* XXX force sync mode for this target XXX */
+ esp_schedule_reset(esp);
+ return 0;
+ }
+
+ esp_advance_dma(esp, ent, cmd, bytes_sent);
+ esp_event(esp, ESP_EVENT_CHECK_PHASE);
+ goto again;
+ break;
+ }
+
+ case ESP_EVENT_STATUS: {
+ struct esp_cmd_entry *ent = esp->active_cmd;
+
+ if (esp->ireg & ESP_INTR_FDONE) {
+ ent->status = esp_read8(ESP_FDATA);
+ ent->message = esp_read8(ESP_FDATA);
+ scsi_esp_cmd(esp, ESP_CMD_MOK);
+ } else if (esp->ireg == ESP_INTR_BSERV) {
+ ent->status = esp_read8(ESP_FDATA);
+ ent->message = 0xff;
+ esp_event(esp, ESP_EVENT_MSGIN);
+ return 0;
+ }
+
+ if (ent->message != COMMAND_COMPLETE) {
+ printk("ESP: Unexpected message %x in status\n",
+ ent->message);
+ esp_schedule_reset(esp);
+ return 0;
+ }
+
+ esp_event(esp, ESP_EVENT_FREE_BUS);
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ break;
+ }
+ case ESP_EVENT_FREE_BUS: {
+ struct esp_cmd_entry *ent = esp->active_cmd;
+ struct scsi_cmnd *cmd = ent->cmd;
+
+ if (ent->message == COMMAND_COMPLETE ||
+ ent->message == DISCONNECT)
+ scsi_esp_cmd(esp, ESP_CMD_ESEL);
+
+ if (ent->message == COMMAND_COMPLETE) {
+ esp_log_cmddone("ESP: Command done status[%x] "
+ "message[%x]\n",
+ ent->status, ent->message);
+ if (ent->status == SAM_STAT_TASK_SET_FULL)
+ esp_event_queue_full(esp, ent);
+
+ if (ent->status == SAM_STAT_CHECK_CONDITION &&
+ !(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) {
+ ent->flags |= ESP_CMD_FLAG_AUTOSENSE;
+ esp_autosense(esp, ent);
+ } else {
+ esp_cmd_is_done(esp, ent, cmd,
+ compose_result(ent->status,
+ ent->message,
+ DID_OK));
+ }
+ } else if (ent->message == DISCONNECT) {
+ esp_log_disconnect("ESP: Disconnecting tgt[%d] "
+ "tag[%x:%x]\n",
+ cmd->device->id,
+ ent->tag[0], ent->tag[1]);
+
+ esp->active_cmd = NULL;
+ esp_maybe_execute_command(esp);
+ } else {
+ printk("ESP: Unexpected message %x in freebus\n",
+ ent->message);
+ esp_schedule_reset(esp);
+ return 0;
+ }
+ if (esp->active_cmd)
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ break;
+ }
+ case ESP_EVENT_MSGOUT: {
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+
+ if (esp_debug & ESP_DEBUG_MSGOUT) {
+ int i;
+ printk("ESP: Sending message [ ");
+ for (i = 0; i < esp->msg_out_len; i++)
+ printk("%02x ", esp->msg_out[i]);
+ printk("]\n");
+ }
+
+ if (esp->rev == FASHME) {
+ int i;
+
+ /* Always use the fifo. */
+ for (i = 0; i < esp->msg_out_len; i++) {
+ esp_write8(esp->msg_out[i], ESP_FDATA);
+ esp_write8(0, ESP_FDATA);
+ }
+ scsi_esp_cmd(esp, ESP_CMD_TI);
+ } else {
+ if (esp->msg_out_len == 1) {
+ esp_write8(esp->msg_out[0], ESP_FDATA);
+ scsi_esp_cmd(esp, ESP_CMD_TI);
+ } else {
+ /* Use DMA. */
+ memcpy(esp->command_block,
+ esp->msg_out,
+ esp->msg_out_len);
+
+ esp->ops->send_dma_cmd(esp,
+ esp->command_block_dma,
+ esp->msg_out_len,
+ esp->msg_out_len,
+ 0,
+ ESP_CMD_DMA|ESP_CMD_TI);
+ }
+ }
+ esp_event(esp, ESP_EVENT_MSGOUT_DONE);
+ break;
+ }
+ case ESP_EVENT_MSGOUT_DONE:
+ if (esp->rev == FASHME) {
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ } else {
+ if (esp->msg_out_len > 1)
+ esp->ops->dma_invalidate(esp);
+ }
+
+ if (!(esp->ireg & ESP_INTR_DC)) {
+ if (esp->rev != FASHME)
+ scsi_esp_cmd(esp, ESP_CMD_NULL);
+ }
+ esp_event(esp, ESP_EVENT_CHECK_PHASE);
+ goto again;
+ case ESP_EVENT_MSGIN:
+ if (esp->ireg & ESP_INTR_BSERV) {
+ if (esp->rev == FASHME) {
+ if (!(esp_read8(ESP_STATUS2) &
+ ESP_STAT2_FEMPTY))
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ } else {
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ if (esp->rev == ESP100)
+ scsi_esp_cmd(esp, ESP_CMD_NULL);
+ }
+ scsi_esp_cmd(esp, ESP_CMD_TI);
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ return 1;
+ }
+ if (esp->ireg & ESP_INTR_FDONE) {
+ u8 val;
+
+ if (esp->rev == FASHME)
+ val = esp->fifo[0];
+ else
+ val = esp_read8(ESP_FDATA);
+ esp->msg_in[esp->msg_in_len++] = val;
+
+ esp_log_msgin("ESP: Got msgin byte %x\n", val);
+
+ if (!esp_msgin_process(esp))
+ esp->msg_in_len = 0;
+
+ if (esp->rev == FASHME)
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+
+ scsi_esp_cmd(esp, ESP_CMD_MOK);
+
+ if (esp->event != ESP_EVENT_FREE_BUS)
+ esp_event(esp, ESP_EVENT_CHECK_PHASE);
+ } else {
+ printk("ESP: MSGIN neither BSERV not FDON, resetting");
+ esp_schedule_reset(esp);
+ return 0;
+ }
+ break;
+ case ESP_EVENT_CMD_START:
+ memcpy(esp->command_block, esp->cmd_bytes_ptr,
+ esp->cmd_bytes_left);
+ if (esp->rev == FASHME)
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ esp->ops->send_dma_cmd(esp, esp->command_block_dma,
+ esp->cmd_bytes_left, 16, 0,
+ ESP_CMD_DMA | ESP_CMD_TI);
+ esp_event(esp, ESP_EVENT_CMD_DONE);
+ esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
+ break;
+ case ESP_EVENT_CMD_DONE:
+ esp->ops->dma_invalidate(esp);
+ if (esp->ireg & ESP_INTR_BSERV) {
+ esp_event(esp, ESP_EVENT_CHECK_PHASE);
+ goto again;
+ }
+ esp_schedule_reset(esp);
+ return 0;
+ break;
+
+ case ESP_EVENT_RESET:
+ scsi_esp_cmd(esp, ESP_CMD_RS);
+ break;
+
+ default:
+ printk("ESP: Unexpected event %x, resetting\n",
+ esp->event);
+ esp_schedule_reset(esp);
+ return 0;
+ break;
+ }
+ return 1;
+}
+
+static void esp_reset_cleanup_one(struct esp *esp, struct esp_cmd_entry *ent)
+{
+ struct scsi_cmnd *cmd = ent->cmd;
+
+ esp_unmap_dma(esp, cmd);
+ esp_free_lun_tag(ent, cmd->device->hostdata);
+ cmd->result = DID_RESET << 16;
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) {
+ esp->ops->unmap_single(esp, ent->sense_dma,
+ SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+ ent->sense_ptr = NULL;
+ }
+
+ cmd->scsi_done(cmd);
+ list_del(&ent->list);
+ esp_put_ent(esp, ent);
+}
+
+static void esp_clear_hold(struct scsi_device *dev, void *data)
+{
+ struct esp_lun_data *lp = dev->hostdata;
+
+ BUG_ON(lp->num_tagged);
+ lp->hold = 0;
+}
+
+static void esp_reset_cleanup(struct esp *esp)
+{
+ struct esp_cmd_entry *ent, *tmp;
+ int i;
+
+ list_for_each_entry_safe(ent, tmp, &esp->queued_cmds, list) {
+ struct scsi_cmnd *cmd = ent->cmd;
+
+ list_del(&ent->list);
+ cmd->result = DID_RESET << 16;
+ cmd->scsi_done(cmd);
+ esp_put_ent(esp, ent);
+ }
+
+ list_for_each_entry_safe(ent, tmp, &esp->active_cmds, list) {
+ if (ent == esp->active_cmd)
+ esp->active_cmd = NULL;
+ esp_reset_cleanup_one(esp, ent);
+ }
+
+ BUG_ON(esp->active_cmd != NULL);
+
+ /* Force renegotiation of sync/wide transfers. */
+ for (i = 0; i < ESP_MAX_TARGET; i++) {
+ struct esp_target_data *tp = &esp->target[i];
+
+ tp->esp_period = 0;
+ tp->esp_offset = 0;
+ tp->esp_config3 &= ~(ESP_CONFIG3_EWIDE |
+ ESP_CONFIG3_FSCSI |
+ ESP_CONFIG3_FAST);
+ tp->flags &= ~ESP_TGT_WIDE;
+ tp->flags |= ESP_TGT_CHECK_NEGO;
+
+ if (tp->starget)
+ starget_for_each_device(tp->starget, NULL,
+ esp_clear_hold);
+ }
+}
+
+/* Runs under host->lock */
+static void __esp_interrupt(struct esp *esp)
+{
+ int finish_reset, intr_done;
+ u8 phase;
+
+ esp->sreg = esp_read8(ESP_STATUS);
+
+ if (esp->flags & ESP_FLAG_RESETTING) {
+ finish_reset = 1;
+ } else {
+ if (esp_check_gross_error(esp))
+ return;
+
+ finish_reset = esp_check_spur_intr(esp);
+ if (finish_reset < 0)
+ return;
+ }
+
+ esp->ireg = esp_read8(ESP_INTRPT);
+
+ if (esp->ireg & ESP_INTR_SR)
+ finish_reset = 1;
+
+ if (finish_reset) {
+ esp_reset_cleanup(esp);
+ if (esp->eh_reset) {
+ complete(esp->eh_reset);
+ esp->eh_reset = NULL;
+ }
+ return;
+ }
+
+ phase = (esp->sreg & ESP_STAT_PMASK);
+ if (esp->rev == FASHME) {
+ if (((phase != ESP_DIP && phase != ESP_DOP) &&
+ esp->select_state == ESP_SELECT_NONE &&
+ esp->event != ESP_EVENT_STATUS &&
+ esp->event != ESP_EVENT_DATA_DONE) ||
+ (esp->ireg & ESP_INTR_RSEL)) {
+ esp->sreg2 = esp_read8(ESP_STATUS2);
+ if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
+ (esp->sreg2 & ESP_STAT2_F1BYTE))
+ hme_read_fifo(esp);
+ }
+ }
+
+ esp_log_intr("ESP: intr sreg[%02x] seqreg[%02x] "
+ "sreg2[%02x] ireg[%02x]\n",
+ esp->sreg, esp->seqreg, esp->sreg2, esp->ireg);
+
+ intr_done = 0;
+
+ if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN | ESP_INTR_IC)) {
+ printk("ESP: unexpected IREG %02x\n", esp->ireg);
+ if (esp->ireg & ESP_INTR_IC)
+ esp_dump_cmd_log(esp);
+
+ esp_schedule_reset(esp);
+ } else {
+ if (!(esp->ireg & ESP_INTR_RSEL)) {
+ /* Some combination of FDONE, BSERV, DC. */
+ if (esp->select_state != ESP_SELECT_NONE)
+ intr_done = esp_finish_select(esp);
+ } else if (esp->ireg & ESP_INTR_RSEL) {
+ if (esp->active_cmd)
+ (void) esp_finish_select(esp);
+ intr_done = esp_reconnect(esp);
+ }
+ }
+ while (!intr_done)
+ intr_done = esp_process_event(esp);
+}
+
+irqreturn_t scsi_esp_intr(int irq, void *dev_id)
+{
+ struct esp *esp = dev_id;
+ unsigned long flags;
+ irqreturn_t ret;
+
+ spin_lock_irqsave(esp->host->host_lock, flags);
+ ret = IRQ_NONE;
+ if (esp->ops->irq_pending(esp)) {
+ ret = IRQ_HANDLED;
+ for (;;) {
+ int i;
+
+ __esp_interrupt(esp);
+ if (!(esp->flags & ESP_FLAG_QUICKIRQ_CHECK))
+ break;
+ esp->flags &= ~ESP_FLAG_QUICKIRQ_CHECK;
+
+ for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) {
+ if (esp->ops->irq_pending(esp))
+ break;
+ }
+ if (i == ESP_QUICKIRQ_LIMIT)
+ break;
+ }
+ }
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(scsi_esp_intr);
+
+static void __devinit esp_get_revision(struct esp *esp)
+{
+ u8 val;
+
+ esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
+ esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
+ esp_write8(esp->config2, ESP_CFG2);
+
+ val = esp_read8(ESP_CFG2);
+ val &= ~ESP_CONFIG2_MAGIC;
+ if (val != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
+ /* If what we write to cfg2 does not come back, cfg2 is not
+ * implemented, therefore this must be a plain esp100.
+ */
+ esp->rev = ESP100;
+ } else {
+ esp->config2 = 0;
+ esp_set_all_config3(esp, 5);
+ esp->prev_cfg3 = 5;
+ esp_write8(esp->config2, ESP_CFG2);
+ esp_write8(0, ESP_CFG3);
+ esp_write8(esp->prev_cfg3, ESP_CFG3);
+
+ val = esp_read8(ESP_CFG3);
+ if (val != 5) {
+ /* The cfg2 register is implemented, however
+ * cfg3 is not, must be esp100a.
+ */
+ esp->rev = ESP100A;
+ } else {
+ esp_set_all_config3(esp, 0);
+ esp->prev_cfg3 = 0;
+ esp_write8(esp->prev_cfg3, ESP_CFG3);
+
+ /* All of cfg{1,2,3} implemented, must be one of
+ * the fas variants, figure out which one.
+ */
+ if (esp->cfact == 0 || esp->cfact > ESP_CCF_F5) {
+ esp->rev = FAST;
+ esp->sync_defp = SYNC_DEFP_FAST;
+ } else {
+ esp->rev = ESP236;
+ }
+ esp->config2 = 0;
+ esp_write8(esp->config2, ESP_CFG2);
+ }
+ }
+}
+
+static void __devinit esp_init_swstate(struct esp *esp)
+{
+ int i;
+
+ INIT_LIST_HEAD(&esp->queued_cmds);
+ INIT_LIST_HEAD(&esp->active_cmds);
+ INIT_LIST_HEAD(&esp->esp_cmd_pool);
+
+ /* Start with a clear state, domain validation (via ->slave_configure,
+ * spi_dv_device()) will attempt to enable SYNC, WIDE, and tagged
+ * commands.
+ */
+ for (i = 0 ; i < ESP_MAX_TARGET; i++) {
+ esp->target[i].flags = 0;
+ esp->target[i].nego_goal_period = 0;
+ esp->target[i].nego_goal_offset = 0;
+ esp->target[i].nego_goal_width = 0;
+ esp->target[i].nego_goal_tags = 0;
+ }
+}
+
+/* This places the ESP into a known state at boot time. */
+static void __devinit esp_bootup_reset(struct esp *esp)
+{
+ u8 val;
+
+ /* Reset the DMA */
+ esp->ops->reset_dma(esp);
+
+ /* Reset the ESP */
+ esp_reset_esp(esp);
+
+ /* Reset the SCSI bus, but tell ESP not to generate an irq */
+ val = esp_read8(ESP_CFG1);
+ val |= ESP_CONFIG1_SRRDISAB;
+ esp_write8(val, ESP_CFG1);
+
+ scsi_esp_cmd(esp, ESP_CMD_RS);
+ udelay(400);
+
+ esp_write8(esp->config1, ESP_CFG1);
+
+ /* Eat any bitrot in the chip and we are done... */
+ esp_read8(ESP_INTRPT);
+}
+
+static void __devinit esp_set_clock_params(struct esp *esp)
+{
+ int fmhz;
+ u8 ccf;
+
+ /* This is getting messy but it has to be done correctly or else
+ * you get weird behavior all over the place. We are trying to
+ * basically figure out three pieces of information.
+ *
+ * a) Clock Conversion Factor
+ *
+ * This is a representation of the input crystal clock frequency
+ * going into the ESP on this machine. Any operation whose timing
+ * is longer than 400ns depends on this value being correct. For
+ * example, you'll get blips for arbitration/selection during high
+ * load or with multiple targets if this is not set correctly.
+ *
+ * b) Selection Time-Out
+ *
+ * The ESP isn't very bright and will arbitrate for the bus and try
+ * to select a target forever if you let it. This value tells the
+ * ESP when it has taken too long to negotiate and that it should
+ * interrupt the CPU so we can see what happened. The value is
+ * computed as follows (from NCR/Symbios chip docs).
+ *
+ * (Time Out Period) * (Input Clock)
+ * STO = ----------------------------------
+ * (8192) * (Clock Conversion Factor)
+ *
+ * We use a time out period of 250ms (ESP_BUS_TIMEOUT).
+ *
+ * c) Imperical constants for synchronous offset and transfer period
+ * register values
+ *
+ * This entails the smallest and largest sync period we could ever
+ * handle on this ESP.
+ */
+ fmhz = esp->cfreq;
+
+ ccf = ((fmhz / 1000000) + 4) / 5;
+ if (ccf == 1)
+ ccf = 2;
+
+ /* If we can't find anything reasonable, just assume 20MHZ.
+ * This is the clock frequency of the older sun4c's where I've
+ * been unable to find the clock-frequency PROM property. All
+ * other machines provide useful values it seems.
+ */
+ if (fmhz <= 5000000 || ccf < 1 || ccf > 8) {
+ fmhz = 20000000;
+ ccf = 4;
+ }
+
+ esp->cfact = (ccf == 8 ? 0 : ccf);
+ esp->cfreq = fmhz;
+ esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
+ esp->ctick = ESP_TICK(ccf, esp->ccycle);
+ esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
+ esp->sync_defp = SYNC_DEFP_SLOW;
+}
+
+static const char *esp_chip_names[] = {
+ "ESP100",
+ "ESP100A",
+ "ESP236",
+ "FAS236",
+ "FAS100A",
+ "FAST",
+ "FASHME",
+};
+
+static struct scsi_transport_template *esp_transport_template;
+
+int __devinit scsi_esp_register(struct esp *esp, struct device *dev)
+{
+ static int instance;
+ int err;
+
+ esp->host->transportt = esp_transport_template;
+ esp->host->max_lun = ESP_MAX_LUN;
+ esp->host->cmd_per_lun = 2;
+
+ esp_set_clock_params(esp);
+
+ esp_get_revision(esp);
+
+ esp_init_swstate(esp);
+
+ esp_bootup_reset(esp);
+
+ printk(KERN_INFO PFX "esp%u, regs[%1p:%1p] irq[%u]\n",
+ esp->host->unique_id, esp->regs, esp->dma_regs,
+ esp->host->irq);
+ printk(KERN_INFO PFX "esp%u is a %s, %u MHz (ccf=%u), SCSI ID %u\n",
+ esp->host->unique_id, esp_chip_names[esp->rev],
+ esp->cfreq / 1000000, esp->cfact, esp->scsi_id);
+
+ /* Let the SCSI bus reset settle. */
+ ssleep(esp_bus_reset_settle);
+
+ err = scsi_add_host(esp->host, dev);
+ if (err)
+ return err;
+
+ esp->host->unique_id = instance++;
+
+ scsi_scan_host(esp->host);
+
+ return 0;
+}
+EXPORT_SYMBOL(scsi_esp_register);
+
+void __devexit scsi_esp_unregister(struct esp *esp)
+{
+ scsi_remove_host(esp->host);
+}
+EXPORT_SYMBOL(scsi_esp_unregister);
+
+static int esp_slave_alloc(struct scsi_device *dev)
+{
+ struct esp *esp = host_to_esp(dev->host);
+ struct esp_target_data *tp = &esp->target[dev->id];
+ struct esp_lun_data *lp;
+
+ lp = kzalloc(sizeof(*lp), GFP_KERNEL);
+ if (!lp)
+ return -ENOMEM;
+ dev->hostdata = lp;
+
+ tp->starget = dev->sdev_target;
+
+ spi_min_period(tp->starget) = esp->min_period;
+ spi_max_offset(tp->starget) = 15;
+
+ if (esp->flags & ESP_FLAG_WIDE_CAPABLE)
+ spi_max_width(tp->starget) = 1;
+ else
+ spi_max_width(tp->starget) = 0;
+
+ return 0;
+}
+
+static int esp_slave_configure(struct scsi_device *dev)
+{
+ struct esp *esp = host_to_esp(dev->host);
+ struct esp_target_data *tp = &esp->target[dev->id];
+ int goal_tags, queue_depth;
+
+ goal_tags = 0;
+
+ if (dev->tagged_supported) {
+ /* XXX make this configurable somehow XXX */
+ goal_tags = ESP_DEFAULT_TAGS;
+
+ if (goal_tags > ESP_MAX_TAG)
+ goal_tags = ESP_MAX_TAG;
+ }
+
+ queue_depth = goal_tags;
+ if (queue_depth < dev->host->cmd_per_lun)
+ queue_depth = dev->host->cmd_per_lun;
+
+ if (goal_tags) {
+ scsi_set_tag_type(dev, MSG_ORDERED_TAG);
+ scsi_activate_tcq(dev, queue_depth);
+ } else {
+ scsi_deactivate_tcq(dev, queue_depth);
+ }
+ tp->flags |= ESP_TGT_DISCONNECT;
+
+ if (!spi_initial_dv(dev->sdev_target))
+ spi_dv_device(dev);
+
+ return 0;
+}
+
+static void esp_slave_destroy(struct scsi_device *dev)
+{
+ struct esp_lun_data *lp = dev->hostdata;
+
+ kfree(lp);
+ dev->hostdata = NULL;
+}
+
+static int esp_eh_abort_handler(struct scsi_cmnd *cmd)
+{
+ struct esp *esp = host_to_esp(cmd->device->host);
+ struct esp_cmd_entry *ent, *tmp;
+ struct completion eh_done;
+ unsigned long flags;
+
+ /* XXX This helps a lot with debugging but might be a bit
+ * XXX much for the final driver.
+ */
+ spin_lock_irqsave(esp->host->host_lock, flags);
+ printk(KERN_ERR PFX "esp%d: Aborting command [%p:%02x]\n",
+ esp->host->unique_id, cmd, cmd->cmnd[0]);
+ ent = esp->active_cmd;
+ if (ent)
+ printk(KERN_ERR PFX "esp%d: Current command [%p:%02x]\n",
+ esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
+ list_for_each_entry(ent, &esp->queued_cmds, list) {
+ printk(KERN_ERR PFX "esp%d: Queued command [%p:%02x]\n",
+ esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
+ }
+ list_for_each_entry(ent, &esp->active_cmds, list) {
+ printk(KERN_ERR PFX "esp%d: Active command [%p:%02x]\n",
+ esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
+ }
+ esp_dump_cmd_log(esp);
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ spin_lock_irqsave(esp->host->host_lock, flags);
+
+ ent = NULL;
+ list_for_each_entry(tmp, &esp->queued_cmds, list) {
+ if (tmp->cmd == cmd) {
+ ent = tmp;
+ break;
+ }
+ }
+
+ if (ent) {
+ /* Easiest case, we didn't even issue the command
+ * yet so it is trivial to abort.
+ */
+ list_del(&ent->list);
+
+ cmd->result = DID_ABORT << 16;
+ cmd->scsi_done(cmd);
+
+ esp_put_ent(esp, ent);
+
+ goto out_success;
+ }
+
+ init_completion(&eh_done);
+
+ ent = esp->active_cmd;
+ if (ent && ent->cmd == cmd) {
+ /* Command is the currently active command on
+ * the bus. If we already have an output message
+ * pending, no dice.
+ */
+ if (esp->msg_out_len)
+ goto out_failure;
+
+ /* Send out an abort, encouraging the target to
+ * go to MSGOUT phase by asserting ATN.
+ */
+ esp->msg_out[0] = ABORT_TASK_SET;
+ esp->msg_out_len = 1;
+ ent->eh_done = &eh_done;
+
+ scsi_esp_cmd(esp, ESP_CMD_SATN);
+ } else {
+ /* The command is disconnected. This is not easy to
+ * abort. For now we fail and let the scsi error
+ * handling layer go try a scsi bus reset or host
+ * reset.
+ *
+ * What we could do is put together a scsi command
+ * solely for the purpose of sending an abort message
+ * to the target. Coming up with all the code to
+ * cook up scsi commands, special case them everywhere,
+ * etc. is for questionable gain and it would be better
+ * if the generic scsi error handling layer could do at
+ * least some of that for us.
+ *
+ * Anyways this is an area for potential future improvement
+ * in this driver.
+ */
+ goto out_failure;
+ }
+
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ if (!wait_for_completion_timeout(&eh_done, 5 * HZ)) {
+ spin_lock_irqsave(esp->host->host_lock, flags);
+ ent->eh_done = NULL;
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ return FAILED;
+ }
+
+ return SUCCESS;
+
+out_success:
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+ return SUCCESS;
+
+out_failure:
+ /* XXX This might be a good location to set ESP_TGT_BROKEN
+ * XXX since we know which target/lun in particular is
+ * XXX causing trouble.
+ */
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+ return FAILED;
+}
+
+static int esp_eh_bus_reset_handler(struct scsi_cmnd *cmd)
+{
+ struct esp *esp = host_to_esp(cmd->device->host);
+ struct completion eh_reset;
+ unsigned long flags;
+
+ init_completion(&eh_reset);
+
+ spin_lock_irqsave(esp->host->host_lock, flags);
+
+ esp->eh_reset = &eh_reset;
+
+ /* XXX This is too simple... We should add lots of
+ * XXX checks here so that if we find that the chip is
+ * XXX very wedged we return failure immediately so
+ * XXX that we can perform a full chip reset.
+ */
+ esp->flags |= ESP_FLAG_RESETTING;
+ scsi_esp_cmd(esp, ESP_CMD_RS);
+
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ ssleep(esp_bus_reset_settle);
+
+ if (!wait_for_completion_timeout(&eh_reset, 5 * HZ)) {
+ spin_lock_irqsave(esp->host->host_lock, flags);
+ esp->eh_reset = NULL;
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ return FAILED;
+ }
+
+ return SUCCESS;
+}
+
+/* All bets are off, reset the entire device. */
+static int esp_eh_host_reset_handler(struct scsi_cmnd *cmd)
+{
+ struct esp *esp = host_to_esp(cmd->device->host);
+ unsigned long flags;
+
+ spin_lock_irqsave(esp->host->host_lock, flags);
+ esp_bootup_reset(esp);
+ esp_reset_cleanup(esp);
+ spin_unlock_irqrestore(esp->host->host_lock, flags);
+
+ ssleep(esp_bus_reset_settle);
+
+ return SUCCESS;
+}
+
+static const char *esp_info(struct Scsi_Host *host)
+{
+ return "esp";
+}
+
+struct scsi_host_template scsi_esp_template = {
+ .module = THIS_MODULE,
+ .name = "esp",
+ .info = esp_info,
+ .queuecommand = esp_queuecommand,
+ .slave_alloc = esp_slave_alloc,
+ .slave_configure = esp_slave_configure,
+ .slave_destroy = esp_slave_destroy,
+ .eh_abort_handler = esp_eh_abort_handler,
+ .eh_bus_reset_handler = esp_eh_bus_reset_handler,
+ .eh_host_reset_handler = esp_eh_host_reset_handler,
+ .can_queue = 7,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .use_clustering = ENABLE_CLUSTERING,
+ .max_sectors = 0xffff,
+ .skip_settle_delay = 1,
+};
+EXPORT_SYMBOL(scsi_esp_template);
+
+static void esp_get_signalling(struct Scsi_Host *host)
+{
+ struct esp *esp = host_to_esp(host);
+ enum spi_signal_type type;
+
+ if (esp->flags & ESP_FLAG_DIFFERENTIAL)
+ type = SPI_SIGNAL_HVD;
+ else
+ type = SPI_SIGNAL_SE;
+
+ spi_signalling(host) = type;
+}
+
+static void esp_set_offset(struct scsi_target *target, int offset)
+{
+ struct Scsi_Host *host = dev_to_shost(target->dev.parent);
+ struct esp *esp = host_to_esp(host);
+ struct esp_target_data *tp = &esp->target[target->id];
+
+ tp->nego_goal_offset = offset;
+ tp->flags |= ESP_TGT_CHECK_NEGO;
+}
+
+static void esp_set_period(struct scsi_target *target, int period)
+{
+ struct Scsi_Host *host = dev_to_shost(target->dev.parent);
+ struct esp *esp = host_to_esp(host);
+ struct esp_target_data *tp = &esp->target[target->id];
+
+ tp->nego_goal_period = period;
+ tp->flags |= ESP_TGT_CHECK_NEGO;
+}
+
+static void esp_set_width(struct scsi_target *target, int width)
+{
+ struct Scsi_Host *host = dev_to_shost(target->dev.parent);
+ struct esp *esp = host_to_esp(host);
+ struct esp_target_data *tp = &esp->target[target->id];
+
+ tp->nego_goal_width = (width ? 1 : 0);
+ tp->flags |= ESP_TGT_CHECK_NEGO;
+}
+
+static struct spi_function_template esp_transport_ops = {
+ .set_offset = esp_set_offset,
+ .show_offset = 1,
+ .set_period = esp_set_period,
+ .show_period = 1,
+ .set_width = esp_set_width,
+ .show_width = 1,
+ .get_signalling = esp_get_signalling,
+};
+
+static int __init esp_init(void)
+{
+ BUILD_BUG_ON(sizeof(struct scsi_pointer) <
+ sizeof(struct esp_cmd_priv));
+
+ esp_transport_template = spi_attach_transport(&esp_transport_ops);
+ if (!esp_transport_template)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void __exit esp_exit(void)
+{
+ spi_release_transport(esp_transport_template);
+}
+
+MODULE_DESCRIPTION("ESP SCSI driver core");
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_param(esp_bus_reset_settle, int, 0);
+MODULE_PARM_DESC(esp_bus_reset_settle,
+ "ESP scsi bus reset delay in seconds");
+
+module_param(esp_debug, int, 0);
+MODULE_PARM_DESC(esp_debug,
+"ESP bitmapped debugging message enable value:\n"
+" 0x00000001 Log interrupt events\n"
+" 0x00000002 Log scsi commands\n"
+" 0x00000004 Log resets\n"
+" 0x00000008 Log message in events\n"
+" 0x00000010 Log message out events\n"
+" 0x00000020 Log command completion\n"
+" 0x00000040 Log disconnects\n"
+" 0x00000080 Log data start\n"
+" 0x00000100 Log data done\n"
+" 0x00000200 Log reconnects\n"
+" 0x00000400 Log auto-sense data\n"
+);
+
+module_init(esp_init);
+module_exit(esp_exit);
diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
new file mode 100644
index 00000000000..8d4a6690401
--- /dev/null
+++ b/drivers/scsi/esp_scsi.h
@@ -0,0 +1,560 @@
+/* esp_scsi.h: Defines and structures for the ESP drier.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#ifndef _ESP_SCSI_H
+#define _ESP_SCSI_H
+
+ /* Access Description Offset */
+#define ESP_TCLOW 0x00UL /* rw Low bits transfer count 0x00 */
+#define ESP_TCMED 0x01UL /* rw Mid bits transfer count 0x04 */
+#define ESP_FDATA 0x02UL /* rw FIFO data bits 0x08 */
+#define ESP_CMD 0x03UL /* rw SCSI command bits 0x0c */
+#define ESP_STATUS 0x04UL /* ro ESP status register 0x10 */
+#define ESP_BUSID ESP_STATUS /* wo BusID for sel/resel 0x10 */
+#define ESP_INTRPT 0x05UL /* ro Kind of interrupt 0x14 */
+#define ESP_TIMEO ESP_INTRPT /* wo Timeout for sel/resel 0x14 */
+#define ESP_SSTEP 0x06UL /* ro Sequence step register 0x18 */
+#define ESP_STP ESP_SSTEP /* wo Transfer period/sync 0x18 */
+#define ESP_FFLAGS 0x07UL /* ro Bits current FIFO info 0x1c */
+#define ESP_SOFF ESP_FFLAGS /* wo Sync offset 0x1c */
+#define ESP_CFG1 0x08UL /* rw First cfg register 0x20 */
+#define ESP_CFACT 0x09UL /* wo Clock conv factor 0x24 */
+#define ESP_STATUS2 ESP_CFACT /* ro HME status2 register 0x24 */
+#define ESP_CTEST 0x0aUL /* wo Chip test register 0x28 */
+#define ESP_CFG2 0x0bUL /* rw Second cfg register 0x2c */
+#define ESP_CFG3 0x0cUL /* rw Third cfg register 0x30 */
+#define ESP_TCHI 0x0eUL /* rw High bits transf count 0x38 */
+#define ESP_UID ESP_TCHI /* ro Unique ID code 0x38 */
+#define FAS_RLO ESP_TCHI /* rw HME extended counter 0x38 */
+#define ESP_FGRND 0x0fUL /* rw Data base for fifo 0x3c */
+#define FAS_RHI ESP_FGRND /* rw HME extended counter 0x3c */
+
+#define SBUS_ESP_REG_SIZE 0x40UL
+
+/* Bitfield meanings for the above registers. */
+
+/* ESP config reg 1, read-write, found on all ESP chips */
+#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */
+#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */
+#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */
+#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */
+#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */
+#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */
+
+/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */
+#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236) */
+#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236) */
+#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */
+#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tgtmode) */
+#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */
+#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */
+#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236) */
+#define ESP_CONFIG2_DISPINT 0x20 /* Disable pause irq (hme) */
+#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,216) */
+#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (236) */
+#define ESP_CONFIG2_MKDONE 0x40 /* HME magic feature */
+#define ESP_CONFIG2_HME32 0x80 /* HME 32 extended */
+#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */
+
+/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */
+#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/hme) */
+#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236) */
+#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a/hme) */
+#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236) */
+#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a/hme) */
+#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236) */
+#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a/hme) */
+#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236) */
+#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a/hme) */
+#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236) */
+#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236) */
+#define ESP_CONFIG3_IDBIT3 0x20 /* Bit 3 of HME SCSI-ID (hme) */
+#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236) */
+#define ESP_CONFIG3_EWIDE 0x40 /* Enable Wide-SCSI (hme) */
+#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */
+#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */
+
+/* ESP command register read-write */
+/* Group 1 commands: These may be sent at any point in time to the ESP
+ * chip. None of them can generate interrupts 'cept
+ * the "SCSI bus reset" command if you have not disabled
+ * SCSI reset interrupts in the config1 ESP register.
+ */
+#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */
+#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */
+#define ESP_CMD_RC 0x02 /* Chip reset */
+#define ESP_CMD_RS 0x03 /* SCSI bus reset */
+
+/* Group 2 commands: ESP must be an initiator and connected to a target
+ * for these commands to work.
+ */
+#define ESP_CMD_TI 0x10 /* Transfer Information */
+#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */
+#define ESP_CMD_MOK 0x12 /* Message okie-dokie */
+#define ESP_CMD_TPAD 0x18 /* Transfer Pad */
+#define ESP_CMD_SATN 0x1a /* Set ATN */
+#define ESP_CMD_RATN 0x1b /* De-assert ATN */
+
+/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected
+ * to a target as the initiator for these commands to work.
+ */
+#define ESP_CMD_SMSG 0x20 /* Send message */
+#define ESP_CMD_SSTAT 0x21 /* Send status */
+#define ESP_CMD_SDATA 0x22 /* Send data */
+#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */
+#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */
+#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */
+#define ESP_CMD_DCNCT 0x27 /* Disconnect */
+#define ESP_CMD_RMSG 0x28 /* Receive Message */
+#define ESP_CMD_RCMD 0x29 /* Receive Command */
+#define ESP_CMD_RDATA 0x2a /* Receive Data */
+#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */
+
+/* Group 4 commands: The ESP must be in the disconnected state and must
+ * not be connected to any targets as initiator for
+ * these commands to work.
+ */
+#define ESP_CMD_RSEL 0x40 /* Reselect */
+#define ESP_CMD_SEL 0x41 /* Select w/o ATN */
+#define ESP_CMD_SELA 0x42 /* Select w/ATN */
+#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */
+#define ESP_CMD_ESEL 0x44 /* Enable selection */
+#define ESP_CMD_DSEL 0x45 /* Disable selections */
+#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */
+#define ESP_CMD_RSEL3 0x47 /* Reselect3 */
+
+/* This bit enables the ESP's DMA on the SBus */
+#define ESP_CMD_DMA 0x80 /* Do DMA? */
+
+/* ESP status register read-only */
+#define ESP_STAT_PIO 0x01 /* IO phase bit */
+#define ESP_STAT_PCD 0x02 /* CD phase bit */
+#define ESP_STAT_PMSG 0x04 /* MSG phase bit */
+#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */
+#define ESP_STAT_TDONE 0x08 /* Transfer Completed */
+#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */
+#define ESP_STAT_PERR 0x20 /* Parity error */
+#define ESP_STAT_SPAM 0x40 /* Real bad error */
+/* This indicates the 'interrupt pending' condition on esp236, it is a reserved
+ * bit on other revs of the ESP.
+ */
+#define ESP_STAT_INTR 0x80 /* Interrupt */
+
+/* The status register can be masked with ESP_STAT_PMASK and compared
+ * with the following values to determine the current phase the ESP
+ * (at least thinks it) is in. For our purposes we also add our own
+ * software 'done' bit for our phase management engine.
+ */
+#define ESP_DOP (0) /* Data Out */
+#define ESP_DIP (ESP_STAT_PIO) /* Data In */
+#define ESP_CMDP (ESP_STAT_PCD) /* Command */
+#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */
+#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */
+#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */
+
+/* HME only: status 2 register */
+#define ESP_STAT2_SCHBIT 0x01 /* Upper bits 3-7 of sstep enabled */
+#define ESP_STAT2_FFLAGS 0x02 /* The fifo flags are now latched */
+#define ESP_STAT2_XCNT 0x04 /* The transfer counter is latched */
+#define ESP_STAT2_CREGA 0x08 /* The command reg is active now */
+#define ESP_STAT2_WIDE 0x10 /* Interface on this adapter is wide */
+#define ESP_STAT2_F1BYTE 0x20 /* There is one byte at top of fifo */
+#define ESP_STAT2_FMSB 0x40 /* Next byte in fifo is most significant */
+#define ESP_STAT2_FEMPTY 0x80 /* FIFO is empty */
+
+/* ESP interrupt register read-only */
+#define ESP_INTR_S 0x01 /* Select w/o ATN */
+#define ESP_INTR_SATN 0x02 /* Select w/ATN */
+#define ESP_INTR_RSEL 0x04 /* Reselected */
+#define ESP_INTR_FDONE 0x08 /* Function done */
+#define ESP_INTR_BSERV 0x10 /* Bus service */
+#define ESP_INTR_DC 0x20 /* Disconnect */
+#define ESP_INTR_IC 0x40 /* Illegal command given */
+#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */
+
+/* ESP sequence step register read-only */
+#define ESP_STEP_VBITS 0x07 /* Valid bits */
+#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */
+#define ESP_STEP_SID 0x01 /* One msg byte sent */
+#define ESP_STEP_NCMD 0x02 /* Was not in command phase */
+#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd
+ * bytes to be lost
+ */
+#define ESP_STEP_FINI4 0x04 /* Command was sent ok */
+
+/* Ho hum, some ESP's set the step register to this as well... */
+#define ESP_STEP_FINI5 0x05
+#define ESP_STEP_FINI6 0x06
+#define ESP_STEP_FINI7 0x07
+
+/* ESP chip-test register read-write */
+#define ESP_TEST_TARG 0x01 /* Target test mode */
+#define ESP_TEST_INI 0x02 /* Initiator test mode */
+#define ESP_TEST_TS 0x04 /* Tristate test mode */
+
+/* ESP unique ID register read-only, found on fas236+fas100a only */
+#define ESP_UID_F100A 0x00 /* ESP FAS100A */
+#define ESP_UID_F236 0x02 /* ESP FAS236 */
+#define ESP_UID_REV 0x07 /* ESP revision */
+#define ESP_UID_FAM 0xf8 /* ESP family */
+
+/* ESP fifo flags register read-only */
+/* Note that the following implies a 16 byte FIFO on the ESP. */
+#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */
+#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100) */
+#define ESP_FF_SSTEP 0xe0 /* Sequence step */
+
+/* ESP clock conversion factor register write-only */
+#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */
+#define ESP_CCF_NEVER 0x01 /* Set it to this and die */
+#define ESP_CCF_F2 0x02 /* 10MHz */
+#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */
+#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */
+#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */
+#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */
+#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */
+
+/* HME only... */
+#define ESP_BUSID_RESELID 0x10
+#define ESP_BUSID_CTR32BIT 0x40
+
+#define ESP_BUS_TIMEOUT 250 /* In milli-seconds */
+#define ESP_TIMEO_CONST 8192
+#define ESP_NEG_DEFP(mhz, cfact) \
+ ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
+#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
+#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
+
+/* For slow to medium speed input clock rates we shoot for 5mb/s, but for high
+ * input clock rates we try to do 10mb/s although I don't think a transfer can
+ * even run that fast with an ESP even with DMA2 scatter gather pipelining.
+ */
+#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */
+#define SYNC_DEFP_FAST 0x19 /* 10mb/s */
+
+struct esp_cmd_priv {
+ union {
+ dma_addr_t dma_addr;
+ int num_sg;
+ } u;
+
+ unsigned int cur_residue;
+ struct scatterlist *cur_sg;
+ unsigned int tot_residue;
+};
+#define ESP_CMD_PRIV(CMD) ((struct esp_cmd_priv *)(&(CMD)->SCp))
+
+enum esp_rev {
+ ESP100 = 0x00, /* NCR53C90 - very broken */
+ ESP100A = 0x01, /* NCR53C90A */
+ ESP236 = 0x02,
+ FAS236 = 0x03,
+ FAS100A = 0x04,
+ FAST = 0x05,
+ FASHME = 0x06,
+};
+
+struct esp_cmd_entry {
+ struct list_head list;
+
+ struct scsi_cmnd *cmd;
+
+ unsigned int saved_cur_residue;
+ struct scatterlist *saved_cur_sg;
+ unsigned int saved_tot_residue;
+
+ u8 flags;
+#define ESP_CMD_FLAG_WRITE 0x01 /* DMA is a write */
+#define ESP_CMD_FLAG_ABORT 0x02 /* being aborted */
+#define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */
+
+ u8 tag[2];
+
+ u8 status;
+ u8 message;
+
+ unsigned char *sense_ptr;
+ unsigned char *saved_sense_ptr;
+ dma_addr_t sense_dma;
+
+ struct completion *eh_done;
+};
+
+/* XXX make this configurable somehow XXX */
+#define ESP_DEFAULT_TAGS 16
+
+#define ESP_MAX_TARGET 16
+#define ESP_MAX_LUN 8
+#define ESP_MAX_TAG 256
+
+struct esp_lun_data {
+ struct esp_cmd_entry *non_tagged_cmd;
+ int num_tagged;
+ int hold;
+ struct esp_cmd_entry *tagged_cmds[ESP_MAX_TAG];
+};
+
+struct esp_target_data {
+ /* These are the ESP_STP, ESP_SOFF, and ESP_CFG3 register values which
+ * match the currently negotiated settings for this target. The SCSI
+ * protocol values are maintained in spi_{offset,period,wide}(starget).
+ */
+ u8 esp_period;
+ u8 esp_offset;
+ u8 esp_config3;
+
+ u8 flags;
+#define ESP_TGT_WIDE 0x01
+#define ESP_TGT_DISCONNECT 0x02
+#define ESP_TGT_NEGO_WIDE 0x04
+#define ESP_TGT_NEGO_SYNC 0x08
+#define ESP_TGT_CHECK_NEGO 0x40
+#define ESP_TGT_BROKEN 0x80
+
+ /* When ESP_TGT_CHECK_NEGO is set, on the next scsi command to this
+ * device we will try to negotiate the following parameters.
+ */
+ u8 nego_goal_period;
+ u8 nego_goal_offset;
+ u8 nego_goal_width;
+ u8 nego_goal_tags;
+
+ struct scsi_target *starget;
+};
+
+struct esp_event_ent {
+ u8 type;
+#define ESP_EVENT_TYPE_EVENT 0x01
+#define ESP_EVENT_TYPE_CMD 0x02
+ u8 val;
+
+ u8 sreg;
+ u8 seqreg;
+ u8 sreg2;
+ u8 ireg;
+ u8 select_state;
+ u8 event;
+ u8 __pad;
+};
+
+struct esp;
+struct esp_driver_ops {
+ /* Read and write the ESP 8-bit registers. On some
+ * applications of the ESP chip the registers are at 4-byte
+ * instead of 1-byte intervals.
+ */
+ void (*esp_write8)(struct esp *esp, u8 val, unsigned long reg);
+ u8 (*esp_read8)(struct esp *esp, unsigned long reg);
+
+ /* Map and unmap DMA memory. Eventually the driver will be
+ * converted to the generic DMA API as soon as SBUS is able to
+ * cope with that. At such time we can remove this.
+ */
+ dma_addr_t (*map_single)(struct esp *esp, void *buf,
+ size_t sz, int dir);
+ int (*map_sg)(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir);
+ void (*unmap_single)(struct esp *esp, dma_addr_t addr,
+ size_t sz, int dir);
+ void (*unmap_sg)(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir);
+
+ /* Return non-zero if there is an IRQ pending. Usually this
+ * status bit lives in the DMA controller sitting in front of
+ * the ESP. This has to be accurate or else the ESP interrupt
+ * handler will not run.
+ */
+ int (*irq_pending)(struct esp *esp);
+
+ /* Reset the DMA engine entirely. On return, ESP interrupts
+ * should be enabled. Often the interrupt enabling is
+ * controlled in the DMA engine.
+ */
+ void (*reset_dma)(struct esp *esp);
+
+ /* Drain any pending DMA in the DMA engine after a transfer.
+ * This is for writes to memory.
+ */
+ void (*dma_drain)(struct esp *esp);
+
+ /* Invalidate the DMA engine after a DMA transfer. */
+ void (*dma_invalidate)(struct esp *esp);
+
+ /* Setup an ESP command that will use a DMA transfer.
+ * The 'esp_count' specifies what transfer length should be
+ * programmed into the ESP transfer counter registers, whereas
+ * the 'dma_count' is the length that should be programmed into
+ * the DMA controller. Usually they are the same. If 'write'
+ * is non-zero, this transfer is a write into memory. 'cmd'
+ * holds the ESP command that should be issued by calling
+ * scsi_esp_cmd() at the appropriate time while programming
+ * the DMA hardware.
+ */
+ void (*send_dma_cmd)(struct esp *esp, u32 dma_addr, u32 esp_count,
+ u32 dma_count, int write, u8 cmd);
+
+ /* Return non-zero if the DMA engine is reporting an error
+ * currently.
+ */
+ int (*dma_error)(struct esp *esp);
+};
+
+#define ESP_MAX_MSG_SZ 8
+#define ESP_EVENT_LOG_SZ 32
+
+#define ESP_QUICKIRQ_LIMIT 100
+#define ESP_RESELECT_TAG_LIMIT 2500
+
+struct esp {
+ void __iomem *regs;
+ void __iomem *dma_regs;
+
+ const struct esp_driver_ops *ops;
+
+ struct Scsi_Host *host;
+ void *dev;
+
+ struct esp_cmd_entry *active_cmd;
+
+ struct list_head queued_cmds;
+ struct list_head active_cmds;
+
+ u8 *command_block;
+ dma_addr_t command_block_dma;
+
+ unsigned int data_dma_len;
+
+ /* The following are used to determine the cause of an IRQ. Upon every
+ * IRQ entry we synchronize these with the hardware registers.
+ */
+ u8 sreg;
+ u8 seqreg;
+ u8 sreg2;
+ u8 ireg;
+
+ u32 prev_hme_dmacsr;
+ u8 prev_soff;
+ u8 prev_stp;
+ u8 prev_cfg3;
+ u8 __pad;
+
+ struct list_head esp_cmd_pool;
+
+ struct esp_target_data target[ESP_MAX_TARGET];
+
+ int fifo_cnt;
+ u8 fifo[16];
+
+ struct esp_event_ent esp_event_log[ESP_EVENT_LOG_SZ];
+ int esp_event_cur;
+
+ u8 msg_out[ESP_MAX_MSG_SZ];
+ int msg_out_len;
+
+ u8 msg_in[ESP_MAX_MSG_SZ];
+ int msg_in_len;
+
+ u8 bursts;
+ u8 config1;
+ u8 config2;
+
+ u8 scsi_id;
+ u32 scsi_id_mask;
+
+ enum esp_rev rev;
+
+ u32 flags;
+#define ESP_FLAG_DIFFERENTIAL 0x00000001
+#define ESP_FLAG_RESETTING 0x00000002
+#define ESP_FLAG_DOING_SLOWCMD 0x00000004
+#define ESP_FLAG_WIDE_CAPABLE 0x00000008
+#define ESP_FLAG_QUICKIRQ_CHECK 0x00000010
+
+ u8 select_state;
+#define ESP_SELECT_NONE 0x00 /* Not selecting */
+#define ESP_SELECT_BASIC 0x01 /* Select w/o MSGOUT phase */
+#define ESP_SELECT_MSGOUT 0x02 /* Select with MSGOUT */
+
+ /* When we are not selecting, we are expecting an event. */
+ u8 event;
+#define ESP_EVENT_NONE 0x00
+#define ESP_EVENT_CMD_START 0x01
+#define ESP_EVENT_CMD_DONE 0x02
+#define ESP_EVENT_DATA_IN 0x03
+#define ESP_EVENT_DATA_OUT 0x04
+#define ESP_EVENT_DATA_DONE 0x05
+#define ESP_EVENT_MSGIN 0x06
+#define ESP_EVENT_MSGIN_MORE 0x07
+#define ESP_EVENT_MSGIN_DONE 0x08
+#define ESP_EVENT_MSGOUT 0x09
+#define ESP_EVENT_MSGOUT_DONE 0x0a
+#define ESP_EVENT_STATUS 0x0b
+#define ESP_EVENT_FREE_BUS 0x0c
+#define ESP_EVENT_CHECK_PHASE 0x0d
+#define ESP_EVENT_RESET 0x10
+
+ /* Probed in esp_get_clock_params() */
+ u32 cfact;
+ u32 cfreq;
+ u32 ccycle;
+ u32 ctick;
+ u32 neg_defp;
+ u32 sync_defp;
+
+ /* Computed in esp_reset_esp() */
+ u32 max_period;
+ u32 min_period;
+ u32 radelay;
+
+ /* Slow command state. */
+ u8 *cmd_bytes_ptr;
+ int cmd_bytes_left;
+
+ struct completion *eh_reset;
+
+ struct sbus_dma *dma;
+};
+
+#define host_to_esp(host) ((struct esp *)(host)->hostdata)
+
+/* A front-end driver for the ESP chip should do the following in
+ * it's device probe routine:
+ * 1) Allocate the host and private area using scsi_host_alloc()
+ * with size 'sizeof(struct esp)'. The first argument to
+ * scsi_host_alloc() should be &scsi_esp_template.
+ * 2) Set host->max_id as appropriate.
+ * 3) Set esp->host to the scsi_host itself, and esp->dev
+ * to the device object pointer.
+ * 4) Hook up esp->ops to the front-end implementation.
+ * 5) If the ESP chip supports wide transfers, set ESP_FLAG_WIDE_CAPABLE
+ * in esp->flags.
+ * 6) Map the DMA and ESP chip registers.
+ * 7) DMA map the ESP command block, store the DMA address
+ * in esp->command_block_dma.
+ * 8) Register the scsi_esp_intr() interrupt handler.
+ * 9) Probe for and provide the following chip properties:
+ * esp->scsi_id (assign to esp->host->this_id too)
+ * esp->scsi_id_mask
+ * If ESP bus is differential, set ESP_FLAG_DIFFERENTIAL
+ * esp->cfreq
+ * DMA burst bit mask in esp->bursts, if necessary
+ * 10) Perform any actions necessary before the ESP device can
+ * be programmed for the first time. On some configs, for
+ * example, the DMA engine has to be reset before ESP can
+ * be programmed.
+ * 11) If necessary, call dev_set_drvdata() as needed.
+ * 12) Call scsi_esp_register() with prepared 'esp' structure
+ * and a device pointer if possible.
+ * 13) Check scsi_esp_register() return value, release all resources
+ * if an error was returned.
+ */
+extern struct scsi_host_template scsi_esp_template;
+extern int scsi_esp_register(struct esp *, struct device *);
+
+extern void scsi_esp_unregister(struct esp *);
+extern irqreturn_t scsi_esp_intr(int, void *);
+extern void scsi_esp_cmd(struct esp *, u8);
+
+#endif /* !(_ESP_SCSI_H) */
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 8c81cec8529..60446b88f72 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -3091,6 +3091,7 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
cmdp->u.raw64.direction =
gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN;
memcpy(cmdp->u.raw64.cmd,scp->cmnd,16);
+ cmdp->u.raw64.sg_ranz = 0;
} else {
cmdp->u.raw.reserved = 0;
cmdp->u.raw.mdisc_time = 0;
@@ -3107,6 +3108,7 @@ static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
cmdp->u.raw.direction =
gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN;
memcpy(cmdp->u.raw.cmd,scp->cmnd,12);
+ cmdp->u.raw.sg_ranz = 0;
}
if (scp->use_sg) {
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 38c3a291efa..bd8e7f323c6 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -435,7 +435,7 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
struct class_device *cdev;
struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p;
- down_read(&class->subsys.rwsem);
+ down(&class->sem);
list_for_each_entry(cdev, &class->children, node) {
p = class_to_shost(cdev);
if (p->host_no == hostnum) {
@@ -443,7 +443,7 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
break;
}
}
- up_read(&class->subsys.rwsem);
+ up(&class->sem);
return shost;
}
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index fbc1d5c3b0a..b10eefe735c 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -85,7 +85,7 @@
static int max_id = 64;
static int max_channel = 3;
static int init_timeout = 5;
-static int max_requests = 50;
+static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
#define IBMVSCSI_VERSION "1.5.8"
@@ -538,7 +538,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
int request_status;
int rc;
- /* If we have exhausted our request limit, just fail this request.
+ /* If we have exhausted our request limit, just fail this request,
+ * unless it is for a reset or abort.
* Note that there are rare cases involving driver generated requests
* (such as task management requests) that the mid layer may think we
* can handle more requests (can_queue) when we actually can't
@@ -551,9 +552,30 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
*/
if (request_status < -1)
goto send_error;
- /* Otherwise, if we have run out of requests */
- else if (request_status < 0)
- goto send_busy;
+ /* Otherwise, we may have run out of requests. */
+ /* Abort and reset calls should make it through.
+ * Nothing except abort and reset should use the last two
+ * slots unless we had two or less to begin with.
+ */
+ else if (request_status < 2 &&
+ evt_struct->iu.srp.cmd.opcode != SRP_TSK_MGMT) {
+ /* In the case that we have less than two requests
+ * available, check the server limit as a combination
+ * of the request limit and the number of requests
+ * in-flight (the size of the send list). If the
+ * server limit is greater than 2, return busy so
+ * that the last two are reserved for reset and abort.
+ */
+ int server_limit = request_status;
+ struct srp_event_struct *tmp_evt;
+
+ list_for_each_entry(tmp_evt, &hostdata->sent, list) {
+ server_limit++;
+ }
+
+ if (server_limit > 2)
+ goto send_busy;
+ }
}
/* Copy the IU into the transfer area */
@@ -572,6 +594,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
printk(KERN_ERR "ibmvscsi: send error %d\n",
rc);
+ atomic_inc(&hostdata->request_limit);
goto send_error;
}
@@ -581,7 +604,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
free_event_struct(&hostdata->pool, evt_struct);
- return SCSI_MLQUEUE_HOST_BUSY;
+ atomic_inc(&hostdata->request_limit);
+ return SCSI_MLQUEUE_HOST_BUSY;
send_error:
unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
@@ -831,23 +855,16 @@ static void login_rsp(struct srp_event_struct *evt_struct)
printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n");
- if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta >
- (max_requests - 2))
- evt_struct->xfer_iu->srp.login_rsp.req_lim_delta =
- max_requests - 2;
+ if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta < 0)
+ printk(KERN_ERR "ibmvscsi: Invalid request_limit.\n");
- /* Now we know what the real request-limit is */
+ /* Now we know what the real request-limit is.
+ * This value is set rather than added to request_limit because
+ * request_limit could have been set to -1 by this client.
+ */
atomic_set(&hostdata->request_limit,
evt_struct->xfer_iu->srp.login_rsp.req_lim_delta);
- hostdata->host->can_queue =
- evt_struct->xfer_iu->srp.login_rsp.req_lim_delta - 2;
-
- if (hostdata->host->can_queue < 1) {
- printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n");
- return;
- }
-
/* If we had any pending I/Os, kick them */
scsi_unblock_requests(hostdata->host);
@@ -1337,6 +1354,27 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
return rc;
}
+/**
+ * ibmvscsi_slave_configure: Set the "allow_restart" flag for each disk.
+ * @sdev: struct scsi_device device to configure
+ *
+ * Enable allow_restart for a device if it is a disk. Adjust the
+ * queue_depth here also as is required by the documentation for
+ * struct scsi_host_template.
+ */
+static int ibmvscsi_slave_configure(struct scsi_device *sdev)
+{
+ struct Scsi_Host *shost = sdev->host;
+ unsigned long lock_flags = 0;
+
+ spin_lock_irqsave(shost->host_lock, lock_flags);
+ if (sdev->type == TYPE_DISK)
+ sdev->allow_restart = 1;
+ scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
+ spin_unlock_irqrestore(shost->host_lock, lock_flags);
+ return 0;
+}
+
/* ------------------------------------------------------------
* sysfs attributes
*/
@@ -1482,8 +1520,9 @@ static struct scsi_host_template driver_template = {
.queuecommand = ibmvscsi_queuecommand,
.eh_abort_handler = ibmvscsi_eh_abort_handler,
.eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
+ .slave_configure = ibmvscsi_slave_configure,
.cmd_per_lun = 16,
- .can_queue = 1, /* Updated after SRP_LOGIN */
+ .can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
.this_id = -1,
.sg_tablesize = SG_ALL,
.use_clustering = ENABLE_CLUSTERING,
@@ -1503,6 +1542,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
vdev->dev.driver_data = NULL;
+ driver_template.can_queue = max_requests;
host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
if (!host) {
printk(KERN_ERR "ibmvscsi: couldn't allocate host data\n");
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 5c6d9358292..77cc1d40f5b 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -44,6 +44,8 @@ struct Scsi_Host;
*/
#define MAX_INDIRECT_BUFS 10
+#define IBMVSCSI_MAX_REQUESTS_DEFAULT 100
+
/* ------------------------------------------------------------
* Data Structures
*/
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index 4368ca0e827..6d223dd7644 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -35,7 +35,7 @@
#include "ibmvscsi.h"
#define INITIAL_SRP_LIMIT 16
-#define DEFAULT_MAX_SECTORS 512
+#define DEFAULT_MAX_SECTORS 256
#define TGT_NAME "ibmvstgt"
@@ -248,8 +248,8 @@ static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
md[i].va + mdone);
if (err != H_SUCCESS) {
- eprintk("rdma error %d %d\n", dir, slen);
- goto out;
+ eprintk("rdma error %d %d %ld\n", dir, slen, err);
+ return -EIO;
}
mlen -= slen;
@@ -265,45 +265,35 @@ static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
if (sidx > nsg) {
eprintk("out of sg %p %d %d\n",
iue, sidx, nsg);
- goto out;
+ return -EIO;
}
}
};
rest -= mlen;
}
-out:
-
return 0;
}
-static int ibmvstgt_transfer_data(struct scsi_cmnd *sc,
- void (*done)(struct scsi_cmnd *))
-{
- struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
- int err;
-
- err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
-
- done(sc);
-
- return err;
-}
-
static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
void (*done)(struct scsi_cmnd *))
{
unsigned long flags;
struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
struct srp_target *target = iue->target;
+ int err = 0;
- dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]);
+ dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0],
+ cmd->usg_sg);
+
+ if (sc->use_sg)
+ err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
spin_lock_irqsave(&target->lock, flags);
list_del(&iue->ilist);
spin_unlock_irqrestore(&target->lock, flags);
- if (sc->result != SAM_STAT_GOOD) {
+ if (err|| sc->result != SAM_STAT_GOOD) {
eprintk("operation failed %p %d %x\n",
iue, sc->result, vio_iu(iue)->srp.cmd.cdb[0]);
send_rsp(iue, sc, HARDWARE_ERROR, 0x00);
@@ -503,7 +493,8 @@ static void process_iu(struct viosrp_crq *crq, struct srp_target *target)
{
struct vio_port *vport = target_to_port(target);
struct iu_entry *iue;
- long err, done;
+ long err;
+ int done = 1;
iue = srp_iu_get(target);
if (!iue) {
@@ -518,7 +509,6 @@ static void process_iu(struct viosrp_crq *crq, struct srp_target *target)
if (err != H_SUCCESS) {
eprintk("%ld transferring data error %p\n", err, iue);
- done = 1;
goto out;
}
@@ -794,7 +784,6 @@ static struct scsi_host_template ibmvstgt_sht = {
.use_clustering = DISABLE_CLUSTERING,
.max_sectors = DEFAULT_MAX_SECTORS,
.transfer_response = ibmvstgt_cmd_done,
- .transfer_data = ibmvstgt_transfer_data,
.eh_abort_handler = ibmvstgt_eh_abort_handler,
.tsk_mgmt_response = ibmvstgt_tsk_mgmt_response,
.shost_attrs = ibmvstgt_attrs,
@@ -897,9 +886,9 @@ static int get_system_info(void)
{
struct device_node *rootdn;
const char *id, *model, *name;
- unsigned int *num;
+ const unsigned int *num;
- rootdn = find_path_device("/");
+ rootdn = of_find_node_by_path("/");
if (!rootdn)
return -ENOENT;
@@ -912,10 +901,11 @@ static int get_system_info(void)
if (name)
strncpy(partition_name, name, sizeof(partition_name));
- num = (unsigned int *) get_property(rootdn, "ibm,partition-no", NULL);
+ num = get_property(rootdn, "ibm,partition-no", NULL);
if (num)
partition_number = *num;
+ of_node_put(rootdn);
return 0;
}
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 227c0f2f4d7..0a533f398f5 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -157,7 +157,7 @@ static void gather_partition_info(void)
const unsigned int *p_number_ptr;
/* Retrieve information about this partition */
- rootdn = find_path_device("/");
+ rootdn = of_find_node_by_path("/");
if (!rootdn) {
return;
}
@@ -169,6 +169,7 @@ static void gather_partition_info(void)
p_number_ptr = get_property(rootdn, "ibm,partition-no", NULL);
if (p_number_ptr)
partition_number = *p_number_ptr;
+ of_node_put(rootdn);
}
static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 95045e33710..2c7b77e833f 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -89,10 +89,9 @@ static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL;
static unsigned int ipr_max_speed = 1;
static int ipr_testmode = 0;
static unsigned int ipr_fastfail = 0;
-static unsigned int ipr_transop_timeout = IPR_OPERATIONAL_TIMEOUT;
+static unsigned int ipr_transop_timeout = 0;
static unsigned int ipr_enable_cache = 1;
static unsigned int ipr_debug = 0;
-static int ipr_auto_create = 1;
static DEFINE_SPINLOCK(ipr_driver_lock);
/* This table describes the differences between DMA controller chips */
@@ -159,15 +158,13 @@ module_param_named(enable_cache, ipr_enable_cache, int, 0);
MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)");
module_param_named(debug, ipr_debug, int, 0);
MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)");
-module_param_named(auto_create, ipr_auto_create, int, 0);
-MODULE_PARM_DESC(auto_create, "Auto-create single device RAID 0 arrays when initialized (default: 1)");
MODULE_LICENSE("GPL");
MODULE_VERSION(IPR_DRIVER_VERSION);
/* A constant array of IOASCs/URCs/Error Messages */
static const
struct ipr_error_table_t ipr_error_table[] = {
- {0x00000000, 1, 1,
+ {0x00000000, 1, IPR_DEFAULT_LOG_LEVEL,
"8155: An unknown error was received"},
{0x00330000, 0, 0,
"Soft underlength error"},
@@ -175,37 +172,37 @@ struct ipr_error_table_t ipr_error_table[] = {
"Command to be cancelled not found"},
{0x00808000, 0, 0,
"Qualified success"},
- {0x01080000, 1, 1,
+ {0x01080000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFFE: Soft device bus error recovered by the IOA"},
- {0x01088100, 0, 1,
+ {0x01088100, 0, IPR_DEFAULT_LOG_LEVEL,
"4101: Soft device bus fabric error"},
- {0x01170600, 0, 1,
+ {0x01170600, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF9: Device sector reassign successful"},
- {0x01170900, 0, 1,
+ {0x01170900, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF7: Media error recovered by device rewrite procedures"},
- {0x01180200, 0, 1,
+ {0x01180200, 0, IPR_DEFAULT_LOG_LEVEL,
"7001: IOA sector reassignment successful"},
- {0x01180500, 0, 1,
+ {0x01180500, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF9: Soft media error. Sector reassignment recommended"},
- {0x01180600, 0, 1,
+ {0x01180600, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF7: Media error recovered by IOA rewrite procedures"},
- {0x01418000, 0, 1,
+ {0x01418000, 0, IPR_DEFAULT_LOG_LEVEL,
"FF3D: Soft PCI bus error recovered by the IOA"},
- {0x01440000, 1, 1,
+ {0x01440000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF6: Device hardware error recovered by the IOA"},
- {0x01448100, 0, 1,
+ {0x01448100, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF6: Device hardware error recovered by the device"},
- {0x01448200, 1, 1,
+ {0x01448200, 1, IPR_DEFAULT_LOG_LEVEL,
"FF3D: Soft IOA error recovered by the IOA"},
- {0x01448300, 0, 1,
+ {0x01448300, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFA: Undefined device response recovered by the IOA"},
- {0x014A0000, 1, 1,
+ {0x014A0000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF6: Device bus error, message or command phase"},
- {0x014A8000, 0, 1,
+ {0x014A8000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFE: Task Management Function failed"},
- {0x015D0000, 0, 1,
+ {0x015D0000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF6: Failure prediction threshold exceeded"},
- {0x015D9200, 0, 1,
+ {0x015D9200, 0, IPR_DEFAULT_LOG_LEVEL,
"8009: Impending cache battery pack failure"},
{0x02040400, 0, 0,
"34FF: Disk device format in progress"},
@@ -215,85 +212,85 @@ struct ipr_error_table_t ipr_error_table[] = {
"No ready, IOA shutdown"},
{0x025A0000, 0, 0,
"Not ready, IOA has been shutdown"},
- {0x02670100, 0, 1,
+ {0x02670100, 0, IPR_DEFAULT_LOG_LEVEL,
"3020: Storage subsystem configuration error"},
{0x03110B00, 0, 0,
"FFF5: Medium error, data unreadable, recommend reassign"},
{0x03110C00, 0, 0,
"7000: Medium error, data unreadable, do not reassign"},
- {0x03310000, 0, 1,
+ {0x03310000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF3: Disk media format bad"},
- {0x04050000, 0, 1,
+ {0x04050000, 0, IPR_DEFAULT_LOG_LEVEL,
"3002: Addressed device failed to respond to selection"},
- {0x04080000, 1, 1,
+ {0x04080000, 1, IPR_DEFAULT_LOG_LEVEL,
"3100: Device bus error"},
- {0x04080100, 0, 1,
+ {0x04080100, 0, IPR_DEFAULT_LOG_LEVEL,
"3109: IOA timed out a device command"},
{0x04088000, 0, 0,
"3120: SCSI bus is not operational"},
- {0x04088100, 0, 1,
+ {0x04088100, 0, IPR_DEFAULT_LOG_LEVEL,
"4100: Hard device bus fabric error"},
- {0x04118000, 0, 1,
+ {0x04118000, 0, IPR_DEFAULT_LOG_LEVEL,
"9000: IOA reserved area data check"},
- {0x04118100, 0, 1,
+ {0x04118100, 0, IPR_DEFAULT_LOG_LEVEL,
"9001: IOA reserved area invalid data pattern"},
- {0x04118200, 0, 1,
+ {0x04118200, 0, IPR_DEFAULT_LOG_LEVEL,
"9002: IOA reserved area LRC error"},
- {0x04320000, 0, 1,
+ {0x04320000, 0, IPR_DEFAULT_LOG_LEVEL,
"102E: Out of alternate sectors for disk storage"},
- {0x04330000, 1, 1,
+ {0x04330000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Data transfer underlength error"},
- {0x04338000, 1, 1,
+ {0x04338000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Data transfer overlength error"},
- {0x043E0100, 0, 1,
+ {0x043E0100, 0, IPR_DEFAULT_LOG_LEVEL,
"3400: Logical unit failure"},
- {0x04408500, 0, 1,
+ {0x04408500, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Device microcode is corrupt"},
- {0x04418000, 1, 1,
+ {0x04418000, 1, IPR_DEFAULT_LOG_LEVEL,
"8150: PCI bus error"},
{0x04430000, 1, 0,
"Unsupported device bus message received"},
- {0x04440000, 1, 1,
+ {0x04440000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Disk device problem"},
- {0x04448200, 1, 1,
+ {0x04448200, 1, IPR_DEFAULT_LOG_LEVEL,
"8150: Permanent IOA failure"},
- {0x04448300, 0, 1,
+ {0x04448300, 0, IPR_DEFAULT_LOG_LEVEL,
"3010: Disk device returned wrong response to IOA"},
- {0x04448400, 0, 1,
+ {0x04448400, 0, IPR_DEFAULT_LOG_LEVEL,
"8151: IOA microcode error"},
{0x04448500, 0, 0,
"Device bus status error"},
- {0x04448600, 0, 1,
+ {0x04448600, 0, IPR_DEFAULT_LOG_LEVEL,
"8157: IOA error requiring IOA reset to recover"},
{0x04448700, 0, 0,
"ATA device status error"},
{0x04490000, 0, 0,
"Message reject received from the device"},
- {0x04449200, 0, 1,
+ {0x04449200, 0, IPR_DEFAULT_LOG_LEVEL,
"8008: A permanent cache battery pack failure occurred"},
- {0x0444A000, 0, 1,
+ {0x0444A000, 0, IPR_DEFAULT_LOG_LEVEL,
"9090: Disk unit has been modified after the last known status"},
- {0x0444A200, 0, 1,
+ {0x0444A200, 0, IPR_DEFAULT_LOG_LEVEL,
"9081: IOA detected device error"},
- {0x0444A300, 0, 1,
+ {0x0444A300, 0, IPR_DEFAULT_LOG_LEVEL,
"9082: IOA detected device error"},
- {0x044A0000, 1, 1,
+ {0x044A0000, 1, IPR_DEFAULT_LOG_LEVEL,
"3110: Device bus error, message or command phase"},
- {0x044A8000, 1, 1,
+ {0x044A8000, 1, IPR_DEFAULT_LOG_LEVEL,
"3110: SAS Command / Task Management Function failed"},
- {0x04670400, 0, 1,
+ {0x04670400, 0, IPR_DEFAULT_LOG_LEVEL,
"9091: Incorrect hardware configuration change has been detected"},
- {0x04678000, 0, 1,
+ {0x04678000, 0, IPR_DEFAULT_LOG_LEVEL,
"9073: Invalid multi-adapter configuration"},
- {0x04678100, 0, 1,
+ {0x04678100, 0, IPR_DEFAULT_LOG_LEVEL,
"4010: Incorrect connection between cascaded expanders"},
- {0x04678200, 0, 1,
+ {0x04678200, 0, IPR_DEFAULT_LOG_LEVEL,
"4020: Connections exceed IOA design limits"},
- {0x04678300, 0, 1,
+ {0x04678300, 0, IPR_DEFAULT_LOG_LEVEL,
"4030: Incorrect multipath connection"},
- {0x04679000, 0, 1,
+ {0x04679000, 0, IPR_DEFAULT_LOG_LEVEL,
"4110: Unsupported enclosure function"},
- {0x046E0000, 0, 1,
+ {0x046E0000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Command to logical unit failed"},
{0x05240000, 1, 0,
"Illegal request, invalid request type or request packet"},
@@ -313,101 +310,103 @@ struct ipr_error_table_t ipr_error_table[] = {
"Illegal request, command sequence error"},
{0x052C8000, 1, 0,
"Illegal request, dual adapter support not enabled"},
- {0x06040500, 0, 1,
+ {0x06040500, 0, IPR_DEFAULT_LOG_LEVEL,
"9031: Array protection temporarily suspended, protection resuming"},
- {0x06040600, 0, 1,
+ {0x06040600, 0, IPR_DEFAULT_LOG_LEVEL,
"9040: Array protection temporarily suspended, protection resuming"},
- {0x06288000, 0, 1,
+ {0x06288000, 0, IPR_DEFAULT_LOG_LEVEL,
"3140: Device bus not ready to ready transition"},
- {0x06290000, 0, 1,
+ {0x06290000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFB: SCSI bus was reset"},
{0x06290500, 0, 0,
"FFFE: SCSI bus transition to single ended"},
{0x06290600, 0, 0,
"FFFE: SCSI bus transition to LVD"},
- {0x06298000, 0, 1,
+ {0x06298000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFB: SCSI bus was reset by another initiator"},
- {0x063F0300, 0, 1,
+ {0x063F0300, 0, IPR_DEFAULT_LOG_LEVEL,
"3029: A device replacement has occurred"},
- {0x064C8000, 0, 1,
+ {0x064C8000, 0, IPR_DEFAULT_LOG_LEVEL,
"9051: IOA cache data exists for a missing or failed device"},
- {0x064C8100, 0, 1,
+ {0x064C8100, 0, IPR_DEFAULT_LOG_LEVEL,
"9055: Auxiliary cache IOA contains cache data needed by the primary IOA"},
- {0x06670100, 0, 1,
+ {0x06670100, 0, IPR_DEFAULT_LOG_LEVEL,
"9025: Disk unit is not supported at its physical location"},
- {0x06670600, 0, 1,
+ {0x06670600, 0, IPR_DEFAULT_LOG_LEVEL,
"3020: IOA detected a SCSI bus configuration error"},
- {0x06678000, 0, 1,
+ {0x06678000, 0, IPR_DEFAULT_LOG_LEVEL,
"3150: SCSI bus configuration error"},
- {0x06678100, 0, 1,
+ {0x06678100, 0, IPR_DEFAULT_LOG_LEVEL,
"9074: Asymmetric advanced function disk configuration"},
- {0x06678300, 0, 1,
+ {0x06678300, 0, IPR_DEFAULT_LOG_LEVEL,
"4040: Incomplete multipath connection between IOA and enclosure"},
- {0x06678400, 0, 1,
+ {0x06678400, 0, IPR_DEFAULT_LOG_LEVEL,
"4041: Incomplete multipath connection between enclosure and device"},
- {0x06678500, 0, 1,
+ {0x06678500, 0, IPR_DEFAULT_LOG_LEVEL,
"9075: Incomplete multipath connection between IOA and remote IOA"},
- {0x06678600, 0, 1,
+ {0x06678600, 0, IPR_DEFAULT_LOG_LEVEL,
"9076: Configuration error, missing remote IOA"},
- {0x06679100, 0, 1,
+ {0x06679100, 0, IPR_DEFAULT_LOG_LEVEL,
"4050: Enclosure does not support a required multipath function"},
- {0x06690200, 0, 1,
+ {0x06690200, 0, IPR_DEFAULT_LOG_LEVEL,
"9041: Array protection temporarily suspended"},
- {0x06698200, 0, 1,
+ {0x06698200, 0, IPR_DEFAULT_LOG_LEVEL,
"9042: Corrupt array parity detected on specified device"},
- {0x066B0200, 0, 1,
+ {0x066B0200, 0, IPR_DEFAULT_LOG_LEVEL,
"9030: Array no longer protected due to missing or failed disk unit"},
- {0x066B8000, 0, 1,
+ {0x066B8000, 0, IPR_DEFAULT_LOG_LEVEL,
"9071: Link operational transition"},
- {0x066B8100, 0, 1,
+ {0x066B8100, 0, IPR_DEFAULT_LOG_LEVEL,
"9072: Link not operational transition"},
- {0x066B8200, 0, 1,
+ {0x066B8200, 0, IPR_DEFAULT_LOG_LEVEL,
"9032: Array exposed but still protected"},
- {0x066B9100, 0, 1,
+ {0x066B8300, 0, IPR_DEFAULT_LOG_LEVEL + 1,
+ "70DD: Device forced failed by disrupt device command"},
+ {0x066B9100, 0, IPR_DEFAULT_LOG_LEVEL,
"4061: Multipath redundancy level got better"},
- {0x066B9200, 0, 1,
+ {0x066B9200, 0, IPR_DEFAULT_LOG_LEVEL,
"4060: Multipath redundancy level got worse"},
{0x07270000, 0, 0,
"Failure due to other device"},
- {0x07278000, 0, 1,
+ {0x07278000, 0, IPR_DEFAULT_LOG_LEVEL,
"9008: IOA does not support functions expected by devices"},
- {0x07278100, 0, 1,
+ {0x07278100, 0, IPR_DEFAULT_LOG_LEVEL,
"9010: Cache data associated with attached devices cannot be found"},
- {0x07278200, 0, 1,
+ {0x07278200, 0, IPR_DEFAULT_LOG_LEVEL,
"9011: Cache data belongs to devices other than those attached"},
- {0x07278400, 0, 1,
+ {0x07278400, 0, IPR_DEFAULT_LOG_LEVEL,
"9020: Array missing 2 or more devices with only 1 device present"},
- {0x07278500, 0, 1,
+ {0x07278500, 0, IPR_DEFAULT_LOG_LEVEL,
"9021: Array missing 2 or more devices with 2 or more devices present"},
- {0x07278600, 0, 1,
+ {0x07278600, 0, IPR_DEFAULT_LOG_LEVEL,
"9022: Exposed array is missing a required device"},
- {0x07278700, 0, 1,
+ {0x07278700, 0, IPR_DEFAULT_LOG_LEVEL,
"9023: Array member(s) not at required physical locations"},
- {0x07278800, 0, 1,
+ {0x07278800, 0, IPR_DEFAULT_LOG_LEVEL,
"9024: Array not functional due to present hardware configuration"},
- {0x07278900, 0, 1,
+ {0x07278900, 0, IPR_DEFAULT_LOG_LEVEL,
"9026: Array not functional due to present hardware configuration"},
- {0x07278A00, 0, 1,
+ {0x07278A00, 0, IPR_DEFAULT_LOG_LEVEL,
"9027: Array is missing a device and parity is out of sync"},
- {0x07278B00, 0, 1,
+ {0x07278B00, 0, IPR_DEFAULT_LOG_LEVEL,
"9028: Maximum number of arrays already exist"},
- {0x07278C00, 0, 1,
+ {0x07278C00, 0, IPR_DEFAULT_LOG_LEVEL,
"9050: Required cache data cannot be located for a disk unit"},
- {0x07278D00, 0, 1,
+ {0x07278D00, 0, IPR_DEFAULT_LOG_LEVEL,
"9052: Cache data exists for a device that has been modified"},
- {0x07278F00, 0, 1,
+ {0x07278F00, 0, IPR_DEFAULT_LOG_LEVEL,
"9054: IOA resources not available due to previous problems"},
- {0x07279100, 0, 1,
+ {0x07279100, 0, IPR_DEFAULT_LOG_LEVEL,
"9092: Disk unit requires initialization before use"},
- {0x07279200, 0, 1,
+ {0x07279200, 0, IPR_DEFAULT_LOG_LEVEL,
"9029: Incorrect hardware configuration change has been detected"},
- {0x07279600, 0, 1,
+ {0x07279600, 0, IPR_DEFAULT_LOG_LEVEL,
"9060: One or more disk pairs are missing from an array"},
- {0x07279700, 0, 1,
+ {0x07279700, 0, IPR_DEFAULT_LOG_LEVEL,
"9061: One or more disks are missing from an array"},
- {0x07279800, 0, 1,
+ {0x07279800, 0, IPR_DEFAULT_LOG_LEVEL,
"9062: One or more disks are missing from an array"},
- {0x07279900, 0, 1,
+ {0x07279900, 0, IPR_DEFAULT_LOG_LEVEL,
"9063: Maximum number of functional arrays has been exceeded"},
{0x0B260000, 0, 0,
"Aborted command, invalid descriptor"},
@@ -481,12 +480,16 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+ dma_addr_t dma_addr = be32_to_cpu(ioarcb->ioarcb_host_pci_addr);
memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt));
ioarcb->write_data_transfer_length = 0;
ioarcb->read_data_transfer_length = 0;
ioarcb->write_ioadl_len = 0;
ioarcb->read_ioadl_len = 0;
+ ioarcb->write_ioadl_addr =
+ cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl));
+ ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
ioasa->ioasc = 0;
ioasa->residual_data_len = 0;
ioasa->u.gata.status = 0;
@@ -1610,7 +1613,7 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
/* Set indication we have logged an error */
ioa_cfg->errors_logged++;
- if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL)
+ if (ioa_cfg->log_level < ipr_error_table[error_index].log_hcam)
return;
if (be32_to_cpu(hostrcb->hcam.length) > sizeof(hostrcb->hcam.u.raw))
hostrcb->hcam.length = cpu_to_be32(sizeof(hostrcb->hcam.u.raw));
@@ -3770,7 +3773,8 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg,
* Return value:
* 0 on success / non-zero on failure
**/
-static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes)
+static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes,
+ unsigned long deadline)
{
struct ipr_sata_port *sata_port = ap->private_data;
struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
@@ -3849,6 +3853,8 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) {
if (ipr_cmd->scsi_cmd)
ipr_cmd->done = ipr_scsi_eh_done;
+ if (ipr_cmd->qc)
+ ipr_cmd->done = ipr_sata_eh_done;
if (ipr_cmd->qc && !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) {
ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
@@ -4229,6 +4235,14 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
sglist = scsi_cmd->request_buffer;
+ if (ipr_cmd->dma_use_sg <= ARRAY_SIZE(ioarcb->add_data.u.ioadl)) {
+ ioadl = ioarcb->add_data.u.ioadl;
+ ioarcb->write_ioadl_addr =
+ cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) +
+ offsetof(struct ipr_ioarcb, add_data));
+ ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
+ }
+
for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
ioadl[i].flags_and_data_len =
cpu_to_be32(ioadl_flags | sg_dma_len(&sglist[i]));
@@ -4259,6 +4273,11 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
scsi_cmd->sc_data_direction);
if (likely(!pci_dma_mapping_error(ipr_cmd->dma_handle))) {
+ ioadl = ioarcb->add_data.u.ioadl;
+ ioarcb->write_ioadl_addr =
+ cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) +
+ offsetof(struct ipr_ioarcb, add_data));
+ ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
ipr_cmd->dma_use_sg = 1;
ioadl[0].flags_and_data_len =
cpu_to_be32(ioadl_flags | length | IPR_IOADL_FLAGS_LAST);
@@ -4345,11 +4364,9 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd)
**/
static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd)
{
- struct ipr_ioarcb *ioarcb;
- struct ipr_ioasa *ioasa;
-
- ioarcb = &ipr_cmd->ioarcb;
- ioasa = &ipr_cmd->ioasa;
+ struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+ struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+ dma_addr_t dma_addr = be32_to_cpu(ioarcb->ioarcb_host_pci_addr);
memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt));
ioarcb->write_data_transfer_length = 0;
@@ -4358,6 +4375,9 @@ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd)
ioarcb->read_ioadl_len = 0;
ioasa->ioasc = 0;
ioasa->residual_data_len = 0;
+ ioarcb->write_ioadl_addr =
+ cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl));
+ ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
}
/**
@@ -4456,12 +4476,13 @@ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg,
{
int i;
u16 data_len;
- u32 ioasc;
+ u32 ioasc, fd_ioasc;
struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
__be32 *ioasa_data = (__be32 *)ioasa;
int error_index;
ioasc = be32_to_cpu(ioasa->ioasc) & IPR_IOASC_IOASC_MASK;
+ fd_ioasc = be32_to_cpu(ioasa->fd_ioasc) & IPR_IOASC_IOASC_MASK;
if (0 == ioasc)
return;
@@ -4469,13 +4490,19 @@ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg,
if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL)
return;
- error_index = ipr_get_error(ioasc);
+ if (ioasc == IPR_IOASC_BUS_WAS_RESET && fd_ioasc)
+ error_index = ipr_get_error(fd_ioasc);
+ else
+ error_index = ipr_get_error(ioasc);
if (ioa_cfg->log_level < IPR_MAX_LOG_LEVEL) {
/* Don't log an error if the IOA already logged one */
if (ioasa->ilid != 0)
return;
+ if (!ipr_is_gscsi(res))
+ return;
+
if (ipr_error_table[error_index].log_ioasa == 0)
return;
}
@@ -4635,11 +4662,11 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
return;
}
- if (ipr_is_gscsi(res))
- ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
- else
+ if (!ipr_is_gscsi(res))
ipr_gen_sense(ipr_cmd);
+ ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
+
switch (ioasc & IPR_IOASC_IOASC_MASK) {
case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST:
if (ipr_is_naca_model(res))
@@ -5120,7 +5147,7 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
struct ipr_ioarcb_ata_regs *regs;
if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead))
- return -EIO;
+ return AC_ERR_SYSTEM;
ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
ioarcb = &ipr_cmd->ioarcb;
@@ -5165,7 +5192,7 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
default:
WARN_ON(1);
- return -1;
+ return AC_ERR_INVALID;
}
mb();
@@ -6187,7 +6214,7 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd)
dev_info(&ioa_cfg->pdev->dev, "Initializing IOA.\n");
ipr_cmd->timer.data = (unsigned long) ipr_cmd;
- ipr_cmd->timer.expires = jiffies + (ipr_transop_timeout * HZ);
+ ipr_cmd->timer.expires = jiffies + (ioa_cfg->transop_timeout * HZ);
ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout;
ipr_cmd->done = ipr_reset_ioa_job;
add_timer(&ipr_cmd->timer);
@@ -6384,6 +6411,7 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START);
if (rc != PCIBIOS_SUCCESSFUL) {
+ pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev);
ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
rc = IPR_RC_JOB_CONTINUE;
} else {
@@ -7116,8 +7144,6 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
ioa_cfg->pdev = pdev;
ioa_cfg->log_level = ipr_log_level;
ioa_cfg->doorbell = IPR_DOORBELL;
- if (!ipr_auto_create)
- ioa_cfg->doorbell |= IPR_RUNTIME_RESET;
sprintf(ioa_cfg->eye_catcher, IPR_EYECATCHER);
sprintf(ioa_cfg->trace_start, IPR_TRACE_START_LABEL);
sprintf(ioa_cfg->ipr_free_label, IPR_FREEQ_LABEL);
@@ -7232,6 +7258,13 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
goto out_scsi_host_put;
}
+ if (ipr_transop_timeout)
+ ioa_cfg->transop_timeout = ipr_transop_timeout;
+ else if (dev_id->driver_data & IPR_USE_LONG_TRANSOP_TIMEOUT)
+ ioa_cfg->transop_timeout = IPR_LONG_OPERATIONAL_TIMEOUT;
+ else
+ ioa_cfg->transop_timeout = IPR_OPERATIONAL_TIMEOUT;
+
ipr_regs_pci = pci_resource_start(pdev, 0);
rc = pci_request_regions(pdev, IPR_NAME);
@@ -7539,29 +7572,45 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0, 0 },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575D, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, 0 },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E, 0, 0, 0 },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SCAMP_E,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574D, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
{ }
};
MODULE_DEVICE_TABLE(pci, ipr_pci_table);
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 88f285de97b..bc53d7cebe0 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -37,8 +37,8 @@
/*
* Literals
*/
-#define IPR_DRIVER_VERSION "2.3.1"
-#define IPR_DRIVER_DATE "(January 23, 2007)"
+#define IPR_DRIVER_VERSION "2.3.2"
+#define IPR_DRIVER_DATE "(March 23, 2007)"
/*
* IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -55,6 +55,7 @@
#define IPR_NUM_BASE_CMD_BLKS 100
#define PCI_DEVICE_ID_IBM_OBSIDIAN_E 0x0339
+#define PCI_DEVICE_ID_IBM_SCAMP_E 0x034A
#define IPR_SUBS_DEV_ID_2780 0x0264
#define IPR_SUBS_DEV_ID_5702 0x0266
@@ -69,8 +70,12 @@
#define IPR_SUBS_DEV_ID_572A 0x02C1
#define IPR_SUBS_DEV_ID_572B 0x02C2
#define IPR_SUBS_DEV_ID_572F 0x02C3
+#define IPR_SUBS_DEV_ID_574D 0x030B
+#define IPR_SUBS_DEV_ID_574E 0x030A
#define IPR_SUBS_DEV_ID_575B 0x030D
#define IPR_SUBS_DEV_ID_575C 0x0338
+#define IPR_SUBS_DEV_ID_575D 0x033E
+#define IPR_SUBS_DEV_ID_57B3 0x033A
#define IPR_SUBS_DEV_ID_57B7 0x0360
#define IPR_SUBS_DEV_ID_57B8 0x02C2
@@ -104,6 +109,9 @@
#define IPR_IOASC_IOA_WAS_RESET 0x10000001
#define IPR_IOASC_PCI_ACCESS_ERROR 0x10000002
+/* Driver data flags */
+#define IPR_USE_LONG_TRANSOP_TIMEOUT 0x00000001
+
#define IPR_DEFAULT_MAX_ERROR_DUMP 984
#define IPR_NUM_LOG_HCAMS 2
#define IPR_NUM_CFG_CHG_HCAMS 2
@@ -179,6 +187,7 @@
#define IPR_SET_SUP_DEVICE_TIMEOUT (2 * 60 * HZ)
#define IPR_REQUEST_SENSE_TIMEOUT (10 * HZ)
#define IPR_OPERATIONAL_TIMEOUT (5 * 60)
+#define IPR_LONG_OPERATIONAL_TIMEOUT (12 * 60)
#define IPR_WAIT_FOR_RESET_TIMEOUT (2 * HZ)
#define IPR_CHECK_FOR_RESET_TIMEOUT (HZ / 10)
#define IPR_WAIT_FOR_BIST_TIMEOUT (2 * HZ)
@@ -413,9 +422,25 @@ struct ipr_ioarcb_ata_regs {
u8 ctl;
}__attribute__ ((packed, aligned(4)));
+struct ipr_ioadl_desc {
+ __be32 flags_and_data_len;
+#define IPR_IOADL_FLAGS_MASK 0xff000000
+#define IPR_IOADL_GET_FLAGS(x) (be32_to_cpu(x) & IPR_IOADL_FLAGS_MASK)
+#define IPR_IOADL_DATA_LEN_MASK 0x00ffffff
+#define IPR_IOADL_GET_DATA_LEN(x) (be32_to_cpu(x) & IPR_IOADL_DATA_LEN_MASK)
+#define IPR_IOADL_FLAGS_READ 0x48000000
+#define IPR_IOADL_FLAGS_READ_LAST 0x49000000
+#define IPR_IOADL_FLAGS_WRITE 0x68000000
+#define IPR_IOADL_FLAGS_WRITE_LAST 0x69000000
+#define IPR_IOADL_FLAGS_LAST 0x01000000
+
+ __be32 address;
+}__attribute__((packed, aligned (8)));
+
struct ipr_ioarcb_add_data {
union {
struct ipr_ioarcb_ata_regs regs;
+ struct ipr_ioadl_desc ioadl[5];
__be32 add_cmd_parms[10];
}u;
}__attribute__ ((packed, aligned(4)));
@@ -447,21 +472,6 @@ struct ipr_ioarcb {
struct ipr_ioarcb_add_data add_data;
}__attribute__((packed, aligned (4)));
-struct ipr_ioadl_desc {
- __be32 flags_and_data_len;
-#define IPR_IOADL_FLAGS_MASK 0xff000000
-#define IPR_IOADL_GET_FLAGS(x) (be32_to_cpu(x) & IPR_IOADL_FLAGS_MASK)
-#define IPR_IOADL_DATA_LEN_MASK 0x00ffffff
-#define IPR_IOADL_GET_DATA_LEN(x) (be32_to_cpu(x) & IPR_IOADL_DATA_LEN_MASK)
-#define IPR_IOADL_FLAGS_READ 0x48000000
-#define IPR_IOADL_FLAGS_READ_LAST 0x49000000
-#define IPR_IOADL_FLAGS_WRITE 0x68000000
-#define IPR_IOADL_FLAGS_WRITE_LAST 0x69000000
-#define IPR_IOADL_FLAGS_LAST 0x01000000
-
- __be32 address;
-}__attribute__((packed, aligned (8)));
-
struct ipr_ioasa_vset {
__be32 failing_lba_hi;
__be32 failing_lba_lo;
@@ -1119,6 +1129,7 @@ struct ipr_ioa_cfg {
struct ipr_bus_attributes bus_attr[IPR_MAX_NUM_BUSES];
+ unsigned int transop_timeout;
const struct ipr_chip_cfg_t *chip_cfg;
void __iomem *hdw_dma_regs; /* iomapped PCI memory space */
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 8f55e143143..c9a3abf9e7b 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -527,12 +527,12 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
* than 8K, but there are no targets that currently do this.
* For now we fail until we find a vendor that needs it
*/
- if (DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH <
+ if (ISCSI_DEF_MAX_RECV_SEG_LEN <
tcp_conn->in.datalen) {
printk(KERN_ERR "iscsi_tcp: received buffer of len %u "
"but conn buffer is only %u (opcode %0x)\n",
tcp_conn->in.datalen,
- DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, opcode);
+ ISCSI_DEF_MAX_RECV_SEG_LEN, opcode);
rc = ISCSI_ERR_PROTO;
break;
}
@@ -1762,7 +1762,7 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
* due to strange issues with iser these are not set
* in iscsi_conn_setup
*/
- conn->max_recv_dlength = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH;
+ conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
tcp_conn = kzalloc(sizeof(*tcp_conn), GFP_KERNEL);
if (!tcp_conn)
@@ -1777,14 +1777,24 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
CRYPTO_ALG_ASYNC);
tcp_conn->tx_hash.flags = 0;
- if (IS_ERR(tcp_conn->tx_hash.tfm))
+ if (IS_ERR(tcp_conn->tx_hash.tfm)) {
+ printk(KERN_ERR "Could not create connection due to crc32c "
+ "loading error %ld. Make sure the crc32c module is "
+ "built as a module or into the kernel\n",
+ PTR_ERR(tcp_conn->tx_hash.tfm));
goto free_tcp_conn;
+ }
tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
CRYPTO_ALG_ASYNC);
tcp_conn->rx_hash.flags = 0;
- if (IS_ERR(tcp_conn->rx_hash.tfm))
+ if (IS_ERR(tcp_conn->rx_hash.tfm)) {
+ printk(KERN_ERR "Could not create connection due to crc32c "
+ "loading error %ld. Make sure the crc32c module is "
+ "built as a module or into the kernel\n",
+ PTR_ERR(tcp_conn->rx_hash.tfm));
goto free_tx_tfm;
+ }
return cls_conn;
@@ -2138,6 +2148,7 @@ static struct scsi_host_template iscsi_sht = {
.change_queue_depth = iscsi_change_queue_depth,
.can_queue = ISCSI_XMIT_CMDS_MAX - 1,
.sg_tablesize = ISCSI_SG_TABLESIZE,
+ .max_sectors = 0xFFFF,
.cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
.eh_abort_handler = iscsi_eh_abort,
.eh_host_reset_handler = iscsi_eh_host_reset,
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 7c75771c77f..3f5b9b445b2 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -25,6 +25,7 @@
#include <linux/mutex.h>
#include <linux/kfifo.h>
#include <linux/delay.h>
+#include <asm/unaligned.h>
#include <net/tcp.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
@@ -269,14 +270,14 @@ invalid_datalen:
goto out;
}
- senselen = be16_to_cpu(*(__be16 *)data);
+ senselen = be16_to_cpu(get_unaligned((__be16 *) data));
if (datalen < senselen)
goto invalid_datalen;
memcpy(sc->sense_buffer, data + 2,
min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
debug_scsi("copied %d bytes of sense\n",
- min(senselen, SCSI_SENSE_BUFFERSIZE));
+ min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
}
if (sc->sc_data_direction == DMA_TO_DEVICE)
@@ -577,7 +578,7 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
}
EXPORT_SYMBOL_GPL(iscsi_conn_failure);
-static int iscsi_xmit_imm_task(struct iscsi_conn *conn)
+static int iscsi_xmit_mtask(struct iscsi_conn *conn)
{
struct iscsi_hdr *hdr = conn->mtask->hdr;
int rc, was_logout = 0;
@@ -591,6 +592,9 @@ static int iscsi_xmit_imm_task(struct iscsi_conn *conn)
if (rc)
return rc;
+ /* done with this in-progress mtask */
+ conn->mtask = NULL;
+
if (was_logout) {
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
return -ENODATA;
@@ -643,11 +647,9 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
conn->ctask = NULL;
}
if (conn->mtask) {
- rc = iscsi_xmit_imm_task(conn);
+ rc = iscsi_xmit_mtask(conn);
if (rc)
goto again;
- /* done with this in-progress mtask */
- conn->mtask = NULL;
}
/* process immediate first */
@@ -658,12 +660,10 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
list_add_tail(&conn->mtask->running,
&conn->mgmt_run_list);
spin_unlock_bh(&conn->session->lock);
- rc = iscsi_xmit_imm_task(conn);
+ rc = iscsi_xmit_mtask(conn);
if (rc)
goto again;
}
- /* done with this mtask */
- conn->mtask = NULL;
}
/* process command queue */
@@ -701,12 +701,10 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
list_add_tail(&conn->mtask->running,
&conn->mgmt_run_list);
spin_unlock_bh(&conn->session->lock);
- rc = tt->xmit_mgmt_task(conn, conn->mtask);
- if (rc)
+ rc = iscsi_xmit_mtask(conn);
+ if (rc)
goto again;
}
- /* done with this mtask */
- conn->mtask = NULL;
}
return -ENODATA;
@@ -1523,7 +1521,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
}
spin_unlock_bh(&session->lock);
- data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL);
+ data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL);
if (!data)
goto login_mtask_data_alloc_fail;
conn->login_mtask->data = conn->data = data;
@@ -1597,6 +1595,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
wake_up(&conn->ehwait);
}
+ /* flush queued up work because we free the connection below */
+ scsi_flush_work(session->host);
+
spin_lock_bh(&session->lock);
kfree(conn->data);
kfree(conn->persistent_address);
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index dc70c180e11..e34442e405e 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -22,7 +22,6 @@
*
*/
-#include <linux/pci.h>
#include <linux/scatterlist.h>
#include "sas_internal.h"
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
index 89403b00e04..5631c199a8e 100644
--- a/drivers/scsi/libsrp.c
+++ b/drivers/scsi/libsrp.c
@@ -22,7 +22,6 @@
#include <linux/kfifo.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
-#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_tcq.h>
@@ -225,8 +224,7 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
struct srp_direct_buf *md = NULL;
struct scatterlist dummy, *sg = NULL;
dma_addr_t token = 0;
- long err;
- unsigned int done = 0;
+ int err = 0;
int nmd, nsg = 0, len;
if (dma_map || ext_desc) {
@@ -258,8 +256,8 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
sg_dma_address(&dummy) = token;
err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
id->table_desc.len);
- if (err < 0) {
- eprintk("Error copying indirect table %ld\n", err);
+ if (err) {
+ eprintk("Error copying indirect table %d\n", err);
goto free_mem;
}
} else {
@@ -272,6 +270,7 @@ rdma:
nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL);
if (!nsg) {
eprintk("fail to map %p %d\n", iue, sc->use_sg);
+ err = -EIO;
goto free_mem;
}
len = min(sc->request_bufflen, id->len);
@@ -287,7 +286,7 @@ free_mem:
if (token && dma_map)
dma_free_coherent(iue->target->dev, id->table_desc.len, md, token);
- return done;
+ return err;
}
static int data_out_desc_size(struct srp_cmd *cmd)
@@ -352,7 +351,7 @@ int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
break;
default:
eprintk("Unknown format %d %x\n", dir, format);
- break;
+ err = -EINVAL;
}
return err;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 9d014e5a81c..dcf6106f557 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -671,7 +671,7 @@ static int
lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd, int len)
{
uint8_t lenlo, lenhi;
- uint32_t Length;
+ int Length;
int i, j;
int finished = 0;
int index = 0;
@@ -1817,10 +1817,9 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev,
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
- if (state == pci_channel_io_perm_failure) {
- lpfc_pci_remove_one(pdev);
+ if (state == pci_channel_io_perm_failure)
return PCI_ERS_RESULT_DISCONNECT;
- }
+
pci_disable_device(pdev);
/*
* There may be I/Os dropped by the firmware.
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 0aa3304f6b9..7fc6e06ea7e 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -2088,7 +2088,7 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor)
static inline int
make_local_pdev(adapter_t *adapter, struct pci_dev **pdev)
{
- *pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+ *pdev = alloc_pci_dev();
if( *pdev == NULL ) return -1;
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index a967fadb743..08060fb478b 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -87,6 +87,7 @@ MODULE_AUTHOR("Willem Riede");
MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
module_param(max_dev, int, 0444);
MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h
deleted file mode 100644
index 0ebd8ce9e1d..00000000000
--- a/drivers/scsi/pci2000.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/****************************************************************************
- * Perceptive Solutions, Inc. PCI-2000 device driver for Linux.
- *
- * pci2000.h - Linux Host Driver for PCI-2000 IntelliCache SCSI Adapters
- *
- * Copyright (c) 1997-1999 Perceptive Solutions, Inc.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that redistributions of source
- * code retain the above copyright notice and this comment without
- * modification.
- *
- * Technical updates and product information at:
- * http://www.psidisk.com
- *
- * Please send questions, comments, bug reports to:
- * tech@psidisk.com Technical Support
- *
- ****************************************************************************/
-#ifndef _PCI2000_H
-#define _PCI2000_H
-
-#include <linux/types.h>
-
-#ifndef PSI_EIDE_SCSIOP
-#define PSI_EIDE_SCSIOP 1
-
-#define LINUXVERSION(v,p,s) (((v)<<16) + ((p)<<8) + (s))
-
-/************************************************/
-/* definition of standard data types */
-/************************************************/
-#define CHAR char
-#define UCHAR unsigned char
-#define SHORT short
-#define USHORT unsigned short
-#define BOOL long
-#define LONG long
-#define ULONG unsigned long
-#define VOID void
-
-typedef CHAR *PCHAR;
-typedef UCHAR *PUCHAR;
-typedef SHORT *PSHORT;
-typedef USHORT *PUSHORT;
-typedef BOOL *PBOOL;
-typedef LONG *PLONG;
-typedef ULONG *PULONG;
-typedef VOID *PVOID;
-
-
-/************************************************/
-/* Misc. macros */
-/************************************************/
-#define ANY2SCSI(up, p) \
-((UCHAR *)up)[0] = (((ULONG)(p)) >> 8); \
-((UCHAR *)up)[1] = ((ULONG)(p));
-
-#define SCSI2LONG(up) \
-( (((long)*(((UCHAR *)up))) << 16) \
-+ (((long)(((UCHAR *)up)[1])) << 8) \
-+ ((long)(((UCHAR *)up)[2])) )
-
-#define XANY2SCSI(up, p) \
-((UCHAR *)up)[0] = ((long)(p)) >> 24; \
-((UCHAR *)up)[1] = ((long)(p)) >> 16; \
-((UCHAR *)up)[2] = ((long)(p)) >> 8; \
-((UCHAR *)up)[3] = ((long)(p));
-
-#define XSCSI2LONG(up) \
-( (((long)(((UCHAR *)up)[0])) << 24) \
-+ (((long)(((UCHAR *)up)[1])) << 16) \
-+ (((long)(((UCHAR *)up)[2])) << 8) \
-+ ((long)(((UCHAR *)up)[3])) )
-
-/************************************************/
-/* SCSI CDB operation codes */
-/************************************************/
-#define SCSIOP_TEST_UNIT_READY 0x00
-#define SCSIOP_REZERO_UNIT 0x01
-#define SCSIOP_REWIND 0x01
-#define SCSIOP_REQUEST_BLOCK_ADDR 0x02
-#define SCSIOP_REQUEST_SENSE 0x03
-#define SCSIOP_FORMAT_UNIT 0x04
-#define SCSIOP_READ_BLOCK_LIMITS 0x05
-#define SCSIOP_REASSIGN_BLOCKS 0x07
-#define SCSIOP_READ6 0x08
-#define SCSIOP_RECEIVE 0x08
-#define SCSIOP_WRITE6 0x0A
-#define SCSIOP_PRINT 0x0A
-#define SCSIOP_SEND 0x0A
-#define SCSIOP_SEEK6 0x0B
-#define SCSIOP_TRACK_SELECT 0x0B
-#define SCSIOP_SLEW_PRINT 0x0B
-#define SCSIOP_SEEK_BLOCK 0x0C
-#define SCSIOP_PARTITION 0x0D
-#define SCSIOP_READ_REVERSE 0x0F
-#define SCSIOP_WRITE_FILEMARKS 0x10
-#define SCSIOP_FLUSH_BUFFER 0x10
-#define SCSIOP_SPACE 0x11
-#define SCSIOP_INQUIRY 0x12
-#define SCSIOP_VERIFY6 0x13
-#define SCSIOP_RECOVER_BUF_DATA 0x14
-#define SCSIOP_MODE_SELECT 0x15
-#define SCSIOP_RESERVE_UNIT 0x16
-#define SCSIOP_RELEASE_UNIT 0x17
-#define SCSIOP_COPY 0x18
-#define SCSIOP_ERASE 0x19
-#define SCSIOP_MODE_SENSE 0x1A
-#define SCSIOP_START_STOP_UNIT 0x1B
-#define SCSIOP_STOP_PRINT 0x1B
-#define SCSIOP_LOAD_UNLOAD 0x1B
-#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C
-#define SCSIOP_SEND_DIAGNOSTIC 0x1D
-#define SCSIOP_MEDIUM_REMOVAL 0x1E
-#define SCSIOP_READ_CAPACITY 0x25
-#define SCSIOP_READ 0x28
-#define SCSIOP_WRITE 0x2A
-#define SCSIOP_SEEK 0x2B
-#define SCSIOP_LOCATE 0x2B
-#define SCSIOP_WRITE_VERIFY 0x2E
-#define SCSIOP_VERIFY 0x2F
-#define SCSIOP_SEARCH_DATA_HIGH 0x30
-#define SCSIOP_SEARCH_DATA_EQUAL 0x31
-#define SCSIOP_SEARCH_DATA_LOW 0x32
-#define SCSIOP_SET_LIMITS 0x33
-#define SCSIOP_READ_POSITION 0x34
-#define SCSIOP_SYNCHRONIZE_CACHE 0x35
-#define SCSIOP_COMPARE 0x39
-#define SCSIOP_COPY_COMPARE 0x3A
-#define SCSIOP_WRITE_DATA_BUFF 0x3B
-#define SCSIOP_READ_DATA_BUFF 0x3C
-#define SCSIOP_CHANGE_DEFINITION 0x40
-#define SCSIOP_READ_SUB_CHANNEL 0x42
-#define SCSIOP_READ_TOC 0x43
-#define SCSIOP_READ_HEADER 0x44
-#define SCSIOP_PLAY_AUDIO 0x45
-#define SCSIOP_PLAY_AUDIO_MSF 0x47
-#define SCSIOP_PLAY_TRACK_INDEX 0x48
-#define SCSIOP_PLAY_TRACK_RELATIVE 0x49
-#define SCSIOP_PAUSE_RESUME 0x4B
-#define SCSIOP_LOG_SELECT 0x4C
-#define SCSIOP_LOG_SENSE 0x4D
-#define SCSIOP_MODE_SELECT10 0x55
-#define SCSIOP_MODE_SENSE10 0x5A
-#define SCSIOP_LOAD_UNLOAD_SLOT 0xA6
-#define SCSIOP_MECHANISM_STATUS 0xBD
-#define SCSIOP_READ_CD 0xBE
-
-// SCSI read capacity structure
-typedef struct _READ_CAPACITY_DATA
- {
- ULONG blks; /* total blocks (converted to little endian) */
- ULONG blksiz; /* size of each (converted to little endian) */
- } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
-
-// SCSI inquiry data
-typedef struct _INQUIRYDATA
- {
- UCHAR DeviceType :5;
- UCHAR DeviceTypeQualifier :3;
- UCHAR DeviceTypeModifier :7;
- UCHAR RemovableMedia :1;
- UCHAR Versions;
- UCHAR ResponseDataFormat;
- UCHAR AdditionalLength;
- UCHAR Reserved[2];
- UCHAR SoftReset :1;
- UCHAR CommandQueue :1;
- UCHAR Reserved2 :1;
- UCHAR LinkedCommands :1;
- UCHAR Synchronous :1;
- UCHAR Wide16Bit :1;
- UCHAR Wide32Bit :1;
- UCHAR RelativeAddressing :1;
- UCHAR VendorId[8];
- UCHAR ProductId[16];
- UCHAR ProductRevisionLevel[4];
- UCHAR VendorSpecific[20];
- UCHAR Reserved3[40];
- } INQUIRYDATA, *PINQUIRYDATA;
-
-#endif
-
-// function prototypes
-int Pci2000_Detect (struct scsi_host_template *tpnt);
-int Pci2000_Command (Scsi_Cmnd *SCpnt);
-int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
-int Pci2000_Abort (Scsi_Cmnd *SCpnt);
-int Pci2000_Reset (Scsi_Cmnd *SCpnt, unsigned int flags);
-int Pci2000_Release (struct Scsi_Host *pshost);
-int Pci2000_BiosParam (struct scsi_device *sdev,
- struct block_device *bdev,
- sector_t capacity, int geom[]);
-
-#endif
diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig
index eac8e179cff..7dd787f6ab2 100644
--- a/drivers/scsi/pcmcia/Kconfig
+++ b/drivers/scsi/pcmcia/Kconfig
@@ -3,11 +3,11 @@
#
menu "PCMCIA SCSI adapter support"
- depends on SCSI!=n && PCMCIA!=n && MODULES
+ depends on SCSI!=n && PCMCIA!=n
config PCMCIA_AHA152X
tristate "Adaptec AHA152X PCMCIA support"
- depends on m && !64BIT
+ depends on !64BIT
select SCSI_SPI_ATTRS
help
Say Y here if you intend to attach this type of PCMCIA SCSI host
@@ -18,7 +18,6 @@ config PCMCIA_AHA152X
config PCMCIA_FDOMAIN
tristate "Future Domain PCMCIA support"
- depends on m
help
Say Y here if you intend to attach this type of PCMCIA SCSI host
adapter to your computer.
@@ -28,7 +27,7 @@ config PCMCIA_FDOMAIN
config PCMCIA_NINJA_SCSI
tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support"
- depends on m && !64BIT
+ depends on !64BIT
help
If you intend to attach this type of PCMCIA SCSI host adapter to
your computer, say Y here and read
@@ -62,7 +61,6 @@ config PCMCIA_NINJA_SCSI
config PCMCIA_QLOGIC
tristate "Qlogic PCMCIA support"
- depends on m
help
Say Y here if you intend to attach this type of PCMCIA SCSI host
adapter to your computer.
@@ -72,7 +70,6 @@ config PCMCIA_QLOGIC
config PCMCIA_SYM53C500
tristate "Symbios 53c500 PCMCIA support"
- depends on m
help
Say Y here if you have a New Media Bus Toaster or other PCMCIA
SCSI adapter based on the Symbios 53c500 controller.
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 05f4f2a378e..e8948b679f5 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1478,14 +1478,17 @@ typedef union {
uint32_t b24 : 24;
struct {
- uint8_t d_id[3];
- uint8_t rsvd_1;
- } r;
-
- struct {
+#ifdef __BIG_ENDIAN
+ uint8_t domain;
+ uint8_t area;
+ uint8_t al_pa;
+#elif __LITTLE_ENDIAN
uint8_t al_pa;
uint8_t area;
uint8_t domain;
+#else
+#error "__BIG_ENDIAN or __LITTLE_ENDIAN must be defined!"
+#endif
uint8_t rsvd_1;
} b;
} port_id_t;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 98c01cd5e1a..3e296ab845b 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -11,6 +11,11 @@
#include "qla_devtbl.h"
+#ifdef CONFIG_SPARC
+#include <asm/prom.h>
+#include <asm/pbm.h>
+#endif
+
/* XXX(hch): this is ugly, but we don't want to pull in exioctl.h */
#ifndef EXT_IS_LUN_BIT_SET
#define EXT_IS_LUN_BIT_SET(P,L) \
@@ -88,12 +93,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
- rval = ha->isp_ops.nvram_config(ha);
- if (rval) {
- DEBUG2(printk("scsi(%ld): Unable to verify NVRAM data.\n",
- ha->host_no));
- return rval;
- }
+ ha->isp_ops.nvram_config(ha);
if (ha->flags.disable_serdes) {
/* Mask HBA via NVRAM settings? */
@@ -1393,6 +1393,28 @@ qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *de
}
}
+/* On sparc systems, obtain port and node WWN from firmware
+ * properties.
+ */
+static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, nvram_t *nv)
+{
+#ifdef CONFIG_SPARC
+ struct pci_dev *pdev = ha->pdev;
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct device_node *dp = pcp->prom_node;
+ u8 *val;
+ int len;
+
+ val = of_get_property(dp, "port-wwn", &len);
+ if (val && len >= WWN_SIZE)
+ memcpy(nv->port_name, val, WWN_SIZE);
+
+ val = of_get_property(dp, "node-wwn", &len);
+ if (val && len >= WWN_SIZE)
+ memcpy(nv->node_name, val, WWN_SIZE);
+#endif
+}
+
/*
* NVRAM configuration for ISP 2xxx
*
@@ -1409,6 +1431,7 @@ qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *de
int
qla2x00_nvram_config(scsi_qla_host_t *ha)
{
+ int rval;
uint8_t chksum = 0;
uint16_t cnt;
uint8_t *dptr1, *dptr2;
@@ -1417,6 +1440,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
uint8_t *ptr = (uint8_t *)ha->request_ring;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+ rval = QLA_SUCCESS;
+
/* Determine NVRAM starting address. */
ha->nvram_size = sizeof(nvram_t);
ha->nvram_base = 0;
@@ -1440,7 +1465,57 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
"checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
nv->nvram_version);
- return QLA_FUNCTION_FAILED;
+ qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
+ "invalid -- WWPN) defaults.\n");
+
+ /*
+ * Set default initialization control block.
+ */
+ memset(nv, 0, ha->nvram_size);
+ nv->parameter_block_version = ICB_VERSION;
+
+ if (IS_QLA23XX(ha)) {
+ nv->firmware_options[0] = BIT_2 | BIT_1;
+ nv->firmware_options[1] = BIT_7 | BIT_5;
+ nv->add_firmware_options[0] = BIT_5;
+ nv->add_firmware_options[1] = BIT_5 | BIT_4;
+ nv->frame_payload_size = __constant_cpu_to_le16(2048);
+ nv->special_options[1] = BIT_7;
+ } else if (IS_QLA2200(ha)) {
+ nv->firmware_options[0] = BIT_2 | BIT_1;
+ nv->firmware_options[1] = BIT_7 | BIT_5;
+ nv->add_firmware_options[0] = BIT_5;
+ nv->add_firmware_options[1] = BIT_5 | BIT_4;
+ nv->frame_payload_size = __constant_cpu_to_le16(1024);
+ } else if (IS_QLA2100(ha)) {
+ nv->firmware_options[0] = BIT_3 | BIT_1;
+ nv->firmware_options[1] = BIT_5;
+ nv->frame_payload_size = __constant_cpu_to_le16(1024);
+ }
+
+ nv->max_iocb_allocation = __constant_cpu_to_le16(256);
+ nv->execution_throttle = __constant_cpu_to_le16(16);
+ nv->retry_count = 8;
+ nv->retry_delay = 1;
+
+ nv->port_name[0] = 33;
+ nv->port_name[3] = 224;
+ nv->port_name[4] = 139;
+
+ qla2xxx_nvram_wwn_from_ofw(ha, nv);
+
+ nv->login_timeout = 4;
+
+ /*
+ * Set default host adapter parameters
+ */
+ nv->host_p[1] = BIT_2;
+ nv->reset_delay = 5;
+ nv->port_down_retry_count = 8;
+ nv->max_luns_per_target = __constant_cpu_to_le16(8);
+ nv->link_down_timeout = 60;
+
+ rval = 1;
}
#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
@@ -1653,7 +1728,11 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
}
}
- return QLA_SUCCESS;
+ if (rval) {
+ DEBUG2_3(printk(KERN_WARNING
+ "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
+ }
+ return (rval);
}
static void
@@ -3071,9 +3150,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
ha->isp_ops.get_flash_version(ha, ha->request_ring);
- rval = ha->isp_ops.nvram_config(ha);
- if (rval)
- goto isp_abort_retry;
+ ha->isp_ops.nvram_config(ha);
if (!qla2x00_restart_isp(ha)) {
clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
@@ -3103,7 +3180,6 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
}
}
} else { /* failed the ISP abort */
-isp_abort_retry:
ha->flags.online = 1;
if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
if (ha->isp_abort_cnt == 0) {
@@ -3290,9 +3366,32 @@ qla24xx_reset_adapter(scsi_qla_host_t *ha)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
+/* On sparc systems, obtain port and node WWN from firmware
+ * properties.
+ */
+static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, struct nvram_24xx *nv)
+{
+#ifdef CONFIG_SPARC
+ struct pci_dev *pdev = ha->pdev;
+ struct pcidev_cookie *pcp = pdev->sysdata;
+ struct device_node *dp = pcp->prom_node;
+ u8 *val;
+ int len;
+
+ val = of_get_property(dp, "port-wwn", &len);
+ if (val && len >= WWN_SIZE)
+ memcpy(nv->port_name, val, WWN_SIZE);
+
+ val = of_get_property(dp, "node-wwn", &len);
+ if (val && len >= WWN_SIZE)
+ memcpy(nv->node_name, val, WWN_SIZE);
+#endif
+}
+
int
qla24xx_nvram_config(scsi_qla_host_t *ha)
{
+ int rval;
struct init_cb_24xx *icb;
struct nvram_24xx *nv;
uint32_t *dptr;
@@ -3300,6 +3399,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
uint32_t chksum;
uint16_t cnt;
+ rval = QLA_SUCCESS;
icb = (struct init_cb_24xx *)ha->init_cb;
nv = (struct nvram_24xx *)ha->request_ring;
@@ -3332,7 +3432,52 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
"checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
le16_to_cpu(nv->nvram_version));
- return QLA_FUNCTION_FAILED;
+ qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
+ "invalid -- WWPN) defaults.\n");
+
+ /*
+ * Set default initialization control block.
+ */
+ memset(nv, 0, ha->nvram_size);
+ nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
+ nv->version = __constant_cpu_to_le16(ICB_VERSION);
+ nv->frame_payload_size = __constant_cpu_to_le16(2048);
+ nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
+ nv->exchange_count = __constant_cpu_to_le16(0);
+ nv->hard_address = __constant_cpu_to_le16(124);
+ nv->port_name[0] = 0x21;
+ nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
+ nv->port_name[2] = 0x00;
+ nv->port_name[3] = 0xe0;
+ nv->port_name[4] = 0x8b;
+ nv->port_name[5] = 0x1c;
+ nv->port_name[6] = 0x55;
+ nv->port_name[7] = 0x86;
+ nv->node_name[0] = 0x20;
+ nv->node_name[1] = 0x00;
+ nv->node_name[2] = 0x00;
+ nv->node_name[3] = 0xe0;
+ nv->node_name[4] = 0x8b;
+ nv->node_name[5] = 0x1c;
+ nv->node_name[6] = 0x55;
+ nv->node_name[7] = 0x86;
+ qla24xx_nvram_wwn_from_ofw(ha, nv);
+ nv->login_retry_count = __constant_cpu_to_le16(8);
+ nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
+ nv->login_timeout = __constant_cpu_to_le16(0);
+ nv->firmware_options_1 =
+ __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
+ nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
+ nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
+ nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
+ nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
+ nv->efi_parameters = __constant_cpu_to_le32(0);
+ nv->reset_delay = 5;
+ nv->max_luns_per_target = __constant_cpu_to_le16(128);
+ nv->port_down_retry_count = __constant_cpu_to_le16(30);
+ nv->link_down_timeout = __constant_cpu_to_le16(30);
+
+ rval = 1;
}
/* Reset Initialization control block */
@@ -3479,7 +3624,11 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
ha->flags.process_response_queue = 1;
}
- return QLA_SUCCESS;
+ if (rval) {
+ DEBUG2_3(printk(KERN_WARNING
+ "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
+ }
+ return (rval);
}
static int
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 83376f6ac3d..71e32a24852 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -1280,14 +1280,14 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name,
} else {
if (name != NULL) {
/* This function returns name in big endian. */
- name[0] = LSB(mcp->mb[2]);
- name[1] = MSB(mcp->mb[2]);
- name[2] = LSB(mcp->mb[3]);
- name[3] = MSB(mcp->mb[3]);
- name[4] = LSB(mcp->mb[6]);
- name[5] = MSB(mcp->mb[6]);
- name[6] = LSB(mcp->mb[7]);
- name[7] = MSB(mcp->mb[7]);
+ name[0] = MSB(mcp->mb[2]);
+ name[1] = LSB(mcp->mb[2]);
+ name[2] = MSB(mcp->mb[3]);
+ name[3] = LSB(mcp->mb[3]);
+ name[4] = MSB(mcp->mb[6]);
+ name[5] = LSB(mcp->mb[6]);
+ name[6] = MSB(mcp->mb[7]);
+ name[7] = LSB(mcp->mb[7]);
}
DEBUG11(printk("qla2x00_get_port_name(%ld): done.\n",
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 68f5d24b938..b78919a318e 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -62,7 +62,7 @@ MODULE_PARM_DESC(ql2xallocfwdump,
"vary by ISP type. Default is 1 - allocate memory.");
int ql2xextended_error_logging;
-module_param(ql2xextended_error_logging, int, S_IRUGO|S_IRUSR);
+module_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xextended_error_logging,
"Option to enable extended error logging, "
"Default is 0 - no logging. 1 - log errors.");
@@ -157,6 +157,8 @@ static struct scsi_host_template qla24xx_driver_template = {
.slave_alloc = qla2xxx_slave_alloc,
.slave_destroy = qla2xxx_slave_destroy,
+ .scan_finished = qla2xxx_scan_finished,
+ .scan_start = qla2xxx_scan_start,
.change_queue_depth = qla2x00_change_queue_depth,
.change_queue_type = qla2x00_change_queue_type,
.this_id = -1,
@@ -1705,6 +1707,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
scsi_host_put(ha->host);
+ pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
@@ -1747,8 +1750,6 @@ qla2x00_free_device(scsi_qla_host_t *ha)
if (ha->iobase)
iounmap(ha->iobase);
pci_release_regions(ha->pdev);
-
- pci_disable_device(ha->pdev);
}
static inline void
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index ff1dd4175a7..206bda093da 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -466,6 +466,7 @@ qla24xx_read_flash_dword(scsi_qla_host_t *ha, uint32_t addr)
udelay(10);
else
rval = QLA_FUNCTION_TIMEOUT;
+ cond_resched();
}
/* TODO: What happens if we time out? */
@@ -508,6 +509,7 @@ qla24xx_write_flash_dword(scsi_qla_host_t *ha, uint32_t addr, uint32_t data)
udelay(10);
else
rval = QLA_FUNCTION_TIMEOUT;
+ cond_resched();
}
return rval;
}
@@ -1255,6 +1257,7 @@ qla2x00_poll_flash(scsi_qla_host_t *ha, uint32_t addr, uint8_t poll_data,
}
udelay(10);
barrier();
+ cond_resched();
}
return status;
}
@@ -1403,6 +1406,7 @@ qla2x00_read_flash_data(scsi_qla_host_t *ha, uint8_t *tmp_buf, uint32_t saddr,
if (saddr % 100)
udelay(10);
*tmp_buf = data;
+ cond_resched();
}
}
@@ -1449,7 +1453,6 @@ uint8_t *
qla2x00_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
uint32_t offset, uint32_t length)
{
- unsigned long flags;
uint32_t addr, midpoint;
uint8_t *data;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
@@ -1458,7 +1461,6 @@ qla2x00_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
qla2x00_suspend_hba(ha);
/* Go with read. */
- spin_lock_irqsave(&ha->hardware_lock, flags);
midpoint = ha->optrom_size / 2;
qla2x00_flash_enable(ha);
@@ -1473,7 +1475,6 @@ qla2x00_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
*data = qla2x00_read_flash_byte(ha, addr);
}
qla2x00_flash_disable(ha);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* Resume HBA. */
qla2x00_resume_hba(ha);
@@ -1487,7 +1488,6 @@ qla2x00_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
{
int rval;
- unsigned long flags;
uint8_t man_id, flash_id, sec_number, data;
uint16_t wd;
uint32_t addr, liter, sec_mask, rest_addr;
@@ -1500,7 +1500,6 @@ qla2x00_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
sec_number = 0;
/* Reset ISP chip. */
- spin_lock_irqsave(&ha->hardware_lock, flags);
WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
@@ -1689,10 +1688,10 @@ update_flash:
rval = QLA_FUNCTION_FAILED;
break;
}
+ cond_resched();
}
} while (0);
qla2x00_flash_disable(ha);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* Resume HBA. */
qla2x00_resume_hba(ha);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 61347aee55c..dc85495c337 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.01.07-k5"
+#define QLA2XXX_VERSION "8.01.07-k6"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 1
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 9b827ceec50..c4195ea869e 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -1281,7 +1281,7 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
(struct scatterlist *)Cmnd->request_buffer,
Cmnd->use_sg,
Cmnd->sc_data_direction);
- } else {
+ } else if (Cmnd->request_bufflen) {
sbus_unmap_single(qpti->sdev,
(__u32)((unsigned long)Cmnd->SCp.ptr),
Cmnd->request_bufflen,
@@ -1403,7 +1403,7 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi
struct scsi_host_template *tpnt = match->data;
struct Scsi_Host *host;
struct qlogicpti *qpti;
- char *fcode;
+ const char *fcode;
/* Sometimes Antares cards come up not completely
* setup, and we get a report of a zero IRQ.
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 1c89ee3e69b..4c1e3133476 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -344,7 +344,6 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
void scsi_log_send(struct scsi_cmnd *cmd)
{
unsigned int level;
- struct scsi_device *sdev;
/*
* If ML QUEUE log level is greater than or equal to:
@@ -361,22 +360,17 @@ void scsi_log_send(struct scsi_cmnd *cmd)
level = SCSI_LOG_LEVEL(SCSI_LOG_MLQUEUE_SHIFT,
SCSI_LOG_MLQUEUE_BITS);
if (level > 1) {
- sdev = cmd->device;
- sdev_printk(KERN_INFO, sdev, "send ");
+ scmd_printk(KERN_INFO, cmd, "Send: ");
if (level > 2)
printk("0x%p ", cmd);
- /*
- * spaces to match disposition and cmd->result
- * output in scsi_log_completion.
- */
- printk(" ");
+ printk("\n");
scsi_print_command(cmd);
if (level > 3) {
printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
" done = 0x%p, queuecommand 0x%p\n",
cmd->request_buffer, cmd->request_bufflen,
cmd->done,
- sdev->host->hostt->queuecommand);
+ cmd->device->host->hostt->queuecommand);
}
}
@@ -386,7 +380,6 @@ void scsi_log_send(struct scsi_cmnd *cmd)
void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
{
unsigned int level;
- struct scsi_device *sdev;
/*
* If ML COMPLETE log level is greater than or equal to:
@@ -405,8 +398,7 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
SCSI_LOG_MLCOMPLETE_BITS);
if (((level > 0) && (cmd->result || disposition != SUCCESS)) ||
(level > 1)) {
- sdev = cmd->device;
- sdev_printk(KERN_INFO, sdev, "done ");
+ scmd_printk(KERN_INFO, cmd, "Done: ");
if (level > 2)
printk("0x%p ", cmd);
/*
@@ -415,40 +407,35 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
*/
switch (disposition) {
case SUCCESS:
- printk("SUCCESS");
+ printk("SUCCESS\n");
break;
case NEEDS_RETRY:
- printk("RETRY ");
+ printk("RETRY\n");
break;
case ADD_TO_MLQUEUE:
- printk("MLQUEUE");
+ printk("MLQUEUE\n");
break;
case FAILED:
- printk("FAILED ");
+ printk("FAILED\n");
break;
case TIMEOUT_ERROR:
/*
* If called via scsi_times_out.
*/
- printk("TIMEOUT");
+ printk("TIMEOUT\n");
break;
default:
- printk("UNKNOWN");
+ printk("UNKNOWN\n");
}
- printk(" %8x ", cmd->result);
+ scsi_print_result(cmd);
scsi_print_command(cmd);
- if (status_byte(cmd->result) & CHECK_CONDITION) {
- /*
- * XXX The scsi_print_sense formatting/prefix
- * doesn't match this function.
- */
+ if (status_byte(cmd->result) & CHECK_CONDITION)
scsi_print_sense("", cmd);
- }
- if (level > 3) {
- printk(KERN_INFO "scsi host busy %d failed %d\n",
- sdev->host->host_busy,
- sdev->host->host_failed);
- }
+ if (level > 3)
+ scmd_printk(KERN_INFO, cmd,
+ "scsi host busy %d failed %d\n",
+ cmd->device->host->host_busy,
+ cmd->device->host->host_failed);
}
}
}
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index b8edcf5b545..3963e7013bd 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -184,10 +184,19 @@ int scsi_delete_timer(struct scsi_cmnd *scmd)
**/
void scsi_times_out(struct scsi_cmnd *scmd)
{
+ enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+
scsi_log_completion(scmd, TIMEOUT_ERROR);
if (scmd->device->host->transportt->eh_timed_out)
- switch (scmd->device->host->transportt->eh_timed_out(scmd)) {
+ eh_timed_out = scmd->device->host->transportt->eh_timed_out;
+ else if (scmd->device->host->hostt->eh_timed_out)
+ eh_timed_out = scmd->device->host->hostt->eh_timed_out;
+ else
+ eh_timed_out = NULL;
+
+ if (eh_timed_out)
+ switch (eh_timed_out(scmd)) {
case EH_HANDLED:
__scsi_done(scmd);
return;
@@ -716,7 +725,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
*/
if (copy_sense) {
if (!SCSI_SENSE_VALID(scmd)) {
- memcpy(scmd->sense_buffer, scmd->request_buffer,
+ memcpy(scmd->sense_buffer, page_address(sgl.page),
sizeof(scmd->sense_buffer));
}
__free_page(sgl.page);
@@ -923,10 +932,12 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
if (scmd->device->allow_restart) {
- int rtn;
+ int i, rtn = NEEDS_RETRY;
+
+ for (i = 0; rtn == NEEDS_RETRY && i < 2; i++)
+ rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
+ START_UNIT_TIMEOUT, 0);
- rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
- START_UNIT_TIMEOUT, 0);
if (rtn == SUCCESS)
return 0;
}
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 9f7482d0b59..61fbcdcbb00 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -31,7 +31,7 @@
#define SG_MEMPOOL_NR ARRAY_SIZE(scsi_sg_pools)
-#define SG_MEMPOOL_SIZE 32
+#define SG_MEMPOOL_SIZE 2
struct scsi_host_sg_pool {
size_t size;
@@ -848,8 +848,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
memcpy(req->sense, cmd->sense_buffer, len);
req->sense_len = len;
}
- } else
- req->data_len = cmd->resid;
+ }
+ req->data_len = cmd->resid;
}
/*
@@ -968,9 +968,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
}
if (result) {
if (!(req->cmd_flags & REQ_QUIET)) {
- scmd_printk(KERN_INFO, cmd,
- "SCSI error: return code = 0x%08x\n",
- result);
+ scsi_print_result(cmd);
if (driver_byte(result) & DRIVER_SENSE)
scsi_print_sense("", cmd);
}
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index 1b59b27e887..4bf9aa547c7 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -50,7 +50,7 @@ scsi_nl_rcv_msg(struct sk_buff *skb)
while (skb->len >= NLMSG_SPACE(0)) {
err = 0;
- nlh = (struct nlmsghdr *) skb->data;
+ nlh = nlmsg_hdr(skb);
if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) ||
(skb->len < nlh->nlmsg_len)) {
printk(KERN_WARNING "%s: discarding partial skb\n",
@@ -168,7 +168,8 @@ scsi_netlink_init(void)
}
scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT,
- SCSI_NL_GRP_CNT, scsi_nl_rcv, THIS_MODULE);
+ SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL,
+ THIS_MODULE);
if (!scsi_nl_sock) {
printk(KERN_ERR "%s: register of recieve handler failed\n",
__FUNCTION__);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 0949145304e..a67f315244d 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -181,10 +181,8 @@ int scsi_complete_async_scans(void)
return 0;
}
-#ifdef MODULE
/* Only exported for the benefit of scsi_wait_scan */
EXPORT_SYMBOL_GPL(scsi_complete_async_scans);
-#endif
/**
* scsi_unlock_floptical - unlock device via a special MODE SENSE command
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index c275dcac3f1..67a38a1409b 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -276,8 +276,22 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
}
+static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ int i = 0;
+ int length = 0;
+
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
+ envp[i] = NULL;
+ return 0;
+}
+
static int scsi_bus_suspend(struct device * dev, pm_message_t state)
{
+ struct device_driver *drv = dev->driver;
struct scsi_device *sdev = to_scsi_device(dev);
struct scsi_host_template *sht = sdev->host->hostt;
int err;
@@ -286,28 +300,51 @@ static int scsi_bus_suspend(struct device * dev, pm_message_t state)
if (err)
return err;
- if (sht->suspend)
+ /* call HLD suspend first */
+ if (drv && drv->suspend) {
+ err = drv->suspend(dev, state);
+ if (err)
+ return err;
+ }
+
+ /* then, call host suspend */
+ if (sht->suspend) {
err = sht->suspend(sdev, state);
+ if (err) {
+ if (drv && drv->resume)
+ drv->resume(dev);
+ return err;
+ }
+ }
- return err;
+ return 0;
}
static int scsi_bus_resume(struct device * dev)
{
+ struct device_driver *drv = dev->driver;
struct scsi_device *sdev = to_scsi_device(dev);
struct scsi_host_template *sht = sdev->host->hostt;
- int err = 0;
+ int err = 0, err2 = 0;
+ /* call host resume first */
if (sht->resume)
err = sht->resume(sdev);
+ /* then, call HLD resume */
+ if (drv && drv->resume)
+ err2 = drv->resume(dev);
+
scsi_device_resume(sdev);
- return err;
+
+ /* favor LLD failure */
+ return err ? err : err2;;
}
struct bus_type scsi_bus_type = {
.name = "scsi",
.match = scsi_bus_match,
+ .uevent = scsi_bus_uevent,
.suspend = scsi_bus_suspend,
.resume = scsi_bus_resume,
};
@@ -452,10 +489,22 @@ store_rescan_field (struct device *dev, struct device_attribute *attr, const cha
}
static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field);
+static void sdev_store_delete_callback(struct device *dev)
+{
+ scsi_remove_device(to_scsi_device(dev));
+}
+
static ssize_t sdev_store_delete(struct device *dev, struct device_attribute *attr, const char *buf,
size_t count)
{
- scsi_remove_device(to_scsi_device(dev));
+ int rc;
+
+ /* An attribute cannot be unregistered by one of its own methods,
+ * so we have to use this roundabout approach.
+ */
+ rc = device_schedule_callback(dev, sdev_store_delete_callback);
+ if (rc)
+ count = rc;
return count;
};
static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
@@ -535,6 +584,14 @@ show_sdev_iostat(iorequest_cnt);
show_sdev_iostat(iodone_cnt);
show_sdev_iostat(ioerr_cnt);
+static ssize_t
+sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev;
+ sdev = to_scsi_device(dev);
+ return snprintf (buf, 20, SCSI_DEVICE_MODALIAS_FMT "\n", sdev->type);
+}
+static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL);
/* Default template for device attributes. May NOT be modified */
static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
@@ -554,6 +611,7 @@ static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
&dev_attr_iorequest_cnt,
&dev_attr_iodone_cnt,
&dev_attr_ioerr_cnt,
+ &dev_attr_modalias,
NULL
};
diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
index 0e08817fdec..ca22ddf8174 100644
--- a/drivers/scsi/scsi_tgt_if.c
+++ b/drivers/scsi/scsi_tgt_if.c
@@ -179,10 +179,12 @@ static int event_recv_msg(struct tgt_event *ev)
switch (ev->hdr.type) {
case TGT_UEVENT_CMD_RSP:
err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no,
- ev->p.cmd_rsp.tag,
ev->p.cmd_rsp.result,
- ev->p.cmd_rsp.len,
+ ev->p.cmd_rsp.tag,
ev->p.cmd_rsp.uaddr,
+ ev->p.cmd_rsp.len,
+ ev->p.cmd_rsp.sense_uaddr,
+ ev->p.cmd_rsp.sense_len,
ev->p.cmd_rsp.rw);
break;
case TGT_UEVENT_TSK_MGMT_RSP:
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index d402aff5f31..2570f48a69c 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -28,7 +28,6 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tgt.h>
-#include <../drivers/md/dm-bio-list.h>
#include "scsi_tgt_priv.h"
@@ -42,16 +41,12 @@ static struct kmem_cache *scsi_tgt_cmd_cache;
struct scsi_tgt_cmd {
/* TODO replace work with James b's code */
struct work_struct work;
- /* TODO replace the lists with a large bio */
- struct bio_list xfer_done_list;
- struct bio_list xfer_list;
+ /* TODO fix limits of some drivers */
+ struct bio *bio;
struct list_head hash_list;
struct request *rq;
u64 tag;
-
- void *buffer;
- unsigned bufflen;
};
#define TGT_HASH_ORDER 4
@@ -93,7 +88,12 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
if (!tcmd)
goto put_dev;
- rq = blk_get_request(shost->uspace_req_q, write, gfp_mask);
+ /*
+ * The blk helpers are used to the READ/WRITE requests
+ * transfering data from a initiator point of view. Since
+ * we are in target mode we want the opposite.
+ */
+ rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask);
if (!rq)
goto free_tcmd;
@@ -111,8 +111,6 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
rq->cmd_flags |= REQ_TYPE_BLOCK_PC;
rq->end_io_data = tcmd;
- bio_list_init(&tcmd->xfer_list);
- bio_list_init(&tcmd->xfer_done_list);
tcmd->rq = rq;
return cmd;
@@ -157,22 +155,6 @@ void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
}
EXPORT_SYMBOL_GPL(scsi_host_put_command);
-static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd)
-{
- struct bio *bio;
-
- /* must call bio_endio in case bio was bounced */
- while ((bio = bio_list_pop(&tcmd->xfer_done_list))) {
- bio_endio(bio, bio->bi_size, 0);
- bio_unmap_user(bio);
- }
-
- while ((bio = bio_list_pop(&tcmd->xfer_list))) {
- bio_endio(bio, bio->bi_size, 0);
- bio_unmap_user(bio);
- }
-}
-
static void cmd_hashlist_del(struct scsi_cmnd *cmd)
{
struct request_queue *q = cmd->request->q;
@@ -185,6 +167,11 @@ static void cmd_hashlist_del(struct scsi_cmnd *cmd)
spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
}
+static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd)
+{
+ blk_rq_unmap_user(tcmd->bio);
+}
+
static void scsi_tgt_cmd_destroy(struct work_struct *work)
{
struct scsi_tgt_cmd *tcmd =
@@ -193,16 +180,6 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work)
dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction,
rq_data_dir(cmd->request));
- /*
- * We fix rq->cmd_flags here since when we told bio_map_user
- * to write vm for WRITE commands, blk_rq_bio_prep set
- * rq_data_dir the flags to READ.
- */
- if (cmd->sc_data_direction == DMA_TO_DEVICE)
- cmd->request->cmd_flags |= REQ_RW;
- else
- cmd->request->cmd_flags &= ~REQ_RW;
-
scsi_unmap_user_pages(tcmd);
scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd);
}
@@ -215,6 +192,7 @@ static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd,
struct list_head *head;
tcmd->tag = tag;
+ tcmd->bio = NULL;
INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy);
spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
head = &qdata->cmd_hash[cmd_hashfn(tag)];
@@ -349,10 +327,14 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
scsi_tgt_uspace_send_status(cmd, tcmd->tag);
+
+ if (cmd->request_buffer)
+ scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
+
queue_work(scsi_tgtd, &tcmd->work);
}
-static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
+static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
{
struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
int err;
@@ -365,30 +347,12 @@ static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
case SCSI_MLQUEUE_DEVICE_BUSY:
return -EAGAIN;
}
-
return 0;
}
-static void scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
-{
- struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
- int err;
-
- err = __scsi_tgt_transfer_response(cmd);
- if (!err)
- return;
-
- cmd->result = DID_BUS_BUSY << 16;
- err = scsi_tgt_uspace_send_status(cmd, tcmd->tag);
- if (err <= 0)
- /* the eh will have to pick this up */
- printk(KERN_ERR "Could not send cmd %p status\n", cmd);
-}
-
static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
{
struct request *rq = cmd->request;
- struct scsi_tgt_cmd *tcmd = rq->end_io_data;
int count;
cmd->use_sg = rq->nr_phys_segments;
@@ -398,143 +362,54 @@ static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
cmd->request_bufflen = rq->data_len;
- dprintk("cmd %p addr %p cnt %d %lu\n", cmd, tcmd->buffer, cmd->use_sg,
- rq_data_dir(rq));
+ dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq));
count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer);
if (likely(count <= cmd->use_sg)) {
cmd->use_sg = count;
return 0;
}
- eprintk("cmd %p addr %p cnt %d\n", cmd, tcmd->buffer, cmd->use_sg);
+ eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg);
scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
return -EINVAL;
}
/* TODO: test this crap and replace bio_map_user with new interface maybe */
static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd,
- int rw)
+ unsigned long uaddr, unsigned int len, int rw)
{
struct request_queue *q = cmd->request->q;
struct request *rq = cmd->request;
- void *uaddr = tcmd->buffer;
- unsigned int len = tcmd->bufflen;
- struct bio *bio;
int err;
- while (len > 0) {
- dprintk("%lx %u\n", (unsigned long) uaddr, len);
- bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw);
- if (IS_ERR(bio)) {
- err = PTR_ERR(bio);
- dprintk("fail to map %lx %u %d %x\n",
- (unsigned long) uaddr, len, err, cmd->cmnd[0]);
- goto unmap_bios;
- }
-
- uaddr += bio->bi_size;
- len -= bio->bi_size;
-
+ dprintk("%lx %u\n", uaddr, len);
+ err = blk_rq_map_user(q, rq, (void *)uaddr, len);
+ if (err) {
/*
- * The first bio is added and merged. We could probably
- * try to add others using scsi_merge_bio() but for now
- * we keep it simple. The first bio should be pretty large
- * (either hitting the 1 MB bio pages limit or a queue limit)
- * already but for really large IO we may want to try and
- * merge these.
+ * TODO: need to fixup sg_tablesize, max_segment_size,
+ * max_sectors, etc for modern HW and software drivers
+ * where this value is bogus.
+ *
+ * TODO2: we can alloc a reserve buffer of max size
+ * we can handle and do the slow copy path for really large
+ * IO.
*/
- if (!rq->bio) {
- blk_rq_bio_prep(q, rq, bio);
- rq->data_len = bio->bi_size;
- } else
- /* put list of bios to transfer in next go around */
- bio_list_add(&tcmd->xfer_list, bio);
+ eprintk("Could not handle request of size %u.\n", len);
+ return err;
}
- cmd->offset = 0;
+ tcmd->bio = rq->bio;
err = scsi_tgt_init_cmd(cmd, GFP_KERNEL);
if (err)
- goto unmap_bios;
+ goto unmap_rq;
return 0;
-unmap_bios:
- if (rq->bio) {
- bio_unmap_user(rq->bio);
- while ((bio = bio_list_pop(&tcmd->xfer_list)))
- bio_unmap_user(bio);
- }
-
+unmap_rq:
+ scsi_unmap_user_pages(tcmd);
return err;
}
-static int scsi_tgt_transfer_data(struct scsi_cmnd *);
-
-static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd)
-{
- struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
- struct bio *bio;
- int err;
-
- /* should we free resources here on error ? */
- if (cmd->result) {
-send_uspace_err:
- err = scsi_tgt_uspace_send_status(cmd, tcmd->tag);
- if (err <= 0)
- /* the tgt uspace eh will have to pick this up */
- printk(KERN_ERR "Could not send cmd %p status\n", cmd);
- return;
- }
-
- dprintk("cmd %p request_bufflen %u bufflen %u\n",
- cmd, cmd->request_bufflen, tcmd->bufflen);
-
- scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
- bio_list_add(&tcmd->xfer_done_list, cmd->request->bio);
-
- tcmd->buffer += cmd->request_bufflen;
- cmd->offset += cmd->request_bufflen;
-
- if (!tcmd->xfer_list.head) {
- scsi_tgt_transfer_response(cmd);
- return;
- }
-
- dprintk("cmd2 %p request_bufflen %u bufflen %u\n",
- cmd, cmd->request_bufflen, tcmd->bufflen);
-
- bio = bio_list_pop(&tcmd->xfer_list);
- BUG_ON(!bio);
-
- blk_rq_bio_prep(cmd->request->q, cmd->request, bio);
- cmd->request->data_len = bio->bi_size;
- err = scsi_tgt_init_cmd(cmd, GFP_ATOMIC);
- if (err) {
- cmd->result = DID_ERROR << 16;
- goto send_uspace_err;
- }
-
- if (scsi_tgt_transfer_data(cmd)) {
- cmd->result = DID_NO_CONNECT << 16;
- goto send_uspace_err;
- }
-}
-
-static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd)
-{
- int err;
- struct Scsi_Host *host = scsi_tgt_cmd_to_host(cmd);
-
- err = host->hostt->transfer_data(cmd, scsi_tgt_data_transfer_done);
- switch (err) {
- case SCSI_MLQUEUE_HOST_BUSY:
- case SCSI_MLQUEUE_DEVICE_BUSY:
- return -EAGAIN;
- default:
- return 0;
- }
-}
-
static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr,
unsigned len)
{
@@ -584,8 +459,9 @@ static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag)
return rq;
}
-int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
- unsigned long uaddr, u8 rw)
+int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
+ unsigned long uaddr, u32 len, unsigned long sense_uaddr,
+ u32 sense_len, u8 rw)
{
struct Scsi_Host *shost;
struct scsi_cmnd *cmd;
@@ -617,8 +493,9 @@ int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
}
cmd = rq->special;
- dprintk("cmd %p result %d len %d bufflen %u %lu %x\n", cmd,
- result, len, cmd->request_bufflen, rq_data_dir(rq), cmd->cmnd[0]);
+ dprintk("cmd %p scb %x result %d len %d bufflen %u %lu %x\n",
+ cmd, cmd->cmnd[0], result, len, cmd->request_bufflen,
+ rq_data_dir(rq), cmd->cmnd[0]);
if (result == TASK_ABORTED) {
scsi_tgt_abort_cmd(shost, cmd);
@@ -629,36 +506,36 @@ int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
* in the request_* values
*/
tcmd = cmd->request->end_io_data;
- tcmd->buffer = (void *)uaddr;
- tcmd->bufflen = len;
cmd->result = result;
- if (!tcmd->bufflen || cmd->request_buffer) {
- err = __scsi_tgt_transfer_response(cmd);
- goto done;
- }
+ if (cmd->result == SAM_STAT_CHECK_CONDITION)
+ scsi_tgt_copy_sense(cmd, sense_uaddr, sense_len);
- /*
- * TODO: Do we need to handle case where request does not
- * align with LLD.
- */
- err = scsi_map_user_pages(rq->end_io_data, cmd, rw);
- if (err) {
- eprintk("%p %d\n", cmd, err);
- err = -EAGAIN;
- goto done;
- }
+ if (len) {
+ err = scsi_map_user_pages(rq->end_io_data, cmd, uaddr, len, rw);
+ if (err) {
+ /*
+ * user-space daemon bugs or OOM
+ * TODO: we can do better for OOM.
+ */
+ struct scsi_tgt_queuedata *qdata;
+ struct list_head *head;
+ unsigned long flags;
- /* userspace failure */
- if (cmd->result) {
- if (status_byte(cmd->result) == CHECK_CONDITION)
- scsi_tgt_copy_sense(cmd, uaddr, len);
- err = __scsi_tgt_transfer_response(cmd);
- goto done;
- }
- /* ask the target LLD to transfer the data to the buffer */
- err = scsi_tgt_transfer_data(cmd);
+ eprintk("cmd %p ret %d uaddr %lx len %d rw %d\n",
+ cmd, err, uaddr, len, rw);
+
+ qdata = shost->uspace_req_q->queuedata;
+ head = &qdata->cmd_hash[cmd_hashfn(tcmd->tag)];
+
+ spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
+ list_add(&tcmd->hash_list, head);
+ spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
+ goto done;
+ }
+ }
+ err = scsi_tgt_transfer_response(cmd);
done:
scsi_host_put(shost);
return err;
diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h
index 84488c51ff6..e9e6db1c417 100644
--- a/drivers/scsi/scsi_tgt_priv.h
+++ b/drivers/scsi/scsi_tgt_priv.h
@@ -18,8 +18,9 @@ extern int scsi_tgt_if_init(void);
extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun,
u64 tag);
extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag);
-extern int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
- unsigned long uaddr, u8 rw);
+extern int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
+ unsigned long uaddr, u32 len, unsigned long sense_uaddr,
+ u32 sense_len, u8 rw);
extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
struct scsi_lun *scsilun, void *data);
extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 58afdb40170..14c4f065b2b 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -200,6 +200,8 @@ static const struct {
{ FC_PORTSPEED_2GBIT, "2 Gbit" },
{ FC_PORTSPEED_4GBIT, "4 Gbit" },
{ FC_PORTSPEED_10GBIT, "10 Gbit" },
+ { FC_PORTSPEED_8GBIT, "8 Gbit" },
+ { FC_PORTSPEED_16GBIT, "16 Gbit" },
{ FC_PORTSPEED_NOT_NEGOTIATED, "Not Negotiated" },
};
fc_bitfield_name_search(port_speed, fc_port_speed_names)
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index ce0d14af33c..caf1836bbec 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -49,7 +49,7 @@ struct iscsi_internal {
struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
};
-static int iscsi_session_nr; /* sysfs session id for next new session */
+static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
/*
* list of registered transports and lock that must
@@ -300,7 +300,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
int err;
ihost = shost->shost_data;
- session->sid = iscsi_session_nr++;
+ session->sid = atomic_add_return(1, &iscsi_session_nr);
session->target_id = target_id;
snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
@@ -1081,7 +1081,7 @@ iscsi_if_rx(struct sock *sk, int len)
struct nlmsghdr *nlh;
struct iscsi_uevent *ev;
- nlh = (struct nlmsghdr *)skb->data;
+ nlh = nlmsg_hdr(skb);
if (nlh->nlmsg_len < sizeof(*nlh) ||
skb->len < nlh->nlmsg_len) {
break;
@@ -1419,6 +1419,8 @@ static __init int iscsi_transport_init(void)
printk(KERN_INFO "Loading iSCSI transport class v%s.\n",
ISCSI_TRANSPORT_VERSION);
+ atomic_set(&iscsi_session_nr, 0);
+
err = class_register(&iscsi_transport_class);
if (err)
return err;
@@ -1435,7 +1437,7 @@ static __init int iscsi_transport_init(void)
if (err)
goto unregister_conn_class;
- nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx,
+ nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx, NULL,
THIS_MODULE);
if (!nls) {
err = -ENOBUFS;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5a8f55fea5f..00e46662296 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -58,16 +58,10 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/scsicam.h>
+#include <scsi/sd.h>
#include "scsi_logging.h"
-/*
- * More than enough for everybody ;) The huge number of majors
- * is a leftover from 16bit dev_t days, we don't really need that
- * much numberspace.
- */
-#define SD_MAJORS 16
-
MODULE_AUTHOR("Eric Youngdale");
MODULE_DESCRIPTION("SCSI disk (sd) driver");
MODULE_LICENSE("GPL");
@@ -88,45 +82,9 @@ MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK12_MAJOR);
MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR);
MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR);
MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR);
-
-/*
- * This is limited by the naming scheme enforced in sd_probe,
- * add another character to it if you really need more disks.
- */
-#define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26)
-
-/*
- * Time out in seconds for disks and Magneto-opticals (which are slower).
- */
-#define SD_TIMEOUT (30 * HZ)
-#define SD_MOD_TIMEOUT (75 * HZ)
-
-/*
- * Number of allowed retries
- */
-#define SD_MAX_RETRIES 5
-#define SD_PASSTHROUGH_RETRIES 1
-
-/*
- * Size of the initial data buffer for mode and read capacity data
- */
-#define SD_BUF_SIZE 512
-
-struct scsi_disk {
- struct scsi_driver *driver; /* always &sd_template */
- struct scsi_device *device;
- struct class_device cdev;
- struct gendisk *disk;
- unsigned int openers; /* protected by BKL for now, yuck */
- sector_t capacity; /* size in 512-byte sectors */
- u32 index;
- u8 media_present;
- u8 write_prot;
- unsigned WCE : 1; /* state of disk WCE bit */
- unsigned RCD : 1; /* state of disk RCD bit, unused */
- unsigned DPOFUA : 1; /* state of disk DPOFUA bit */
-};
-#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev)
+MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
static DEFINE_IDR(sd_index_idr);
static DEFINE_SPINLOCK(sd_index_lock);
@@ -136,20 +94,6 @@ static DEFINE_SPINLOCK(sd_index_lock);
* object after last put) */
static DEFINE_MUTEX(sd_ref_mutex);
-static int sd_revalidate_disk(struct gendisk *disk);
-static void sd_rw_intr(struct scsi_cmnd * SCpnt);
-
-static int sd_probe(struct device *);
-static int sd_remove(struct device *);
-static void sd_shutdown(struct device *dev);
-static void sd_rescan(struct device *);
-static int sd_init_command(struct scsi_cmnd *);
-static int sd_issue_flush(struct device *, sector_t *);
-static void sd_prepare_flush(request_queue_t *, struct request *);
-static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
- unsigned char *buffer);
-static void scsi_disk_release(struct class_device *cdev);
-
static const char *sd_cache_types[] = {
"write through", "none", "write back",
"write back, no read (daft)"
@@ -199,13 +143,27 @@ static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf,
if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT,
SD_MAX_RETRIES, &data, &sshdr)) {
if (scsi_sense_valid(&sshdr))
- scsi_print_sense_hdr(sdkp->disk->disk_name, &sshdr);
+ sd_print_sense_hdr(sdkp, &sshdr);
return -EINVAL;
}
sd_revalidate_disk(sdkp->disk);
return count;
}
+static ssize_t sd_store_manage_start_stop(struct class_device *cdev,
+ const char *buf, size_t count)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(cdev);
+ struct scsi_device *sdp = sdkp->device;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ sdp->manage_start_stop = simple_strtoul(buf, NULL, 10);
+
+ return count;
+}
+
static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf,
size_t count)
{
@@ -238,6 +196,14 @@ static ssize_t sd_show_fua(struct class_device *cdev, char *buf)
return snprintf(buf, 20, "%u\n", sdkp->DPOFUA);
}
+static ssize_t sd_show_manage_start_stop(struct class_device *cdev, char *buf)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(cdev);
+ struct scsi_device *sdp = sdkp->device;
+
+ return snprintf(buf, 20, "%u\n", sdp->manage_start_stop);
+}
+
static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(cdev);
@@ -251,6 +217,8 @@ static struct class_device_attribute sd_disk_attrs[] = {
__ATTR(FUA, S_IRUGO, sd_show_fua, NULL),
__ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart,
sd_store_allow_restart),
+ __ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop,
+ sd_store_manage_start_stop),
__ATTR_NULL,
};
@@ -267,6 +235,8 @@ static struct scsi_driver sd_template = {
.name = "sd",
.probe = sd_probe,
.remove = sd_remove,
+ .suspend = sd_suspend,
+ .resume = sd_resume,
.shutdown = sd_shutdown,
},
.rescan = sd_rescan,
@@ -371,15 +341,19 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
unsigned int this_count = SCpnt->request_bufflen >> 9;
unsigned int timeout = sdp->timeout;
- SCSI_LOG_HLQUEUE(1, printk("sd_init_command: disk=%s, block=%llu, "
- "count=%d\n", disk->disk_name,
- (unsigned long long)block, this_count));
+ SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
+ "sd_init_command: block=%llu, "
+ "count=%d\n",
+ (unsigned long long)block,
+ this_count));
if (!sdp || !scsi_device_online(sdp) ||
block + rq->nr_sectors > get_capacity(disk)) {
- SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n",
- rq->nr_sectors));
- SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
+ SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
+ "Finishing %ld sectors\n",
+ rq->nr_sectors));
+ SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
+ "Retry with 0x%p\n", SCpnt));
return 0;
}
@@ -391,8 +365,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
return 0;
}
- SCSI_LOG_HLQUEUE(2, printk("%s : block=%llu\n",
- disk->disk_name, (unsigned long long)block));
+ SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
+ (unsigned long long)block));
/*
* If we have a 1K hardware sectorsize, prevent access to single
@@ -407,7 +381,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
*/
if (sdp->sector_size == 1024) {
if ((block & 1) || (rq->nr_sectors & 1)) {
- printk(KERN_ERR "sd: Bad block number requested");
+ scmd_printk(KERN_ERR, SCpnt,
+ "Bad block number requested\n");
return 0;
} else {
block = block >> 1;
@@ -416,7 +391,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
}
if (sdp->sector_size == 2048) {
if ((block & 3) || (rq->nr_sectors & 3)) {
- printk(KERN_ERR "sd: Bad block number requested");
+ scmd_printk(KERN_ERR, SCpnt,
+ "Bad block number requested\n");
return 0;
} else {
block = block >> 2;
@@ -425,7 +401,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
}
if (sdp->sector_size == 4096) {
if ((block & 7) || (rq->nr_sectors & 7)) {
- printk(KERN_ERR "sd: Bad block number requested");
+ scmd_printk(KERN_ERR, SCpnt,
+ "Bad block number requested\n");
return 0;
} else {
block = block >> 3;
@@ -442,13 +419,15 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->cmnd[0] = READ_6;
SCpnt->sc_data_direction = DMA_FROM_DEVICE;
} else {
- printk(KERN_ERR "sd: Unknown command %x\n", rq->cmd_flags);
+ scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags);
return 0;
}
- SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
- disk->disk_name, (rq_data_dir(rq) == WRITE) ?
- "writing" : "reading", this_count, rq->nr_sectors));
+ SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
+ "%s %d/%ld 512 byte blocks.\n",
+ (rq_data_dir(rq) == WRITE) ?
+ "writing" : "reading", this_count,
+ rq->nr_sectors));
SCpnt->cmnd[1] = 0;
@@ -490,7 +469,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
* during operation and thus turned off
* use_10_for_rw.
*/
- printk(KERN_ERR "sd: FUA write on READ/WRITE(6) drive\n");
+ scmd_printk(KERN_ERR, SCpnt,
+ "FUA write on READ/WRITE(6) drive\n");
return 0;
}
@@ -549,7 +529,7 @@ static int sd_open(struct inode *inode, struct file *filp)
return -ENXIO;
- SCSI_LOG_HLQUEUE(3, printk("sd_open: disk=%s\n", disk->disk_name));
+ SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_open\n"));
sdev = sdkp->device;
@@ -619,7 +599,7 @@ static int sd_release(struct inode *inode, struct file *filp)
struct scsi_disk *sdkp = scsi_disk(disk);
struct scsi_device *sdev = sdkp->device;
- SCSI_LOG_HLQUEUE(3, printk("sd_release: disk=%s\n", disk->disk_name));
+ SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_release\n"));
if (!--sdkp->openers && sdev->removable) {
if (scsi_block_when_processing_errors(sdev))
@@ -732,8 +712,7 @@ static int sd_media_changed(struct gendisk *disk)
struct scsi_device *sdp = sdkp->device;
int retval;
- SCSI_LOG_HLQUEUE(3, printk("sd_media_changed: disk=%s\n",
- disk->disk_name));
+ SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n"));
if (!sdp->removable)
return 0;
@@ -786,9 +765,10 @@ not_present:
return 1;
}
-static int sd_sync_cache(struct scsi_device *sdp)
+static int sd_sync_cache(struct scsi_disk *sdkp)
{
int retries, res;
+ struct scsi_device *sdp = sdkp->device;
struct scsi_sense_hdr sshdr;
if (!scsi_device_online(sdp))
@@ -809,28 +789,27 @@ static int sd_sync_cache(struct scsi_device *sdp)
break;
}
- if (res) { printk(KERN_WARNING "FAILED\n status = %x, message = %02x, "
- "host = %d, driver = %02x\n ",
- status_byte(res), msg_byte(res),
- host_byte(res), driver_byte(res));
- if (driver_byte(res) & DRIVER_SENSE)
- scsi_print_sense_hdr("sd", &sshdr);
+ if (res) {
+ sd_print_result(sdkp, res);
+ if (driver_byte(res) & DRIVER_SENSE)
+ sd_print_sense_hdr(sdkp, &sshdr);
}
- return res;
+ if (res)
+ return -EIO;
+ return 0;
}
static int sd_issue_flush(struct device *dev, sector_t *error_sector)
{
int ret = 0;
- struct scsi_device *sdp = to_scsi_device(dev);
struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
if (!sdkp)
return -ENODEV;
if (sdkp->WCE)
- ret = sd_sync_cache(sdp);
+ ret = sd_sync_cache(sdkp);
scsi_disk_put(sdkp);
return ret;
}
@@ -928,12 +907,14 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
sense_deferred = scsi_sense_is_deferred(&sshdr);
}
#ifdef CONFIG_SCSI_LOGGING
- SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n",
- SCpnt->request->rq_disk->disk_name, result));
+ SCSI_LOG_HLCOMPLETE(1, scsi_print_result(SCpnt));
if (sense_valid) {
- SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[respc,sk,asc,"
- "ascq]=%x,%x,%x,%x\n", sshdr.response_code,
- sshdr.sense_key, sshdr.asc, sshdr.ascq));
+ SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt,
+ "sd_rw_intr: sb[respc,sk,asc,"
+ "ascq]=%x,%x,%x,%x\n",
+ sshdr.response_code,
+ sshdr.sense_key, sshdr.asc,
+ sshdr.ascq));
}
#endif
if (driver_byte(result) != DRIVER_SENSE &&
@@ -1025,7 +1006,7 @@ static int media_not_present(struct scsi_disk *sdkp,
* spinup disk - called only in sd_revalidate_disk()
*/
static void
-sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
+sd_spinup_disk(struct scsi_disk *sdkp)
{
unsigned char cmd[10];
unsigned long spintime_expire = 0;
@@ -1069,9 +1050,10 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
if ((driver_byte(the_result) & DRIVER_SENSE) == 0) {
/* no sense, TUR either succeeded or failed
* with a status error */
- if(!spintime && !scsi_status_is_good(the_result))
- printk(KERN_NOTICE "%s: Unit Not Ready, "
- "error = 0x%x\n", diskname, the_result);
+ if(!spintime && !scsi_status_is_good(the_result)) {
+ sd_printk(KERN_NOTICE, sdkp, "Unit Not Ready\n");
+ sd_print_result(sdkp, the_result);
+ }
break;
}
@@ -1096,8 +1078,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
*/
} else if (sense_valid && sshdr.sense_key == NOT_READY) {
if (!spintime) {
- printk(KERN_NOTICE "%s: Spinning up disk...",
- diskname);
+ sd_printk(KERN_NOTICE, sdkp, "Spinning up disk...");
cmd[0] = START_STOP;
cmd[1] = 1; /* Return immediately */
memset((void *) &cmd[2], 0, 8);
@@ -1130,9 +1111,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
/* we don't understand the sense code, so it's
* probably pointless to loop */
if(!spintime) {
- printk(KERN_NOTICE "%s: Unit Not Ready, "
- "sense:\n", diskname);
- scsi_print_sense_hdr("", &sshdr);
+ sd_printk(KERN_NOTICE, sdkp, "Unit Not Ready\n");
+ sd_print_sense_hdr(sdkp, &sshdr);
}
break;
}
@@ -1151,8 +1131,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
* read disk capacity
*/
static void
-sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
- unsigned char *buffer)
+sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
{
unsigned char cmd[16];
int the_result, retries;
@@ -1191,18 +1170,12 @@ repeat:
} while (the_result && retries);
if (the_result && !longrc) {
- printk(KERN_NOTICE "%s : READ CAPACITY failed.\n"
- "%s : status=%x, message=%02x, host=%d, driver=%02x \n",
- diskname, diskname,
- status_byte(the_result),
- msg_byte(the_result),
- host_byte(the_result),
- driver_byte(the_result));
-
+ sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY failed\n");
+ sd_print_result(sdkp, the_result);
if (driver_byte(the_result) & DRIVER_SENSE)
- scsi_print_sense_hdr("sd", &sshdr);
+ sd_print_sense_hdr(sdkp, &sshdr);
else
- printk("%s : sense not available. \n", diskname);
+ sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n");
/* Set dirty bit for removable devices if not ready -
* sometimes drives will not report this properly. */
@@ -1218,16 +1191,10 @@ repeat:
return;
} else if (the_result && longrc) {
/* READ CAPACITY(16) has been failed */
- printk(KERN_NOTICE "%s : READ CAPACITY(16) failed.\n"
- "%s : status=%x, message=%02x, host=%d, driver=%02x \n",
- diskname, diskname,
- status_byte(the_result),
- msg_byte(the_result),
- host_byte(the_result),
- driver_byte(the_result));
- printk(KERN_NOTICE "%s : use 0xffffffff as device size\n",
- diskname);
-
+ sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n");
+ sd_print_result(sdkp, the_result);
+ sd_printk(KERN_NOTICE, sdkp, "Use 0xffffffff as device size\n");
+
sdkp->capacity = 1 + (sector_t) 0xffffffff;
goto got_data;
}
@@ -1238,14 +1205,14 @@ repeat:
if (buffer[0] == 0xff && buffer[1] == 0xff &&
buffer[2] == 0xff && buffer[3] == 0xff) {
if(sizeof(sdkp->capacity) > 4) {
- printk(KERN_NOTICE "%s : very big device. try to use"
- " READ CAPACITY(16).\n", diskname);
+ sd_printk(KERN_NOTICE, sdkp, "Very big device. "
+ "Trying to use READ CAPACITY(16).\n");
longrc = 1;
goto repeat;
}
- printk(KERN_ERR "%s: too big for this kernel. Use a "
- "kernel compiled with support for large block "
- "devices.\n", diskname);
+ sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use "
+ "a kernel compiled with support for large "
+ "block devices.\n");
sdkp->capacity = 0;
goto got_data;
}
@@ -1284,8 +1251,8 @@ repeat:
got_data:
if (sector_size == 0) {
sector_size = 512;
- printk(KERN_NOTICE "%s : sector size 0 reported, "
- "assuming 512.\n", diskname);
+ sd_printk(KERN_NOTICE, sdkp, "Sector size 0 reported, "
+ "assuming 512.\n");
}
if (sector_size != 512 &&
@@ -1293,8 +1260,8 @@ got_data:
sector_size != 2048 &&
sector_size != 4096 &&
sector_size != 256) {
- printk(KERN_NOTICE "%s : unsupported sector size "
- "%d.\n", diskname, sector_size);
+ sd_printk(KERN_NOTICE, sdkp, "Unsupported sector size %d.\n",
+ sector_size);
/*
* The user might want to re-format the drive with
* a supported sectorsize. Once this happens, it
@@ -1327,10 +1294,10 @@ got_data:
mb -= sz - 974;
sector_div(mb, 1950);
- printk(KERN_NOTICE "SCSI device %s: "
- "%llu %d-byte hdwr sectors (%llu MB)\n",
- diskname, (unsigned long long)sdkp->capacity,
- hard_sector, (unsigned long long)mb);
+ sd_printk(KERN_NOTICE, sdkp,
+ "%llu %d-byte hardware sectors (%llu MB)\n",
+ (unsigned long long)sdkp->capacity,
+ hard_sector, (unsigned long long)mb);
}
/* Rescale capacity to 512-byte units */
@@ -1362,8 +1329,7 @@ sd_do_mode_sense(struct scsi_device *sdp, int dbd, int modepage,
* called with buffer of length SD_BUF_SIZE
*/
static void
-sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
- unsigned char *buffer)
+sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
{
int res;
struct scsi_device *sdp = sdkp->device;
@@ -1371,7 +1337,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
set_disk_ro(sdkp->disk, 0);
if (sdp->skip_ms_page_3f) {
- printk(KERN_NOTICE "%s: assuming Write Enabled\n", diskname);
+ sd_printk(KERN_NOTICE, sdkp, "Assuming Write Enabled\n");
return;
}
@@ -1403,15 +1369,16 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
}
if (!scsi_status_is_good(res)) {
- printk(KERN_WARNING
- "%s: test WP failed, assume Write Enabled\n", diskname);
+ sd_printk(KERN_WARNING, sdkp,
+ "Test WP failed, assume Write Enabled\n");
} else {
sdkp->write_prot = ((data.device_specific & 0x80) != 0);
set_disk_ro(sdkp->disk, sdkp->write_prot);
- printk(KERN_NOTICE "%s: Write Protect is %s\n", diskname,
- sdkp->write_prot ? "on" : "off");
- printk(KERN_DEBUG "%s: Mode Sense: %02x %02x %02x %02x\n",
- diskname, buffer[0], buffer[1], buffer[2], buffer[3]);
+ sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n",
+ sdkp->write_prot ? "on" : "off");
+ sd_printk(KERN_DEBUG, sdkp,
+ "Mode Sense: %02x %02x %02x %02x\n",
+ buffer[0], buffer[1], buffer[2], buffer[3]);
}
}
@@ -1420,8 +1387,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
* called with buffer of length SD_BUF_SIZE
*/
static void
-sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
- unsigned char *buffer)
+sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
{
int len = 0, res;
struct scsi_device *sdp = sdkp->device;
@@ -1450,8 +1416,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
if (!data.header_length) {
modepage = 6;
- printk(KERN_ERR "%s: missing header in MODE_SENSE response\n",
- diskname);
+ sd_printk(KERN_ERR, sdkp, "Missing header in MODE_SENSE response\n");
}
/* that went OK, now ask for the proper length */
@@ -1478,13 +1443,12 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
int offset = data.header_length + data.block_descriptor_length;
if (offset >= SD_BUF_SIZE - 2) {
- printk(KERN_ERR "%s: malformed MODE SENSE response",
- diskname);
+ sd_printk(KERN_ERR, sdkp, "Malformed MODE SENSE response\n");
goto defaults;
}
if ((buffer[offset] & 0x3f) != modepage) {
- printk(KERN_ERR "%s: got wrong page\n", diskname);
+ sd_printk(KERN_ERR, sdkp, "Got wrong page\n");
goto defaults;
}
@@ -1498,14 +1462,13 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
sdkp->DPOFUA = (data.device_specific & 0x10) != 0;
if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) {
- printk(KERN_NOTICE "SCSI device %s: uses "
- "READ/WRITE(6), disabling FUA\n", diskname);
+ sd_printk(KERN_NOTICE, sdkp,
+ "Uses READ/WRITE(6), disabling FUA\n");
sdkp->DPOFUA = 0;
}
- printk(KERN_NOTICE "SCSI device %s: "
- "write cache: %s, read cache: %s, %s\n",
- diskname,
+ sd_printk(KERN_NOTICE, sdkp,
+ "Write cache: %s, read cache: %s, %s\n",
sdkp->WCE ? "enabled" : "disabled",
sdkp->RCD ? "disabled" : "enabled",
sdkp->DPOFUA ? "supports DPO and FUA"
@@ -1518,15 +1481,13 @@ bad_sense:
if (scsi_sense_valid(&sshdr) &&
sshdr.sense_key == ILLEGAL_REQUEST &&
sshdr.asc == 0x24 && sshdr.ascq == 0x0)
- printk(KERN_NOTICE "%s: cache data unavailable\n",
- diskname); /* Invalid field in CDB */
+ /* Invalid field in CDB */
+ sd_printk(KERN_NOTICE, sdkp, "Cache data unavailable\n");
else
- printk(KERN_ERR "%s: asking for cache data failed\n",
- diskname);
+ sd_printk(KERN_ERR, sdkp, "Asking for cache data failed\n");
defaults:
- printk(KERN_ERR "%s: assuming drive cache: write through\n",
- diskname);
+ sd_printk(KERN_ERR, sdkp, "Assuming drive cache: write through\n");
sdkp->WCE = 0;
sdkp->RCD = 0;
sdkp->DPOFUA = 0;
@@ -1544,7 +1505,8 @@ static int sd_revalidate_disk(struct gendisk *disk)
unsigned char *buffer;
unsigned ordered;
- SCSI_LOG_HLQUEUE(3, printk("sd_revalidate_disk: disk=%s\n", disk->disk_name));
+ SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp,
+ "sd_revalidate_disk\n"));
/*
* If the device is offline, don't try and read capacity or any
@@ -1555,8 +1517,8 @@ static int sd_revalidate_disk(struct gendisk *disk)
buffer = kmalloc(SD_BUF_SIZE, GFP_KERNEL | __GFP_DMA);
if (!buffer) {
- printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation "
- "failure.\n");
+ sd_printk(KERN_WARNING, sdkp, "sd_revalidate_disk: Memory "
+ "allocation failure.\n");
goto out;
}
@@ -1568,16 +1530,16 @@ static int sd_revalidate_disk(struct gendisk *disk)
sdkp->WCE = 0;
sdkp->RCD = 0;
- sd_spinup_disk(sdkp, disk->disk_name);
+ sd_spinup_disk(sdkp);
/*
* Without media there is no reason to ask; moreover, some devices
* react badly if we do.
*/
if (sdkp->media_present) {
- sd_read_capacity(sdkp, disk->disk_name, buffer);
- sd_read_write_protect_flag(sdkp, disk->disk_name, buffer);
- sd_read_cache_type(sdkp, disk->disk_name, buffer);
+ sd_read_capacity(sdkp, buffer);
+ sd_read_write_protect_flag(sdkp, buffer);
+ sd_read_cache_type(sdkp, buffer);
}
/*
@@ -1709,8 +1671,8 @@ static int sd_probe(struct device *dev)
dev_set_drvdata(dev, sdkp);
add_disk(gd);
- sdev_printk(KERN_NOTICE, sdp, "Attached scsi %sdisk %s\n",
- sdp->removable ? "removable " : "", gd->disk_name);
+ sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
+ sdp->removable ? "removable " : "");
return 0;
@@ -1774,6 +1736,31 @@ static void scsi_disk_release(struct class_device *cdev)
kfree(sdkp);
}
+static int sd_start_stop_device(struct scsi_disk *sdkp, int start)
+{
+ unsigned char cmd[6] = { START_STOP }; /* START_VALID */
+ struct scsi_sense_hdr sshdr;
+ struct scsi_device *sdp = sdkp->device;
+ int res;
+
+ if (start)
+ cmd[4] |= 1; /* START */
+
+ if (!scsi_device_online(sdp))
+ return -ENODEV;
+
+ res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
+ SD_TIMEOUT, SD_MAX_RETRIES);
+ if (res) {
+ sd_printk(KERN_WARNING, sdkp, "START_STOP FAILED\n");
+ sd_print_result(sdkp, res);
+ if (driver_byte(res) & DRIVER_SENSE)
+ sd_print_sense_hdr(sdkp, &sshdr);
+ }
+
+ return res;
+}
+
/*
* Send a SYNCHRONIZE CACHE instruction down to the device through
* the normal SCSI command structure. Wait for the command to
@@ -1781,20 +1768,62 @@ static void scsi_disk_release(struct class_device *cdev)
*/
static void sd_shutdown(struct device *dev)
{
- struct scsi_device *sdp = to_scsi_device(dev);
struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
if (!sdkp)
return; /* this can happen */
if (sdkp->WCE) {
- printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n",
- sdkp->disk->disk_name);
- sd_sync_cache(sdp);
+ sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
+ sd_sync_cache(sdkp);
+ }
+
+ if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) {
+ sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
+ sd_start_stop_device(sdkp, 0);
}
+
scsi_disk_put(sdkp);
}
+static int sd_suspend(struct device *dev, pm_message_t mesg)
+{
+ struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
+ int ret;
+
+ if (!sdkp)
+ return 0; /* this can happen */
+
+ if (sdkp->WCE) {
+ sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
+ ret = sd_sync_cache(sdkp);
+ if (ret)
+ return ret;
+ }
+
+ if (mesg.event == PM_EVENT_SUSPEND &&
+ sdkp->device->manage_start_stop) {
+ sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
+ ret = sd_start_stop_device(sdkp, 0);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sd_resume(struct device *dev)
+{
+ struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
+
+ if (!sdkp->device->manage_start_stop)
+ return 0;
+
+ sd_printk(KERN_NOTICE, sdkp, "Starting disk\n");
+
+ return sd_start_stop_device(sdkp, 1);
+}
+
/**
* init_sd - entry point for this driver (both when built in or when
* a module).
@@ -1852,3 +1881,19 @@ static void __exit exit_sd(void)
module_init(init_sd);
module_exit(exit_sd);
+
+static void sd_print_sense_hdr(struct scsi_disk *sdkp,
+ struct scsi_sense_hdr *sshdr)
+{
+ sd_printk(KERN_INFO, sdkp, "");
+ scsi_show_sense_hdr(sshdr);
+ sd_printk(KERN_INFO, sdkp, "");
+ scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+}
+
+static void sd_print_result(struct scsi_disk *sdkp, int result)
+{
+ sd_printk(KERN_INFO, sdkp, "");
+ scsi_show_result(result);
+}
+
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 81e3bc7b02a..570977cf9ef 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -917,6 +917,8 @@ sg_ioctl(struct inode *inode, struct file *filp,
return result;
if (val < 0)
return -EINVAL;
+ val = min_t(int, val,
+ sdp->device->request_queue->max_sectors * 512);
if (val != sfp->reserve.bufflen) {
if (sg_res_in_use(sfp) || sfp->mmap_called)
return -EBUSY;
@@ -925,7 +927,8 @@ sg_ioctl(struct inode *inode, struct file *filp,
}
return 0;
case SG_GET_RESERVED_SIZE:
- val = (int) sfp->reserve.bufflen;
+ val = min_t(int, sfp->reserve.bufflen,
+ sdp->device->request_queue->max_sectors * 512);
return put_user(val, ip);
case SG_SET_COMMAND_Q:
result = get_user(val, ip);
@@ -1061,6 +1064,9 @@ sg_ioctl(struct inode *inode, struct file *filp,
if (sdp->detached)
return -ENODEV;
return scsi_ioctl(sdp->device, cmd_in, p);
+ case BLKSECTGET:
+ return put_user(sdp->device->request_queue->max_sectors * 512,
+ ip);
default:
if (read_only)
return -EPERM; /* don't know so take safe approach */
@@ -2339,6 +2345,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
{
Sg_fd *sfp;
unsigned long iflags;
+ int bufflen;
sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN);
if (!sfp)
@@ -2369,7 +2376,9 @@ sg_add_sfp(Sg_device * sdp, int dev)
if (unlikely(sg_big_buff != def_reserved_size))
sg_big_buff = def_reserved_size;
- sg_build_reserve(sfp, sg_big_buff);
+ bufflen = min_t(int, sg_big_buff,
+ sdp->device->request_queue->max_sectors * 512);
+ sg_build_reserve(sfp, bufflen);
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n",
sfp->reserve.bufflen, sfp->reserve.k_use_sg));
return sfp;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 1857d68e719..f9a52af7f5b 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -62,6 +62,8 @@
MODULE_DESCRIPTION("SCSI cdrom (sr) driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_CDROM_MAJOR);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_ROM);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM);
#define SR_DISKS 256
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 98d8411bbcc..55bfeccf68a 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -89,6 +89,7 @@ MODULE_AUTHOR("Kai Makisara");
MODULE_DESCRIPTION("SCSI tape (st) driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(SCSI_TAPE_MAJOR);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
/* Set 'perm' (4th argument) to 0 to disable module_param's definition
* of sysfs parameters (which module_param doesn't yet support).
diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c
new file mode 100644
index 00000000000..bbeb2451d32
--- /dev/null
+++ b/drivers/scsi/sun_esp.c
@@ -0,0 +1,635 @@
+/* sun_esp.c: ESP front-end for Sparc SBUS systems.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <asm/sbus.h>
+
+#include <scsi/scsi_host.h>
+
+#include "esp_scsi.h"
+
+#define DRV_MODULE_NAME "sun_esp"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_VERSION "1.000"
+#define DRV_MODULE_RELDATE "April 19, 2007"
+
+#define dma_read32(REG) \
+ sbus_readl(esp->dma_regs + (REG))
+#define dma_write32(VAL, REG) \
+ sbus_writel((VAL), esp->dma_regs + (REG))
+
+static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sdev)
+{
+ struct sbus_dev *sdev = esp->dev;
+ struct sbus_dma *dma;
+
+ if (dma_sdev != NULL) {
+ for_each_dvma(dma) {
+ if (dma->sdev == dma_sdev)
+ break;
+ }
+ } else {
+ for_each_dvma(dma) {
+ if (dma->sdev == NULL)
+ break;
+
+ /* If bus + slot are the same and it has the
+ * correct OBP name, it's ours.
+ */
+ if (sdev->bus == dma->sdev->bus &&
+ sdev->slot == dma->sdev->slot &&
+ (!strcmp(dma->sdev->prom_name, "dma") ||
+ !strcmp(dma->sdev->prom_name, "espdma")))
+ break;
+ }
+ }
+
+ if (dma == NULL) {
+ printk(KERN_ERR PFX "[%s] Cannot find dma.\n",
+ sdev->ofdev.node->full_name);
+ return -ENODEV;
+ }
+ esp->dma = dma;
+ esp->dma_regs = dma->regs;
+
+ return 0;
+
+}
+
+static int __devinit esp_sbus_map_regs(struct esp *esp, int hme)
+{
+ struct sbus_dev *sdev = esp->dev;
+ struct resource *res;
+
+ /* On HME, two reg sets exist, first is DVMA,
+ * second is ESP registers.
+ */
+ if (hme)
+ res = &sdev->resource[1];
+ else
+ res = &sdev->resource[0];
+
+ esp->regs = sbus_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");
+ if (!esp->regs)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int __devinit esp_sbus_map_command_block(struct esp *esp)
+{
+ struct sbus_dev *sdev = esp->dev;
+
+ esp->command_block = sbus_alloc_consistent(sdev, 16,
+ &esp->command_block_dma);
+ if (!esp->command_block)
+ return -ENOMEM;
+ return 0;
+}
+
+static int __devinit esp_sbus_register_irq(struct esp *esp)
+{
+ struct Scsi_Host *host = esp->host;
+ struct sbus_dev *sdev = esp->dev;
+
+ host->irq = sdev->irqs[0];
+ return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);
+}
+
+static void __devinit esp_get_scsi_id(struct esp *esp)
+{
+ struct sbus_dev *sdev = esp->dev;
+ struct device_node *dp = sdev->ofdev.node;
+
+ esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff);
+ if (esp->scsi_id != 0xff)
+ goto done;
+
+ esp->scsi_id = of_getintprop_default(dp, "scsi-initiator-id", 0xff);
+ if (esp->scsi_id != 0xff)
+ goto done;
+
+ if (!sdev->bus) {
+ /* SUN4 */
+ esp->scsi_id = 7;
+ goto done;
+ }
+
+ esp->scsi_id = of_getintprop_default(sdev->bus->ofdev.node,
+ "scsi-initiator-id", 7);
+
+done:
+ esp->host->this_id = esp->scsi_id;
+ esp->scsi_id_mask = (1 << esp->scsi_id);
+}
+
+static void __devinit esp_get_differential(struct esp *esp)
+{
+ struct sbus_dev *sdev = esp->dev;
+ struct device_node *dp = sdev->ofdev.node;
+
+ if (of_find_property(dp, "differential", NULL))
+ esp->flags |= ESP_FLAG_DIFFERENTIAL;
+ else
+ esp->flags &= ~ESP_FLAG_DIFFERENTIAL;
+}
+
+static void __devinit esp_get_clock_params(struct esp *esp)
+{
+ struct sbus_dev *sdev = esp->dev;
+ struct device_node *dp = sdev->ofdev.node;
+ struct device_node *bus_dp;
+ int fmhz;
+
+ bus_dp = NULL;
+ if (sdev != NULL && sdev->bus != NULL)
+ bus_dp = sdev->bus->ofdev.node;
+
+ fmhz = of_getintprop_default(dp, "clock-frequency", 0);
+ if (fmhz == 0)
+ fmhz = (!bus_dp) ? 0 :
+ of_getintprop_default(bus_dp, "clock-frequency", 0);
+
+ esp->cfreq = fmhz;
+}
+
+static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
+{
+ struct sbus_dev *sdev = esp->dev;
+ struct device_node *dp = sdev->ofdev.node;
+ u8 bursts;
+
+ bursts = of_getintprop_default(dp, "burst-sizes", 0xff);
+ if (dma) {
+ struct device_node *dma_dp = dma->ofdev.node;
+ u8 val = of_getintprop_default(dma_dp, "burst-sizes", 0xff);
+ if (val != 0xff)
+ bursts &= val;
+ }
+
+ if (sdev->bus) {
+ u8 val = of_getintprop_default(sdev->bus->ofdev.node,
+ "burst-sizes", 0xff);
+ if (val != 0xff)
+ bursts &= val;
+ }
+
+ if (bursts == 0xff ||
+ (bursts & DMA_BURST16) == 0 ||
+ (bursts & DMA_BURST32) == 0)
+ bursts = (DMA_BURST32 - 1);
+
+ esp->bursts = bursts;
+}
+
+static void __devinit esp_sbus_get_props(struct esp *esp, struct sbus_dev *espdma)
+{
+ esp_get_scsi_id(esp);
+ esp_get_differential(esp);
+ esp_get_clock_params(esp);
+ esp_get_bursts(esp, espdma);
+}
+
+static void sbus_esp_write8(struct esp *esp, u8 val, unsigned long reg)
+{
+ sbus_writeb(val, esp->regs + (reg * 4UL));
+}
+
+static u8 sbus_esp_read8(struct esp *esp, unsigned long reg)
+{
+ return sbus_readb(esp->regs + (reg * 4UL));
+}
+
+static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf,
+ size_t sz, int dir)
+{
+ return sbus_map_single(esp->dev, buf, sz, dir);
+}
+
+static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir)
+{
+ return sbus_map_sg(esp->dev, sg, num_sg, dir);
+}
+
+static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr,
+ size_t sz, int dir)
+{
+ sbus_unmap_single(esp->dev, addr, sz, dir);
+}
+
+static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir)
+{
+ sbus_unmap_sg(esp->dev, sg, num_sg, dir);
+}
+
+static int sbus_esp_irq_pending(struct esp *esp)
+{
+ if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
+ return 1;
+ return 0;
+}
+
+static void sbus_esp_reset_dma(struct esp *esp)
+{
+ int can_do_burst16, can_do_burst32, can_do_burst64;
+ int can_do_sbus64, lim;
+ u32 val;
+
+ can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
+ can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;
+ can_do_burst64 = 0;
+ can_do_sbus64 = 0;
+ if (sbus_can_dma_64bit(esp->dev))
+ can_do_sbus64 = 1;
+ if (sbus_can_burst64(esp->sdev))
+ can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;
+
+ /* Put the DVMA into a known state. */
+ if (esp->dma->revision != dvmahme) {
+ val = dma_read32(DMA_CSR);
+ dma_write32(val | DMA_RST_SCSI, DMA_CSR);
+ dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
+ }
+ switch (esp->dma->revision) {
+ case dvmahme:
+ dma_write32(DMA_RESET_FAS366, DMA_CSR);
+ dma_write32(DMA_RST_SCSI, DMA_CSR);
+
+ esp->prev_hme_dmacsr = (DMA_PARITY_OFF | DMA_2CLKS |
+ DMA_SCSI_DISAB | DMA_INT_ENAB);
+
+ esp->prev_hme_dmacsr &= ~(DMA_ENABLE | DMA_ST_WRITE |
+ DMA_BRST_SZ);
+
+ if (can_do_burst64)
+ esp->prev_hme_dmacsr |= DMA_BRST64;
+ else if (can_do_burst32)
+ esp->prev_hme_dmacsr |= DMA_BRST32;
+
+ if (can_do_sbus64) {
+ esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
+ sbus_set_sbus64(esp->dev, esp->bursts);
+ }
+
+ lim = 1000;
+ while (dma_read32(DMA_CSR) & DMA_PEND_READ) {
+ if (--lim == 0) {
+ printk(KERN_ALERT PFX "esp%d: DMA_PEND_READ "
+ "will not clear!\n",
+ esp->host->unique_id);
+ break;
+ }
+ udelay(1);
+ }
+
+ dma_write32(0, DMA_CSR);
+ dma_write32(esp->prev_hme_dmacsr, DMA_CSR);
+
+ dma_write32(0, DMA_ADDR);
+ break;
+
+ case dvmarev2:
+ if (esp->rev != ESP100) {
+ val = dma_read32(DMA_CSR);
+ dma_write32(val | DMA_3CLKS, DMA_CSR);
+ }
+ break;
+
+ case dvmarev3:
+ val = dma_read32(DMA_CSR);
+ val &= ~DMA_3CLKS;
+ val |= DMA_2CLKS;
+ if (can_do_burst32) {
+ val &= ~DMA_BRST_SZ;
+ val |= DMA_BRST32;
+ }
+ dma_write32(val, DMA_CSR);
+ break;
+
+ case dvmaesc1:
+ val = dma_read32(DMA_CSR);
+ val |= DMA_ADD_ENABLE;
+ val &= ~DMA_BCNT_ENAB;
+ if (!can_do_burst32 && can_do_burst16) {
+ val |= DMA_ESC_BURST;
+ } else {
+ val &= ~(DMA_ESC_BURST);
+ }
+ dma_write32(val, DMA_CSR);
+ break;
+
+ default:
+ break;
+ }
+
+ /* Enable interrupts. */
+ val = dma_read32(DMA_CSR);
+ dma_write32(val | DMA_INT_ENAB, DMA_CSR);
+}
+
+static void sbus_esp_dma_drain(struct esp *esp)
+{
+ u32 csr;
+ int lim;
+
+ if (esp->dma->revision == dvmahme)
+ return;
+
+ csr = dma_read32(DMA_CSR);
+ if (!(csr & DMA_FIFO_ISDRAIN))
+ return;
+
+ if (esp->dma->revision != dvmarev3 && esp->dma->revision != dvmaesc1)
+ dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);
+
+ lim = 1000;
+ while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) {
+ if (--lim == 0) {
+ printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n",
+ esp->host->unique_id);
+ break;
+ }
+ udelay(1);
+ }
+}
+
+static void sbus_esp_dma_invalidate(struct esp *esp)
+{
+ if (esp->dma->revision == dvmahme) {
+ dma_write32(DMA_RST_SCSI, DMA_CSR);
+
+ esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
+ (DMA_PARITY_OFF | DMA_2CLKS |
+ DMA_SCSI_DISAB | DMA_INT_ENAB)) &
+ ~(DMA_ST_WRITE | DMA_ENABLE));
+
+ dma_write32(0, DMA_CSR);
+ dma_write32(esp->prev_hme_dmacsr, DMA_CSR);
+
+ /* This is necessary to avoid having the SCSI channel
+ * engine lock up on us.
+ */
+ dma_write32(0, DMA_ADDR);
+ } else {
+ u32 val;
+ int lim;
+
+ lim = 1000;
+ while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) {
+ if (--lim == 0) {
+ printk(KERN_ALERT PFX "esp%d: DMA will not "
+ "invalidate!\n", esp->host->unique_id);
+ break;
+ }
+ udelay(1);
+ }
+
+ val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);
+ val |= DMA_FIFO_INV;
+ dma_write32(val, DMA_CSR);
+ val &= ~DMA_FIFO_INV;
+ dma_write32(val, DMA_CSR);
+ }
+}
+
+static void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
+ u32 dma_count, int write, u8 cmd)
+{
+ u32 csr;
+
+ BUG_ON(!(cmd & ESP_CMD_DMA));
+
+ sbus_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
+ sbus_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
+ if (esp->rev == FASHME) {
+ sbus_esp_write8(esp, (esp_count >> 16) & 0xff, FAS_RLO);
+ sbus_esp_write8(esp, 0, FAS_RHI);
+
+ scsi_esp_cmd(esp, cmd);
+
+ csr = esp->prev_hme_dmacsr;
+ csr |= DMA_SCSI_DISAB | DMA_ENABLE;
+ if (write)
+ csr |= DMA_ST_WRITE;
+ else
+ csr &= ~DMA_ST_WRITE;
+ esp->prev_hme_dmacsr = csr;
+
+ dma_write32(dma_count, DMA_COUNT);
+ dma_write32(addr, DMA_ADDR);
+ dma_write32(csr, DMA_CSR);
+ } else {
+ csr = dma_read32(DMA_CSR);
+ csr |= DMA_ENABLE;
+ if (write)
+ csr |= DMA_ST_WRITE;
+ else
+ csr &= ~DMA_ST_WRITE;
+ dma_write32(csr, DMA_CSR);
+ if (esp->dma->revision == dvmaesc1) {
+ u32 end = PAGE_ALIGN(addr + dma_count + 16U);
+ dma_write32(end - addr, DMA_COUNT);
+ }
+ dma_write32(addr, DMA_ADDR);
+
+ scsi_esp_cmd(esp, cmd);
+ }
+
+}
+
+static int sbus_esp_dma_error(struct esp *esp)
+{
+ u32 csr = dma_read32(DMA_CSR);
+
+ if (csr & DMA_HNDL_ERROR)
+ return 1;
+
+ return 0;
+}
+
+static const struct esp_driver_ops sbus_esp_ops = {
+ .esp_write8 = sbus_esp_write8,
+ .esp_read8 = sbus_esp_read8,
+ .map_single = sbus_esp_map_single,
+ .map_sg = sbus_esp_map_sg,
+ .unmap_single = sbus_esp_unmap_single,
+ .unmap_sg = sbus_esp_unmap_sg,
+ .irq_pending = sbus_esp_irq_pending,
+ .reset_dma = sbus_esp_reset_dma,
+ .dma_drain = sbus_esp_dma_drain,
+ .dma_invalidate = sbus_esp_dma_invalidate,
+ .send_dma_cmd = sbus_esp_send_dma_cmd,
+ .dma_error = sbus_esp_dma_error,
+};
+
+static int __devinit esp_sbus_probe_one(struct device *dev,
+ struct sbus_dev *esp_dev,
+ struct sbus_dev *espdma,
+ struct sbus_bus *sbus,
+ int hme)
+{
+ struct scsi_host_template *tpnt = &scsi_esp_template;
+ struct Scsi_Host *host;
+ struct esp *esp;
+ int err;
+
+ host = scsi_host_alloc(tpnt, sizeof(struct esp));
+
+ err = -ENOMEM;
+ if (!host)
+ goto fail;
+
+ host->max_id = (hme ? 16 : 8);
+ esp = host_to_esp(host);
+
+ esp->host = host;
+ esp->dev = esp_dev;
+ esp->ops = &sbus_esp_ops;
+
+ if (hme)
+ esp->flags |= ESP_FLAG_WIDE_CAPABLE;
+
+ err = esp_sbus_find_dma(esp, espdma);
+ if (err < 0)
+ goto fail_unlink;
+
+ err = esp_sbus_map_regs(esp, hme);
+ if (err < 0)
+ goto fail_unlink;
+
+ err = esp_sbus_map_command_block(esp);
+ if (err < 0)
+ goto fail_unmap_regs;
+
+ err = esp_sbus_register_irq(esp);
+ if (err < 0)
+ goto fail_unmap_command_block;
+
+ esp_sbus_get_props(esp, espdma);
+
+ /* Before we try to touch the ESP chip, ESC1 dma can
+ * come up with the reset bit set, so make sure that
+ * is clear first.
+ */
+ if (esp->dma->revision == dvmaesc1) {
+ u32 val = dma_read32(DMA_CSR);
+
+ dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
+ }
+
+ dev_set_drvdata(&esp_dev->ofdev.dev, esp);
+
+ err = scsi_esp_register(esp, dev);
+ if (err)
+ goto fail_free_irq;
+
+ return 0;
+
+fail_free_irq:
+ free_irq(host->irq, esp);
+fail_unmap_command_block:
+ sbus_free_consistent(esp->dev, 16,
+ esp->command_block,
+ esp->command_block_dma);
+fail_unmap_regs:
+ sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+fail_unlink:
+ scsi_host_put(host);
+fail:
+ return err;
+}
+
+static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct device_node *dp = dev->node;
+ struct sbus_dev *dma_sdev = NULL;
+ int hme = 0;
+
+ if (dp->parent &&
+ (!strcmp(dp->parent->name, "espdma") ||
+ !strcmp(dp->parent->name, "dma")))
+ dma_sdev = sdev->parent;
+ else if (!strcmp(dp->name, "SUNW,fas")) {
+ dma_sdev = sdev;
+ hme = 1;
+ }
+
+ return esp_sbus_probe_one(&dev->dev, sdev, dma_sdev,
+ sdev->bus, hme);
+}
+
+static int __devexit esp_sbus_remove(struct of_device *dev)
+{
+ struct esp *esp = dev_get_drvdata(&dev->dev);
+ unsigned int irq = esp->host->irq;
+ u32 val;
+
+ scsi_esp_unregister(esp);
+
+ /* Disable interrupts. */
+ val = dma_read32(DMA_CSR);
+ dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);
+
+ free_irq(irq, esp);
+ sbus_free_consistent(esp->dev, 16,
+ esp->command_block,
+ esp->command_block_dma);
+ sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+
+ scsi_host_put(esp->host);
+
+ return 0;
+}
+
+static struct of_device_id esp_match[] = {
+ {
+ .name = "SUNW,esp",
+ },
+ {
+ .name = "SUNW,fas",
+ },
+ {
+ .name = "esp",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, esp_match);
+
+static struct of_platform_driver esp_sbus_driver = {
+ .name = "esp",
+ .match_table = esp_match,
+ .probe = esp_sbus_probe,
+ .remove = __devexit_p(esp_sbus_remove),
+};
+
+static int __init sunesp_init(void)
+{
+ return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit sunesp_exit(void)
+{
+ of_unregister_driver(&esp_sbus_driver);
+}
+
+MODULE_DESCRIPTION("Sun ESP SCSI driver");
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(sunesp_init);
+module_exit(sunesp_exit);
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index a583e89238f..3158949ffa6 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -2680,7 +2680,7 @@ static int __init dc390_module_init(void)
printk (KERN_INFO "DC390: Using safe settings.\n");
}
- return pci_module_init(&dc390_driver);
+ return pci_register_driver(&dc390_driver);
}
static void __exit dc390_module_exit(void)