diff options
Diffstat (limited to 'drivers/scsi')
69 files changed, 4255 insertions, 4068 deletions
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index e874b89..96f4cab0 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 fcc4cb6..e62d23f 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, @@ -1793,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 70cff4c..51e884f 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -146,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 d789e61..1e82c69 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 39ecd0d..45ca3e8 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 e21070f..72b0393 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 ae34768..33682ce 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 1b97f60..5824a75 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 d38b628..42c7dcd 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 0f948c2..350ea7f 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 c76b611..a8ace56 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 d953c3f..9c5fcfb 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 d242e26..0c71315 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 6f1a178..f4b5e97 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 1d239f6..cbbfbc9 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 911ea17..5e6620f 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 cd93f9a..88da670 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 2be03e9..6054881 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 147c83c..9218f29 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 954c7c2..e1bd57b 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 50ef785..75733b0 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 8f43ff7..db6ab1a 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 12497da..03bfed6 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 0f920c8..eff846a 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 642de7b..6f8403b 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 f917bdd..efadb8d 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 61f6024..2a458d6 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 5a49216..100b49ba 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 82d2486..cc784e8 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 4bf4477..94bc894 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 cd36e81..f7b9dbd 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 635c148..5016af5c 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_scsi.c b/drivers/scsi/esp_scsi.c index 99ce033..ec71061 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2212,7 +2212,7 @@ static void __devinit esp_init_swstate(struct esp *esp) } /* This places the ESP into a known state at boot time. */ -static void __devinit esp_bootup_reset(struct esp *esp) +static void esp_bootup_reset(struct esp *esp) { u8 val; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index fbc1d5c..b10eefe 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 5c6d935..77cc1d4 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 140dd97..8ba7dd0 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, diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index e9bd299..2c7b77e 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)); @@ -3850,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; @@ -4230,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])); @@ -4260,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); @@ -4346,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; @@ -4359,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; } /** @@ -4457,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; @@ -4470,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; } @@ -4636,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)) @@ -5121,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; @@ -5166,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(); @@ -6188,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); @@ -6385,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 { @@ -7117,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); @@ -7233,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); @@ -7540,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 88f285d..bc53d7c 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 8f55e14..c9a3abf 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 7c75771..3f5b9b4 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 dc70c18..e34442e 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 89403b0..5631c19 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 057fd7e0..dcf6106 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; diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 0aa3304..7fc6e06 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 a967fad..08060fb 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 0ebd8ce..0000000 --- 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 eac8e17..7dd787f 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 05f4f2a..e8948b6 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 98c01cd..3e296ab 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 83376f6..71e32a24 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 68f5d24..b78919a 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 ff1dd41..206bda0 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(®->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 61347ae..dc85495 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/scsi.c b/drivers/scsi/scsi.c index 1c89ee3..4c1e313 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 918bb60..3963e70 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; @@ -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 05d79af..61fbcdc 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -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_scan.c b/drivers/scsi/scsi_scan.c index 0949145..a67f315 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 939de0d..67a38a1 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, }; @@ -547,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[] = { @@ -566,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 0e08817..ca22ddf 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 d402aff..2570f48 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 84488c5..e9e6db1 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 58afdb4..14c4f06 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 aabaa05..caf1836 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", @@ -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; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 5a8f55f..00e4666 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 81e3bc7..570977c 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 1857d68..f9a52af 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 98d8411..55bfecc 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 index 8c766bc..bbeb245 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -5,6 +5,7 @@ #include <linux/kernel.h> #include <linux/types.h> +#include <linux/delay.h> #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index a583e89..3158949 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) |