diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-18 22:25:31 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-18 22:25:31 +0400 |
commit | 2cca775baecbfede2fec20c99add709232311fe7 (patch) | |
tree | b0eefe80881d263ba7976174144ae4e9cf238425 /drivers/scsi | |
parent | eddeb0e2d863e3941d8768e70cb50c6120e61fa0 (diff) | |
parent | 94795b61e84994a3b058f92d041d1fb3d869c7d5 (diff) | |
download | linux-2cca775baecbfede2fec20c99add709232311fe7.tar.xz |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (137 commits)
[SCSI] iscsi: bidi support for iscsi_tcp
[SCSI] iscsi: bidi support at the generic libiscsi level
[SCSI] iscsi: extended cdb support
[SCSI] zfcp: Fix error handling for blocked unit for send FCP command
[SCSI] zfcp: Remove zfcp_erp_wait from slave destory handler to fix deadlock
[SCSI] zfcp: fix 31 bit compile warnings
[SCSI] bsg: no need to set BSG_F_BLOCK bit in bsg_complete_all_commands
[SCSI] bsg: remove minor in struct bsg_device
[SCSI] bsg: use better helper list functions
[SCSI] bsg: replace kobject_get with blk_get_queue
[SCSI] bsg: takes a ref to struct device in fops->open
[SCSI] qla1280: remove version check
[SCSI] libsas: fix endianness bug in sas_ata
[SCSI] zfcp: fix compiler warning caused by poking inside new semaphore (linux-next)
[SCSI] aacraid: Do not describe check_reset parameter with its value
[SCSI] aacraid: Fix down_interruptible() to check the return value
[SCSI] sun3_scsi_vme: add MODULE_LICENSE
[SCSI] st: rename flush_write_buffer()
[SCSI] tgt: use KMEM_CACHE macro
[SCSI] initio: fix big endian problems for auto request sense
...
Diffstat (limited to 'drivers/scsi')
100 files changed, 3194 insertions, 2778 deletions
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index b4912d1cee2a..51c3ebf1c7d1 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1838,12 +1838,11 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, if (scsi_sg_count(srb)) { if ((scsi_sg_count(srb) == 1) && (scsi_bufflen(srb) < TW_MIN_SGL_LENGTH)) { - if (srb->sc_data_direction == DMA_TO_DEVICE || srb->sc_data_direction == DMA_BIDIRECTIONAL) { - struct scatterlist *sg = scsi_sglist(srb); - char *buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; - memcpy(tw_dev->generic_buffer_virt[request_id], buf, sg->length); - kunmap_atomic(buf - sg->offset, KM_IRQ0); - } + if (srb->sc_data_direction == DMA_TO_DEVICE || + srb->sc_data_direction == DMA_BIDIRECTIONAL) + scsi_sg_copy_to_buffer(srb, + tw_dev->generic_buffer_virt[request_id], + TW_SECTOR_SIZE); command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH); } else { @@ -1915,13 +1914,11 @@ static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int re (cmd->sc_data_direction == DMA_FROM_DEVICE || cmd->sc_data_direction == DMA_BIDIRECTIONAL)) { if (scsi_sg_count(cmd) == 1) { - struct scatterlist *sg = scsi_sglist(tw_dev->srb[request_id]); - char *buf; - unsigned long flags = 0; + unsigned long flags; + void *buf = tw_dev->generic_buffer_virt[request_id]; + local_irq_save(flags); - buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; - memcpy(buf, tw_dev->generic_buffer_virt[request_id], sg->length); - kunmap_atomic(buf - sg->offset, KM_IRQ0); + scsi_sg_copy_from_buffer(cmd, buf, TW_SECTOR_SIZE); local_irq_restore(flags); } } @@ -2028,8 +2025,6 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id } tw_dev = (TW_Device_Extension *)host->hostdata; - memset(tw_dev, 0, sizeof(TW_Device_Extension)); - /* Save values to device extension */ tw_dev->host = host; tw_dev->tw_pci_dev = pdev; diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index d09532162217..adb98a297210 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1463,18 +1463,10 @@ static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id, void *data, unsigned int len) { struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - void *buf; - unsigned int transfer_len; - unsigned long flags = 0; - struct scatterlist *sg = scsi_sglist(cmd); + unsigned long flags; local_irq_save(flags); - buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; - transfer_len = min(sg->length, len); - - memcpy(buf, data, transfer_len); - - kunmap_atomic(buf - sg->offset, KM_IRQ0); + scsi_sg_copy_from_buffer(cmd, data, len); local_irq_restore(flags); } @@ -2294,8 +2286,6 @@ static int __devinit tw_probe(struct pci_dev *pdev, const struct pci_device_id * } tw_dev = (TW_Device_Extension *)host->hostdata; - memset(tw_dev, 0, sizeof(TW_Device_Extension)); - /* Save values to device extension */ tw_dev->host = host; tw_dev->tw_pci_dev = pdev; diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index 4d3ebb1af490..2d689af24664 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -896,7 +896,7 @@ static int __init BusLogic_InitializeFlashPointProbeInfo(struct BusLogic_HostAda IRQ_Channel = PCI_Device->irq; IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); -#ifndef CONFIG_SCSI_OMIT_FLASHPOINT +#ifdef CONFIG_SCSI_FLASHPOINT if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) { BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " "FlashPoint Host Adapter\n", NULL, BaseAddress0); BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address); @@ -1006,6 +1006,9 @@ static void __init BusLogic_InitializeProbeInfoList(struct BusLogic_HostAdapter } +#else +#define BusLogic_InitializeProbeInfoList(adapter) \ + BusLogic_InitializeProbeInfoListISA(adapter) #endif /* CONFIG_PCI */ diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h index bfbfb5c3a8f6..73f237a1ed94 100644 --- a/drivers/scsi/BusLogic.h +++ b/drivers/scsi/BusLogic.h @@ -34,23 +34,6 @@ #endif /* - FlashPoint support is only available for the Intel x86 Architecture with - CONFIG_PCI set. -*/ - -#ifndef __i386__ -#undef CONFIG_SCSI_OMIT_FLASHPOINT -#define CONFIG_SCSI_OMIT_FLASHPOINT -#endif - -#ifndef CONFIG_PCI -#undef CONFIG_SCSI_OMIT_FLASHPOINT -#define CONFIG_SCSI_OMIT_FLASHPOINT -#define BusLogic_InitializeProbeInfoListISA BusLogic_InitializeProbeInfoList -#endif - - -/* Define the maximum number of BusLogic Host Adapters supported by this driver. */ @@ -178,7 +161,7 @@ static int BusLogic_HostAdapterAddressCount[3] = { 0, BusLogic_MultiMasterAddres Define macros for testing the Host Adapter Type. */ -#ifndef CONFIG_SCSI_OMIT_FLASHPOINT +#ifdef CONFIG_SCSI_FLASHPOINT #define BusLogic_MultiMasterHostAdapterP(HostAdapter) \ (HostAdapter->HostAdapterType == BusLogic_MultiMaster) @@ -871,7 +854,7 @@ struct BusLogic_CCB { void (*CallbackFunction) (struct BusLogic_CCB *); /* Bytes 40-43 */ u32 BaseAddress; /* Bytes 44-47 */ enum BusLogic_CompletionCode CompletionCode; /* Byte 48 */ -#ifndef CONFIG_SCSI_OMIT_FLASHPOINT +#ifdef CONFIG_SCSI_FLASHPOINT unsigned char:8; /* Byte 49 */ unsigned short OS_Flags; /* Bytes 50-51 */ unsigned char Private[48]; /* Bytes 52-99 */ diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c index 1c9078191d9e..b374e457e5e2 100644 --- a/drivers/scsi/FlashPoint.c +++ b/drivers/scsi/FlashPoint.c @@ -16,7 +16,7 @@ */ -#ifndef CONFIG_SCSI_OMIT_FLASHPOINT +#ifdef CONFIG_SCSI_FLASHPOINT #define MAX_CARDS 8 #undef BUSTYPE_PCI @@ -7626,7 +7626,7 @@ FlashPoint__HandleInterrupt(FlashPoint_CardHandle_T CardHandle) #define FlashPoint_InterruptPending FlashPoint__InterruptPending #define FlashPoint_HandleInterrupt FlashPoint__HandleInterrupt -#else /* CONFIG_SCSI_OMIT_FLASHPOINT */ +#else /* !CONFIG_SCSI_FLASHPOINT */ /* Define prototypes for the FlashPoint SCCB Manager Functions. @@ -7641,4 +7641,4 @@ extern bool FlashPoint_InterruptPending(FlashPoint_CardHandle_T); extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T); extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T); -#endif /* CONFIG_SCSI_OMIT_FLASHPOINT */ +#endif /* CONFIG_SCSI_FLASHPOINT */ diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index b9d374082b65..7f78e3ea517d 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -588,18 +588,20 @@ config SCSI_BUSLOGIC <http://www.tldp.org/docs.html#howto>, and the files <file:Documentation/scsi/BusLogic.txt> and <file:Documentation/scsi/FlashPoint.txt> for more information. + Note that support for FlashPoint is only available for 32-bit + x86 configurations. To compile this driver as a module, choose M here: the module will be called BusLogic. -config SCSI_OMIT_FLASHPOINT - bool "Omit FlashPoint support" - depends on SCSI_BUSLOGIC +config SCSI_FLASHPOINT + bool "FlashPoint support" + depends on SCSI_BUSLOGIC && PCI && X86_32 help - This option allows you to omit the FlashPoint support from the + This option allows you to add FlashPoint support to the BusLogic SCSI driver. The FlashPoint SCCB Manager code is - substantial, so users of MultiMaster Host Adapters may wish to omit - it. + substantial, so users of MultiMaster Host Adapters may not + wish to include it. config SCSI_DMX3191D tristate "DMX3191D SCSI support" diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index 5ac3a3e8dfaf..07d572feceed 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -179,6 +179,9 @@ int __init a2091_detect(struct scsi_host_template *tpnt) DMA(instance)->DAWR = DAWR_A2091; regs.SASR = &(DMA(instance)->SASR); regs.SCMD = &(DMA(instance)->SCMD); + HDATA(instance)->no_sync = 0xff; + HDATA(instance)->fast = 0; + HDATA(instance)->dma_mode = CTRL_DMA; wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10); request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI", instance); diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index 3aeec963940b..8b449d8acacd 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -178,6 +178,9 @@ int __init a3000_detect(struct scsi_host_template *tpnt) DMA(a3000_host)->DAWR = DAWR_A3000; regs.SASR = &(DMA(a3000_host)->SASR); regs.SCMD = &(DMA(a3000_host)->SCMD); + HDATA(a3000_host)->no_sync = 0xff; + HDATA(a3000_host)->fast = 0; + HDATA(a3000_host)->dma_mode = CTRL_DMA; wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15); if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI", a3000_intr)) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index c05092fd3a9d..369fcf78f396 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -205,7 +205,7 @@ MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health" int aac_check_reset = 1; module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the" +MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the" " adapter. a value of -1 forces the reset to adapters programmed to" " ignore it."); @@ -379,24 +379,6 @@ int aac_get_containers(struct aac_dev *dev) return status; } -static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigned int offset, unsigned int len) -{ - void *buf; - int transfer_len; - struct scatterlist *sg = scsi_sglist(scsicmd); - - buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; - transfer_len = min(sg->length, len + offset); - - transfer_len -= offset; - if (buf && transfer_len > 0) - memcpy(buf + offset, data, transfer_len); - - flush_kernel_dcache_page(kmap_atomic_to_page(buf - sg->offset)); - kunmap_atomic(buf - sg->offset, KM_IRQ0); - -} - static void get_container_name_callback(void *context, struct fib * fibptr) { struct aac_get_name_resp * get_name_reply; @@ -419,14 +401,17 @@ static void get_container_name_callback(void *context, struct fib * fibptr) while (*sp == ' ') ++sp; if (*sp) { + struct inquiry_data inq; char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)]; int count = sizeof(d); char *dp = d; do { *dp++ = (*sp) ? *sp++ : ' '; } while (--count > 0); - aac_internal_transfer(scsicmd, d, - offsetof(struct inquiry_data, inqd_pid), sizeof(d)); + + scsi_sg_copy_to_buffer(scsicmd, &inq, sizeof(inq)); + memcpy(inq.inqd_pid, d, sizeof(d)); + scsi_sg_copy_from_buffer(scsicmd, &inq, sizeof(inq)); } } @@ -811,7 +796,7 @@ static void get_container_serial_callback(void *context, struct fib * fibptr) sp[2] = 0; sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X", le32_to_cpu(get_serial_reply->uid)); - aac_internal_transfer(scsicmd, sp, 0, sizeof(sp)); + scsi_sg_copy_from_buffer(scsicmd, sp, sizeof(sp)); } scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; @@ -1986,8 +1971,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) arr[4] = 0x0; arr[5] = 0x80; arr[1] = scsicmd->cmnd[2]; - aac_internal_transfer(scsicmd, &inq_data, 0, - sizeof(inq_data)); + scsi_sg_copy_from_buffer(scsicmd, &inq_data, + sizeof(inq_data)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; } else if (scsicmd->cmnd[2] == 0x80) { @@ -1995,8 +1980,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) arr[3] = setinqserial(dev, &arr[4], scmd_id(scsicmd)); arr[1] = scsicmd->cmnd[2]; - aac_internal_transfer(scsicmd, &inq_data, 0, - sizeof(inq_data)); + scsi_sg_copy_from_buffer(scsicmd, &inq_data, + sizeof(inq_data)); return aac_get_container_serial(scsicmd); } else { /* vpd page not implemented */ @@ -2027,7 +2012,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) if (cid == host->this_id) { setinqstr(dev, (void *) (inq_data.inqd_vid), ARRAY_SIZE(container_types)); inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */ - aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data)); + scsi_sg_copy_from_buffer(scsicmd, &inq_data, + sizeof(inq_data)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); return 0; @@ -2036,7 +2022,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) return -1; 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)); + scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data)); return aac_get_container_name(scsicmd); } case SERVICE_ACTION_IN: @@ -2047,6 +2033,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) { u64 capacity; char cp[13]; + unsigned int alloc_len; dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n")); capacity = fsa_dev_ptr[cid].size - 1; @@ -2063,18 +2050,16 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) cp[10] = 2; cp[11] = 0; cp[12] = 0; - aac_internal_transfer(scsicmd, cp, 0, - min_t(size_t, scsicmd->cmnd[13], sizeof(cp))); - if (sizeof(cp) < scsicmd->cmnd[13]) { - unsigned int len, offset = sizeof(cp); - memset(cp, 0, offset); - do { - len = min_t(size_t, scsicmd->cmnd[13] - offset, - sizeof(cp)); - aac_internal_transfer(scsicmd, cp, offset, len); - } while ((offset += len) < scsicmd->cmnd[13]); - } + alloc_len = ((scsicmd->cmnd[10] << 24) + + (scsicmd->cmnd[11] << 16) + + (scsicmd->cmnd[12] << 8) + scsicmd->cmnd[13]); + + alloc_len = min_t(size_t, alloc_len, sizeof(cp)); + scsi_sg_copy_from_buffer(scsicmd, cp, alloc_len); + if (alloc_len < scsi_bufflen(scsicmd)) + scsi_set_resid(scsicmd, + scsi_bufflen(scsicmd) - alloc_len); /* Do not cache partition table for arrays */ scsicmd->device->removable = 1; @@ -2104,7 +2089,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) cp[5] = 0; cp[6] = 2; cp[7] = 0; - aac_internal_transfer(scsicmd, cp, 0, sizeof(cp)); + scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp)); /* Do not cache partition table for arrays */ scsicmd->device->removable = 1; @@ -2139,7 +2124,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) if (mode_buf_length > scsicmd->cmnd[4]) mode_buf_length = scsicmd->cmnd[4]; } - aac_internal_transfer(scsicmd, mode_buf, 0, mode_buf_length); + scsi_sg_copy_from_buffer(scsicmd, mode_buf, mode_buf_length); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); @@ -2174,7 +2159,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) if (mode_buf_length > scsicmd->cmnd[8]) mode_buf_length = scsicmd->cmnd[8]; } - aac_internal_transfer(scsicmd, mode_buf, 0, mode_buf_length); + scsi_sg_copy_from_buffer(scsicmd, mode_buf, mode_buf_length); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 47434499e82b..23a8e9f8dcb4 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -515,10 +515,12 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, } udelay(5); } - } else - (void)down_interruptible(&fibptr->event_wait); + } else if (down_interruptible(&fibptr->event_wait) == 0) { + fibptr->done = 2; + up(&fibptr->event_wait); + } spin_lock_irqsave(&fibptr->event_lock, flags); - if (fibptr->done == 0) { + if ((fibptr->done == 0) || (fibptr->done == 2)) { fibptr->done = 2; /* Tell interrupt we aborted */ spin_unlock_irqrestore(&fibptr->event_lock, flags); return -EINTR; @@ -594,7 +596,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid) if (le32_to_cpu(*q->headers.consumer) >= q->entries) *q->headers.consumer = cpu_to_le32(1); else - *q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1); + le32_add_cpu(q->headers.consumer, 1); if (wasfull) { switch (qid) { diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 72fccd9f40df..0081aa357c8b 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1413,6 +1413,10 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, unsigned long flags; int nseg; + nseg = scsi_dma_map(cmd); + if (nseg < 0) + return SCSI_MLQUEUE_HOST_BUSY; + ahd_lock(ahd, &flags); /* @@ -1430,6 +1434,7 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { ahd->flags |= AHD_RESOURCE_SHORTAGE; ahd_unlock(ahd, &flags); + scsi_dma_unmap(cmd); return SCSI_MLQUEUE_HOST_BUSY; } @@ -1485,8 +1490,6 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, ahd_set_sense_residual(scb, 0); scb->sg_count = 0; - nseg = scsi_dma_map(cmd); - BUG_ON(nseg < 0); if (nseg > 0) { void *sg = scb->sg_list; struct scatterlist *cur_seg; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 282aff6f852e..42ad48e09f02 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1398,12 +1398,18 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev, return SCSI_MLQUEUE_DEVICE_BUSY; } + nseg = scsi_dma_map(cmd); + if (nseg < 0) + return SCSI_MLQUEUE_HOST_BUSY; + /* * Get an scb to use. */ scb = ahc_get_scb(ahc); - if (!scb) + if (!scb) { + scsi_dma_unmap(cmd); return SCSI_MLQUEUE_HOST_BUSY; + } scb->io_ctx = cmd; scb->platform_data->dev = dev; @@ -1464,8 +1470,6 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev, ahc_set_sense_residual(scb, 0); scb->sg_count = 0; - nseg = scsi_dma_map(cmd); - BUG_ON(nseg < 0); if (nseg > 0) { struct ahc_dma_seg *sg; struct scatterlist *cur_seg; diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y index 6066998ed562..702e2dbd11fb 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y @@ -1837,7 +1837,7 @@ type_check(symbol_t *symbol, expression_t *expression, int opcode) int and_op; and_op = FALSE; - if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ) + if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || opcode == AIC_OP_JZ) and_op = TRUE; /* diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h index eb8efdcefe48..2ef459e9cda1 100644 --- a/drivers/scsi/aic94xx/aic94xx.h +++ b/drivers/scsi/aic94xx/aic94xx.h @@ -58,7 +58,6 @@ extern struct kmem_cache *asd_dma_token_cache; extern struct kmem_cache *asd_ascb_cache; -extern char sas_addr_str[2*SAS_ADDR_SIZE + 1]; static inline void asd_stringify_sas_addr(char *p, const u8 *sas_addr) { @@ -68,21 +67,6 @@ static inline void asd_stringify_sas_addr(char *p, const u8 *sas_addr) *p = '\0'; } -static inline void asd_destringify_sas_addr(u8 *sas_addr, const char *p) -{ - int i; - for (i = 0; i < SAS_ADDR_SIZE; i++) { - u8 h, l; - if (!*p) - break; - h = isdigit(*p) ? *p-'0' : *p-'A'+10; - p++; - l = isdigit(*p) ? *p-'0' : *p-'A'+10; - p++; - sas_addr[i] = (h<<4) | l; - } -} - struct asd_ha_struct; struct asd_ascb; diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c index 72042cae7768..2e2ddec9c0b6 100644 --- a/drivers/scsi/aic94xx/aic94xx_dev.c +++ b/drivers/scsi/aic94xx/aic94xx_dev.c @@ -35,7 +35,7 @@ #define SET_DDB(_ddb, _ha) set_bit(_ddb, (_ha)->hw_prof.ddb_bitmap) #define CLEAR_DDB(_ddb, _ha) clear_bit(_ddb, (_ha)->hw_prof.ddb_bitmap) -static inline int asd_get_ddb(struct asd_ha_struct *asd_ha) +static int asd_get_ddb(struct asd_ha_struct *asd_ha) { int ddb, i; @@ -71,7 +71,7 @@ out: #define NCQ_DATA_SCB_PTR offsetof(struct asd_ddb_stp_sata_target_port, ncq_data_scb_ptr) #define ITNL_TIMEOUT offsetof(struct asd_ddb_ssp_smp_target_port, itnl_timeout) -static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb) +static void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb) { if (!ddb || ddb >= 0xFFFF) return; @@ -79,7 +79,7 @@ static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb) CLEAR_DDB(ddb, asd_ha); } -static inline void asd_set_ddb_type(struct domain_device *dev) +static void asd_set_ddb_type(struct domain_device *dev) { struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; int ddb = (int) (unsigned long) dev->lldd_dev; @@ -109,7 +109,7 @@ static int asd_init_sata_tag_ddb(struct domain_device *dev) return 0; } -static inline int asd_init_sata(struct domain_device *dev) +static int asd_init_sata(struct domain_device *dev) { struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; int ddb = (int) (unsigned long) dev->lldd_dev; diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c index 3d8c4ff1f2ef..67eeba3bdb06 100644 --- a/drivers/scsi/aic94xx/aic94xx_dump.c +++ b/drivers/scsi/aic94xx/aic94xx_dump.c @@ -738,6 +738,8 @@ static void asd_dump_lseq_state(struct asd_ha_struct *asd_ha, int lseq) PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TIMER_TERM_TS); } +#if 0 + /** * asd_dump_ddb_site -- dump a CSEQ DDB site * @asd_ha: pointer to host adapter structure @@ -880,6 +882,8 @@ void asd_dump_scb_sites(struct asd_ha_struct *asd_ha) } } +#endif /* 0 */ + /** * ads_dump_seq_state -- dump CSEQ and LSEQ states * @asd_ha: pointer to host adapter structure @@ -922,7 +926,9 @@ void asd_dump_frame_rcvd(struct asd_phy *phy, spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); } -static inline void asd_dump_scb(struct asd_ascb *ascb, int ind) +#if 0 + +static void asd_dump_scb(struct asd_ascb *ascb, int ind) { asd_printk("scb%d: vaddr: 0x%p, dma_handle: 0x%llx, next: 0x%llx, " "index:%d, opcode:0x%02x\n", @@ -956,4 +962,6 @@ void asd_dump_scb_list(struct asd_ascb *ascb, int num) } } +#endif /* 0 */ + #endif /* ASD_DEBUG */ diff --git a/drivers/scsi/aic94xx/aic94xx_dump.h b/drivers/scsi/aic94xx/aic94xx_dump.h index 0c388e7da6bb..191a753d42a7 100644 --- a/drivers/scsi/aic94xx/aic94xx_dump.h +++ b/drivers/scsi/aic94xx/aic94xx_dump.h @@ -29,24 +29,15 @@ #ifdef ASD_DEBUG -void asd_dump_ddb_0(struct asd_ha_struct *asd_ha); -void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no); -void asd_dump_scb_sites(struct asd_ha_struct *asd_ha); void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask); void asd_dump_frame_rcvd(struct asd_phy *phy, struct done_list_struct *dl); -void asd_dump_scb_list(struct asd_ascb *ascb, int num); #else /* ASD_DEBUG */ -static inline void asd_dump_ddb_0(struct asd_ha_struct *asd_ha) { } -static inline void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, - u16 site_no) { } -static inline void asd_dump_scb_sites(struct asd_ha_struct *asd_ha) { } static inline void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask) { } static inline void asd_dump_frame_rcvd(struct asd_phy *phy, struct done_list_struct *dl) { } -static inline void asd_dump_scb_list(struct asd_ascb *ascb, int num) { } #endif /* ASD_DEBUG */ #endif /* _AIC94XX_DUMP_H_ */ diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c index 098b5f39cd31..83a78222896d 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.c +++ b/drivers/scsi/aic94xx/aic94xx_hwi.c @@ -27,6 +27,7 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/module.h> +#include <linux/firmware.h> #include "aic94xx.h" #include "aic94xx_reg.h" @@ -38,16 +39,14 @@ u32 MBAR0_SWB_SIZE; /* ---------- Initialization ---------- */ -static void asd_get_user_sas_addr(struct asd_ha_struct *asd_ha) +static int asd_get_user_sas_addr(struct asd_ha_struct *asd_ha) { - extern char sas_addr_str[]; - /* If the user has specified a WWN it overrides other settings - */ - if (sas_addr_str[0] != '\0') - asd_destringify_sas_addr(asd_ha->hw_prof.sas_addr, - sas_addr_str); - else if (asd_ha->hw_prof.sas_addr[0] != 0) - asd_stringify_sas_addr(sas_addr_str, asd_ha->hw_prof.sas_addr); + /* adapter came with a sas address */ + if (asd_ha->hw_prof.sas_addr[0]) + return 0; + + return sas_request_addr(asd_ha->sas_ha.core.shost, + asd_ha->hw_prof.sas_addr); } static void asd_propagate_sas_addr(struct asd_ha_struct *asd_ha) @@ -251,7 +250,7 @@ static int asd_init_scbs(struct asd_ha_struct *asd_ha) return 0; } -static inline void asd_get_max_scb_ddb(struct asd_ha_struct *asd_ha) +static void asd_get_max_scb_ddb(struct asd_ha_struct *asd_ha) { asd_ha->hw_prof.max_scbs = asd_get_cmdctx_size(asd_ha)/ASD_SCB_SIZE; asd_ha->hw_prof.max_ddbs = asd_get_devctx_size(asd_ha)/ASD_DDB_SIZE; @@ -657,8 +656,7 @@ int asd_init_hw(struct asd_ha_struct *asd_ha) asd_init_ctxmem(asd_ha); - asd_get_user_sas_addr(asd_ha); - if (!asd_ha->hw_prof.sas_addr[0]) { + if (asd_get_user_sas_addr(asd_ha)) { asd_printk("No SAS Address provided for %s\n", pci_name(asd_ha->pcidev)); err = -ENODEV; @@ -773,7 +771,7 @@ static void asd_dl_tasklet_handler(unsigned long data) * asd_process_donelist_isr -- schedule processing of done list entries * @asd_ha: pointer to host adapter structure */ -static inline void asd_process_donelist_isr(struct asd_ha_struct *asd_ha) +static void asd_process_donelist_isr(struct asd_ha_struct *asd_ha) { tasklet_schedule(&asd_ha->seq.dl_tasklet); } @@ -782,7 +780,7 @@ static inline void asd_process_donelist_isr(struct asd_ha_struct *asd_ha) * asd_com_sas_isr -- process device communication interrupt (COMINT) * @asd_ha: pointer to host adapter structure */ -static inline void asd_com_sas_isr(struct asd_ha_struct *asd_ha) +static void asd_com_sas_isr(struct asd_ha_struct *asd_ha) { u32 comstat = asd_read_reg_dword(asd_ha, COMSTAT); @@ -821,7 +819,7 @@ static inline void asd_com_sas_isr(struct asd_ha_struct *asd_ha) asd_chip_reset(asd_ha); } -static inline void asd_arp2_err(struct asd_ha_struct *asd_ha, u32 dchstatus) +static void asd_arp2_err(struct asd_ha_struct *asd_ha, u32 dchstatus) { static const char *halt_code[256] = { "UNEXPECTED_INTERRUPT0", @@ -908,7 +906,7 @@ static inline void asd_arp2_err(struct asd_ha_struct *asd_ha, u32 dchstatus) * asd_dch_sas_isr -- process device channel interrupt (DEVINT) * @asd_ha: pointer to host adapter structure */ -static inline void asd_dch_sas_isr(struct asd_ha_struct *asd_ha) +static void asd_dch_sas_isr(struct asd_ha_struct *asd_ha) { u32 dchstatus = asd_read_reg_dword(asd_ha, DCHSTATUS); @@ -923,7 +921,7 @@ static inline void asd_dch_sas_isr(struct asd_ha_struct *asd_ha) * ads_rbi_exsi_isr -- process external system interface interrupt (INITERR) * @asd_ha: pointer to host adapter structure */ -static inline void asd_rbi_exsi_isr(struct asd_ha_struct *asd_ha) +static void asd_rbi_exsi_isr(struct asd_ha_struct *asd_ha) { u32 stat0r = asd_read_reg_dword(asd_ha, ASISTAT0R); @@ -971,7 +969,7 @@ static inline void asd_rbi_exsi_isr(struct asd_ha_struct *asd_ha) * * Asserted on PCIX errors: target abort, etc. */ -static inline void asd_hst_pcix_isr(struct asd_ha_struct *asd_ha) +static void asd_hst_pcix_isr(struct asd_ha_struct *asd_ha) { u16 status; u32 pcix_status; @@ -1044,8 +1042,8 @@ irqreturn_t asd_hw_isr(int irq, void *dev_id) /* ---------- SCB handling ---------- */ -static inline struct asd_ascb *asd_ascb_alloc(struct asd_ha_struct *asd_ha, - gfp_t gfp_flags) +static struct asd_ascb *asd_ascb_alloc(struct asd_ha_struct *asd_ha, + gfp_t gfp_flags) { extern struct kmem_cache *asd_ascb_cache; struct asd_seq_data *seq = &asd_ha->seq; @@ -1144,8 +1142,8 @@ struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct * * LOCKING: called with the pending list lock held. */ -static inline void asd_swap_head_scb(struct asd_ha_struct *asd_ha, - struct asd_ascb *ascb) +static void asd_swap_head_scb(struct asd_ha_struct *asd_ha, + struct asd_ascb *ascb) { struct asd_seq_data *seq = &asd_ha->seq; struct asd_ascb *last = list_entry(ascb->list.prev, @@ -1171,7 +1169,7 @@ static inline void asd_swap_head_scb(struct asd_ha_struct *asd_ha, * intended to be called from asd_post_ascb_list(), just prior to * posting the SCBs to the sequencer. */ -static inline void asd_start_scb_timers(struct list_head *list) +static void asd_start_scb_timers(struct list_head *list) { struct asd_ascb *ascb; list_for_each_entry(ascb, list, list) { diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h index abc757559c1a..8c1c28239e93 100644 --- a/drivers/scsi/aic94xx/aic94xx_hwi.h +++ b/drivers/scsi/aic94xx/aic94xx_hwi.h @@ -391,8 +391,6 @@ void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc); void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op); void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op); int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask); -void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id, - u8 subfunc); void asd_ascb_timedout(unsigned long data); int asd_chip_hardrst(struct asd_ha_struct *asd_ha); diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 88d1e731b65e..90f5e0a6f2e3 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -56,8 +56,6 @@ MODULE_PARM_DESC(collector, "\n" "\tThe aic94xx SAS LLDD supports both modes.\n" "\tDefault: 0 (Direct Mode).\n"); -char sas_addr_str[2*SAS_ADDR_SIZE + 1] = ""; - static struct scsi_transport_template *aic94xx_transport_template; static int asd_scan_finished(struct Scsi_Host *, unsigned long); static void asd_scan_start(struct Scsi_Host *); @@ -547,7 +545,7 @@ static struct asd_pcidev_struct { }, }; -static inline int asd_create_ha_caches(struct asd_ha_struct *asd_ha) +static int asd_create_ha_caches(struct asd_ha_struct *asd_ha) { asd_ha->scb_pool = dma_pool_create(ASD_DRIVER_NAME "_scb_pool", &asd_ha->pcidev->dev, @@ -565,7 +563,7 @@ static inline int asd_create_ha_caches(struct asd_ha_struct *asd_ha) * asd_free_edbs -- free empty data buffers * asd_ha: pointer to host adapter structure */ -static inline void asd_free_edbs(struct asd_ha_struct *asd_ha) +static void asd_free_edbs(struct asd_ha_struct *asd_ha) { struct asd_seq_data *seq = &asd_ha->seq; int i; @@ -576,7 +574,7 @@ static inline void asd_free_edbs(struct asd_ha_struct *asd_ha) seq->edb_arr = NULL; } -static inline void asd_free_escbs(struct asd_ha_struct *asd_ha) +static void asd_free_escbs(struct asd_ha_struct *asd_ha) { struct asd_seq_data *seq = &asd_ha->seq; int i; @@ -591,7 +589,7 @@ static inline void asd_free_escbs(struct asd_ha_struct *asd_ha) seq->escb_arr = NULL; } -static inline void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha) +static void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha) { int i; diff --git a/drivers/scsi/aic94xx/aic94xx_reg.c b/drivers/scsi/aic94xx/aic94xx_reg.c index f210dac3203d..56b17c22526e 100644 --- a/drivers/scsi/aic94xx/aic94xx_reg.c +++ b/drivers/scsi/aic94xx/aic94xx_reg.c @@ -32,8 +32,8 @@ * Offset comes before value to remind that the operation of * this function is *offs = val. */ -static inline void asd_write_byte(struct asd_ha_struct *asd_ha, - unsigned long offs, u8 val) +static void asd_write_byte(struct asd_ha_struct *asd_ha, + unsigned long offs, u8 val) { if (unlikely(asd_ha->iospace)) outb(val, @@ -43,8 +43,8 @@ static inline void asd_write_byte(struct asd_ha_struct *asd_ha, wmb(); } -static inline void asd_write_word(struct asd_ha_struct *asd_ha, - unsigned long offs, u16 val) +static void asd_write_word(struct asd_ha_struct *asd_ha, + unsigned long offs, u16 val) { if (unlikely(asd_ha->iospace)) outw(val, @@ -54,8 +54,8 @@ static inline void asd_write_word(struct asd_ha_struct *asd_ha, wmb(); } -static inline void asd_write_dword(struct asd_ha_struct *asd_ha, - unsigned long offs, u32 val) +static void asd_write_dword(struct asd_ha_struct *asd_ha, + unsigned long offs, u32 val) { if (unlikely(asd_ha->iospace)) outl(val, @@ -67,8 +67,7 @@ static inline void asd_write_dword(struct asd_ha_struct *asd_ha, /* Reading from device address space. */ -static inline u8 asd_read_byte(struct asd_ha_struct *asd_ha, - unsigned long offs) +static u8 asd_read_byte(struct asd_ha_struct *asd_ha, unsigned long offs) { u8 val; if (unlikely(asd_ha->iospace)) @@ -80,8 +79,8 @@ static inline u8 asd_read_byte(struct asd_ha_struct *asd_ha, return val; } -static inline u16 asd_read_word(struct asd_ha_struct *asd_ha, - unsigned long offs) +static u16 asd_read_word(struct asd_ha_struct *asd_ha, + unsigned long offs) { u16 val; if (unlikely(asd_ha->iospace)) @@ -93,8 +92,8 @@ static inline u16 asd_read_word(struct asd_ha_struct *asd_ha, return val; } -static inline u32 asd_read_dword(struct asd_ha_struct *asd_ha, - unsigned long offs) +static u32 asd_read_dword(struct asd_ha_struct *asd_ha, + unsigned long offs) { u32 val; if (unlikely(asd_ha->iospace)) @@ -124,22 +123,22 @@ static inline u32 asd_mem_offs_swb(void) /* We know that the register wanted is in the range * of the sliding window. */ -#define ASD_READ_SW(ww, type, ord) \ -static inline type asd_read_##ww##_##ord (struct asd_ha_struct *asd_ha,\ - u32 reg) \ -{ \ - struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \ - u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\ - return asd_read_##ord (asd_ha, (unsigned long) map_offs); \ +#define ASD_READ_SW(ww, type, ord) \ +static type asd_read_##ww##_##ord(struct asd_ha_struct *asd_ha, \ + u32 reg) \ +{ \ + struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \ + u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\ + return asd_read_##ord(asd_ha, (unsigned long)map_offs); \ } -#define ASD_WRITE_SW(ww, type, ord) \ -static inline void asd_write_##ww##_##ord (struct asd_ha_struct *asd_ha,\ - u32 reg, type val) \ -{ \ - struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \ - u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\ - asd_write_##ord (asd_ha, (unsigned long) map_offs, val); \ +#define ASD_WRITE_SW(ww, type, ord) \ +static void asd_write_##ww##_##ord(struct asd_ha_struct *asd_ha, \ + u32 reg, type val) \ +{ \ + struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \ + u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\ + asd_write_##ord(asd_ha, (unsigned long)map_offs, val); \ } ASD_READ_SW(swa, u8, byte); @@ -186,7 +185,7 @@ ASD_WRITE_SW(swc, u32, dword); * @asd_ha: pointer to host adapter structure * @reg: register desired to be within range of the new window */ -static inline void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg) +static void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg) { u32 base = reg & ~(MBAR0_SWB_SIZE-1); pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base); diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index ab350504ca5a..46643319c520 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c @@ -50,7 +50,7 @@ | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \ | CURRENT_OOB_ERROR) -static inline void get_lrate_mode(struct asd_phy *phy, u8 oob_mode) +static void get_lrate_mode(struct asd_phy *phy, u8 oob_mode) { struct sas_phy *sas_phy = phy->sas_phy.phy; @@ -81,7 +81,7 @@ static inline void get_lrate_mode(struct asd_phy *phy, u8 oob_mode) phy->sas_phy.oob_mode = SATA_OOB_MODE; } -static inline void asd_phy_event_tasklet(struct asd_ascb *ascb, +static void asd_phy_event_tasklet(struct asd_ascb *ascb, struct done_list_struct *dl) { struct asd_ha_struct *asd_ha = ascb->ha; @@ -125,8 +125,7 @@ static inline void asd_phy_event_tasklet(struct asd_ascb *ascb, } /* If phys are enabled sparsely, this will do the right thing. */ -static inline unsigned ord_phy(struct asd_ha_struct *asd_ha, - struct asd_phy *phy) +static unsigned ord_phy(struct asd_ha_struct *asd_ha, struct asd_phy *phy) { u8 enabled_mask = asd_ha->hw_prof.enabled_phys; int i, k = 0; @@ -151,7 +150,7 @@ static inline unsigned ord_phy(struct asd_ha_struct *asd_ha, * LOCKING: the frame_rcvd_lock needs to be held since this parses the frame * buffer. */ -static inline void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr) +static void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr) { if (phy->sas_phy.frame_rcvd[0] == 0x34 && phy->sas_phy.oob_mode == SATA_OOB_MODE) { @@ -232,9 +231,9 @@ static void asd_deform_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy) spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags); } -static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb, - struct done_list_struct *dl, - int edb_id, int phy_id) +static void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb, + struct done_list_struct *dl, + int edb_id, int phy_id) { unsigned long flags; int edb_el = edb_id + ascb->edb_index; @@ -255,9 +254,9 @@ static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb, sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED); } -static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb, - struct done_list_struct *dl, - int phy_id) +static void asd_link_reset_err_tasklet(struct asd_ascb *ascb, + struct done_list_struct *dl, + int phy_id) { struct asd_ha_struct *asd_ha = ascb->ha; struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; @@ -308,9 +307,9 @@ out: ; } -static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb, - struct done_list_struct *dl, - int phy_id) +static void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb, + struct done_list_struct *dl, + int phy_id) { unsigned long flags; struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha; @@ -715,7 +714,7 @@ out: asd_ascb_free(ascb); } -static inline void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd) +static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd) { /* disable all speeds, then enable defaults */ *speed_mask = SAS_SPEED_60_DIS | SAS_SPEED_30_DIS | SAS_SPEED_15_DIS @@ -820,6 +819,8 @@ void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc) /* ---------- INITIATE LINK ADM TASK ---------- */ +#if 0 + static void link_adm_tasklet_complete(struct asd_ascb *ascb, struct done_list_struct *dl) { @@ -852,6 +853,8 @@ void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id, ascb->tasklet_complete = link_adm_tasklet_complete; } +#endif /* 0 */ + /* ---------- SCB timer ---------- */ /** diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c index 2a4c933eb89c..4446e3d584dc 100644 --- a/drivers/scsi/aic94xx/aic94xx_sds.c +++ b/drivers/scsi/aic94xx/aic94xx_sds.c @@ -590,8 +590,8 @@ static int asd_reset_flash(struct asd_ha_struct *asd_ha) return err; } -static inline int asd_read_flash_seg(struct asd_ha_struct *asd_ha, - void *buffer, u32 offs, int size) +static int asd_read_flash_seg(struct asd_ha_struct *asd_ha, + void *buffer, u32 offs, int size) { asd_read_reg_string(asd_ha, buffer, asd_ha->hw_prof.flash.bar+offs, size); diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c index c750fbf7013b..f4272ac4c685 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.c +++ b/drivers/scsi/aic94xx/aic94xx_seq.c @@ -60,7 +60,7 @@ static u16 last_scb_site_no; * * Return 0 on success, negative on failure. */ -int asd_pause_cseq(struct asd_ha_struct *asd_ha) +static int asd_pause_cseq(struct asd_ha_struct *asd_ha) { int count = PAUSE_TRIES; u32 arp2ctl; @@ -87,7 +87,7 @@ int asd_pause_cseq(struct asd_ha_struct *asd_ha) * * Return 0 on success, negative on error. */ -int asd_unpause_cseq(struct asd_ha_struct *asd_ha) +static int asd_unpause_cseq(struct asd_ha_struct *asd_ha) { u32 arp2ctl; int count = PAUSE_TRIES; @@ -115,7 +115,7 @@ int asd_unpause_cseq(struct asd_ha_struct *asd_ha) * * Return 0 on success, negative on error. */ -static inline int asd_seq_pause_lseq(struct asd_ha_struct *asd_ha, int lseq) +static int asd_seq_pause_lseq(struct asd_ha_struct *asd_ha, int lseq) { u32 arp2ctl; int count = PAUSE_TRIES; @@ -143,7 +143,7 @@ static inline int asd_seq_pause_lseq(struct asd_ha_struct *asd_ha, int lseq) * * Return 0 on success, negative on failure. */ -int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask) +static int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask) { int lseq; int err = 0; @@ -164,7 +164,7 @@ int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask) * * Return 0 on success, negative on error. */ -static inline int asd_seq_unpause_lseq(struct asd_ha_struct *asd_ha, int lseq) +static int asd_seq_unpause_lseq(struct asd_ha_struct *asd_ha, int lseq) { u32 arp2ctl; int count = PAUSE_TRIES; @@ -186,27 +186,6 @@ static inline int asd_seq_unpause_lseq(struct asd_ha_struct *asd_ha, int lseq) } -/** - * asd_unpause_lseq - unpause the link sequencer(s) - * @asd_ha: pointer to host adapter structure - * @lseq_mask: mask of link sequencers of interest - * - * Return 0 on success, negative on failure. - */ -int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask) -{ - int lseq; - int err = 0; - - for_each_sequencer(lseq_mask, lseq_mask, lseq) { - err = asd_seq_unpause_lseq(asd_ha, lseq); - if (err) - return err; - } - - return err; -} - /* ---------- Downloading CSEQ/LSEQ microcode ---------- */ static int asd_verify_cseq(struct asd_ha_struct *asd_ha, const u8 *_prog, diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h index 2ea6a0d52208..ad787c55525f 100644 --- a/drivers/scsi/aic94xx/aic94xx_seq.h +++ b/drivers/scsi/aic94xx/aic94xx_seq.h @@ -58,10 +58,6 @@ struct sequencer_file_header { } __attribute__((packed)); #ifdef __KERNEL__ -int asd_pause_cseq(struct asd_ha_struct *asd_ha); -int asd_unpause_cseq(struct asd_ha_struct *asd_ha); -int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask); -int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask); int asd_init_seqs(struct asd_ha_struct *asd_ha); int asd_start_seqs(struct asd_ha_struct *asd_ha); int asd_release_firmware(void); diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c index 008df9ab92a5..326765c9caf8 100644 --- a/drivers/scsi/aic94xx/aic94xx_task.c +++ b/drivers/scsi/aic94xx/aic94xx_task.c @@ -33,7 +33,7 @@ static void asd_unbuild_ata_ascb(struct asd_ascb *a); static void asd_unbuild_smp_ascb(struct asd_ascb *a); static void asd_unbuild_ssp_ascb(struct asd_ascb *a); -static inline void asd_can_dequeue(struct asd_ha_struct *asd_ha, int num) +static void asd_can_dequeue(struct asd_ha_struct *asd_ha, int num) { unsigned long flags; @@ -51,9 +51,9 @@ static const u8 data_dir_flags[] = { [PCI_DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */ }; -static inline int asd_map_scatterlist(struct sas_task *task, - struct sg_el *sg_arr, - gfp_t gfp_flags) +static int asd_map_scatterlist(struct sas_task *task, + struct sg_el *sg_arr, + gfp_t gfp_flags) { struct asd_ascb *ascb = task->lldd_task; struct asd_ha_struct *asd_ha = ascb->ha; @@ -131,7 +131,7 @@ err_unmap: return res; } -static inline void asd_unmap_scatterlist(struct asd_ascb *ascb) +static void asd_unmap_scatterlist(struct asd_ascb *ascb) { struct asd_ha_struct *asd_ha = ascb->ha; struct sas_task *task = ascb->uldd_task; @@ -527,7 +527,7 @@ static void asd_unbuild_ssp_ascb(struct asd_ascb *a) /* ---------- Execute Task ---------- */ -static inline int asd_can_queue(struct asd_ha_struct *asd_ha, int num) +static int asd_can_queue(struct asd_ha_struct *asd_ha, int num) { int res = 0; unsigned long flags; diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c index b9ac8f703a1d..633ff40c736a 100644 --- a/drivers/scsi/aic94xx/aic94xx_tmf.c +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c @@ -336,7 +336,7 @@ static void asd_tmf_tasklet_complete(struct asd_ascb *ascb, asd_ascb_free(ascb); } -static inline int asd_clear_nexus(struct sas_task *task) +static int asd_clear_nexus(struct sas_task *task) { int res = TMF_RESP_FUNC_FAILED; int leftover; diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index 3bedf2466bd1..8e53f02cc311 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -2983,7 +2983,6 @@ static struct scsi_host_template acornscsi_template = { .this_id = 7, .sg_tablesize = SG_ALL, .cmd_per_lun = 2, - .unchecked_isa_dma = 0, .use_clustering = DISABLE_CLUSTERING, .proc_name = "acornscsi", }; diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c index 49d838e90a24..a3398fe70a9c 100644 --- a/drivers/scsi/arm/cumana_1.c +++ b/drivers/scsi/arm/cumana_1.c @@ -222,7 +222,6 @@ static struct scsi_host_template cumanascsi_template = { .this_id = 7, .sg_tablesize = SG_ALL, .cmd_per_lun = 2, - .unchecked_isa_dma = 0, .use_clustering = DISABLE_CLUSTERING, .proc_name = "CumanaSCSI-1", }; diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 7aad15436d24..92d1cb1b21cb 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -113,7 +113,7 @@ static const struct { unsigned char asc; unsigned char ascq; int errno; -} err[] = { +} ch_err[] = { /* Just filled in what looks right. Hav'nt checked any standard paper for these errno assignments, so they may be wrong... */ { @@ -155,11 +155,11 @@ static int ch_find_errno(struct scsi_sense_hdr *sshdr) /* Check to see if additional sense information is available */ if (scsi_sense_valid(sshdr) && sshdr->asc != 0) { - for (i = 0; err[i].errno != 0; i++) { - if (err[i].sense == sshdr->sense_key && - err[i].asc == sshdr->asc && - err[i].ascq == sshdr->ascq) { - errno = -err[i].errno; + for (i = 0; ch_err[i].errno != 0; i++) { + if (ch_err[i].sense == sshdr->sense_key && + ch_err[i].asc == sshdr->asc && + ch_err[i].ascq == sshdr->ascq) { + errno = -ch_err[i].errno; break; } } @@ -721,8 +721,8 @@ static long ch_ioctl(struct file *file, case CHIOGELEM: { struct changer_get_element cge; - u_char cmd[12]; - u_char *buffer; + u_char ch_cmd[12]; + u_char *buffer; unsigned int elem; int result,i; @@ -739,17 +739,18 @@ static long ch_ioctl(struct file *file, mutex_lock(&ch->lock); voltag_retry: - memset(cmd,0,sizeof(cmd)); - cmd[0] = READ_ELEMENT_STATUS; - cmd[1] = (ch->device->lun << 5) | + memset(ch_cmd, 0, sizeof(ch_cmd)); + ch_cmd[0] = READ_ELEMENT_STATUS; + ch_cmd[1] = (ch->device->lun << 5) | (ch->voltags ? 0x10 : 0) | ch_elem_to_typecode(ch,elem); - cmd[2] = (elem >> 8) & 0xff; - cmd[3] = elem & 0xff; - cmd[5] = 1; - cmd[9] = 255; + ch_cmd[2] = (elem >> 8) & 0xff; + ch_cmd[3] = elem & 0xff; + ch_cmd[5] = 1; + ch_cmd[9] = 255; - if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) { + result = ch_do_scsi(ch, ch_cmd, buffer, 256, DMA_FROM_DEVICE); + if (!result) { cge.cge_status = buffer[18]; cge.cge_flags = 0; if (buffer[18] & CESTATUS_EXCEPT) { diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index e351db6c0077..075e2397273c 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -4761,7 +4761,6 @@ static struct scsi_host_template dc395x_driver_template = { .cmd_per_lun = DC395x_MAX_CMD_PER_LUN, .eh_abort_handler = dc395x_eh_abort, .eh_bus_reset_handler = dc395x_eh_bus_reset, - .unchecked_isa_dma = 0, .use_clustering = DISABLE_CLUSTERING, }; diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index b5a60926e556..952505c006df 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -815,8 +815,6 @@ static int register_pio_HBA(long base, struct get_conf *gc, struct pci_dev *pdev else hd->primary = 1; - sh->unchecked_isa_dma = 0; /* We can only do PIO */ - hd->next = NULL; /* build a linked list of all HBAs */ hd->prev = last_HBA; if (hd->prev != NULL) diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 0b2080d33575..c6d6e7c6559a 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -85,10 +85,10 @@ /* The meaning of the Scsi_Pointer members in this driver is as follows: * ptr: Chaining - * this_residual: gdth_bufflen - * buffer: gdth_sglist + * this_residual: unused + * buffer: unused * dma_handle: unused - * buffers_residual: gdth_sg_count + * buffers_residual: unused * Status: unused * Message: unused * have_data_in: unused @@ -372,47 +372,6 @@ static const struct file_operations gdth_fops = { .release = gdth_close, }; -/* - * gdth scsi_command access wrappers. - * below 6 functions are used throughout the driver to access scsi_command's - * io parameters. The reason we do not use the regular accessors from - * scsi_cmnd.h is because of gdth_execute(). Since it is unrecommended for - * llds to directly set scsi_cmnd's IO members. This driver will use SCp - * members for IO parameters, and will copy scsi_cmnd's members to Scp - * members in queuecommand. For internal commands through gdth_execute() - * SCp's members will be set directly. - */ -static inline unsigned gdth_bufflen(struct scsi_cmnd *cmd) -{ - return (unsigned)cmd->SCp.this_residual; -} - -static inline void gdth_set_bufflen(struct scsi_cmnd *cmd, unsigned bufflen) -{ - cmd->SCp.this_residual = bufflen; -} - -static inline unsigned gdth_sg_count(struct scsi_cmnd *cmd) -{ - return (unsigned)cmd->SCp.buffers_residual; -} - -static inline void gdth_set_sg_count(struct scsi_cmnd *cmd, unsigned sg_count) -{ - cmd->SCp.buffers_residual = sg_count; -} - -static inline struct scatterlist *gdth_sglist(struct scsi_cmnd *cmd) -{ - return cmd->SCp.buffer; -} - -static inline void gdth_set_sglist(struct scsi_cmnd *cmd, - struct scatterlist *sglist) -{ - cmd->SCp.buffer = sglist; -} - #include "gdth_proc.h" #include "gdth_proc.c" @@ -591,125 +550,111 @@ static int __init gdth_search_isa(ulong32 bios_adr) #endif /* CONFIG_ISA */ #ifdef CONFIG_PCI -static void gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt, - ushort vendor, ushort dev); +static bool gdth_pci_registered; -static int __init gdth_search_pci(gdth_pci_str *pcistr) +static bool gdth_search_vortex(ushort device) { - ushort device, cnt; - - TRACE(("gdth_search_pci()\n")); - - cnt = 0; - for (device = 0; device <= PCI_DEVICE_ID_VORTEX_GDT6555; ++device) - gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, device); - for (device = PCI_DEVICE_ID_VORTEX_GDT6x17RP; - device <= PCI_DEVICE_ID_VORTEX_GDTMAXRP; ++device) - gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, device); - gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, - PCI_DEVICE_ID_VORTEX_GDTNEWRX); - gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, - PCI_DEVICE_ID_VORTEX_GDTNEWRX2); - gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_SRC); - gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_SRC_XSCALE); - return cnt; + if (device <= PCI_DEVICE_ID_VORTEX_GDT6555) + return true; + if (device >= PCI_DEVICE_ID_VORTEX_GDT6x17RP && + device <= PCI_DEVICE_ID_VORTEX_GDTMAXRP) + return true; + if (device == PCI_DEVICE_ID_VORTEX_GDTNEWRX || + device == PCI_DEVICE_ID_VORTEX_GDTNEWRX2) + return true; + return false; } +static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out); +static int gdth_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent); +static void gdth_pci_remove_one(struct pci_dev *pdev); +static void gdth_remove_one(gdth_ha_str *ha); + /* Vortex only makes RAID controllers. * We do not really want to specify all 550 ids here, so wildcard match. */ -static struct pci_device_id gdthtable[] __maybe_unused = { - {PCI_VENDOR_ID_VORTEX,PCI_ANY_ID,PCI_ANY_ID, PCI_ANY_ID}, - {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC,PCI_ANY_ID,PCI_ANY_ID}, - {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC_XSCALE,PCI_ANY_ID,PCI_ANY_ID}, - {0} +static const struct pci_device_id gdthtable[] = { + { PCI_VDEVICE(VORTEX, PCI_ANY_ID) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SRC) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SRC_XSCALE) }, + { } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, gdthtable); + +static struct pci_driver gdth_pci_driver = { + .name = "gdth", + .id_table = gdthtable, + .probe = gdth_pci_init_one, + .remove = gdth_pci_remove_one, }; -MODULE_DEVICE_TABLE(pci,gdthtable); -static void __init gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt, - ushort vendor, ushort device) +static void gdth_pci_remove_one(struct pci_dev *pdev) { - ulong base0, base1, base2; - struct pci_dev *pdev; + gdth_ha_str *ha = pci_get_drvdata(pdev); + + pci_set_drvdata(pdev, NULL); + + list_del(&ha->list); + gdth_remove_one(ha); + + pci_disable_device(pdev); +} + +static int gdth_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + ushort vendor = pdev->vendor; + ushort device = pdev->device; + ulong base0, base1, base2; + int rc; + gdth_pci_str gdth_pcistr; + gdth_ha_str *ha = NULL; - TRACE(("gdth_search_dev() cnt %d vendor %x device %x\n", - *cnt, vendor, device)); + TRACE(("gdth_search_dev() cnt %d vendor %x device %x\n", + gdth_ctr_count, vendor, device)); - pdev = NULL; - while ((pdev = pci_get_device(vendor, device, pdev)) - != NULL) { - if (pci_enable_device(pdev)) - continue; - if (*cnt >= MAXHA) { - pci_dev_put(pdev); - return; - } + memset(&gdth_pcistr, 0, sizeof(gdth_pcistr)); + + if (vendor == PCI_VENDOR_ID_VORTEX && !gdth_search_vortex(device)) + return -ENODEV; + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + if (gdth_ctr_count >= MAXHA) + return -EBUSY; /* GDT PCI controller found, resources are already in pdev */ - pcistr[*cnt].pdev = pdev; - pcistr[*cnt].irq = pdev->irq; + gdth_pcistr.pdev = pdev; base0 = pci_resource_flags(pdev, 0); base1 = pci_resource_flags(pdev, 1); base2 = pci_resource_flags(pdev, 2); if (device <= PCI_DEVICE_ID_VORTEX_GDT6000B || /* GDT6000/B */ device >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) { /* MPR */ if (!(base0 & IORESOURCE_MEM)) - continue; - pcistr[*cnt].dpmem = pci_resource_start(pdev, 0); + return -ENODEV; + gdth_pcistr.dpmem = pci_resource_start(pdev, 0); } else { /* GDT6110, GDT6120, .. */ if (!(base0 & IORESOURCE_MEM) || !(base2 & IORESOURCE_MEM) || !(base1 & IORESOURCE_IO)) - continue; - pcistr[*cnt].dpmem = pci_resource_start(pdev, 2); - pcistr[*cnt].io_mm = pci_resource_start(pdev, 0); - pcistr[*cnt].io = pci_resource_start(pdev, 1); + return -ENODEV; + gdth_pcistr.dpmem = pci_resource_start(pdev, 2); + gdth_pcistr.io = pci_resource_start(pdev, 1); } TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n", - pcistr[*cnt].pdev->bus->number, - PCI_SLOT(pcistr[*cnt].pdev->devfn), - pcistr[*cnt].irq, pcistr[*cnt].dpmem)); - (*cnt)++; - } -} + gdth_pcistr.pdev->bus->number, + PCI_SLOT(gdth_pcistr.pdev->devfn), + gdth_pcistr.irq, + gdth_pcistr.dpmem)); -static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt) -{ - gdth_pci_str temp; - int i, changed; - - TRACE(("gdth_sort_pci() cnt %d\n",cnt)); - if (cnt == 0) - return; + rc = gdth_pci_probe_one(&gdth_pcistr, &ha); + if (rc) + return rc; - do { - changed = FALSE; - for (i = 0; i < cnt-1; ++i) { - if (!reverse_scan) { - if ((pcistr[i].pdev->bus->number > pcistr[i+1].pdev->bus->number) || - (pcistr[i].pdev->bus->number == pcistr[i+1].pdev->bus->number && - PCI_SLOT(pcistr[i].pdev->devfn) > - PCI_SLOT(pcistr[i+1].pdev->devfn))) { - temp = pcistr[i]; - pcistr[i] = pcistr[i+1]; - pcistr[i+1] = temp; - changed = TRUE; - } - } else { - if ((pcistr[i].pdev->bus->number < pcistr[i+1].pdev->bus->number) || - (pcistr[i].pdev->bus->number == pcistr[i+1].pdev->bus->number && - PCI_SLOT(pcistr[i].pdev->devfn) < - PCI_SLOT(pcistr[i+1].pdev->devfn))) { - temp = pcistr[i]; - pcistr[i] = pcistr[i+1]; - pcistr[i+1] = temp; - changed = TRUE; - } - } - } - } while (changed); + return 0; } #endif /* CONFIG_PCI */ @@ -909,7 +854,8 @@ static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha) #endif /* CONFIG_ISA */ #ifdef CONFIG_PCI -static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) +static int gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, + gdth_ha_str *ha) { register gdt6_dpram_str __iomem *dp6_ptr; register gdt6c_dpram_str __iomem *dp6c_ptr; @@ -921,14 +867,14 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) TRACE(("gdth_init_pci()\n")); - if (pcistr->pdev->vendor == PCI_VENDOR_ID_INTEL) + if (pdev->vendor == PCI_VENDOR_ID_INTEL) ha->oem_id = OEM_ID_INTEL; else ha->oem_id = OEM_ID_ICP; - ha->brd_phys = (pcistr->pdev->bus->number << 8) | (pcistr->pdev->devfn & 0xf8); - ha->stype = (ulong32)pcistr->pdev->device; - ha->irq = pcistr->irq; - ha->pdev = pcistr->pdev; + ha->brd_phys = (pdev->bus->number << 8) | (pdev->devfn & 0xf8); + ha->stype = (ulong32)pdev->device; + ha->irq = pdev->irq; + ha->pdev = pdev; if (ha->pdev->device <= PCI_DEVICE_ID_VORTEX_GDT6000B) { /* GDT6000/B */ TRACE2(("init_pci() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq)); @@ -956,8 +902,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) continue; } iounmap(ha->brd); - pci_write_config_dword(pcistr->pdev, - PCI_BASE_ADDRESS_0, i); + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, i); ha->brd = ioremap(i, sizeof(gdt6_dpram_str)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); @@ -1066,8 +1011,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) continue; } iounmap(ha->brd); - pci_write_config_dword(pcistr->pdev, - PCI_BASE_ADDRESS_2, i); + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_2, i); ha->brd = ioremap(i, sizeof(gdt6c_dpram_str)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); @@ -1159,16 +1103,16 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) } /* manipulate config. space to enable DPMEM, start RP controller */ - pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command); + pci_read_config_word(pdev, PCI_COMMAND, &command); command |= 6; - pci_write_config_word(pcistr->pdev, PCI_COMMAND, command); - if (pci_resource_start(pcistr->pdev, 8) == 1UL) - pci_resource_start(pcistr->pdev, 8) = 0UL; + pci_write_config_word(pdev, PCI_COMMAND, command); + if (pci_resource_start(pdev, 8) == 1UL) + pci_resource_start(pdev, 8) = 0UL; i = 0xFEFF0001UL; - pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, i); + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, i); gdth_delay(1); - pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, - pci_resource_start(pcistr->pdev, 8)); + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, + pci_resource_start(pdev, 8)); dp6m_ptr = ha->brd; @@ -1195,8 +1139,7 @@ static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha) continue; } iounmap(ha->brd); - pci_write_config_dword(pcistr->pdev, - PCI_BASE_ADDRESS_0, i); + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, i); ha->brd = ioremap(i, sizeof(gdt6m_dpram_str)); if (ha->brd == NULL) { printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); @@ -2353,12 +2296,12 @@ static void gdth_next(gdth_ha_str *ha) static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, char *buffer, ushort count) { - ushort cpcount,i, max_sg = gdth_sg_count(scp); + ushort cpcount,i, max_sg = scsi_sg_count(scp); ushort cpsum,cpnow; struct scatterlist *sl; char *address; - cpcount = min_t(ushort, count, gdth_bufflen(scp)); + cpcount = min_t(ushort, count, scsi_bufflen(scp)); if (cpcount) { cpsum=0; @@ -2366,7 +2309,7 @@ static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, unsigned long flags; cpnow = (ushort)sl->length; TRACE(("copy_internal() now %d sum %d count %d %d\n", - cpnow, cpsum, cpcount, gdth_bufflen(scp))); + cpnow, cpsum, cpcount, scsi_bufflen(scp))); if (cpsum+cpnow > cpcount) cpnow = cpcount - cpsum; cpsum += cpnow; @@ -2589,10 +2532,10 @@ static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, ushort hdrive) cmdp->u.cache.BlockCnt = blockcnt; } - if (gdth_bufflen(scp)) { + if (scsi_bufflen(scp)) { cmndinfo->dma_dir = (read_write == 1 ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - sgcnt = pci_map_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp), + sgcnt = pci_map_sg(ha->pdev, scsi_sglist(scp), scsi_sg_count(scp), cmndinfo->dma_dir); if (mode64) { struct scatterlist *sl; @@ -2739,7 +2682,7 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) cmdp->u.raw64.lun = l; cmdp->u.raw64.bus = b; cmdp->u.raw64.priority = 0; - cmdp->u.raw64.sdlen = gdth_bufflen(scp); + cmdp->u.raw64.sdlen = scsi_bufflen(scp); cmdp->u.raw64.sense_len = 16; cmdp->u.raw64.sense_data = sense_paddr; cmdp->u.raw64.direction = @@ -2756,7 +2699,7 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) cmdp->u.raw.bus = b; cmdp->u.raw.priority = 0; cmdp->u.raw.link_p = 0; - cmdp->u.raw.sdlen = gdth_bufflen(scp); + cmdp->u.raw.sdlen = scsi_bufflen(scp); cmdp->u.raw.sense_len = 16; cmdp->u.raw.sense_data = sense_paddr; cmdp->u.raw.direction = @@ -2765,9 +2708,9 @@ static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, unchar b) cmdp->u.raw.sg_ranz = 0; } - if (gdth_bufflen(scp)) { + if (scsi_bufflen(scp)) { cmndinfo->dma_dir = PCI_DMA_BIDIRECTIONAL; - sgcnt = pci_map_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp), + sgcnt = pci_map_sg(ha->pdev, scsi_sglist(scp), scsi_sg_count(scp), cmndinfo->dma_dir); if (mode64) { struct scatterlist *sl; @@ -3388,8 +3331,8 @@ static int gdth_sync_event(gdth_ha_str *ha, int service, unchar index, /* retry */ return 2; } - if (gdth_bufflen(scp)) - pci_unmap_sg(ha->pdev, gdth_sglist(scp), gdth_sg_count(scp), + if (scsi_bufflen(scp)) + pci_unmap_sg(ha->pdev, scsi_sglist(scp), scsi_sg_count(scp), cmndinfo->dma_dir); if (cmndinfo->sense_paddr) @@ -4031,10 +3974,6 @@ static int gdth_queuecommand(struct scsi_cmnd *scp, gdth_update_timeout(scp, scp->timeout_per_command * 6); cmndinfo->priority = DEFAULT_PRI; - gdth_set_bufflen(scp, scsi_bufflen(scp)); - gdth_set_sg_count(scp, scsi_sg_count(scp)); - gdth_set_sglist(scp, scsi_sglist(scp)); - return __gdth_queuecommand(ha, scp, cmndinfo); } @@ -4955,12 +4894,16 @@ static int __init gdth_eisa_probe_one(ushort eisa_slot) #endif /* CONFIG_EISA */ #ifdef CONFIG_PCI -static int __init gdth_pci_probe_one(gdth_pci_str *pcistr, int ctr) +static int gdth_pci_probe_one(gdth_pci_str *pcistr, + gdth_ha_str **ha_out) { struct Scsi_Host *shp; gdth_ha_str *ha; dma_addr_t scratch_dma_handle = 0; int error, i; + struct pci_dev *pdev = pcistr->pdev; + + *ha_out = NULL; shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str)); if (!shp) @@ -4968,13 +4911,13 @@ static int __init gdth_pci_probe_one(gdth_pci_str *pcistr, int ctr) ha = shost_priv(shp); error = -ENODEV; - if (!gdth_init_pci(&pcistr[ctr],ha)) + if (!gdth_init_pci(pdev, pcistr, ha)) goto out_host_put; /* controller found and initialized */ printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n", - pcistr[ctr].pdev->bus->number, - PCI_SLOT(pcistr[ctr].pdev->devfn), + pdev->bus->number, + PCI_SLOT(pdev->devfn), ha->irq); error = request_irq(ha->irq, gdth_interrupt, @@ -5019,7 +4962,7 @@ static int __init gdth_pci_probe_one(gdth_pci_str *pcistr, int ctr) ha->scratch_busy = FALSE; ha->req_first = NULL; - ha->tid_cnt = pcistr[ctr].pdev->device >= 0x200 ? MAXID : MAX_HDRIVES; + ha->tid_cnt = pdev->device >= 0x200 ? MAXID : MAX_HDRIVES; if (max_ids > 0 && max_ids < ha->tid_cnt) ha->tid_cnt = max_ids; for (i = 0; i < GDTH_MAXCMDS; ++i) @@ -5039,16 +4982,16 @@ static int __init gdth_pci_probe_one(gdth_pci_str *pcistr, int ctr) /* 64-bit DMA only supported from FW >= x.43 */ if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) || !ha->dma64_support) { - if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) { + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { printk(KERN_WARNING "GDT-PCI %d: " "Unable to set 32-bit DMA\n", ha->hanum); goto out_free_coal_stat; } } else { shp->max_cmd_len = 16; - if (!pci_set_dma_mask(pcistr[ctr].pdev, DMA_64BIT_MASK)) { + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { printk("GDT-PCI %d: 64-bit DMA enabled\n", ha->hanum); - } else if (pci_set_dma_mask(pcistr[ctr].pdev, DMA_32BIT_MASK)) { + } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { printk(KERN_WARNING "GDT-PCI %d: " "Unable to set 64/32-bit DMA\n", ha->hanum); goto out_free_coal_stat; @@ -5062,13 +5005,17 @@ static int __init gdth_pci_probe_one(gdth_pci_str *pcistr, int ctr) spin_lock_init(&ha->smp_lock); gdth_enable_int(ha); - error = scsi_add_host(shp, &pcistr[ctr].pdev->dev); + error = scsi_add_host(shp, &pdev->dev); if (error) goto out_free_coal_stat; list_add_tail(&ha->list, &gdth_instances); + pci_set_drvdata(ha->pdev, ha); + scsi_scan_host(shp); + *ha_out = ha; + return 0; out_free_coal_stat: @@ -5185,16 +5132,8 @@ static int __init gdth_init(void) #ifdef CONFIG_PCI /* scanning for PCI controllers */ - { - gdth_pci_str pcistr[MAXHA]; - int cnt,ctr; - - cnt = gdth_search_pci(pcistr); - printk("GDT-HA: Found %d PCI Storage RAID Controllers\n", cnt); - gdth_sort_pci(pcistr,cnt); - for (ctr = 0; ctr < cnt; ++ctr) - gdth_pci_probe_one(pcistr, ctr); - } + if (pci_register_driver(&gdth_pci_driver) == 0) + gdth_pci_registered = true; #endif /* CONFIG_PCI */ TRACE2(("gdth_detect() %d controller detected\n", gdth_ctr_count)); @@ -5227,6 +5166,11 @@ static void __exit gdth_exit(void) del_timer_sync(&gdth_timer); #endif +#ifdef CONFIG_PCI + if (gdth_pci_registered) + pci_unregister_driver(&gdth_pci_driver); +#endif + list_for_each_entry(ha, &gdth_instances, list) gdth_remove_one(ha); } diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h index 26e4e92515e0..ca92476727cf 100644 --- a/drivers/scsi/gdth.h +++ b/drivers/scsi/gdth.h @@ -839,8 +839,6 @@ typedef struct { struct pci_dev *pdev; ulong dpmem; /* DPRAM address */ ulong io; /* IO address */ - ulong io_mm; /* IO address mem. mapped */ - unchar irq; /* IRQ */ } gdth_pci_str; diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index 91f85226d08f..ca7363752401 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -322,6 +322,9 @@ int __init gvp11_detect(struct scsi_host_template *tpnt) */ regs.SASR = &(DMA(instance)->SASR); regs.SCMD = &(DMA(instance)->SCMD); + HDATA(instance)->no_sync = 0xff; + HDATA(instance)->fast = 0; + HDATA(instance)->dma_mode = CTRL_DMA; wd33c93_init(instance, regs, dma_setup, dma_stop, (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10 : WD33C93_FS_12_15); diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index ed7e0a1fc34d..1592640a87b5 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -347,7 +347,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->unchecked_isa_dma = sht->unchecked_isa_dma; shost->use_clustering = sht->use_clustering; shost->ordered_tag = sht->ordered_tag; - shost->active_mode = sht->supported_mode; if (sht->supported_mode == MODE_UNKNOWN) /* means we didn't set it ... default to INITIATOR */ diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index ff149ad6bc4e..beecda991682 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -338,7 +338,8 @@ static int iop_get_config_mv(struct hptiop_hba *hba, req->header.size = cpu_to_le32(sizeof(struct hpt_iop_request_get_config)); req->header.result = cpu_to_le32(IOP_RESULT_PENDING); - req->header.context = cpu_to_le64(IOP_REQUEST_TYPE_GET_CONFIG<<5); + req->header.context = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG<<5); + req->header.context_hi32 = 0; if (iop_send_sync_request_mv(hba, 0, 20000)) { dprintk("Get config send cmd failed\n"); @@ -392,7 +393,8 @@ static int iop_set_config_mv(struct hptiop_hba *hba, req->header.size = cpu_to_le32(sizeof(struct hpt_iop_request_set_config)); req->header.result = cpu_to_le32(IOP_RESULT_PENDING); - req->header.context = cpu_to_le64(IOP_REQUEST_TYPE_SET_CONFIG<<5); + req->header.context = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG<<5); + req->header.context_hi32 = 0; if (iop_send_sync_request_mv(hba, 0, 20000)) { dprintk("Set config send cmd failed\n"); @@ -903,7 +905,6 @@ static struct scsi_host_template driver_template = { .eh_device_reset_handler = hptiop_reset, .eh_bus_reset_handler = hptiop_reset, .info = hptiop_info, - .unchecked_isa_dma = 0, .emulated = 0, .use_clustering = ENABLE_CLUSTERING, .proc_name = driver_name, diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index 0cc8868ea35d..dbae3fdb8506 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -2581,8 +2581,8 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c /* Map the sense buffer into bus memory */ dma_addr = dma_map_single(&host->pci_dev->dev, cmnd->sense_buffer, SENSE_SIZE, DMA_FROM_DEVICE); - cblk->senseptr = cpu_to_le32((u32)dma_addr); - cblk->senselen = cpu_to_le32(SENSE_SIZE); + cblk->senseptr = (u32)dma_addr; + cblk->senselen = SENSE_SIZE; cmnd->SCp.ptr = (char *)(unsigned long)dma_addr; cblk->cdblen = cmnd->cmd_len; @@ -2606,7 +2606,7 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c dma_addr = dma_map_single(&host->pci_dev->dev, &cblk->sglist[0], sizeof(struct sg_entry) * TOTAL_SG_ENTRY, DMA_BIDIRECTIONAL); - cblk->bufptr = cpu_to_le32((u32)dma_addr); + cblk->bufptr = (u32)dma_addr; cmnd->SCp.dma_handle = dma_addr; cblk->sglen = nseg; @@ -2616,7 +2616,8 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c sg = &cblk->sglist[0]; scsi_for_each_sg(cmnd, sglist, cblk->sglen, i) { sg->data = cpu_to_le32((u32)sg_dma_address(sglist)); - total_len += sg->len = cpu_to_le32((u32)sg_dma_len(sglist)); + sg->len = cpu_to_le32((u32)sg_dma_len(sglist)); + total_len += sg_dma_len(sglist); ++sg; } diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 7ed568f180ae..7c615c70ec5c 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -2377,7 +2377,7 @@ ips_get_bios_version(ips_ha_t * ha, int intr) if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) return; - outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP); + outl(1, ha->io_addr + IPS_REG_FLAP); if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ @@ -2385,21 +2385,21 @@ ips_get_bios_version(ips_ha_t * ha, int intr) return; /* Get Major version */ - outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP); + outl(0x1FF, ha->io_addr + IPS_REG_FLAP); if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ major = inb(ha->io_addr + IPS_REG_FLDP); /* Get Minor version */ - outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP); + outl(0x1FE, ha->io_addr + IPS_REG_FLAP); if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ minor = inb(ha->io_addr + IPS_REG_FLDP); /* Get SubMinor version */ - outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP); + outl(0x1FD, ha->io_addr + IPS_REG_FLAP); if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ @@ -3502,27 +3502,11 @@ ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr) static void ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count) { - int i; - unsigned int min_cnt, xfer_cnt; - char *cdata = (char *) data; - unsigned char *buffer; - unsigned long flags; - struct scatterlist *sg = scsi_sglist(scmd); - - for (i = 0, xfer_cnt = 0; - (i < scsi_sg_count(scmd)) && (xfer_cnt < count); i++) { - min_cnt = min(count - xfer_cnt, sg[i].length); - - /* kmap_atomic() ensures addressability of the data buffer.*/ - /* local_irq_save() protects the KM_IRQ0 address slot. */ - local_irq_save(flags); - buffer = kmap_atomic(sg_page(&sg[i]), KM_IRQ0) + sg[i].offset; - memcpy(buffer, &cdata[xfer_cnt], min_cnt); - kunmap_atomic(buffer - sg[i].offset, KM_IRQ0); - local_irq_restore(flags); + unsigned long flags; - xfer_cnt += min_cnt; - } + local_irq_save(flags); + scsi_sg_copy_from_buffer(scmd, data, count); + local_irq_restore(flags); } /****************************************************************************/ @@ -3535,27 +3519,11 @@ ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count) static void ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count) { - int i; - unsigned int min_cnt, xfer_cnt; - char *cdata = (char *) data; - unsigned char *buffer; - unsigned long flags; - struct scatterlist *sg = scsi_sglist(scmd); - - for (i = 0, xfer_cnt = 0; - (i < scsi_sg_count(scmd)) && (xfer_cnt < count); i++) { - min_cnt = min(count - xfer_cnt, sg[i].length); - - /* kmap_atomic() ensures addressability of the data buffer.*/ - /* local_irq_save() protects the KM_IRQ0 address slot. */ - local_irq_save(flags); - buffer = kmap_atomic(sg_page(&sg[i]), KM_IRQ0) + sg[i].offset; - memcpy(&cdata[xfer_cnt], buffer, min_cnt); - kunmap_atomic(buffer - sg[i].offset, KM_IRQ0); - local_irq_restore(flags); + unsigned long flags; - xfer_cnt += min_cnt; - } + local_irq_save(flags); + scsi_sg_copy_to_buffer(scmd, data, count); + local_irq_restore(flags); } /****************************************************************************/ @@ -3696,9 +3664,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb) scb->cmd.basic_io.sg_count = scb->sg_len; if (scb->cmd.basic_io.lba) - scb->cmd.basic_io.lba = - cpu_to_le32(le32_to_cpu - (scb->cmd.basic_io.lba) + + le32_add_cpu(&scb->cmd.basic_io.lba, le16_to_cpu(scb->cmd.basic_io. sector_count)); else @@ -3744,9 +3710,7 @@ ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb) scb->cmd.basic_io.sg_count = scb->sg_len; if (scb->cmd.basic_io.lba) - scb->cmd.basic_io.lba = - cpu_to_le32(le32_to_cpu - (scb->cmd.basic_io.lba) + + le32_add_cpu(&scb->cmd.basic_io.lba, le16_to_cpu(scb->cmd.basic_io. sector_count)); else @@ -4888,7 +4852,7 @@ ips_init_copperhead(ips_ha_t * ha) return (0); /* setup CCCR */ - outl(cpu_to_le32(0x1010), ha->io_addr + IPS_REG_CCCR); + outl(0x1010, ha->io_addr + IPS_REG_CCCR); /* Enable busmastering */ outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR); @@ -5270,12 +5234,12 @@ ips_statinit(ips_ha_t * ha) ha->adapt->p_status_tail = ha->adapt->status; phys_status_start = ha->adapt->hw_status_start; - outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQSR); - outl(cpu_to_le32(phys_status_start + IPS_STATUS_Q_SIZE), + outl(phys_status_start, ha->io_addr + IPS_REG_SQSR); + outl(phys_status_start + IPS_STATUS_Q_SIZE, ha->io_addr + IPS_REG_SQER); - outl(cpu_to_le32(phys_status_start + IPS_STATUS_SIZE), + outl(phys_status_start + IPS_STATUS_SIZE, ha->io_addr + IPS_REG_SQHR); - outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQTR); + outl(phys_status_start, ha->io_addr + IPS_REG_SQTR); ha->adapt->hw_status_tail = phys_status_start; } @@ -5332,7 +5296,7 @@ ips_statupd_copperhead(ips_ha_t * ha) ha->adapt->hw_status_tail = ha->adapt->hw_status_start; } - outl(cpu_to_le32(ha->adapt->hw_status_tail), + outl(ha->adapt->hw_status_tail, ha->io_addr + IPS_REG_SQTR); return (ha->adapt->p_status_tail->value); @@ -5434,8 +5398,8 @@ ips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb) } /* end if */ } /* end while */ - outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_CCSAR); - outw(cpu_to_le32(IPS_BIT_START_CMD), ha->io_addr + IPS_REG_CCCR); + outl(scb->scb_busaddr, ha->io_addr + IPS_REG_CCSAR); + outw(IPS_BIT_START_CMD, ha->io_addr + IPS_REG_CCCR); return (IPS_SUCCESS); } @@ -5520,7 +5484,7 @@ ips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb) ips_name, ha->host_num, scb->cmd.basic_io.command_id); } - outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_I2O_INMSGQ); + outl(scb->scb_busaddr, ha->io_addr + IPS_REG_I2O_INMSGQ); return (IPS_SUCCESS); } @@ -6412,7 +6376,7 @@ ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, for (i = 0; i < buffersize; i++) { /* write a byte */ - outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP); + outl(i + offset, ha->io_addr + IPS_REG_FLAP); if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ @@ -6597,7 +6561,7 @@ ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) return (1); - outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP); + outl(1, ha->io_addr + IPS_REG_FLAP); if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) @@ -6606,7 +6570,7 @@ ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, checksum = 0xff; for (i = 2; i < buffersize; i++) { - outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP); + outl(i + offset, ha->io_addr + IPS_REG_FLAP); if (ha->pcidev->revision == IPS_REVID_TROMBONE64) udelay(25); /* 25 us */ @@ -6842,7 +6806,6 @@ ips_register_scsi(int index) sh->sg_tablesize = sh->hostt->sg_tablesize; sh->can_queue = sh->hostt->can_queue; sh->cmd_per_lun = sh->hostt->cmd_per_lun; - sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma; sh->use_clustering = sh->hostt->use_clustering; sh->max_sectors = 128; diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 8a178674cb18..72b9b2a0eba3 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -528,6 +528,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) struct iscsi_session *session = conn->session; struct scsi_cmnd *sc = ctask->sc; int datasn = be32_to_cpu(rhdr->datasn); + unsigned total_in_length = scsi_in(sc)->length; iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); if (tcp_conn->in.datalen == 0) @@ -542,10 +543,10 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) tcp_ctask->exp_datasn++; tcp_ctask->data_offset = be32_to_cpu(rhdr->offset); - if (tcp_ctask->data_offset + tcp_conn->in.datalen > scsi_bufflen(sc)) { + if (tcp_ctask->data_offset + tcp_conn->in.datalen > total_in_length) { debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n", __FUNCTION__, tcp_ctask->data_offset, - tcp_conn->in.datalen, scsi_bufflen(sc)); + tcp_conn->in.datalen, total_in_length); return ISCSI_ERR_DATA_OFFSET; } @@ -558,8 +559,8 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) if (res_count > 0 && (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || - res_count <= scsi_bufflen(sc))) - scsi_set_resid(sc, res_count); + res_count <= total_in_length)) + scsi_in(sc)->resid = res_count; else sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; @@ -670,11 +671,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_length, session->max_burst); r2t->data_offset = be32_to_cpu(rhdr->data_offset); - if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) { + if (r2t->data_offset + r2t->data_length > scsi_out(ctask->sc)->length) { iscsi_conn_printk(KERN_ERR, conn, "invalid R2T with data len %u at offset %u " "and total length %d\n", r2t->data_length, - r2t->data_offset, scsi_bufflen(ctask->sc)); + r2t->data_offset, scsi_out(ctask->sc)->length); __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); return ISCSI_ERR_DATALEN; @@ -771,6 +772,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) if (tcp_conn->in.datalen) { struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct hash_desc *rx_hash = NULL; + struct scsi_data_buffer *sdb = scsi_in(ctask->sc); /* * Setup copy of Data-In into the Scsi_Cmnd @@ -788,8 +790,8 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) tcp_ctask->data_offset, tcp_conn->in.datalen); return iscsi_segment_seek_sg(&tcp_conn->in.segment, - scsi_sglist(ctask->sc), - scsi_sg_count(ctask->sc), + sdb->table.sgl, + sdb->table.nents, tcp_ctask->data_offset, tcp_conn->in.datalen, iscsi_tcp_process_data_in, @@ -1332,7 +1334,8 @@ iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask) return 0; /* If we have immediate data, attach a payload */ - err = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc), scsi_sg_count(sc), + err = iscsi_tcp_send_data_prep(conn, scsi_out(sc)->table.sgl, + scsi_out(sc)->table.nents, 0, ctask->imm_count); if (err) return err; @@ -1386,6 +1389,7 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct scsi_cmnd *sc = ctask->sc; + struct scsi_data_buffer *sdb = scsi_out(sc); int rc = 0; flush: @@ -1412,9 +1416,8 @@ flush: ctask->itt, tcp_ctask->sent, ctask->data_count); iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr)); - rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc), - scsi_sg_count(sc), - tcp_ctask->sent, + rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl, + sdb->table.nents, tcp_ctask->sent, ctask->data_count); if (rc) goto fail; @@ -1460,8 +1463,8 @@ flush: iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr, sizeof(struct iscsi_hdr)); - rc = iscsi_tcp_send_data_prep(conn, scsi_sglist(sc), - scsi_sg_count(sc), + rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl, + sdb->table.nents, r2t->data_offset + r2t->sent, r2t->data_count); if (rc) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index bdd7de7da39a..010c1b9b178c 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -137,6 +137,70 @@ static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len) return 0; } +/* + * make an extended cdb AHS + */ +static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask) +{ + struct scsi_cmnd *cmd = ctask->sc; + unsigned rlen, pad_len; + unsigned short ahslength; + struct iscsi_ecdb_ahdr *ecdb_ahdr; + int rc; + + ecdb_ahdr = iscsi_next_hdr(ctask); + rlen = cmd->cmd_len - ISCSI_CDB_SIZE; + + BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb)); + ahslength = rlen + sizeof(ecdb_ahdr->reserved); + + pad_len = iscsi_padding(rlen); + + rc = iscsi_add_hdr(ctask, sizeof(ecdb_ahdr->ahslength) + + sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len); + if (rc) + return rc; + + if (pad_len) + memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len); + + ecdb_ahdr->ahslength = cpu_to_be16(ahslength); + ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB; + ecdb_ahdr->reserved = 0; + memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen); + + debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d " + "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n", + cmd->cmd_len, rlen, pad_len, ahslength, ctask->hdr_len); + + return 0; +} + +static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask) +{ + struct scsi_cmnd *sc = ctask->sc; + struct iscsi_rlength_ahdr *rlen_ahdr; + int rc; + + rlen_ahdr = iscsi_next_hdr(ctask); + rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr)); + if (rc) + return rc; + + rlen_ahdr->ahslength = + cpu_to_be16(sizeof(rlen_ahdr->read_length) + + sizeof(rlen_ahdr->reserved)); + rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH; + rlen_ahdr->reserved = 0; + rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length); + + debug_scsi("bidi-in rlen_ahdr->read_length(%d) " + "rlen_ahdr->ahslength(%d)\n", + be32_to_cpu(rlen_ahdr->read_length), + be16_to_cpu(rlen_ahdr->ahslength)); + return 0; +} + /** * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu * @ctask: iscsi cmd task @@ -150,7 +214,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) struct iscsi_session *session = conn->session; struct iscsi_cmd *hdr = ctask->hdr; struct scsi_cmnd *sc = ctask->sc; - unsigned hdrlength; + unsigned hdrlength, cmd_len; int rc; ctask->hdr_len = 0; @@ -161,17 +225,30 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) hdr->flags = ISCSI_ATTR_SIMPLE; int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); hdr->itt = build_itt(ctask->itt, session->age); - hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); hdr->cmdsn = cpu_to_be32(session->cmdsn); session->cmdsn++; hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); - memcpy(hdr->cdb, sc->cmnd, sc->cmd_len); - if (sc->cmd_len < MAX_COMMAND_SIZE) - memset(&hdr->cdb[sc->cmd_len], 0, - MAX_COMMAND_SIZE - sc->cmd_len); + cmd_len = sc->cmd_len; + if (cmd_len < ISCSI_CDB_SIZE) + memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len); + else if (cmd_len > ISCSI_CDB_SIZE) { + rc = iscsi_prep_ecdb_ahs(ctask); + if (rc) + return rc; + cmd_len = ISCSI_CDB_SIZE; + } + memcpy(hdr->cdb, sc->cmnd, cmd_len); ctask->imm_count = 0; + if (scsi_bidi_cmnd(sc)) { + hdr->flags |= ISCSI_FLAG_CMD_READ; + rc = iscsi_prep_bidi_ahs(ctask); + if (rc) + return rc; + } if (sc->sc_data_direction == DMA_TO_DEVICE) { + unsigned out_len = scsi_out(sc)->length; + hdr->data_length = cpu_to_be32(out_len); hdr->flags |= ISCSI_FLAG_CMD_WRITE; /* * Write counters: @@ -192,19 +269,19 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) ctask->unsol_datasn = 0; if (session->imm_data_en) { - if (scsi_bufflen(sc) >= session->first_burst) + if (out_len >= session->first_burst) ctask->imm_count = min(session->first_burst, conn->max_xmit_dlength); else - ctask->imm_count = min(scsi_bufflen(sc), + ctask->imm_count = min(out_len, conn->max_xmit_dlength); hton24(hdr->dlength, ctask->imm_count); } else zero_data(hdr->dlength); if (!session->initial_r2t_en) { - ctask->unsol_count = min((session->first_burst), - (scsi_bufflen(sc))) - ctask->imm_count; + ctask->unsol_count = min(session->first_burst, out_len) + - ctask->imm_count; ctask->unsol_offset = ctask->imm_count; } @@ -214,6 +291,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) } else { hdr->flags |= ISCSI_FLAG_CMD_FINAL; zero_data(hdr->dlength); + hdr->data_length = cpu_to_be32(scsi_in(sc)->length); if (sc->sc_data_direction == DMA_FROM_DEVICE) hdr->flags |= ISCSI_FLAG_CMD_READ; @@ -232,10 +310,12 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) return EIO; conn->scsicmd_pdus_cnt++; - debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " - "cmdsn %d win %d]\n", - sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", - conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc), + debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x " + "len %d bidi_len %d cmdsn %d win %d]\n", + scsi_bidi_cmnd(sc) ? "bidirectional" : + sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", + conn->id, sc, sc->cmnd[0], ctask->itt, + scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); return 0; } @@ -298,7 +378,12 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, conn->session->tt->cleanup_cmd_task(conn, ctask); sc->result = err; - scsi_set_resid(sc, scsi_bufflen(sc)); + if (!scsi_bidi_cmnd(sc)) + scsi_set_resid(sc, scsi_bufflen(sc)); + else { + scsi_out(sc)->resid = scsi_out(sc)->length; + scsi_in(sc)->resid = scsi_in(sc)->length; + } if (conn->ctask == ctask) conn->ctask = NULL; /* release ref from queuecommand */ @@ -433,6 +518,18 @@ invalid_datalen: min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); } + if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | + ISCSI_FLAG_CMD_BIDI_OVERFLOW)) { + int res_count = be32_to_cpu(rhdr->bi_residual_count); + + if (scsi_bidi_cmnd(sc) && res_count > 0 && + (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW || + res_count <= scsi_in(sc)->length)) + scsi_in(sc)->resid = res_count; + else + sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; + } + if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | ISCSI_FLAG_CMD_OVERFLOW)) { int res_count = be32_to_cpu(rhdr->residual_count); @@ -440,13 +537,11 @@ invalid_datalen: if (res_count > 0 && (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || res_count <= scsi_bufflen(sc))) + /* write side for bidi or uni-io set_resid */ scsi_set_resid(sc, res_count); else sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - } else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | - ISCSI_FLAG_CMD_BIDI_OVERFLOW)) - sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - + } out: debug_scsi("done [sc %lx res %d itt 0x%x]\n", (long)sc, sc->result, ctask->itt); @@ -1102,7 +1197,12 @@ reject: fault: spin_unlock(&session->lock); debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); - scsi_set_resid(sc, scsi_bufflen(sc)); + if (!scsi_bidi_cmnd(sc)) + scsi_set_resid(sc, scsi_bufflen(sc)); + else { + scsi_out(sc)->resid = scsi_out(sc)->length; + scsi_in(sc)->resid = scsi_in(sc)->length; + } sc->scsi_done(sc); spin_lock(host->host_lock); return 0; diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index a4811e4106df..744f06d04a36 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -691,7 +691,7 @@ static int sas_discover_sata_dev(struct domain_device *dev) /* incomplete response */ SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to " "dev %llx\n", SAS_ADDR(dev->sas_addr)); - if (!le16_to_cpu(identify_x[83] & (1<<6))) + if (!(identify_x[83] & cpu_to_le16(1<<6))) goto cont1; res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES, ATA_FEATURE_PUP_STBY_SPIN_UP, diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 1f8241563c6c..601ec5b6a7f6 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -24,6 +24,8 @@ */ #include <linux/kthread.h> +#include <linux/firmware.h> +#include <linux/ctype.h> #include "sas_internal.h" @@ -1064,6 +1066,45 @@ void sas_target_destroy(struct scsi_target *starget) return; } +static void sas_parse_addr(u8 *sas_addr, const char *p) +{ + int i; + for (i = 0; i < SAS_ADDR_SIZE; i++) { + u8 h, l; + if (!*p) + break; + h = isdigit(*p) ? *p-'0' : toupper(*p)-'A'+10; + p++; + l = isdigit(*p) ? *p-'0' : toupper(*p)-'A'+10; + p++; + sas_addr[i] = (h<<4) | l; + } +} + +#define SAS_STRING_ADDR_SIZE 16 + +int sas_request_addr(struct Scsi_Host *shost, u8 *addr) +{ + int res; + const struct firmware *fw; + + res = request_firmware(&fw, "sas_addr", &shost->shost_gendev); + if (res) + return res; + + if (fw->size < SAS_STRING_ADDR_SIZE) { + res = -ENODEV; + goto out; + } + + sas_parse_addr(addr, fw->data); + +out: + release_firmware(fw); + return res; +} +EXPORT_SYMBOL_GPL(sas_request_addr); + EXPORT_SYMBOL_GPL(sas_queuecommand); EXPORT_SYMBOL_GPL(sas_target_alloc); EXPORT_SYMBOL_GPL(sas_slave_configure); diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 2ab2d24dcc15..ec0b0f6e5e1a 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -23,7 +23,7 @@ struct lpfc_sli2_slim; -#define LPFC_MAX_TARGET 256 /* max number of targets supported */ +#define LPFC_MAX_TARGET 4096 /* max number of targets supported */ #define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els requests */ #define LPFC_MAX_NS_RETRY 3 /* Number of retry attempts to contact @@ -268,7 +268,6 @@ struct lpfc_vport { #define FC_NLP_MORE 0x40 /* More node to process in node tbl */ #define FC_OFFLINE_MODE 0x80 /* Interface is offline for diag */ #define FC_FABRIC 0x100 /* We are fabric attached */ -#define FC_ESTABLISH_LINK 0x200 /* Reestablish Link */ #define FC_RSCN_DISCOVERY 0x400 /* Auth all devices after RSCN */ #define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */ #define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */ @@ -433,8 +432,6 @@ struct lpfc_hba { uint32_t fc_eventTag; /* event tag for link attention */ - - struct timer_list fc_estabtmo; /* link establishment timer */ /* These fields used to be binfo */ uint32_t fc_pref_DID; /* preferred D_ID */ uint8_t fc_pref_ALPA; /* preferred AL_PA */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index b12a841703ca..74c9fc204211 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1954,7 +1954,9 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, (phba->sysfs_mbox.mbox->mb.mbxCommand != MBX_DUMP_MEMORY && phba->sysfs_mbox.mbox->mb.mbxCommand != - MBX_RESTART)) { + MBX_RESTART && + phba->sysfs_mbox.mbox->mb.mbxCommand != + MBX_WRITE_VPARMS)) { sysfs_mbox_idle(phba); spin_unlock_irq(&phba->hbalock); return -EPERM; @@ -1962,7 +1964,11 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, phba->sysfs_mbox.mbox->vport = vport; - if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { + /* Don't allow mailbox commands to be sent when blocked + * or when in the middle of discovery + */ + if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO || + vport->fc_flag & FC_NDISC_ACTIVE) { sysfs_mbox_idle(phba); spin_unlock_irq(&phba->hbalock); return -EAGAIN; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 3d0ccd9b341d..153afae567b5 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -63,7 +63,7 @@ lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, { if (!mp) { lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "0146 Ignoring unsolicted CT No HBQ " + "0146 Ignoring unsolicited CT No HBQ " "status = x%x\n", piocbq->iocb.ulpStatus); } @@ -438,7 +438,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) (!(vport->ct_flags & FC_CT_RFF_ID)) || (!vport->cfg_restrict_login)) { ndlp = lpfc_setup_disc_node(vport, Did); - if (ndlp) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, "Parse GID_FTrsp: " @@ -543,7 +543,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_dmabuf *outp; struct lpfc_sli_ct_request *CTrsp; struct lpfc_nodelist *ndlp; - int rc, retry; + int rc; /* First save ndlp, before we overwrite it */ ndlp = cmdiocb->context_un.ndlp; @@ -563,45 +563,29 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (vport->load_flag & FC_UNLOADING) goto out; - if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) { + if (lpfc_els_chk_latt(vport)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0216 Link event during NS query\n"); lpfc_vport_set_state(vport, FC_VPORT_FAILED); goto out; } - + if (lpfc_error_lost_link(irsp)) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "0226 NS query failed due to link event\n"); + goto out; + } if (irsp->ulpStatus) { /* Check for retry */ if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { - retry = 1; - if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (irsp->un.ulpWord[4]) { - case IOERR_NO_RESOURCES: - /* We don't increment the retry - * count for this case. - */ - break; - case IOERR_LINK_DOWN: - case IOERR_SLI_ABORTED: - case IOERR_SLI_DOWN: - retry = 0; - break; - default: - vport->fc_ns_retry++; - } - } - else + if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT || + irsp->un.ulpWord[4] != IOERR_NO_RESOURCES) vport->fc_ns_retry++; - if (retry) { - /* CT command is being retried */ - rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, + /* CT command is being retried */ + rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, vport->fc_ns_retry, 0); - if (rc == 0) { - /* success */ - goto out; - } - } + if (rc == 0) + goto out; } lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, @@ -780,7 +764,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* This is a target port, unregistered port, or the GFF_ID failed */ ndlp = lpfc_setup_disc_node(vport, did); - if (ndlp) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0242 Process x%x GFF " "NameServer Rsp Data: x%x x%x x%x\n", diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 783d1eea13ef..90272e65957a 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -503,6 +503,8 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) ndlp->nlp_sid); if (ndlp->nlp_type & NLP_FCP_INITIATOR) len += snprintf(buf+len, size-len, "FCP_INITIATOR "); + len += snprintf(buf+len, size-len, "usgmap:%x ", + ndlp->nlp_usg_map); len += snprintf(buf+len, size-len, "refcnt:%x", atomic_read(&ndlp->kref.refcount)); len += snprintf(buf+len, size-len, "\n"); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index cbb68a942255..886c5f1b11d2 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -719,9 +719,9 @@ lpfc_els_abort_flogi(struct lpfc_hba *phba) if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR && icmd->un.elsreq64.bdl.ulpIoTag32) { ndlp = (struct lpfc_nodelist *)(iocb->context1); - if (ndlp && (ndlp->nlp_DID == Fabric_DID)) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + (ndlp->nlp_DID == Fabric_DID)) lpfc_sli_issue_abort_iotag(phba, pring, iocb); - } } } spin_unlock_irq(&phba->hbalock); @@ -829,7 +829,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, struct fc_rport *rport; struct serv_parm *sp; uint8_t name[sizeof(struct lpfc_name)]; - uint32_t rc; + uint32_t rc, keepDID = 0; /* Fabric nodes can have the same WWPN so we don't bother searching * by WWPN. Just return the ndlp that was given to us. @@ -858,11 +858,17 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, return ndlp; lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID); } else if (!NLP_CHK_NODE_ACT(new_ndlp)) { + rc = memcmp(&ndlp->nlp_portname, name, + sizeof(struct lpfc_name)); + if (!rc) + return ndlp; new_ndlp = lpfc_enable_node(vport, new_ndlp, NLP_STE_UNUSED_NODE); if (!new_ndlp) return ndlp; - } + keepDID = new_ndlp->nlp_DID; + } else + keepDID = new_ndlp->nlp_DID; lpfc_unreg_rpi(vport, new_ndlp); new_ndlp->nlp_DID = ndlp->nlp_DID; @@ -893,12 +899,24 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, } new_ndlp->nlp_type = ndlp->nlp_type; } + /* We shall actually free the ndlp with both nlp_DID and + * nlp_portname fields equals 0 to avoid any ndlp on the + * nodelist never to be used. + */ + if (ndlp->nlp_DID == 0) { + spin_lock_irq(&phba->ndlp_lock); + NLP_SET_FREE_REQ(ndlp); + spin_unlock_irq(&phba->ndlp_lock); + } + /* Two ndlps cannot have the same did on the nodelist */ + ndlp->nlp_DID = keepDID; lpfc_drop_node(vport, ndlp); } else { lpfc_unreg_rpi(vport, ndlp); - ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */ + /* Two ndlps cannot have the same did */ + ndlp->nlp_DID = keepDID; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); } return new_ndlp; @@ -2091,7 +2109,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } phba->fc_stat.elsXmitRetry++; - if (ndlp && delay) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp) && delay) { phba->fc_stat.elsDelayRetry++; ndlp->nlp_retry = cmdiocb->retry; @@ -2121,7 +2139,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_issue_els_fdisc(vport, ndlp, cmdiocb->retry); return 1; case ELS_CMD_PLOGI: - if (ndlp) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); @@ -2302,7 +2320,7 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); - if (ndlp) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { lpfc_nlp_put(ndlp); /* This is the end of the default RPI cleanup logic for this * ndlp. If no other discovery threads are using this ndlp. @@ -2335,7 +2353,8 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * function can have cmdiocb->contest1 (ndlp) field set to NULL. */ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt); - if (ndlp && (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) { /* A LS_RJT associated with Default RPI cleanup has its own * seperate code path. */ @@ -2344,7 +2363,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } /* Check to see if link went down during discovery */ - if (!ndlp || lpfc_els_chk_latt(vport)) { + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || lpfc_els_chk_latt(vport)) { if (mbox) { mp = (struct lpfc_dmabuf *) mbox->context1; if (mp) { @@ -2353,7 +2372,8 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } mempool_free(mbox, phba->mbox_mem_pool); } - if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI)) + if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + (ndlp->nlp_flag & NLP_RM_DFLT_RPI)) if (lpfc_nlp_not_used(ndlp)) { ndlp = NULL; /* Indicate the node has already released, @@ -2443,7 +2463,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, mempool_free(mbox, phba->mbox_mem_pool); } out: - if (ndlp) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI); spin_unlock_irq(shost->host_lock); @@ -3139,6 +3159,8 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* Another thread is walking fc_rscn_id_list on this vport */ spin_unlock_irq(shost->host_lock); vport->fc_flag |= FC_RSCN_DISCOVERY; + /* Send back ACC */ + lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); return 0; } /* Indicate we are walking fc_rscn_id_list on this vport */ @@ -3928,7 +3950,7 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) else { struct lpfc_nodelist *ndlp; ndlp = __lpfc_findnode_rpi(vport, cmd->ulpContext); - if (ndlp) + if (ndlp && NLP_CHK_NODE_ACT(ndlp)) remote_ID = ndlp->nlp_DID; } lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, @@ -4097,21 +4119,22 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, newnode = 1; if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) ndlp->nlp_type |= NLP_FABRIC; - } else { - if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - goto dropit; - } - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { - /* This is simular to the new node path */ - ndlp = lpfc_nlp_get(ndlp); - if (!ndlp) - goto dropit; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - newnode = 1; - } + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, + NLP_STE_UNUSED_NODE); + if (!ndlp) + goto dropit; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + newnode = 1; + if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) + ndlp->nlp_type |= NLP_FABRIC; + } else if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { + /* This is similar to the new node path */ + ndlp = lpfc_nlp_get(ndlp); + if (!ndlp) + goto dropit; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + newnode = 1; } phba->fc_stat.elsRcvFrame++; @@ -4451,7 +4474,6 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) return; } lpfc_nlp_init(vport, ndlp, NameServer_DID); - ndlp->nlp_type |= NLP_FABRIC; } else if (!NLP_CHK_NODE_ACT(ndlp)) { ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); if (!ndlp) { @@ -4465,6 +4487,7 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) return; } } + ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); @@ -4481,8 +4504,8 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) if (ndlp_fdmi) { lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID); ndlp_fdmi->nlp_type |= NLP_FABRIC; - ndlp_fdmi->nlp_state = - NLP_STE_PLOGI_ISSUE; + lpfc_nlp_set_state(vport, ndlp_fdmi, + NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, 0); } @@ -5074,39 +5097,3 @@ void lpfc_fabric_abort_hba(struct lpfc_hba *phba) (piocb->iocb_cmpl) (phba, piocb, piocb); } } - - -#if 0 -void lpfc_fabric_abort_flogi(struct lpfc_hba *phba) -{ - LIST_HEAD(completions); - struct lpfc_iocbq *tmp_iocb, *piocb; - IOCB_t *cmd; - struct lpfc_nodelist *ndlp; - - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list, - list) { - - cmd = &piocb->iocb; - ndlp = (struct lpfc_nodelist *) piocb->context1; - if (cmd->ulpCommand == CMD_ELS_REQUEST64_CR && - ndlp != NULL && - ndlp->nlp_DID == Fabric_DID) - list_move_tail(&piocb->list, &completions); - } - spin_unlock_irq(&phba->hbalock); - - while (!list_empty(&completions)) { - piocb = list_get_first(&completions, struct lpfc_iocbq, list); - list_del_init(&piocb->list); - - cmd = &piocb->iocb; - cmd->ulpStatus = IOSTAT_LOCAL_REJECT; - cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; - (piocb->iocb_cmpl) (phba, piocb, piocb); - } -} -#endif /* 0 */ - - diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 976653440fba..7cb68feb04fd 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -69,7 +69,7 @@ lpfc_terminate_rport_io(struct fc_rport *rport) rdata = rport->dd_data; ndlp = rdata->pnode; - if (!ndlp) { + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) printk(KERN_ERR "Cannot find remote node" " to terminate I/O Data x%x\n", @@ -114,7 +114,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) rdata = rport->dd_data; ndlp = rdata->pnode; - if (!ndlp) + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) return; vport = ndlp->vport; @@ -243,8 +243,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) if (warn_on) { lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, "0203 Devloss timeout on " - "WWPN %x:%x:%x:%x:%x:%x:%x:%x " - "NPort x%x Data: x%x x%x x%x\n", + "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " + "NPort x%06x Data: x%x x%x x%x\n", *name, *(name+1), *(name+2), *(name+3), *(name+4), *(name+5), *(name+6), *(name+7), ndlp->nlp_DID, ndlp->nlp_flag, @@ -252,8 +252,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0204 Devloss timeout on " - "WWPN %x:%x:%x:%x:%x:%x:%x:%x " - "NPort x%x Data: x%x x%x x%x\n", + "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " + "NPort x%06x Data: x%x x%x x%x\n", *name, *(name+1), *(name+2), *(name+3), *(name+4), *(name+5), *(name+6), *(name+7), ndlp->nlp_DID, ndlp->nlp_flag, @@ -399,7 +399,10 @@ lpfc_work_done(struct lpfc_hba *phba) vport = vports[i]; if (vport == NULL) break; + spin_lock_irq(&vport->work_port_lock); work_port_events = vport->work_port_events; + vport->work_port_events &= ~work_port_events; + spin_unlock_irq(&vport->work_port_lock); if (work_port_events & WORKER_DISC_TMO) lpfc_disc_timeout_handler(vport); if (work_port_events & WORKER_ELS_TMO) @@ -416,9 +419,6 @@ lpfc_work_done(struct lpfc_hba *phba) lpfc_ramp_down_queue_handler(phba); if (work_port_events & WORKER_RAMP_UP_QUEUE) lpfc_ramp_up_queue_handler(phba); - spin_lock_irq(&vport->work_port_lock); - vport->work_port_events &= ~work_port_events; - spin_unlock_irq(&vport->work_port_lock); } lpfc_destroy_vport_work_array(phba, vports); @@ -430,10 +430,10 @@ lpfc_work_done(struct lpfc_hba *phba) if (pring->flag & LPFC_STOP_IOCB_EVENT) { pring->flag |= LPFC_DEFERRED_RING_EVENT; } else { + pring->flag &= ~LPFC_DEFERRED_RING_EVENT; lpfc_sli_handle_slow_ring_event(phba, pring, (status & HA_RXMASK)); - pring->flag &= ~LPFC_DEFERRED_RING_EVENT; } /* * Turn on Ring interrupts @@ -519,7 +519,9 @@ lpfc_do_work(void *p) schedule(); } } + spin_lock_irq(&phba->hbalock); phba->work_wait = NULL; + spin_unlock_irq(&phba->hbalock); return 0; } @@ -809,11 +811,9 @@ out: mempool_free(pmb, phba->mbox_mem_pool); spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_ABORT_DISCOVERY | FC_ESTABLISH_LINK); + vport->fc_flag &= ~FC_ABORT_DISCOVERY; spin_unlock_irq(shost->host_lock); - del_timer_sync(&phba->fc_estabtmo); - lpfc_can_disctmo(vport); /* turn on Link Attention interrupts */ @@ -1340,10 +1340,14 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) i++) { if (vports[i]->port_type == LPFC_PHYSICAL_PORT) continue; + if (phba->fc_topology == TOPOLOGY_LOOP) { + lpfc_vport_set_state(vports[i], + FC_VPORT_LINKDOWN); + continue; + } if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) lpfc_initial_fdisc(vports[i]); - else if (phba->sli3_options & - LPFC_SLI3_NPIV_ENABLED) { + else { lpfc_vport_set_state(vports[i], FC_VPORT_NO_FABRIC_SUPP); lpfc_printf_vlog(vport, KERN_ERR, @@ -2190,10 +2194,6 @@ lpfc_matchdid(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (did == Bcast_DID) return 0; - if (ndlp->nlp_DID == 0) { - return 0; - } - /* First check for Direct match */ if (ndlp->nlp_DID == did) return 1; @@ -2301,7 +2301,8 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) return ndlp; } - if (vport->fc_flag & FC_RSCN_MODE) { + if ((vport->fc_flag & FC_RSCN_MODE) && + !(vport->fc_flag & FC_NDISC_ACTIVE)) { if (lpfc_rscn_payload_check(vport, did)) { /* If we've already recieved a PLOGI from this NPort * we don't need to try to discover it again. @@ -2947,24 +2948,6 @@ __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) return NULL; } -#if 0 -/* - * Search node lists for a remote port matching filter criteria - * Caller needs to hold host_lock before calling this routine. - */ -struct lpfc_nodelist * -lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp; - - spin_lock_irq(shost->host_lock); - ndlp = __lpfc_find_node(vport, filter, param); - spin_unlock_irq(shost->host_lock); - return ndlp; -} -#endif /* 0 */ - /* * This routine looks up the ndlp lists for the given RPI. If rpi found it * returns the node list element pointer else return NULL. @@ -2975,20 +2958,6 @@ __lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) return __lpfc_find_node(vport, lpfc_filter_by_rpi, &rpi); } -#if 0 -struct lpfc_nodelist * -lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp; - - spin_lock_irq(shost->host_lock); - ndlp = __lpfc_findnode_rpi(vport, rpi); - spin_unlock_irq(shost->host_lock); - return ndlp; -} -#endif /* 0 */ - /* * This routine looks up the ndlp lists for the given WWPN. If WWPN found it * returns the node element list pointer else return NULL. diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 22843751c2ca..fa757b251f82 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -559,8 +559,10 @@ lpfc_hb_timeout(unsigned long ptr) phba->pport->work_port_events |= WORKER_HB_TMO; spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); + spin_lock_irqsave(&phba->hbalock, iflag); if (phba->work_wait) wake_up(phba->work_wait); + spin_unlock_irqrestore(&phba->hbalock, iflag); return; } @@ -714,12 +716,10 @@ lpfc_handle_eratt(struct lpfc_hba *phba) struct lpfc_vport *vport = phba->pport; struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; - struct lpfc_vport **vports; uint32_t event_data; unsigned long temperature; struct temp_event temp_event_data; struct Scsi_Host *shost; - int i; /* If the pci channel is offline, ignore possible errors, * since we cannot communicate with the pci card anyway. */ @@ -729,25 +729,14 @@ lpfc_handle_eratt(struct lpfc_hba *phba) if (!phba->cfg_enable_hba_reset) return; - if (phba->work_hs & HS_FFER6 || - phba->work_hs & HS_FFER5) { + if (phba->work_hs & HS_FFER6) { /* Re-establishing Link */ lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, "1301 Re-establishing Link " "Data: x%x x%x x%x\n", phba->work_hs, phba->work_status[0], phba->work_status[1]); - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for(i = 0; - i <= phba->max_vpi && vports[i] != NULL; - i++){ - shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(shost->host_lock); - vports[i]->fc_flag |= FC_ESTABLISH_LINK; - spin_unlock_irq(shost->host_lock); - } - lpfc_destroy_vport_work_array(phba, vports); + spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~LPFC_SLI2_ACTIVE; spin_unlock_irq(&phba->hbalock); @@ -761,7 +750,6 @@ lpfc_handle_eratt(struct lpfc_hba *phba) pring = &psli->ring[psli->fcp_ring]; lpfc_sli_abort_iocb_ring(phba, pring); - /* * There was a firmware error. Take the hba offline and then * attempt to restart it. @@ -770,7 +758,6 @@ lpfc_handle_eratt(struct lpfc_hba *phba) lpfc_offline(phba); lpfc_sli_brdrestart(phba); if (lpfc_online(phba) == 0) { /* Initialize the HBA */ - mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60); lpfc_unblock_mgmt_io(phba); return; } @@ -1454,6 +1441,13 @@ lpfc_cleanup(struct lpfc_vport *vport) NLP_SET_FREE_REQ(ndlp); spin_unlock_irq(&phba->ndlp_lock); + if (vport->port_type != LPFC_PHYSICAL_PORT && + ndlp->nlp_DID == Fabric_DID) { + /* Just free up ndlp with Fabric_DID for vports */ + lpfc_nlp_put(ndlp); + continue; + } + if (ndlp->nlp_type & NLP_FABRIC) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); @@ -1491,31 +1485,6 @@ lpfc_cleanup(struct lpfc_vport *vport) return; } -static void -lpfc_establish_link_tmo(unsigned long ptr) -{ - struct lpfc_hba *phba = (struct lpfc_hba *) ptr; - struct lpfc_vport **vports; - unsigned long iflag; - int i; - - /* Re-establishing Link, timer expired */ - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1300 Re-establishing Link, timer expired " - "Data: x%x x%x\n", - phba->pport->fc_flag, phba->pport->port_state); - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { - struct Scsi_Host *shost; - shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irqsave(shost->host_lock, iflag); - vports[i]->fc_flag &= ~FC_ESTABLISH_LINK; - spin_unlock_irqrestore(shost->host_lock, iflag); - } - lpfc_destroy_vport_work_array(phba, vports); -} - void lpfc_stop_vport_timers(struct lpfc_vport *vport) { @@ -1529,7 +1498,6 @@ static void lpfc_stop_phba_timers(struct lpfc_hba *phba) { del_timer_sync(&phba->fcp_poll_timer); - del_timer_sync(&phba->fc_estabtmo); lpfc_stop_vport_timers(phba->pport); del_timer_sync(&phba->sli.mbox_tmo); del_timer_sync(&phba->fabric_block_timer); @@ -2005,10 +1973,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) phba->max_vpi = LPFC_MAX_VPI; /* Initialize timers used by driver */ - init_timer(&phba->fc_estabtmo); - phba->fc_estabtmo.function = lpfc_establish_link_tmo; - phba->fc_estabtmo.data = (unsigned long)phba; - init_timer(&phba->hb_tmofunc); phba->hb_tmofunc.function = lpfc_hb_timeout; phba->hb_tmofunc.data = (unsigned long)phba; @@ -2406,6 +2370,7 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; struct lpfc_sli *psli = &phba->sli; + int error, retval; dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); if (pci_enable_device_mem(pdev)) { @@ -2416,15 +2381,40 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) pci_set_master(pdev); - /* Re-establishing Link */ - spin_lock_irq(shost->host_lock); - phba->pport->fc_flag |= FC_ESTABLISH_LINK; - spin_unlock_irq(shost->host_lock); - spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~LPFC_SLI2_ACTIVE; spin_unlock_irq(&phba->hbalock); + /* Enable configured interrupt method */ + phba->intr_type = NONE; + if (phba->cfg_use_msi == 2) { + error = lpfc_enable_msix(phba); + if (!error) + phba->intr_type = MSIX; + } + + /* Fallback to MSI if MSI-X initialization failed */ + if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) { + retval = pci_enable_msi(phba->pcidev); + if (!retval) + phba->intr_type = MSI; + else + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0470 Enable MSI failed, continuing " + "with IRQ\n"); + } + + /* MSI-X is the only case the doesn't need to call request_irq */ + if (phba->intr_type != MSIX) { + retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, + IRQF_SHARED, LPFC_DRIVER_NAME, phba); + if (retval) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0471 Enable interrupt handler " + "failed\n"); + } else if (phba->intr_type != MSI) + phba->intr_type = INTx; + } /* Take device offline; this will perform cleanup */ lpfc_offline(phba); @@ -2445,9 +2435,7 @@ static void lpfc_io_resume(struct pci_dev *pdev) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - if (lpfc_online(phba) == 0) { - mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60); - } + lpfc_online(phba); } static struct pci_device_id lpfc_id_table[] = { diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index d513813f6697..d08c4c890744 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -451,7 +451,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_unlock_irq(shost->host_lock); if ((ndlp->nlp_flag & NLP_ADISC_SND) && - (vport->num_disc_nodes)) { + (vport->num_disc_nodes)) { /* Check to see if there are more * ADISCs to be sent */ @@ -469,20 +469,23 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_end_rscn(vport); } } - else if (vport->num_disc_nodes) { - /* Check to see if there are more - * PLOGIs to be sent - */ - lpfc_more_plogi(vport); - - if (vport->num_disc_nodes == 0) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); - lpfc_can_disctmo(vport); - lpfc_end_rscn(vport); - } - } + } + } else if ((ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) && + (ndlp->nlp_flag & NLP_NPR_2B_DISC) && + (vport->num_disc_nodes)) { + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + spin_unlock_irq(shost->host_lock); + /* Check to see if there are more + * PLOGIs to be sent + */ + lpfc_more_plogi(vport); + if (vport->num_disc_nodes == 0) { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_NDISC_ACTIVE; + spin_unlock_irq(shost->host_lock); + lpfc_can_disctmo(vport); + lpfc_end_rscn(vport); } } @@ -869,8 +872,11 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, lp = (uint32_t *) prsp->virt; sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); - if (wwn_to_u64(sp->portName.u.wwn) == 0 || - wwn_to_u64(sp->nodeName.u.wwn) == 0) { + + /* Some switches have FDMI servers returning 0 for WWN */ + if ((ndlp->nlp_DID != FDMI_DID) && + (wwn_to_u64(sp->portName.u.wwn) == 0 || + wwn_to_u64(sp->nodeName.u.wwn) == 0)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, "0142 PLOGI RSP: Invalid WWN.\n"); goto out; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 70255c11d3ad..0910a9ab76a5 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -169,6 +169,9 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); shost_for_each_device(sdev, shost) { + if (vports[i]->cfg_lun_queue_depth <= + sdev->queue_depth) + continue; if (sdev->ordered_tags) scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, @@ -578,14 +581,14 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, lpfc_cmd->result == IOERR_NO_RESOURCES || lpfc_cmd->result == RJT_LOGIN_REQUIRED) { cmd->result = ScsiResult(DID_REQUEUE, 0); - break; - } /* else: fall through */ + break; + } /* else: fall through */ default: cmd->result = ScsiResult(DID_ERROR, 0); break; } - if ((pnode == NULL ) + if (!pnode || !NLP_CHK_NODE_ACT(pnode) || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) cmd->result = ScsiResult(DID_BUS_BUSY, SAM_STAT_BUSY); } else { @@ -606,6 +609,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, result = cmd->result; sdev = cmd->device; lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); + spin_lock_irqsave(sdev->host->host_lock, flags); + lpfc_cmd->pCmd = NULL; /* This must be done before scsi_done */ + spin_unlock_irqrestore(sdev->host->host_lock, flags); cmd->scsi_done(cmd); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { @@ -614,7 +620,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, * wake up the thread. */ spin_lock_irqsave(sdev->host->host_lock, flags); - lpfc_cmd->pCmd = NULL; if (lpfc_cmd->waitq) wake_up(lpfc_cmd->waitq); spin_unlock_irqrestore(sdev->host->host_lock, flags); @@ -626,7 +631,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, if (!result) lpfc_rampup_queue_depth(vport, sdev); - if (!result && pnode != NULL && + if (!result && pnode && NLP_CHK_NODE_ACT(pnode) && ((jiffies - pnode->last_ramp_up_time) > LPFC_Q_RAMP_UP_INTERVAL * HZ) && ((jiffies - pnode->last_q_full_time) > @@ -654,7 +659,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, * Check for queue full. If the lun is reporting queue full, then * back off the lun queue depth to prevent target overloads. */ - if (result == SAM_STAT_TASK_SET_FULL && pnode != NULL) { + if (result == SAM_STAT_TASK_SET_FULL && pnode && + NLP_CHK_NODE_ACT(pnode)) { pnode->last_q_full_time = jiffies; shost_for_each_device(tmp_sdev, sdev->host) { @@ -684,7 +690,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, * wake up the thread. */ spin_lock_irqsave(sdev->host->host_lock, flags); - lpfc_cmd->pCmd = NULL; if (lpfc_cmd->waitq) wake_up(lpfc_cmd->waitq); spin_unlock_irqrestore(sdev->host->host_lock, flags); @@ -704,6 +709,9 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, int datadir = scsi_cmnd->sc_data_direction; char tag[2]; + if (!pnode || !NLP_CHK_NODE_ACT(pnode)) + return; + lpfc_cmd->fcp_rsp->rspSnsLen = 0; /* clear task management bits */ lpfc_cmd->fcp_cmnd->fcpCntl2 = 0; @@ -785,9 +793,9 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, struct lpfc_rport_data *rdata = lpfc_cmd->rdata; struct lpfc_nodelist *ndlp = rdata->pnode; - if ((ndlp == NULL) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || + ndlp->nlp_state != NLP_STE_MAPPED_NODE) return 0; - } piocbq = &(lpfc_cmd->cur_iocbq); piocbq->vport = vport; @@ -842,7 +850,7 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport, struct lpfc_iocbq *iocbqrsp; int ret; - if (!rdata->pnode) + if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) return FAILED; lpfc_cmd->rdata = rdata; @@ -959,7 +967,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) * Catch race where our node has transitioned, but the * transport is still transitioning. */ - if (!ndlp) { + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { cmnd->result = ScsiResult(DID_BUS_BUSY, 0); goto out_fail_command; } @@ -1146,7 +1154,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) * target is rediscovered or devloss timeout expires. */ while (1) { - if (!pnode) + if (!pnode || !NLP_CHK_NODE_ACT(pnode)) goto out; if (pnode->nlp_state != NLP_STE_MAPPED_NODE) { @@ -1162,7 +1170,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) goto out; } pnode = rdata->pnode; - if (!pnode) + if (!pnode || !NLP_CHK_NODE_ACT(pnode)) goto out; } if (pnode->nlp_state == NLP_STE_MAPPED_NODE) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index fc0d9501aba6..70a0a9eab211 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2648,7 +2648,6 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) spin_unlock_irq(&phba->pport->work_port_lock); spin_lock_irq(&phba->hbalock); phba->link_state = LPFC_LINK_UNKNOWN; - phba->pport->fc_flag |= FC_ESTABLISH_LINK; psli->sli_flag &= ~LPFC_SLI2_ACTIVE; spin_unlock_irq(&phba->hbalock); @@ -2669,8 +2668,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) lpfc_offline_prep(phba); lpfc_offline(phba); lpfc_sli_brdrestart(phba); - if (lpfc_online(phba) == 0) /* Initialize the HBA */ - mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60); + lpfc_online(phba); lpfc_unblock_mgmt_io(phba); return; } @@ -2687,28 +2685,41 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) unsigned long drvr_flag = 0; volatile uint32_t word0, ldata; void __iomem *to_slim; + int processing_queue = 0; + + spin_lock_irqsave(&phba->hbalock, drvr_flag); + if (!pmbox) { + /* processing mbox queue from intr_handler */ + processing_queue = 1; + phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + pmbox = lpfc_mbox_get(phba); + if (!pmbox) { + spin_unlock_irqrestore(&phba->hbalock, drvr_flag); + return MBX_SUCCESS; + } + } if (pmbox->mbox_cmpl && pmbox->mbox_cmpl != lpfc_sli_def_mbox_cmpl && pmbox->mbox_cmpl != lpfc_sli_wake_mbox_wait) { if(!pmbox->vport) { + spin_unlock_irqrestore(&phba->hbalock, drvr_flag); lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT, "1806 Mbox x%x failed. No vport\n", pmbox->mb.mbxCommand); dump_stack(); - return MBX_NOT_FINISHED; + goto out_not_finished; } } - /* If the PCI channel is in offline state, do not post mbox. */ - if (unlikely(pci_channel_offline(phba->pcidev))) - return MBX_NOT_FINISHED; + if (unlikely(pci_channel_offline(phba->pcidev))) { + spin_unlock_irqrestore(&phba->hbalock, drvr_flag); + goto out_not_finished; + } - spin_lock_irqsave(&phba->hbalock, drvr_flag); psli = &phba->sli; - mb = &pmbox->mb; status = MBX_SUCCESS; @@ -2717,14 +2728,14 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) /* Mbox command <mbxCommand> cannot issue */ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag); - return MBX_NOT_FINISHED; + goto out_not_finished; } if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT && !(readl(phba->HCregaddr) & HC_MBINT_ENA)) { spin_unlock_irqrestore(&phba->hbalock, drvr_flag); LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag); - return MBX_NOT_FINISHED; + goto out_not_finished; } if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { @@ -2738,14 +2749,14 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) /* Mbox command <mbxCommand> cannot issue */ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag); - return MBX_NOT_FINISHED; + goto out_not_finished; } if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) { spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command <mbxCommand> cannot issue */ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag); - return MBX_NOT_FINISHED; + goto out_not_finished; } /* Another mailbox command is still being processed, queue this @@ -2792,7 +2803,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command <mbxCommand> cannot issue */ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag); - return MBX_NOT_FINISHED; + goto out_not_finished; } /* timeout active mbox command */ mod_timer(&psli->mbox_tmo, (jiffies + @@ -2900,7 +2911,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - return MBX_NOT_FINISHED; + goto out_not_finished; } /* Check if we took a mbox interrupt while we were @@ -2967,6 +2978,13 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) spin_unlock_irqrestore(&phba->hbalock, drvr_flag); return status; + +out_not_finished: + if (processing_queue) { + pmbox->mb.mbxStatus = MBX_NOT_FINISHED; + lpfc_mbox_cmpl_put(phba, pmbox); + } + return MBX_NOT_FINISHED; } /* @@ -3463,26 +3481,21 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) phba->pport->work_port_events &= ~WORKER_MBOX_TMO; spin_unlock(&phba->pport->work_port_lock); + /* Return any pending or completed mbox cmds */ + list_splice_init(&phba->sli.mboxq, &completions); if (psli->mbox_active) { list_add_tail(&psli->mbox_active->list, &completions); psli->mbox_active = NULL; psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; } - - /* Return any pending or completed mbox cmds */ - list_splice_init(&phba->sli.mboxq, &completions); list_splice_init(&phba->sli.mboxq_cmpl, &completions); - INIT_LIST_HEAD(&psli->mboxq); - INIT_LIST_HEAD(&psli->mboxq_cmpl); - spin_unlock_irqrestore(&phba->hbalock, flags); while (!list_empty(&completions)) { list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list); pmb->mb.mbxStatus = MBX_NOT_FINISHED; - if (pmb->mbox_cmpl) { + if (pmb->mbox_cmpl) pmb->mbox_cmpl(phba,pmb); - } } return 1; } @@ -3613,6 +3626,15 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpStatus, irsp->un.ulpWord[4]); /* + * If the iocb is not found in Firmware queue the iocb + * might have completed already. Do not free it again. + */ + if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { + spin_unlock_irq(&phba->hbalock); + lpfc_sli_release_iocbq(phba, cmdiocb); + return; + } + /* * make sure we have the right iocbq before taking it * off the txcmplq and try to call completion routine. */ @@ -4174,6 +4196,7 @@ lpfc_intr_handler(int irq, void *dev_id) phba->pport->stopped = 1; } + spin_lock(&phba->hbalock); if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) { pmb = phba->sli.mbox_active; @@ -4184,6 +4207,7 @@ lpfc_intr_handler(int irq, void *dev_id) /* First check out the status word */ lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof(uint32_t)); if (pmbox->mbxOwner != OWN_HOST) { + spin_unlock(&phba->hbalock); /* * Stray Mailbox Interrupt, mbxCommand <cmd> * mbxStatus <status> @@ -4199,10 +4223,10 @@ lpfc_intr_handler(int irq, void *dev_id) /* clear mailbox attention bit */ work_ha_copy &= ~HA_MBATT; } else { + phba->sli.mbox_active = NULL; + spin_unlock(&phba->hbalock); phba->last_completion_time = jiffies; del_timer(&phba->sli.mbox_tmo); - - phba->sli.mbox_active = NULL; if (pmb->mbox_cmpl) { lpfc_sli_pcimem_bcopy(mbox, pmbox, MAILBOX_CMD_SIZE); @@ -4237,10 +4261,15 @@ lpfc_intr_handler(int irq, void *dev_id) pmb->context1 = mp; pmb->context2 = ndlp; pmb->vport = vport; - spin_lock(&phba->hbalock); - phba->sli.sli_flag &= - ~LPFC_SLI_MBOX_ACTIVE; - spin_unlock(&phba->hbalock); + rc = lpfc_sli_issue_mbox(phba, + pmb, + MBX_NOWAIT); + if (rc != MBX_BUSY) + lpfc_printf_log(phba, + KERN_ERR, + LOG_MBOX | LOG_SLI, + "0306 rc should have" + "been MBX_BUSY"); goto send_current_mbox; } } @@ -4250,25 +4279,20 @@ lpfc_intr_handler(int irq, void *dev_id) spin_unlock(&phba->pport->work_port_lock); lpfc_mbox_cmpl_put(phba, pmb); } - } + } else + spin_unlock(&phba->hbalock); if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active == NULL)) { -send_next_mbox: - spin_lock(&phba->hbalock); - phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - pmb = lpfc_mbox_get(phba); - spin_unlock(&phba->hbalock); send_current_mbox: /* Process next mailbox command if there is one */ - if (pmb != NULL) { - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - pmb->mb.mbxStatus = MBX_NOT_FINISHED; - lpfc_mbox_cmpl_put(phba, pmb); - goto send_next_mbox; - } - } - + do { + rc = lpfc_sli_issue_mbox(phba, NULL, + MBX_NOWAIT); + } while (rc == MBX_NOT_FINISHED); + if (rc != MBX_SUCCESS) + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | + LOG_SLI, "0349 rc should be " + "MBX_SUCCESS"); } spin_lock(&phba->hbalock); diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index ca540d1d041e..b22b893019f4 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.2.5" +#define LPFC_DRIVER_VERSION "8.2.6" #define LPFC_DRIVER_NAME "lpfc" diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 86d05beb00b8..6feaf59b0b1b 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -538,7 +538,8 @@ lpfc_vport_delete(struct fc_vport *fc_vport) /* Otherwise, we will perform fabric logo as needed */ if (ndlp && NLP_CHK_NODE_ACT(ndlp) && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && - phba->link_state >= LPFC_LINK_UP) { + phba->link_state >= LPFC_LINK_UP && + phba->fc_topology != TOPOLOGY_LOOP) { if (vport->cfg_enable_da_id) { timeout = msecs_to_jiffies(phba->fc_ratov * 2000); if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0)) diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 3b09ab21d701..0248919bc2df 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -592,7 +592,6 @@ static struct scsi_host_template driver_template = { .this_id = 7, .sg_tablesize = SG_ALL, .cmd_per_lun = CMD_PER_LUN, - .unchecked_isa_dma = 0, .use_clustering = DISABLE_CLUSTERING }; diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 77a62a1b12c3..b937e9cddb23 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -68,6 +68,8 @@ static struct pci_device_id megasas_pci_table[] = { /* xscale IOP */ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078R)}, /* ppc IOP */ + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078DE)}, + /* ppc IOP */ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)}, /* xscale IOP, vega */ {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)}, @@ -488,12 +490,13 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp, /** * megasas_get_frame_count - Computes the number of frames + * @frame_type : type of frame- io or pthru frame * @sge_count : number of sg elements * * Returns the number of frames required for numnber of sge's (sge_count) */ -static u32 megasas_get_frame_count(u8 sge_count) +static u32 megasas_get_frame_count(u8 sge_count, u8 frame_type) { int num_cnt; int sge_bytes; @@ -504,13 +507,22 @@ static u32 megasas_get_frame_count(u8 sge_count) sizeof(struct megasas_sge32); /* - * Main frame can contain 2 SGEs for 64-bit SGLs and - * 3 SGEs for 32-bit SGLs - */ - if (IS_DMA64) - num_cnt = sge_count - 2; - else - num_cnt = sge_count - 3; + * Main frame can contain 2 SGEs for 64-bit SGLs and + * 3 SGEs for 32-bit SGLs for ldio & + * 1 SGEs for 64-bit SGLs and + * 2 SGEs for 32-bit SGLs for pthru frame + */ + if (unlikely(frame_type == PTHRU_FRAME)) { + if (IS_DMA64) + num_cnt = sge_count - 1; + else + num_cnt = sge_count - 2; + } else { + if (IS_DMA64) + num_cnt = sge_count - 2; + else + num_cnt = sge_count - 3; + } if(num_cnt>0){ sge_bytes = sge_sz * num_cnt; @@ -592,7 +604,8 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp, * Compute the total number of frames this command consumes. FW uses * this number to pull sufficient number of frames from host memory. */ - cmd->frame_count = megasas_get_frame_count(pthru->sge_count); + cmd->frame_count = megasas_get_frame_count(pthru->sge_count, + PTHRU_FRAME); return cmd->frame_count; } @@ -709,7 +722,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, * Compute the total number of frames this command consumes. FW uses * this number to pull sufficient number of frames from host memory. */ - cmd->frame_count = megasas_get_frame_count(ldio->sge_count); + cmd->frame_count = megasas_get_frame_count(ldio->sge_count, IO_FRAME); return cmd->frame_count; } @@ -1460,7 +1473,7 @@ megasas_transition_to_ready(struct megasas_instance* instance) instance->instancet->disable_intr(instance->reg_set); writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell); - max_wait = 10; + max_wait = 60; cur_state = MFI_STATE_OPERATIONAL; break; @@ -1980,7 +1993,8 @@ static int megasas_init_mfi(struct megasas_instance *instance) switch(instance->pdev->device) { - case PCI_DEVICE_ID_LSI_SAS1078R: + case PCI_DEVICE_ID_LSI_SAS1078R: + case PCI_DEVICE_ID_LSI_SAS1078DE: instance->instancet = &megasas_instance_template_ppc; break; case PCI_DEVICE_ID_LSI_SAS1064R: @@ -2909,7 +2923,6 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, void *sense = NULL; dma_addr_t sense_handle; u32 *sense_ptr; - unsigned long *sense_buff; memset(kbuff_arr, 0, sizeof(kbuff_arr)); @@ -3014,14 +3027,14 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, */ if (ioc->sense_len) { /* - * sense_buff points to the location that has the user + * sense_ptr points to the location that has the user * sense buffer address */ - sense_buff = (unsigned long *) ((unsigned long)ioc->frame.raw + - ioc->sense_off); + sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw + + ioc->sense_off); - if (copy_to_user((void __user *)(unsigned long)(*sense_buff), - sense, ioc->sense_len)) { + if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)), + sense, ioc->sense_len)) { printk(KERN_ERR "megasas: Failed to copy out to user " "sense data\n"); error = -EFAULT; diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 6466bdf548c2..3a997eb457bf 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -26,6 +26,7 @@ * Device IDs */ #define PCI_DEVICE_ID_LSI_SAS1078R 0x0060 +#define PCI_DEVICE_ID_LSI_SAS1078DE 0x007C #define PCI_DEVICE_ID_LSI_VERDE_ZCR 0x0413 /* @@ -542,6 +543,10 @@ struct megasas_ctrl_info { #define MEGASAS_FW_BUSY 1 +/* Frame Type */ +#define IO_FRAME 0 +#define PTHRU_FRAME 1 + /* * When SCSI mid-layer calls driver's reset routine, driver waits for * MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c index be41aadccae5..d722235111a8 100644 --- a/drivers/scsi/mvme147.c +++ b/drivers/scsi/mvme147.c @@ -82,6 +82,9 @@ int mvme147_detect(struct scsi_host_template *tpnt) mvme147_host->irq = MVME147_IRQ_SCSI_PORT; regs.SASR = (volatile unsigned char *)0xfffe4000; regs.SCMD = (volatile unsigned char *)0xfffe4001; + HDATA(mvme147_host)->no_sync = 0xff; + HDATA(mvme147_host)->fast = 0; + HDATA(mvme147_host)->dma_mode = CTRL_DMA; wd33c93_init(mvme147_host, regs, dma_setup, dma_stop, WD33C93_FS_8_10); if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0, "MVME147 SCSI PORT", mvme147_intr)) diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c index fad6cb5cba28..ce48e2d0193c 100644 --- a/drivers/scsi/ps3rom.c +++ b/drivers/scsi/ps3rom.c @@ -26,6 +26,7 @@ #include <scsi/scsi_dbg.h> #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> +#include <scsi/scsi_eh.h> #include <asm/lv1call.h> #include <asm/ps3stor.h> @@ -90,78 +91,6 @@ static int ps3rom_slave_configure(struct scsi_device *scsi_dev) return 0; } -/* - * copy data from device into scatter/gather buffer - */ -static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf) -{ - int k, req_len, act_len, len, active; - void *kaddr; - struct scatterlist *sgpnt; - unsigned int buflen; - - buflen = scsi_bufflen(cmd); - if (!buflen) - return 0; - - if (!scsi_sglist(cmd)) - return -1; - - active = 1; - req_len = act_len = 0; - scsi_for_each_sg(cmd, sgpnt, scsi_sg_count(cmd), k) { - if (active) { - kaddr = kmap_atomic(sg_page(sgpnt), KM_IRQ0); - len = sgpnt->length; - if ((req_len + len) > buflen) { - active = 0; - len = buflen - req_len; - } - memcpy(kaddr + sgpnt->offset, buf + req_len, len); - flush_kernel_dcache_page(sg_page(sgpnt)); - kunmap_atomic(kaddr, KM_IRQ0); - act_len += len; - } - req_len += sgpnt->length; - } - scsi_set_resid(cmd, buflen - act_len); - return 0; -} - -/* - * copy data from scatter/gather into device's buffer - */ -static int fetch_to_dev_buffer(struct scsi_cmnd *cmd, void *buf) -{ - int k, req_len, len, fin; - void *kaddr; - struct scatterlist *sgpnt; - unsigned int buflen; - - buflen = scsi_bufflen(cmd); - if (!buflen) - return 0; - - if (!scsi_sglist(cmd)) - return -1; - - req_len = fin = 0; - scsi_for_each_sg(cmd, sgpnt, scsi_sg_count(cmd), k) { - kaddr = kmap_atomic(sg_page(sgpnt), KM_IRQ0); - len = sgpnt->length; - if ((req_len + len) > buflen) { - len = buflen - req_len; - fin = 1; - } - memcpy(buf + req_len, kaddr + sgpnt->offset, len); - kunmap_atomic(kaddr, KM_IRQ0); - if (fin) - return req_len + len; - req_len += sgpnt->length; - } - return req_len; -} - static int ps3rom_atapi_request(struct ps3_storage_device *dev, struct scsi_cmnd *cmd) { @@ -195,9 +124,7 @@ static int ps3rom_atapi_request(struct ps3_storage_device *dev, else atapi_cmnd.proto = PIO_DATA_OUT_PROTO; atapi_cmnd.in_out = DIR_WRITE; - res = fetch_to_dev_buffer(cmd, dev->bounce_buf); - if (res < 0) - return DID_ERROR << 16; + scsi_sg_copy_to_buffer(cmd, dev->bounce_buf, dev->bounce_size); break; default: @@ -269,9 +196,7 @@ static int ps3rom_write_request(struct ps3_storage_device *dev, dev_dbg(&dev->sbd.core, "%s:%u: write %u sectors starting at %u\n", __func__, __LINE__, sectors, start_sector); - res = fetch_to_dev_buffer(cmd, dev->bounce_buf); - if (res < 0) - return DID_ERROR << 16; + scsi_sg_copy_to_buffer(cmd, dev->bounce_buf, dev->bounce_size); res = lv1_storage_write(dev->sbd.dev_id, dev->regions[dev->region_idx].id, start_sector, @@ -381,11 +306,13 @@ static irqreturn_t ps3rom_interrupt(int irq, void *data) if (!status) { /* OK, completed */ if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - res = fill_from_dev_buffer(cmd, dev->bounce_buf); - if (res) { - cmd->result = DID_ERROR << 16; - goto done; - } + int len; + + len = scsi_sg_copy_from_buffer(cmd, + dev->bounce_buf, + dev->bounce_size); + + scsi_set_resid(cmd, scsi_bufflen(cmd) - len); } cmd->result = DID_OK << 16; goto done; @@ -404,11 +331,7 @@ static irqreturn_t ps3rom_interrupt(int irq, void *data) goto done; } - cmd->sense_buffer[0] = 0x70; - cmd->sense_buffer[2] = sense_key; - cmd->sense_buffer[7] = 16 - 6; - cmd->sense_buffer[12] = asc; - cmd->sense_buffer[13] = ascq; + scsi_build_sense_buffer(0, cmd->sense_buffer, sense_key, asc, ascq); cmd->result = SAM_STAT_CHECK_CONDITION; done: @@ -427,7 +350,7 @@ static struct scsi_host_template ps3rom_host_template = { .cmd_per_lun = 1, .emulated = 1, /* only sg driver uses this */ .max_sectors = PS3ROM_MAX_SECTORS, - .use_clustering = DISABLE_CLUSTERING, + .use_clustering = ENABLE_CLUSTERING, .module = THIS_MODULE, }; diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 68c0d09ffe78..09ab3eac1c1a 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -333,7 +333,6 @@ #include <linux/module.h> -#include <linux/version.h> #include <linux/types.h> #include <linux/string.h> #include <linux/errno.h> @@ -367,10 +366,6 @@ #include <asm/sn/io.h> #endif -#if LINUX_VERSION_CODE < 0x020600 -#error "Kernels older than 2.6.0 are no longer supported" -#endif - /* * Compile time Options: diff --git a/drivers/scsi/qla2xxx/Kconfig b/drivers/scsi/qla2xxx/Kconfig index 8c865b9e02b5..6208d562890d 100644 --- a/drivers/scsi/qla2xxx/Kconfig +++ b/drivers/scsi/qla2xxx/Kconfig @@ -16,7 +16,8 @@ config SCSI_QLA_FC 22xx ql2200_fw.bin 2300, 2312, 6312 ql2300_fw.bin 2322, 6322 ql2322_fw.bin - 24xx ql2400_fw.bin + 24xx, 54xx ql2400_fw.bin + 25xx ql2500_fw.bin Upon request, the driver caches the firmware image until the driver is unloaded. diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 4894dc886b62..413d8cd6a324 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -849,20 +849,20 @@ static void qla2x00_get_host_speed(struct Scsi_Host *shost) { scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost)); - uint32_t speed = 0; + u32 speed = FC_PORTSPEED_UNKNOWN; switch (ha->link_data_rate) { case PORT_SPEED_1GB: - speed = 1; + speed = FC_PORTSPEED_1GBIT; break; case PORT_SPEED_2GB: - speed = 2; + speed = FC_PORTSPEED_2GBIT; break; case PORT_SPEED_4GB: - speed = 4; + speed = FC_PORTSPEED_4GBIT; break; case PORT_SPEED_8GB: - speed = 8; + speed = FC_PORTSPEED_8GBIT; break; } fc_host_speed(shost) = speed; @@ -900,7 +900,8 @@ qla2x00_get_starget_node_name(struct scsi_target *starget) u64 node_name = 0; list_for_each_entry(fcport, &ha->fcports, list) { - if (starget->id == fcport->os_target_id) { + if (fcport->rport && + starget->id == fcport->rport->scsi_target_id) { node_name = wwn_to_u64(fcport->node_name); break; } @@ -918,7 +919,8 @@ qla2x00_get_starget_port_name(struct scsi_target *starget) u64 port_name = 0; list_for_each_entry(fcport, &ha->fcports, list) { - if (starget->id == fcport->os_target_id) { + if (fcport->rport && + starget->id == fcport->rport->scsi_target_id) { port_name = wwn_to_u64(fcport->port_name); break; } @@ -936,7 +938,8 @@ qla2x00_get_starget_port_id(struct scsi_target *starget) uint32_t port_id = ~0U; list_for_each_entry(fcport, &ha->fcports, list) { - if (starget->id == fcport->os_target_id) { + if (fcport->rport && + starget->id == fcport->rport->scsi_target_id) { port_id = fcport->d_id.b.domain << 16 | fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa; break; @@ -1196,6 +1199,7 @@ struct fc_function_template qla2xxx_transport_functions = { .show_host_node_name = 1, .show_host_port_name = 1, .show_host_supported_classes = 1, + .show_host_supported_speeds = 1, .get_host_port_id = qla2x00_get_host_port_id, .show_host_port_id = 1, @@ -1276,9 +1280,23 @@ struct fc_function_template qla2xxx_transport_vport_functions = { void qla2x00_init_host_attr(scsi_qla_host_t *ha) { + u32 speed = FC_PORTSPEED_UNKNOWN; + fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name); fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name); fc_host_supported_classes(ha->host) = FC_COS_CLASS3; fc_host_max_npiv_vports(ha->host) = ha->max_npiv_vports;; fc_host_npiv_vports_inuse(ha->host) = ha->cur_vport_count; + + if (IS_QLA25XX(ha)) + speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | + FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; + else if (IS_QLA24XX_TYPE(ha)) + speed = FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT | + FC_PORTSPEED_1GBIT; + else if (IS_QLA23XX(ha)) + speed = FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; + else + speed = FC_PORTSPEED_1GBIT; + fc_host_supported_speeds(ha->host) = speed; } diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index d88e98c476b0..9d12d9f26209 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -1410,125 +1410,3 @@ qla2x00_dump_buffer(uint8_t * b, uint32_t size) if (cnt % 16) printk("\n"); } - -/************************************************************************** - * qla2x00_print_scsi_cmd - * Dumps out info about the scsi cmd and srb. - * Input - * cmd : struct scsi_cmnd - **************************************************************************/ -void -qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd) -{ - int i; - struct scsi_qla_host *ha; - srb_t *sp; - - ha = shost_priv(cmd->device->host); - - sp = (srb_t *) cmd->SCp.ptr; - printk("SCSI Command @=0x%p, Handle=0x%p\n", cmd, cmd->host_scribble); - printk(" chan=0x%02x, target=0x%02x, lun=0x%02x, cmd_len=0x%02x\n", - cmd->device->channel, cmd->device->id, cmd->device->lun, - cmd->cmd_len); - printk(" CDB: "); - for (i = 0; i < cmd->cmd_len; i++) { - printk("0x%02x ", cmd->cmnd[i]); - } - printk("\n seg_cnt=%d, allowed=%d, retries=%d\n", - scsi_sg_count(cmd), cmd->allowed, cmd->retries); - printk(" request buffer=0x%p, request buffer len=0x%x\n", - scsi_sglist(cmd), scsi_bufflen(cmd)); - printk(" tag=%d, transfersize=0x%x\n", - cmd->tag, cmd->transfersize); - printk(" serial_number=%lx, SP=%p\n", cmd->serial_number, sp); - printk(" data direction=%d\n", cmd->sc_data_direction); - - if (!sp) - return; - - printk(" sp flags=0x%x\n", sp->flags); -} - -#if defined(QL_DEBUG_ROUTINES) -/* - * qla2x00_formatted_dump_buffer - * Prints string plus buffer. - * - * Input: - * string = Null terminated string (no newline at end). - * buffer = buffer address. - * wd_size = word size 8, 16, 32 or 64 bits - * count = number of words. - */ -void -qla2x00_formatted_dump_buffer(char *string, uint8_t * buffer, - uint8_t wd_size, uint32_t count) -{ - uint32_t cnt; - uint16_t *buf16; - uint32_t *buf32; - - if (strcmp(string, "") != 0) - printk("%s\n",string); - - switch (wd_size) { - case 8: - printk(" 0 1 2 3 4 5 6 7 " - "8 9 Ah Bh Ch Dh Eh Fh\n"); - printk("-----------------------------------------" - "-------------------------------------\n"); - - for (cnt = 1; cnt <= count; cnt++, buffer++) { - printk("%02x",*buffer); - if (cnt % 16 == 0) - printk("\n"); - else - printk(" "); - } - if (cnt % 16 != 0) - printk("\n"); - break; - case 16: - printk(" 0 2 4 6 8 Ah " - " Ch Eh\n"); - printk("-----------------------------------------" - "-------------\n"); - - buf16 = (uint16_t *) buffer; - for (cnt = 1; cnt <= count; cnt++, buf16++) { - printk("%4x",*buf16); - - if (cnt % 8 == 0) - printk("\n"); - else if (*buf16 < 10) - printk(" "); - else - printk(" "); - } - if (cnt % 8 != 0) - printk("\n"); - break; - case 32: - printk(" 0 4 8 Ch\n"); - printk("------------------------------------------\n"); - - buf32 = (uint32_t *) buffer; - for (cnt = 1; cnt <= count; cnt++, buf32++) { - printk("%8x", *buf32); - - if (cnt % 4 == 0) - printk("\n"); - else if (*buf32 < 10) - printk(" "); - else - printk(" "); - } - if (cnt % 4 != 0) - printk("\n"); - break; - default: - break; - } -} -#endif diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 524598afc81c..2e9c0c097f5e 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -22,19 +22,7 @@ /* #define QL_DEBUG_LEVEL_13 */ /* Output fdmi function trace msgs */ /* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */ /* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */ -/* - * Local Macro Definitions. - */ -#if defined(QL_DEBUG_LEVEL_1) || defined(QL_DEBUG_LEVEL_2) || \ - defined(QL_DEBUG_LEVEL_3) || defined(QL_DEBUG_LEVEL_4) || \ - defined(QL_DEBUG_LEVEL_5) || defined(QL_DEBUG_LEVEL_6) || \ - defined(QL_DEBUG_LEVEL_7) || defined(QL_DEBUG_LEVEL_8) || \ - defined(QL_DEBUG_LEVEL_9) || defined(QL_DEBUG_LEVEL_10) || \ - defined(QL_DEBUG_LEVEL_11) || defined(QL_DEBUG_LEVEL_12) || \ - defined(QL_DEBUG_LEVEL_13) || defined(QL_DEBUG_LEVEL_14) || \ - defined(QL_DEBUG_LEVEL_15) - #define QL_DEBUG_ROUTINES -#endif +/* #define QL_DEBUG_LEVEL_16 */ /* Output ISP84XX trace msgs */ /* * Macros use for debugging the driver. @@ -54,6 +42,7 @@ #define DEBUG2_9_10(x) do { if (ql2xextended_error_logging) { x; } } while (0) #define DEBUG2_11(x) do { if (ql2xextended_error_logging) { x; } } while (0) #define DEBUG2_13(x) do { if (ql2xextended_error_logging) { x; } } while (0) +#define DEBUG2_16(x) do { if (ql2xextended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_3) #define DEBUG3(x) do {x;} while (0) @@ -133,6 +122,12 @@ #define DEBUG15(x) do {} while (0) #endif +#if defined(QL_DEBUG_LEVEL_16) +#define DEBUG16(x) do {x;} while (0) +#else +#define DEBUG16(x) do {} while (0) +#endif + /* * Firmware Dump structure definition */ diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 3750319f4968..094d95f0764c 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -24,6 +24,7 @@ #include <linux/workqueue.h> #include <linux/firmware.h> #include <linux/aer.h> +#include <linux/mutex.h> #include <asm/semaphore.h> #include <scsi/scsi.h> @@ -192,9 +193,6 @@ typedef struct srb { uint16_t flags; - /* Single transfer DMA context */ - dma_addr_t dma_handle; - uint32_t request_sense_length; uint8_t *request_sense_ptr; } srb_t; @@ -1542,8 +1540,6 @@ typedef struct fc_port { atomic_t state; uint32_t flags; - unsigned int os_target_id; - int port_login_retry_count; int login_retry; atomic_t port_down_timer; @@ -1613,6 +1609,7 @@ typedef struct fc_port { #define CT_ACCEPT_RESPONSE 0x8002 #define CT_REASON_INVALID_COMMAND_CODE 0x01 #define CT_REASON_CANNOT_PERFORM 0x09 +#define CT_REASON_COMMAND_UNSUPPORTED 0x0b #define CT_EXPL_ALREADY_REGISTERED 0x10 #define NS_N_PORT_TYPE 0x01 @@ -2063,7 +2060,8 @@ struct isp_operations { void (*disable_intrs) (struct scsi_qla_host *); int (*abort_command) (struct scsi_qla_host *, srb_t *); - int (*abort_target) (struct fc_port *); + int (*target_reset) (struct fc_port *, unsigned int); + int (*lun_reset) (struct fc_port *, unsigned int); int (*fabric_login) (struct scsi_qla_host *, uint16_t, uint8_t, uint8_t, uint8_t, uint16_t *, uint8_t); int (*fabric_logout) (struct scsi_qla_host *, uint16_t, uint8_t, @@ -2117,6 +2115,46 @@ struct qla_msix_entry { #define WATCH_INTERVAL 1 /* number of seconds */ +/* Work events. */ +enum qla_work_type { + QLA_EVT_AEN, + QLA_EVT_HWE_LOG, +}; + + +struct qla_work_evt { + struct list_head list; + enum qla_work_type type; + u32 flags; +#define QLA_EVT_FLAG_FREE 0x1 + + union { + struct { + enum fc_host_event_code code; + u32 data; + } aen; + struct { + uint16_t code; + uint16_t d1, d2, d3; + } hwe; + } u; +}; + +struct qla_chip_state_84xx { + struct list_head list; + struct kref kref; + + void *bus; + spinlock_t access_lock; + struct mutex fw_update_mutex; + uint32_t fw_update; + uint32_t op_fw_version; + uint32_t op_fw_size; + uint32_t op_fw_seq_size; + uint32_t diag_fw_version; + uint32_t gold_fw_version; +}; + /* * Linux Host Adapter structure */ @@ -2155,6 +2193,7 @@ typedef struct scsi_qla_host { uint32_t vsan_enabled :1; uint32_t npiv_supported :1; uint32_t fce_enabled :1; + uint32_t hw_event_marker_found :1; } flags; atomic_t loop_state; @@ -2204,6 +2243,7 @@ typedef struct scsi_qla_host { #define DFLG_NO_CABLE BIT_4 #define PCI_DEVICE_ID_QLOGIC_ISP2532 0x2532 +#define PCI_DEVICE_ID_QLOGIC_ISP8432 0x8432 uint32_t device_type; #define DT_ISP2100 BIT_0 #define DT_ISP2200 BIT_1 @@ -2217,7 +2257,8 @@ typedef struct scsi_qla_host { #define DT_ISP5422 BIT_9 #define DT_ISP5432 BIT_10 #define DT_ISP2532 BIT_11 -#define DT_ISP_LAST (DT_ISP2532 << 1) +#define DT_ISP8432 BIT_12 +#define DT_ISP_LAST (DT_ISP8432 << 1) #define DT_IIDMA BIT_26 #define DT_FWI2 BIT_27 @@ -2239,12 +2280,16 @@ typedef struct scsi_qla_host { #define IS_QLA5422(ha) (DT_MASK(ha) & DT_ISP5422) #define IS_QLA5432(ha) (DT_MASK(ha) & DT_ISP5432) #define IS_QLA2532(ha) (DT_MASK(ha) & DT_ISP2532) +#define IS_QLA8432(ha) (DT_MASK(ha) & DT_ISP8432) #define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \ IS_QLA6312(ha) || IS_QLA6322(ha)) #define IS_QLA24XX(ha) (IS_QLA2422(ha) || IS_QLA2432(ha)) #define IS_QLA54XX(ha) (IS_QLA5422(ha) || IS_QLA5432(ha)) #define IS_QLA25XX(ha) (IS_QLA2532(ha)) +#define IS_QLA84XX(ha) (IS_QLA8432(ha)) +#define IS_QLA24XX_TYPE(ha) (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \ + IS_QLA84XX(ha)) #define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA) #define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2) @@ -2356,6 +2401,8 @@ typedef struct scsi_qla_host { uint32_t login_retry_count; int max_q_depth; + struct list_head work_list; + /* Fibre Channel Device List. */ struct list_head fcports; @@ -2423,8 +2470,6 @@ typedef struct scsi_qla_host { #define MBX_TIMEDOUT BIT_5 #define MBX_ACCESS_TIMEDOUT BIT_6 - mbx_cmd_t mc; - /* Basic firmware related information. */ uint16_t fw_major_version; uint16_t fw_minor_version; @@ -2458,6 +2503,10 @@ typedef struct scsi_qla_host { uint64_t fce_wr, fce_rd; struct mutex fce_mutex; + uint32_t hw_event_start; + uint32_t hw_event_ptr; + uint32_t hw_event_pause_errors; + uint8_t host_str[16]; uint32_t pci_attr; uint16_t chip_revision; @@ -2493,6 +2542,13 @@ typedef struct scsi_qla_host { uint8_t fcode_revision[16]; uint32_t fw_revision[4]; + uint16_t fdt_odd_index; + uint32_t fdt_wrt_disable; + uint32_t fdt_erase_cmd; + uint32_t fdt_block_size; + uint32_t fdt_unprotect_sec_cmd; + uint32_t fdt_protect_sec_cmd; + /* Needed for BEACON */ uint16_t beacon_blink_led; uint8_t beacon_color_state; @@ -2538,6 +2594,8 @@ typedef struct scsi_qla_host { #define VP_ERR_ADAP_NORESOURCES 5 uint16_t max_npiv_vports; /* 63 or 125 per topoloty */ int cur_vport_count; + + struct qla_chip_state_84xx *cs84xx; } scsi_qla_host_t; diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 2cd899bfe84b..561a4411719d 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 9337e138ed63..078f2a15f40b 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -719,7 +719,7 @@ struct tsk_mgmt_entry { uint16_t timeout; /* Command timeout. */ - uint8_t lun[8]; /* FCP LUN (BE). */ + struct scsi_lun lun; /* FCP LUN (BE). */ uint32_t control_flags; /* Control Flags. */ #define TCF_NOTMCMD_TO_TARGET BIT_31 @@ -793,7 +793,19 @@ struct device_reg_24xx { #define FA_VPD_NVRAM_ADDR 0x48000 #define FA_FEATURE_ADDR 0x4C000 #define FA_FLASH_DESCR_ADDR 0x50000 -#define FA_HW_EVENT_ADDR 0x54000 +#define FA_HW_EVENT0_ADDR 0x54000 +#define FA_HW_EVENT1_ADDR 0x54200 +#define FA_HW_EVENT_SIZE 0x200 +#define FA_HW_EVENT_ENTRY_SIZE 4 +/* + * Flash Error Log Event Codes. + */ +#define HW_EVENT_RESET_ERR 0xF00B +#define HW_EVENT_ISP_ERR 0xF020 +#define HW_EVENT_PARITY_ERR 0xF022 +#define HW_EVENT_NVRAM_CHKSUM_ERR 0xF023 +#define HW_EVENT_FLASH_FW_ERR 0xF024 + #define FA_BOOT_LOG_ADDR 0x58000 #define FA_FW_DUMP0_ADDR 0x60000 #define FA_FW_DUMP1_ADDR 0x70000 @@ -1174,4 +1186,159 @@ struct vf_evfp_entry_24xx { }; /* END MID Support ***********************************************************/ + +/* Flash Description Table ***************************************************/ + +struct qla_fdt_layout { + uint8_t sig[4]; + uint16_t version; + uint16_t len; + uint16_t checksum; + uint8_t unused1[2]; + uint8_t model[16]; + uint16_t man_id; + uint16_t id; + uint8_t flags; + uint8_t erase_cmd; + uint8_t alt_erase_cmd; + uint8_t wrt_enable_cmd; + uint8_t wrt_enable_bits; + uint8_t wrt_sts_reg_cmd; + uint8_t unprotect_sec_cmd; + uint8_t read_man_id_cmd; + uint32_t block_size; + uint32_t alt_block_size; + uint32_t flash_size; + uint32_t wrt_enable_data; + uint8_t read_id_addr_len; + uint8_t wrt_disable_bits; + uint8_t read_dev_id_len; + uint8_t chip_erase_cmd; + uint16_t read_timeout; + uint8_t protect_sec_cmd; + uint8_t unused2[65]; +}; + +/* 84XX Support **************************************************************/ + +#define MBA_ISP84XX_ALERT 0x800f /* Alert Notification. */ +#define A84_PANIC_RECOVERY 0x1 +#define A84_OP_LOGIN_COMPLETE 0x2 +#define A84_DIAG_LOGIN_COMPLETE 0x3 +#define A84_GOLD_LOGIN_COMPLETE 0x4 + +#define MBC_ISP84XX_RESET 0x3a /* Reset. */ + +#define FSTATE_REMOTE_FC_DOWN BIT_0 +#define FSTATE_NSL_LINK_DOWN BIT_1 +#define FSTATE_IS_DIAG_FW BIT_2 +#define FSTATE_LOGGED_IN BIT_3 +#define FSTATE_WAITING_FOR_VERIFY BIT_4 + +#define VERIFY_CHIP_IOCB_TYPE 0x1B +struct verify_chip_entry_84xx { + uint8_t entry_type; + uint8_t entry_count; + uint8_t sys_defined; + uint8_t entry_status; + + uint32_t handle; + + uint16_t options; +#define VCO_DONT_UPDATE_FW BIT_0 +#define VCO_FORCE_UPDATE BIT_1 +#define VCO_DONT_RESET_UPDATE BIT_2 +#define VCO_DIAG_FW BIT_3 +#define VCO_END_OF_DATA BIT_14 +#define VCO_ENABLE_DSD BIT_15 + + uint16_t reserved_1; + + uint16_t data_seg_cnt; + uint16_t reserved_2[3]; + + uint32_t fw_ver; + uint32_t exchange_address; + + uint32_t reserved_3[3]; + uint32_t fw_size; + uint32_t fw_seq_size; + uint32_t relative_offset; + + uint32_t dseg_address[2]; + uint32_t dseg_length; +}; + +struct verify_chip_rsp_84xx { + uint8_t entry_type; + uint8_t entry_count; + uint8_t sys_defined; + uint8_t entry_status; + + uint32_t handle; + + uint16_t comp_status; +#define CS_VCS_CHIP_FAILURE 0x3 +#define CS_VCS_BAD_EXCHANGE 0x8 +#define CS_VCS_SEQ_COMPLETEi 0x40 + + uint16_t failure_code; +#define VFC_CHECKSUM_ERROR 0x1 +#define VFC_INVALID_LEN 0x2 +#define VFC_ALREADY_IN_PROGRESS 0x8 + + uint16_t reserved_1[4]; + + uint32_t fw_ver; + uint32_t exchange_address; + + uint32_t reserved_2[6]; +}; + +#define ACCESS_CHIP_IOCB_TYPE 0x2B +struct access_chip_84xx { + uint8_t entry_type; + uint8_t entry_count; + uint8_t sys_defined; + uint8_t entry_status; + + uint32_t handle; + + uint16_t options; +#define ACO_DUMP_MEMORY 0x0 +#define ACO_LOAD_MEMORY 0x1 +#define ACO_CHANGE_CONFIG_PARAM 0x2 +#define ACO_REQUEST_INFO 0x3 + + uint16_t reserved1; + + uint16_t dseg_count; + uint16_t reserved2[3]; + + uint32_t parameter1; + uint32_t parameter2; + uint32_t parameter3; + + uint32_t reserved3[3]; + uint32_t total_byte_cnt; + uint32_t reserved4; + + uint32_t dseg_address[2]; + uint32_t dseg_length; +}; + +struct access_chip_rsp_84xx { + uint8_t entry_type; + uint8_t entry_count; + uint8_t sys_defined; + uint8_t entry_status; + + uint32_t handle; + + uint16_t comp_status; + uint16_t failure_code; + uint32_t residual_count; + + uint32_t reserved[12]; +}; #endif diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 193f688ec3d7..a9571c214a9e 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -38,9 +38,6 @@ extern int qla2x00_loop_resync(scsi_qla_host_t *); extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *); extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *); -extern void qla2x00_restart_queues(scsi_qla_host_t *, uint8_t); - -extern void qla2x00_rescan_fcports(scsi_qla_host_t *); extern void qla2x00_update_fcports(scsi_qla_host_t *); extern int qla2x00_abort_isp(scsi_qla_host_t *); @@ -50,6 +47,8 @@ extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *); extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *); +extern void qla84xx_put_chip(struct scsi_qla_host *); + /* * Global Data in qla_os.c source file. */ @@ -67,6 +66,10 @@ extern int num_hosts; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); +extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum + fc_host_event_code, u32); +extern int qla2x00_post_hwe_work(struct scsi_qla_host *, uint16_t , uint16_t, + uint16_t, uint16_t); /* * Global Functions in qla_mid.c source file. @@ -149,12 +152,17 @@ extern int qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t); extern int +qla2x00_issue_iocb_timeout(scsi_qla_host_t *, void *, dma_addr_t, size_t, + uint32_t); + +extern int qla2x00_abort_command(scsi_qla_host_t *, srb_t *); -#if USE_ABORT_TGT extern int -qla2x00_abort_target(fc_port_t *); -#endif +qla2x00_abort_target(struct fc_port *, unsigned int); + +extern int +qla2x00_lun_reset(struct fc_port *, unsigned int); extern int qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *, @@ -220,7 +228,8 @@ qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *, dma_addr_t); extern int qla24xx_abort_command(scsi_qla_host_t *, srb_t *); -extern int qla24xx_abort_target(fc_port_t *); +extern int qla24xx_abort_target(struct fc_port *, unsigned int); +extern int qla24xx_lun_reset(struct fc_port *, unsigned int); extern int qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); @@ -246,6 +255,8 @@ qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); extern int qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); +extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *); + /* * Global Function Prototypes in qla_isr.c source file. */ @@ -298,6 +309,11 @@ extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *); extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *); +extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t, + uint16_t, uint16_t); + +extern void qla2xxx_get_flash_info(scsi_qla_host_t *); + /* * Global Function Prototypes in qla_dbg.c source file. */ @@ -307,7 +323,6 @@ extern void qla24xx_fw_dump(scsi_qla_host_t *, int); extern void qla25xx_fw_dump(scsi_qla_host_t *, int); extern void qla2x00_dump_regs(scsi_qla_host_t *); extern void qla2x00_dump_buffer(uint8_t *, uint32_t); -extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *); /* * Global Function Prototypes in qla_gs.c source file. diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index c1808763d40e..750d7ef83aae 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1,17 +1,11 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ #include "qla_def.h" -static inline struct ct_sns_req * -qla2x00_prep_ct_req(struct ct_sns_req *, uint16_t, uint16_t); - -static inline struct sns_cmd_pkt * -qla2x00_prep_sns_cmd(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); - static int qla2x00_sns_ga_nxt(scsi_qla_host_t *, fc_port_t *); static int qla2x00_sns_gid_pt(scsi_qla_host_t *, sw_info_t *); static int qla2x00_sns_gpn_id(scsi_qla_host_t *, sw_info_t *); @@ -1538,7 +1532,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha) eiter->a.sup_speed = __constant_cpu_to_be32( FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB| FDMI_PORT_SPEED_4GB|FDMI_PORT_SPEED_8GB); - else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) + else if (IS_QLA24XX_TYPE(ha)) eiter->a.sup_speed = __constant_cpu_to_be32( FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB| FDMI_PORT_SPEED_4GB); @@ -1847,8 +1841,10 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list) "GPSC")) != QLA_SUCCESS) { /* FM command unsupported? */ if (rval == QLA_INVALID_COMMAND && - ct_rsp->header.reason_code == - CT_REASON_INVALID_COMMAND_CODE) { + (ct_rsp->header.reason_code == + CT_REASON_INVALID_COMMAND_CODE || + ct_rsp->header.reason_code == + CT_REASON_COMMAND_UNSUPPORTED)) { DEBUG2(printk("scsi(%ld): GPSC command " "unsupported, disabling query...\n", ha->host_no)); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 364be7d06875..01e26087c1dd 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -15,14 +15,6 @@ #include <asm/prom.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) \ - (((P)->mask[L/8] & (0x80 >> (L%8)))?1:0) -#define EXT_SET_LUN_BIT(P,L) \ - ((P)->mask[L/8] |= (0x80 >> (L%8))) -#endif - /* * QLogic ISP2x00 Hardware Support Function Prototypes. */ @@ -45,6 +37,9 @@ static int qla2x00_restart_isp(scsi_qla_host_t *); static int qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev); +static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *); +static int qla84xx_init_chip(scsi_qla_host_t *); + /****************************************************************************/ /* QLogic ISP2x00 Hardware Support Functions. */ /****************************************************************************/ @@ -114,6 +109,15 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) rval = qla2x00_setup_chip(ha); if (rval) return (rval); + qla2xxx_get_flash_info(ha); + } + if (IS_QLA84XX(ha)) { + ha->cs84xx = qla84xx_get_chip(ha); + if (!ha->cs84xx) { + qla_printk(KERN_ERR, ha, + "Unable to configure ISP84XX.\n"); + return QLA_FUNCTION_FAILED; + } } rval = qla2x00_init_rings(ha); @@ -500,6 +504,7 @@ qla2x00_reset_chip(scsi_qla_host_t *ha) static inline void qla24xx_reset_risc(scsi_qla_host_t *ha) { + int hw_evt = 0; unsigned long flags = 0; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; uint32_t cnt, d2; @@ -528,6 +533,8 @@ qla24xx_reset_risc(scsi_qla_host_t *ha) d2 = (uint32_t) RD_REG_WORD(®->mailbox0); barrier(); } + if (cnt == 0) + hw_evt = 1; /* Wait for soft-reset to complete. */ d2 = RD_REG_DWORD(®->ctrl_status); @@ -536,6 +543,10 @@ qla24xx_reset_risc(scsi_qla_host_t *ha) d2 = RD_REG_DWORD(®->ctrl_status); barrier(); } + if (cnt == 0 || hw_evt) + qla2xxx_hw_event_log(ha, HW_EVENT_RESET_ERR, + RD_REG_WORD(®->mailbox1), RD_REG_WORD(®->mailbox2), + RD_REG_WORD(®->mailbox3)); WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); RD_REG_DWORD(®->hccr); @@ -1243,10 +1254,10 @@ static int qla2x00_fw_ready(scsi_qla_host_t *ha) { int rval; - unsigned long wtime, mtime; + unsigned long wtime, mtime, cs84xx_time; uint16_t min_wait; /* Minimum wait time if loop is down */ uint16_t wait_time; /* Wait time if loop is coming ready */ - uint16_t fw_state; + uint16_t state[3]; rval = QLA_SUCCESS; @@ -1275,12 +1286,34 @@ qla2x00_fw_ready(scsi_qla_host_t *ha) ha->host_no)); do { - rval = qla2x00_get_firmware_state(ha, &fw_state); + rval = qla2x00_get_firmware_state(ha, state); if (rval == QLA_SUCCESS) { - if (fw_state < FSTATE_LOSS_OF_SYNC) { + if (state[0] < FSTATE_LOSS_OF_SYNC) { ha->device_flags &= ~DFLG_NO_CABLE; } - if (fw_state == FSTATE_READY) { + if (IS_QLA84XX(ha) && state[0] != FSTATE_READY) { + DEBUG16(printk("scsi(%ld): fw_state=%x " + "84xx=%x.\n", ha->host_no, state[0], + state[2])); + if ((state[2] & FSTATE_LOGGED_IN) && + (state[2] & FSTATE_WAITING_FOR_VERIFY)) { + DEBUG16(printk("scsi(%ld): Sending " + "verify iocb.\n", ha->host_no)); + + cs84xx_time = jiffies; + rval = qla84xx_init_chip(ha); + if (rval != QLA_SUCCESS) + break; + + /* Add time taken to initialize. */ + cs84xx_time = jiffies - cs84xx_time; + wtime += cs84xx_time; + mtime += cs84xx_time; + DEBUG16(printk("scsi(%ld): Increasing " + "wait time by %ld. New time %ld\n", + ha->host_no, cs84xx_time, wtime)); + } + } else if (state[0] == FSTATE_READY) { DEBUG(printk("scsi(%ld): F/W Ready - OK \n", ha->host_no)); @@ -1294,7 +1327,7 @@ qla2x00_fw_ready(scsi_qla_host_t *ha) rval = QLA_FUNCTION_FAILED; if (atomic_read(&ha->loop_down_timer) && - fw_state != FSTATE_READY) { + state[0] != FSTATE_READY) { /* Loop down. Timeout on min_wait for states * other than Wait for Login. */ @@ -1319,11 +1352,11 @@ qla2x00_fw_ready(scsi_qla_host_t *ha) msleep(500); DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n", - ha->host_no, fw_state, jiffies)); + ha->host_no, state[0], jiffies)); } while (1); DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n", - ha->host_no, fw_state, jiffies)); + ha->host_no, state[0], jiffies)); if (rval) { DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n", @@ -1555,6 +1588,10 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet " "invalid -- WWPN) defaults.\n"); + if (chksum) + qla2xxx_hw_event_log(ha, HW_EVENT_NVRAM_CHKSUM_ERR, 0, + MSW(chksum), LSW(chksum)); + /* * Set default initialization control block. */ @@ -2165,20 +2202,6 @@ cleanup_allocation: } static void -qla2x00_probe_for_all_luns(scsi_qla_host_t *ha) -{ - fc_port_t *fcport; - - qla2x00_mark_all_devices_lost(ha, 0); - list_for_each_entry(fcport, &ha->fcports, list) { - if (fcport->port_type != FCT_TARGET) - continue; - - qla2x00_update_fcport(ha, fcport); - } -} - -static void qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport) { #define LS_UNKNOWN 2 @@ -2251,10 +2274,6 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport) if (fcport->port_type == FCT_TARGET) rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; fc_remote_port_rolechg(rport, rport_ids.roles); - - if (rport->scsi_target_id != -1 && - rport->scsi_target_id < ha->host->max_id) - fcport->os_target_id = rport->scsi_target_id; } /* @@ -2434,7 +2453,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) if (fcport->loop_id == FC_NO_LOOP_ID) { fcport->loop_id = next_loopid; - rval = qla2x00_find_new_loop_id(ha, fcport); + rval = qla2x00_find_new_loop_id( + to_qla_parent(ha), fcport); if (rval != QLA_SUCCESS) { /* Ran out of IDs to use */ break; @@ -2459,7 +2479,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) /* Find a new loop ID to use. */ fcport->loop_id = next_loopid; - rval = qla2x00_find_new_loop_id(ha, fcport); + rval = qla2x00_find_new_loop_id(to_qla_parent(ha), + fcport); if (rval != QLA_SUCCESS) { /* Ran out of IDs to use */ break; @@ -3193,25 +3214,6 @@ qla2x00_loop_resync(scsi_qla_host_t *ha) } void -qla2x00_rescan_fcports(scsi_qla_host_t *ha) -{ - int rescan_done; - fc_port_t *fcport; - - rescan_done = 0; - list_for_each_entry(fcport, &ha->fcports, list) { - if ((fcport->flags & FCF_RESCAN_NEEDED) == 0) - continue; - - qla2x00_update_fcport(ha, fcport); - fcport->flags &= ~FCF_RESCAN_NEEDED; - - rescan_done = 1; - } - qla2x00_probe_for_all_luns(ha); -} - -void qla2x00_update_fcports(scsi_qla_host_t *ha) { fc_port_t *fcport; @@ -4044,16 +4046,16 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha) if (!ha->parent) return -EINVAL; - rval = qla2x00_fw_ready(ha); + rval = qla2x00_fw_ready(ha->parent); if (rval == QLA_SUCCESS) { clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); - qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); + qla2x00_marker(ha->parent, 0, 0, MK_SYNC_ALL); } ha->flags.management_server_logged_in = 0; /* Login to SNS first */ - qla24xx_login_fabric(ha, NPH_SNS, 0xff, 0xff, 0xfc, + qla24xx_login_fabric(ha->parent, NPH_SNS, 0xff, 0xff, 0xfc, mb, BIT_1); if (mb[0] != MBS_COMMAND_COMPLETE) { DEBUG15(qla_printk(KERN_INFO, ha, @@ -4067,7 +4069,77 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha) atomic_set(&ha->loop_state, LOOP_UP); set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); - rval = qla2x00_loop_resync(ha); + rval = qla2x00_loop_resync(ha->parent); return rval; } + +/* 84XX Support **************************************************************/ + +static LIST_HEAD(qla_cs84xx_list); +static DEFINE_MUTEX(qla_cs84xx_mutex); + +static struct qla_chip_state_84xx * +qla84xx_get_chip(struct scsi_qla_host *ha) +{ + struct qla_chip_state_84xx *cs84xx; + + mutex_lock(&qla_cs84xx_mutex); + + /* Find any shared 84xx chip. */ + list_for_each_entry(cs84xx, &qla_cs84xx_list, list) { + if (cs84xx->bus == ha->pdev->bus) { + kref_get(&cs84xx->kref); + goto done; + } + } + + cs84xx = kzalloc(sizeof(*cs84xx), GFP_KERNEL); + if (!cs84xx) + goto done; + + kref_init(&cs84xx->kref); + spin_lock_init(&cs84xx->access_lock); + mutex_init(&cs84xx->fw_update_mutex); + cs84xx->bus = ha->pdev->bus; + + list_add_tail(&cs84xx->list, &qla_cs84xx_list); +done: + mutex_unlock(&qla_cs84xx_mutex); + return cs84xx; +} + +static void +__qla84xx_chip_release(struct kref *kref) +{ + struct qla_chip_state_84xx *cs84xx = + container_of(kref, struct qla_chip_state_84xx, kref); + + mutex_lock(&qla_cs84xx_mutex); + list_del(&cs84xx->list); + mutex_unlock(&qla_cs84xx_mutex); + kfree(cs84xx); +} + +void +qla84xx_put_chip(struct scsi_qla_host *ha) +{ + if (ha->cs84xx) + kref_put(&ha->cs84xx->kref, __qla84xx_chip_release); +} + +static int +qla84xx_init_chip(scsi_qla_host_t *ha) +{ + int rval; + uint16_t status[2]; + + mutex_lock(&ha->cs84xx->fw_update_mutex); + + rval = qla84xx_verify_chip(ha, status); + + mutex_unlock(&ha->cs84xx->fw_update_mutex); + + return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED: + QLA_SUCCESS; +} diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 5d1a3f7c408f..e9bae27737d1 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -1,11 +1,10 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ -static __inline__ uint16_t qla2x00_debounce_register(volatile uint16_t __iomem *); /* * qla2x00_debounce_register * Debounce register. @@ -32,94 +31,12 @@ qla2x00_debounce_register(volatile uint16_t __iomem *addr) return (first); } -static __inline__ int qla2x00_normalize_dma_addr( - dma_addr_t *e_addr, uint32_t *e_len, - dma_addr_t *ne_addr, uint32_t *ne_len); - -/** - * qla2x00_normalize_dma_addr() - Normalize an DMA address. - * @e_addr: Raw DMA address - * @e_len: Raw DMA length - * @ne_addr: Normalized second DMA address - * @ne_len: Normalized second DMA length - * - * If the address does not span a 4GB page boundary, the contents of @ne_addr - * and @ne_len are undefined. @e_len is updated to reflect a normalization. - * - * Example: - * - * ffffabc0ffffeeee (e_addr) start of DMA address - * 0000000020000000 (e_len) length of DMA transfer - * ffffabc11fffeeed end of DMA transfer - * - * Is the 4GB boundary crossed? - * - * ffffabc0ffffeeee (e_addr) - * ffffabc11fffeeed (e_addr + e_len - 1) - * 00000001e0000003 ((e_addr ^ (e_addr + e_len - 1)) - * 0000000100000000 ((e_addr ^ (e_addr + e_len - 1)) & ~(0xffffffff) - * - * Compute start of second DMA segment: - * - * ffffabc0ffffeeee (e_addr) - * ffffabc1ffffeeee (0x100000000 + e_addr) - * ffffabc100000000 (0x100000000 + e_addr) & ~(0xffffffff) - * ffffabc100000000 (ne_addr) - * - * Compute length of second DMA segment: - * - * 00000000ffffeeee (e_addr & 0xffffffff) - * 0000000000001112 (0x100000000 - (e_addr & 0xffffffff)) - * 000000001fffeeee (e_len - (0x100000000 - (e_addr & 0xffffffff)) - * 000000001fffeeee (ne_len) - * - * Adjust length of first DMA segment - * - * 0000000020000000 (e_len) - * 0000000000001112 (e_len - ne_len) - * 0000000000001112 (e_len) - * - * Returns non-zero if the specified address was normalized, else zero. - */ -static __inline__ int -qla2x00_normalize_dma_addr( - dma_addr_t *e_addr, uint32_t *e_len, - dma_addr_t *ne_addr, uint32_t *ne_len) -{ - int normalized; - - normalized = 0; - if ((*e_addr ^ (*e_addr + *e_len - 1)) & ~(0xFFFFFFFFULL)) { - /* Compute normalized crossed address and len */ - *ne_addr = (0x100000000ULL + *e_addr) & ~(0xFFFFFFFFULL); - *ne_len = *e_len - (0x100000000ULL - (*e_addr & 0xFFFFFFFFULL)); - *e_len -= *ne_len; - - normalized++; - } - return (normalized); -} - -static __inline__ void qla2x00_poll(scsi_qla_host_t *); static inline void qla2x00_poll(scsi_qla_host_t *ha) { ha->isp_ops->intr_handler(0, ha); } -static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *); -/* - * This routine will wait for fabric devices for - * the reset delay. - */ -static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *ha) -{ - uint16_t fw_state; - - qla2x00_get_firmware_state(ha, &fw_state); -} - -static __inline__ scsi_qla_host_t * to_qla_parent(scsi_qla_host_t *); static __inline__ scsi_qla_host_t * to_qla_parent(scsi_qla_host_t *ha) { @@ -152,7 +69,6 @@ qla2x00_issue_marker(scsi_qla_host_t *ha, int ha_locked) return (QLA_SUCCESS); } -static inline uint8_t *host_to_fcp_swap(uint8_t *, uint32_t); static inline uint8_t * host_to_fcp_swap(uint8_t *fcp, uint32_t bsize) { @@ -166,7 +82,6 @@ host_to_fcp_swap(uint8_t *fcp, uint32_t bsize) return fcp; } -static inline int qla2x00_is_reserved_id(scsi_qla_host_t *, uint16_t); static inline int qla2x00_is_reserved_id(scsi_qla_host_t *ha, uint16_t loop_id) { diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 024c662ec34d..5489d5024673 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -11,9 +11,6 @@ #include <scsi/scsi_tcq.h> -static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd); -static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *); -static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *); static request_t *qla2x00_req_pkt(scsi_qla_host_t *ha); static void qla2x00_isp_cmd(scsi_qla_host_t *ha); diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index f0337036c7bb..285479b62d8f 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -14,9 +14,6 @@ static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t); static void qla2x00_status_entry(scsi_qla_host_t *, void *); static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *); static void qla2x00_error_entry(scsi_qla_host_t *, sts_entry_t *); -static void qla2x00_ms_entry(scsi_qla_host_t *, ms_iocb_entry_t *); - -static void qla24xx_ms_entry(scsi_qla_host_t *, struct ct_entry_24xx *); /** * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200. @@ -33,7 +30,6 @@ qla2100_intr_handler(int irq, void *dev_id) scsi_qla_host_t *ha; struct device_reg_2xxx __iomem *reg; int status; - unsigned long flags; unsigned long iter; uint16_t hccr; uint16_t mb[4]; @@ -48,7 +44,7 @@ qla2100_intr_handler(int irq, void *dev_id) reg = &ha->iobase->isp; status = 0; - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock(&ha->hardware_lock); for (iter = 50; iter--; ) { hccr = RD_REG_WORD(®->hccr); if (hccr & HCCR_RISC_PAUSE) { @@ -99,7 +95,7 @@ qla2100_intr_handler(int irq, void *dev_id) RD_REG_WORD(®->hccr); } } - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock(&ha->hardware_lock); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { @@ -125,7 +121,6 @@ qla2300_intr_handler(int irq, void *dev_id) scsi_qla_host_t *ha; struct device_reg_2xxx __iomem *reg; int status; - unsigned long flags; unsigned long iter; uint32_t stat; uint16_t hccr; @@ -141,7 +136,7 @@ qla2300_intr_handler(int irq, void *dev_id) reg = &ha->iobase->isp; status = 0; - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock(&ha->hardware_lock); for (iter = 50; iter--; ) { stat = RD_REG_DWORD(®->u.isp2300.host_status); if (stat & HSR_RISC_PAUSED) { @@ -211,7 +206,7 @@ qla2300_intr_handler(int irq, void *dev_id) WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD_RELAXED(®->hccr); } - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock(&ha->hardware_lock); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { @@ -276,6 +271,9 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; uint32_t rscn_entry, host_pid; uint8_t rscn_queue_index; + unsigned long flags; + scsi_qla_host_t *vha; + int i; /* Setup to process RIO completion. */ handle_cnt = 0; @@ -351,6 +349,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n", mb[1], mb[2], mb[3]); + qla2x00_post_hwe_work(ha, mb[0], mb[1], mb[2], mb[3]); ha->isp_ops->fw_dump(ha, 1); if (IS_FWI2_CAPABLE(ha)) { @@ -375,6 +374,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->host_no)); qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n"); + qla2x00_post_hwe_work(ha, mb[0], mb[1], mb[2], mb[3]); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); break; @@ -383,6 +383,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->host_no)); qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n"); + qla2x00_post_hwe_work(ha, mb[0], mb[1], mb[2], mb[3]); set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); break; @@ -410,6 +411,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags); ha->flags.management_server_logged_in = 0; + qla2x00_post_aen_work(ha, FCH_EVT_LIP, mb[1]); break; case MBA_LOOP_UP: /* Loop Up Event */ @@ -429,12 +431,14 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) link_speed); ha->flags.management_server_logged_in = 0; + qla2x00_post_aen_work(ha, FCH_EVT_LINKUP, ha->link_data_rate); break; case MBA_LOOP_DOWN: /* Loop Down Event */ - DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN (%x).\n", - ha->host_no, mb[1])); - qla_printk(KERN_INFO, ha, "LOOP DOWN detected (%x).\n", mb[1]); + DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN " + "(%x %x %x).\n", ha->host_no, mb[1], mb[2], mb[3])); + qla_printk(KERN_INFO, ha, "LOOP DOWN detected (%x %x %x).\n", + mb[1], mb[2], mb[3]); if (atomic_read(&ha->loop_state) != LOOP_DOWN) { atomic_set(&ha->loop_state, LOOP_DOWN); @@ -452,6 +456,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->link_data_rate = PORT_SPEED_UNKNOWN; if (ql2xfdmienable) set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); + qla2x00_post_aen_work(ha, FCH_EVT_LINKDOWN, 0); break; case MBA_LIP_RESET: /* LIP reset occurred */ @@ -475,6 +480,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->operating_mode = LOOP; ha->flags.management_server_logged_in = 0; + qla2x00_post_aen_work(ha, FCH_EVT_LIPRESET, mb[1]); break; case MBA_POINT_TO_POINT: /* Point-to-Point */ @@ -538,6 +544,18 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) break; case MBA_PORT_UPDATE: /* Port database update */ + if ((ha->flags.npiv_supported) && (ha->num_vhosts)) { + for_each_mapped_vp_idx(ha, i) { + list_for_each_entry(vha, &ha->vp_list, + vp_list) { + if ((mb[3] & 0xff) + == vha->vp_idx) { + ha = vha; + break; + } + } + } + } /* * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET * event etc. earlier indicating loop is down) then process @@ -572,12 +590,18 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) break; case MBA_RSCN_UPDATE: /* State Change Registration */ - /* Check if the Vport has issued a SCR */ - if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags)) - break; - /* Only handle SCNs for our Vport index. */ - if (ha->flags.npiv_supported && ha->vp_idx != mb[3]) - break; + if ((ha->flags.npiv_supported) && (ha->num_vhosts)) { + for_each_mapped_vp_idx(ha, i) { + list_for_each_entry(vha, &ha->vp_list, + vp_list) { + if ((mb[3] & 0xff) + == vha->vp_idx) { + ha = vha; + break; + } + } + } + } DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n", ha->host_no)); @@ -612,6 +636,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); set_bit(RSCN_UPDATE, &ha->dpc_flags); + qla2x00_post_aen_work(ha, FCH_EVT_RSCN, rscn_entry); break; /* case MBA_RIO_RESPONSE: */ @@ -637,6 +662,42 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n", ha->host_no, mb[1], mb[2])); break; + + case MBA_ISP84XX_ALERT: + DEBUG2(printk("scsi(%ld): ISP84XX Alert Notification -- " + "%04x %04x %04x\n", ha->host_no, mb[1], mb[2], mb[3])); + + spin_lock_irqsave(&ha->cs84xx->access_lock, flags); + switch (mb[1]) { + case A84_PANIC_RECOVERY: + qla_printk(KERN_INFO, ha, "Alert 84XX: panic recovery " + "%04x %04x\n", mb[2], mb[3]); + break; + case A84_OP_LOGIN_COMPLETE: + ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2]; + DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:" + "firmware version %x\n", ha->cs84xx->op_fw_version)); + break; + case A84_DIAG_LOGIN_COMPLETE: + ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2]; + DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:" + "diagnostic firmware version %x\n", + ha->cs84xx->diag_fw_version)); + break; + case A84_GOLD_LOGIN_COMPLETE: + ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2]; + ha->cs84xx->fw_update = 1; + DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX: gold " + "firmware version %x\n", + ha->cs84xx->gold_fw_version)); + break; + default: + qla_printk(KERN_ERR, ha, + "Alert 84xx: Invalid Alert %04x %04x %04x\n", + mb[1], mb[2], mb[3]); + } + spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags); + break; } if (!ha->parent && ha->num_vhosts) @@ -803,9 +864,6 @@ qla2x00_process_response_queue(struct scsi_qla_host *ha) case STATUS_CONT_TYPE: qla2x00_status_cont_entry(ha, (sts_cont_entry_t *)pkt); break; - case MS_IOCB_TYPE: - qla2x00_ms_entry(ha, (ms_iocb_entry_t *)pkt); - break; default: /* Type Not Supported. */ DEBUG4(printk(KERN_WARNING @@ -1340,44 +1398,6 @@ qla2x00_error_entry(scsi_qla_host_t *ha, sts_entry_t *pkt) } /** - * qla2x00_ms_entry() - Process a Management Server entry. - * @ha: SCSI driver HA context - * @index: Response queue out pointer - */ -static void -qla2x00_ms_entry(scsi_qla_host_t *ha, ms_iocb_entry_t *pkt) -{ - srb_t *sp; - - DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n", - __func__, ha->host_no, pkt, pkt->handle1)); - - /* Validate handle. */ - if (pkt->handle1 < MAX_OUTSTANDING_COMMANDS) - sp = ha->outstanding_cmds[pkt->handle1]; - else - sp = NULL; - - if (sp == NULL) { - DEBUG2(printk("scsi(%ld): MS entry - invalid handle\n", - ha->host_no)); - qla_printk(KERN_WARNING, ha, "MS entry - invalid handle\n"); - - set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); - return; - } - - CMD_COMPL_STATUS(sp->cmd) = le16_to_cpu(pkt->status); - CMD_ENTRY_STATUS(sp->cmd) = pkt->entry_status; - - /* Free outstanding command slot. */ - ha->outstanding_cmds[pkt->handle1] = NULL; - - qla2x00_sp_compl(ha, sp); -} - - -/** * qla24xx_mbx_completion() - Process mailbox command completions. * @ha: SCSI driver HA context * @mb0: Mailbox0 register @@ -1449,9 +1469,6 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha) case STATUS_CONT_TYPE: qla2x00_status_cont_entry(ha, (sts_cont_entry_t *)pkt); break; - case MS_IOCB_TYPE: - qla24xx_ms_entry(ha, (struct ct_entry_24xx *)pkt); - break; case VP_RPT_ID_IOCB_TYPE: qla24xx_report_id_acquisition(ha, (struct vp_rpt_id_entry_24xx *)pkt); @@ -1533,7 +1550,6 @@ qla24xx_intr_handler(int irq, void *dev_id) scsi_qla_host_t *ha; struct device_reg_24xx __iomem *reg; int status; - unsigned long flags; unsigned long iter; uint32_t stat; uint32_t hccr; @@ -1549,13 +1565,19 @@ qla24xx_intr_handler(int irq, void *dev_id) reg = &ha->iobase->isp24; status = 0; - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock(&ha->hardware_lock); for (iter = 50; iter--; ) { stat = RD_REG_DWORD(®->host_status); if (stat & HSRX_RISC_PAUSED) { if (pci_channel_offline(ha->pdev)) break; + if (ha->hw_event_pause_errors == 0) + qla2x00_post_hwe_work(ha, HW_EVENT_PARITY_ERR, + 0, MSW(stat), LSW(stat)); + else if (ha->hw_event_pause_errors < 0xffffffff) + ha->hw_event_pause_errors++; + hccr = RD_REG_DWORD(®->hccr); qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " @@ -1597,7 +1619,7 @@ qla24xx_intr_handler(int irq, void *dev_id) WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD_RELAXED(®->hccr); } - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock(&ha->hardware_lock); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { @@ -1608,66 +1630,21 @@ qla24xx_intr_handler(int irq, void *dev_id) return IRQ_HANDLED; } -/** - * qla24xx_ms_entry() - Process a Management Server entry. - * @ha: SCSI driver HA context - * @index: Response queue out pointer - */ -static void -qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt) -{ - srb_t *sp; - - DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n", - __func__, ha->host_no, pkt, pkt->handle)); - - DEBUG9(printk("%s: ct pkt dump:\n", __func__)); - DEBUG9(qla2x00_dump_buffer((void *)pkt, sizeof(struct ct_entry_24xx))); - - /* Validate handle. */ - if (pkt->handle < MAX_OUTSTANDING_COMMANDS) - sp = ha->outstanding_cmds[pkt->handle]; - else - sp = NULL; - - if (sp == NULL) { - DEBUG2(printk("scsi(%ld): MS entry - invalid handle\n", - ha->host_no)); - DEBUG10(printk("scsi(%ld): MS entry - invalid handle\n", - ha->host_no)); - qla_printk(KERN_WARNING, ha, "MS entry - invalid handle %d\n", - pkt->handle); - - set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); - return; - } - - CMD_COMPL_STATUS(sp->cmd) = le16_to_cpu(pkt->comp_status); - CMD_ENTRY_STATUS(sp->cmd) = pkt->entry_status; - - /* Free outstanding command slot. */ - ha->outstanding_cmds[pkt->handle] = NULL; - - qla2x00_sp_compl(ha, sp); -} - static irqreturn_t qla24xx_msix_rsp_q(int irq, void *dev_id) { scsi_qla_host_t *ha; struct device_reg_24xx __iomem *reg; - unsigned long flags; ha = dev_id; reg = &ha->iobase->isp24; - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock(&ha->hardware_lock); qla24xx_process_response_queue(ha); - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock(&ha->hardware_lock); return IRQ_HANDLED; } @@ -1678,7 +1655,6 @@ qla24xx_msix_default(int irq, void *dev_id) scsi_qla_host_t *ha; struct device_reg_24xx __iomem *reg; int status; - unsigned long flags; uint32_t stat; uint32_t hccr; uint16_t mb[4]; @@ -1687,13 +1663,19 @@ qla24xx_msix_default(int irq, void *dev_id) reg = &ha->iobase->isp24; status = 0; - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock(&ha->hardware_lock); do { stat = RD_REG_DWORD(®->host_status); if (stat & HSRX_RISC_PAUSED) { if (pci_channel_offline(ha->pdev)) break; + if (ha->hw_event_pause_errors == 0) + qla2x00_post_hwe_work(ha, HW_EVENT_PARITY_ERR, + 0, MSW(stat), LSW(stat)); + else if (ha->hw_event_pause_errors < 0xffffffff) + ha->hw_event_pause_errors++; + hccr = RD_REG_DWORD(®->hccr); qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " @@ -1734,7 +1716,7 @@ qla24xx_msix_default(int irq, void *dev_id) } WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); } while (0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock(&ha->hardware_lock); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { @@ -1821,10 +1803,9 @@ qla2x00_request_irqs(scsi_qla_host_t *ha) { int ret; device_reg_t __iomem *reg = ha->iobase; - unsigned long flags; /* If possible, enable MSI-X. */ - if (!IS_QLA2432(ha) && !IS_QLA2532(ha)) + if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha)) goto skip_msix; if (IS_QLA2432(ha) && (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX || @@ -1859,7 +1840,7 @@ qla2x00_request_irqs(scsi_qla_host_t *ha) "MSI-X: Falling back-to INTa mode -- %d.\n", ret); skip_msix: - if (!IS_QLA24XX(ha) && !IS_QLA2532(ha)) + if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha)) goto skip_msi; ret = pci_enable_msi(ha->pdev); @@ -1882,7 +1863,7 @@ skip_msi: clear_risc_ints: ha->isp_ops->disable_intrs(ha); - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock_irq(&ha->hardware_lock); if (IS_FWI2_CAPABLE(ha)) { WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_HOST_INT); WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_RISC_INT); @@ -1891,7 +1872,7 @@ clear_risc_ints: WRT_REG_WORD(®->isp.hccr, HCCR_CLR_RISC_INT); WRT_REG_WORD(®->isp.hccr, HCCR_CLR_HOST_INT); } - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irq(&ha->hardware_lock); ha->isp_ops->enable_intrs(ha); fail: diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index bb103580e1ba..7d0a8a4c7719 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -310,7 +310,7 @@ qla2x00_load_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t risc_addr, } mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -367,7 +367,7 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr) } } - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -417,7 +417,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *ha, uint16_t *major, uint16_t *minor, mcp->out_mb = MBX_0; mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; mcp->flags = 0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; rval = qla2x00_mailbox_command(ha, mcp); /* Return mailbox data. */ @@ -466,7 +466,7 @@ qla2x00_get_fw_options(scsi_qla_host_t *ha, uint16_t *fwopts) mcp->mb[0] = MBC_GET_FIRMWARE_OPTION; mcp->out_mb = MBX_0; mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -524,7 +524,7 @@ qla2x00_set_fw_options(scsi_qla_host_t *ha, uint16_t *fwopts) mcp->mb[12] = 0; /* Undocumented, but used */ mcp->out_mb |= MBX_12|MBX_11|MBX_10; } - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -576,7 +576,7 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha) mcp->mb[7] = 0x2525; mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -587,6 +587,14 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha) if (mcp->mb[5] != 0xA5A5 || mcp->mb[6] != 0x5A5A || mcp->mb[7] != 0x2525) rval = QLA_FUNCTION_FAILED; + if (rval == QLA_FUNCTION_FAILED) { + struct device_reg_24xx __iomem *reg = + &ha->iobase->isp24; + + qla2xxx_hw_event_log(ha, HW_EVENT_ISP_ERR, 0, + LSW(RD_REG_DWORD(®->hccr)), + LSW(RD_REG_DWORD(®->istatus))); + } } if (rval != QLA_SUCCESS) { @@ -640,7 +648,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr) mcp->in_mb |= MBX_1; } - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -674,8 +682,8 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr) * Kernel context. */ int -qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr, - size_t size) +qla2x00_issue_iocb_timeout(scsi_qla_host_t *ha, void *buffer, + dma_addr_t phys_addr, size_t size, uint32_t tov) { int rval; mbx_cmd_t mc; @@ -689,7 +697,7 @@ qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr, mcp->mb[7] = LSW(MSD(phys_addr)); mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_2|MBX_0; - mcp->tov = 30; + mcp->tov = tov; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -710,6 +718,14 @@ qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr, return rval; } +int +qla2x00_issue_iocb(scsi_qla_host_t *ha, void *buffer, dma_addr_t phys_addr, + size_t size) +{ + return qla2x00_issue_iocb_timeout(ha, buffer, phys_addr, size, + MBX_TOV_SECONDS); +} + /* * qla2x00_abort_command * Abort command aborts a specified IOCB. @@ -760,7 +776,7 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp) mcp->mb[6] = (uint16_t)sp->cmd->device->lun; mcp->out_mb = MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -776,36 +792,20 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp) return rval; } -#if USE_ABORT_TGT -/* - * qla2x00_abort_target - * Issue abort target mailbox command. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ int -qla2x00_abort_target(fc_port_t *fcport) +qla2x00_abort_target(struct fc_port *fcport, unsigned int l) { - int rval; + int rval, rval2; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; scsi_qla_host_t *ha; - if (fcport == NULL) - return 0; - DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); + l = l; ha = fcport->ha; mcp->mb[0] = MBC_ABORT_TARGET; - mcp->out_mb = MBX_2|MBX_1|MBX_0; + mcp->out_mb = MBX_9|MBX_2|MBX_1|MBX_0; if (HAS_EXTENDED_IDS(ha)) { mcp->mb[1] = fcport->loop_id; mcp->mb[10] = 0; @@ -814,27 +814,70 @@ qla2x00_abort_target(fc_port_t *fcport) mcp->mb[1] = fcport->loop_id << 8; } mcp->mb[2] = ha->loop_reset_delay; + mcp->mb[9] = ha->vp_idx; mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } - /* Issue marker command. */ - ha->marker_needed = 1; + /* Issue marker IOCB. */ + rval2 = qla2x00_marker(ha, fcport->loop_id, 0, MK_SYNC_ID); + if (rval2 != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " + "(%x).\n", __func__, ha->host_no, rval2)); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} + +int +qla2x00_lun_reset(struct fc_port *fcport, unsigned int l) +{ + int rval, rval2; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + scsi_qla_host_t *ha; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); + + ha = fcport->ha; + mcp->mb[0] = MBC_LUN_RESET; + mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; + if (HAS_EXTENDED_IDS(ha)) + mcp->mb[1] = fcport->loop_id; + else + mcp->mb[1] = fcport->loop_id << 8; + mcp->mb[2] = l; + mcp->mb[3] = 0; + mcp->mb[9] = ha->vp_idx; + mcp->in_mb = MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); if (rval != QLA_SUCCESS) { - DEBUG2_3_11(printk("qla2x00_abort_target(%ld): failed=%x.\n", + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, ha->host_no, rval)); + } + + /* Issue marker IOCB. */ + rval2 = qla2x00_marker(ha, fcport->loop_id, l, MK_SYNC_ID_LUN); + if (rval2 != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " + "(%x).\n", __func__, ha->host_no, rval2)); } else { - /*EMPTY*/ - DEBUG11(printk("qla2x00_abort_target(%ld): done.\n", - ha->host_no)); + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return rval; } -#endif /* * qla2x00_get_adapter_id @@ -871,7 +914,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa, mcp->mb[9] = ha->vp_idx; mcp->out_mb = MBX_9|MBX_0; mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); if (mcp->mb[0] == MBS_COMMAND_ERROR) @@ -928,7 +971,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov, mcp->mb[0] = MBC_GET_RETRY_COUNT; mcp->out_mb = MBX_0; mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -995,7 +1038,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size) mcp->in_mb = MBX_5|MBX_4|MBX_0; mcp->buf_size = size; mcp->flags = MBX_DMA_OUT; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; rval = qla2x00_mailbox_command(ha, mcp); if (rval != QLA_SUCCESS) { @@ -1173,7 +1216,7 @@ gpd_error_out: * Kernel context. */ int -qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr) +qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *states) { int rval; mbx_cmd_t mc; @@ -1184,13 +1227,15 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr) mcp->mb[0] = MBC_GET_FIRMWARE_STATE; mcp->out_mb = MBX_0; - mcp->in_mb = MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); - /* Return firmware state. */ - *dptr = mcp->mb[1]; + /* Return firmware states. */ + states[0] = mcp->mb[1]; + states[1] = mcp->mb[2]; + states[2] = mcp->mb[3]; if (rval != QLA_SUCCESS) { /*EMPTY*/ @@ -1246,7 +1291,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name, } mcp->in_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -1318,7 +1363,7 @@ qla2x00_lip_reset(scsi_qla_host_t *ha) mcp->mb[3] = 0; } mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -1743,7 +1788,7 @@ qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, } mcp->in_mb = MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -1791,7 +1836,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha) mcp->mb[3] = 0; mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -1852,7 +1897,7 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma, mcp->out_mb |= MBX_6|MBX_3|MBX_2|MBX_1; } mcp->in_mb = MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -1896,7 +1941,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt, mcp->mb[0] = MBC_GET_RESOURCE_COUNTS; mcp->out_mb = MBX_0; mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -2036,7 +2081,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id, mcp->mb[1] = loop_id << 8; mcp->out_mb |= MBX_1; } - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = IOCTL_CMD; rval = qla2x00_mailbox_command(ha, mcp); @@ -2082,7 +2127,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *ha, struct link_statistics *stats, mcp->mb[10] = 0; mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; mcp->in_mb = MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = IOCTL_CMD; rval = qla2x00_mailbox_command(ha, mcp); @@ -2180,17 +2225,15 @@ struct tsk_mgmt_cmd { } p; }; -int -qla24xx_abort_target(fc_port_t *fcport) +static int +__qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, + unsigned int l) { - int rval; + int rval, rval2; struct tsk_mgmt_cmd *tsk; dma_addr_t tsk_dma; scsi_qla_host_t *ha, *pha; - if (fcport == NULL) - return 0; - DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); ha = fcport->ha; @@ -2207,47 +2250,61 @@ qla24xx_abort_target(fc_port_t *fcport) tsk->p.tsk.entry_count = 1; tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id); tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - tsk->p.tsk.control_flags = __constant_cpu_to_le32(TCF_TARGET_RESET); + tsk->p.tsk.control_flags = cpu_to_le32(type); tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa; tsk->p.tsk.port_id[1] = fcport->d_id.b.area; tsk->p.tsk.port_id[2] = fcport->d_id.b.domain; tsk->p.tsk.vp_index = fcport->vp_idx; + if (type == TCF_LUN_RESET) { + int_to_scsilun(l, &tsk->p.tsk.lun); + host_to_fcp_swap((uint8_t *)&tsk->p.tsk.lun, + sizeof(tsk->p.tsk.lun)); + } rval = qla2x00_issue_iocb(ha, tsk, tsk_dma, 0); if (rval != QLA_SUCCESS) { - DEBUG2_3_11(printk("%s(%ld): failed to issue Target Reset IOCB " - "(%x).\n", __func__, ha->host_no, rval)); - goto atarget_done; + DEBUG2_3_11(printk("%s(%ld): failed to issue %s Reset IOCB " + "(%x).\n", __func__, ha->host_no, name, rval)); } else if (tsk->p.sts.entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- error status (%x).\n", __func__, ha->host_no, tsk->p.sts.entry_status)); rval = QLA_FUNCTION_FAILED; - goto atarget_done; } else if (tsk->p.sts.comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- completion status (%x).\n", __func__, ha->host_no, le16_to_cpu(tsk->p.sts.comp_status))); rval = QLA_FUNCTION_FAILED; - goto atarget_done; } /* Issue marker IOCB. */ - rval = qla2x00_marker(ha, fcport->loop_id, 0, MK_SYNC_ID); - if (rval != QLA_SUCCESS) { + rval2 = qla2x00_marker(ha, fcport->loop_id, l, + type == TCF_LUN_RESET ? MK_SYNC_ID_LUN: MK_SYNC_ID); + if (rval2 != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " - "(%x).\n", __func__, ha->host_no, rval)); + "(%x).\n", __func__, ha->host_no, rval2)); } else { DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } -atarget_done: dma_pool_free(pha->s_dma_pool, tsk, tsk_dma); return rval; } +int +qla24xx_abort_target(struct fc_port *fcport, unsigned int l) +{ + return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l); +} + +int +qla24xx_lun_reset(struct fc_port *fcport, unsigned int l) +{ + return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l); +} + #if 0 int @@ -2304,7 +2361,7 @@ qla2x00_set_serdes_params(scsi_qla_host_t *ha, uint16_t sw_em_1g, mcp->mb[4] = sw_em_4g | BIT_15; mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -2372,7 +2429,7 @@ qla2x00_enable_eft_trace(scsi_qla_host_t *ha, dma_addr_t eft_dma, mcp->mb[7] = TC_AEN_DISABLE; mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); if (rval != QLA_SUCCESS) { @@ -2401,7 +2458,7 @@ qla2x00_disable_eft_trace(scsi_qla_host_t *ha) mcp->mb[1] = TC_EFT_DISABLE; mcp->out_mb = MBX_1|MBX_0; mcp->in_mb = MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); if (rval != QLA_SUCCESS) { @@ -2441,7 +2498,7 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *ha, dma_addr_t fce_dma, mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2| MBX_1|MBX_0; mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); if (rval != QLA_SUCCESS) { @@ -2477,7 +2534,7 @@ qla2x00_disable_fce_trace(scsi_qla_host_t *ha, uint64_t *wr, uint64_t *rd) mcp->out_mb = MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2| MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); if (rval != QLA_SUCCESS) { @@ -2525,7 +2582,7 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr, mcp->mb[10] = 0; mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -2559,7 +2616,7 @@ qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id, mcp->mb[4] = mcp->mb[5] = 0; mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -2877,7 +2934,7 @@ qla2x00_dump_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t addr, } mcp->in_mb = MBX_0; - mcp->tov = 30; + mcp->tov = MBX_TOV_SECONDS; mcp->flags = 0; rval = qla2x00_mailbox_command(ha, mcp); @@ -2890,3 +2947,104 @@ qla2x00_dump_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t addr, return rval; } + +/* 84XX Support **************************************************************/ + +struct cs84xx_mgmt_cmd { + union { + struct verify_chip_entry_84xx req; + struct verify_chip_rsp_84xx rsp; + } p; +}; + +int +qla84xx_verify_chip(struct scsi_qla_host *ha, uint16_t *status) +{ + int rval, retry; + struct cs84xx_mgmt_cmd *mn; + dma_addr_t mn_dma; + uint16_t options; + unsigned long flags; + + DEBUG16(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); + if (mn == NULL) { + DEBUG2_3(printk("%s(%ld): failed to allocate Verify ISP84XX " + "IOCB.\n", __func__, ha->host_no)); + return QLA_MEMORY_ALLOC_FAILED; + } + + /* Force Update? */ + options = ha->cs84xx->fw_update ? VCO_FORCE_UPDATE : 0; + /* Diagnostic firmware? */ + /* options |= MENLO_DIAG_FW; */ + /* We update the firmware with only one data sequence. */ + options |= VCO_END_OF_DATA; + + retry = 0; + do { + memset(mn, 0, sizeof(*mn)); + mn->p.req.entry_type = VERIFY_CHIP_IOCB_TYPE; + mn->p.req.entry_count = 1; + mn->p.req.options = cpu_to_le16(options); + + DEBUG16(printk("%s(%ld): Dump of Verify Request.\n", __func__, + ha->host_no)); + DEBUG16(qla2x00_dump_buffer((uint8_t *)mn, + sizeof(*mn))); + + rval = qla2x00_issue_iocb_timeout(ha, mn, mn_dma, 0, 120); + if (rval != QLA_SUCCESS) { + DEBUG2_16(printk("%s(%ld): failed to issue Verify " + "IOCB (%x).\n", __func__, ha->host_no, rval)); + goto verify_done; + } + + DEBUG16(printk("%s(%ld): Dump of Verify Response.\n", __func__, + ha->host_no)); + DEBUG16(qla2x00_dump_buffer((uint8_t *)mn, + sizeof(*mn))); + + status[0] = le16_to_cpu(mn->p.rsp.comp_status); + status[1] = status[0] == CS_VCS_CHIP_FAILURE ? + le16_to_cpu(mn->p.rsp.failure_code) : 0; + DEBUG2_16(printk("%s(%ld): cs=%x fc=%x\n", __func__, + ha->host_no, status[0], status[1])); + + if (status[0] != CS_COMPLETE) { + rval = QLA_FUNCTION_FAILED; + if (!(options & VCO_DONT_UPDATE_FW)) { + DEBUG2_16(printk("%s(%ld): Firmware update " + "failed. Retrying without update " + "firmware.\n", __func__, ha->host_no)); + options |= VCO_DONT_UPDATE_FW; + options &= ~VCO_FORCE_UPDATE; + retry = 1; + } + } else { + DEBUG2_16(printk("%s(%ld): firmware updated to %x.\n", + __func__, ha->host_no, + le32_to_cpu(mn->p.rsp.fw_ver))); + + /* NOTE: we only update OP firmware. */ + spin_lock_irqsave(&ha->cs84xx->access_lock, flags); + ha->cs84xx->op_fw_version = + le32_to_cpu(mn->p.rsp.fw_ver); + spin_unlock_irqrestore(&ha->cs84xx->access_lock, + flags); + } + } while (retry); + +verify_done: + dma_pool_free(ha->s_dma_pool, mn, mn_dma); + + if (rval != QLA_SUCCESS) { + DEBUG2_16(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } else { + DEBUG16(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index cf784cdafb01..f2b04979e5f0 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -1,20 +1,8 @@ /* - * QLOGIC LINUX SOFTWARE - * - * QLogic ISP2x00 device driver for Linux 2.6.x - * Copyright (C) 2003-2005 QLogic Corporation - * (www.qlogic.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 the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * QLogic Fibre Channel HBA Driver + * Copyright (c) 2003-2008 QLogic Corporation * + * See LICENSE.qla2xxx for copyright and licensing details. */ #include "qla_def.h" @@ -28,8 +16,6 @@ #include <scsi/scsicam.h> #include <linux/delay.h> -void qla2x00_vp_stop_timer(scsi_qla_host_t *); - void qla2x00_vp_stop_timer(scsi_qla_host_t *vha) { @@ -268,9 +254,17 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha) static int qla2x00_do_dpc_vp(scsi_qla_host_t *vha) { + scsi_qla_host_t *ha = vha->parent; + if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) { /* VP acquired. complete port configuration */ - qla24xx_configure_vp(vha); + if (atomic_read(&ha->loop_state) == LOOP_READY) { + qla24xx_configure_vp(vha); + } else { + set_bit(VP_IDX_ACQUIRED, &vha->vp_flags); + set_bit(VP_DPC_NEEDED, &ha->dpc_flags); + } + return 0; } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3c1b43356adb..8b33b163b1d4 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -26,9 +26,6 @@ char qla2x00_version_str[40]; */ static struct kmem_cache *srb_cachep; -/* - * Ioctl related information. - */ int num_hosts; int ql2xlogintimeout = 20; module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR); @@ -103,9 +100,9 @@ static int qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)); static int qla2xxx_eh_abort(struct scsi_cmnd *); static int qla2xxx_eh_device_reset(struct scsi_cmnd *); +static int qla2xxx_eh_target_reset(struct scsi_cmnd *); static int qla2xxx_eh_bus_reset(struct scsi_cmnd *); static int qla2xxx_eh_host_reset(struct scsi_cmnd *); -static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *); static int qla2x00_change_queue_depth(struct scsi_device *, int); static int qla2x00_change_queue_type(struct scsi_device *, int); @@ -117,6 +114,7 @@ static struct scsi_host_template qla2x00_driver_template = { .eh_abort_handler = qla2xxx_eh_abort, .eh_device_reset_handler = qla2xxx_eh_device_reset, + .eh_target_reset_handler = qla2xxx_eh_target_reset, .eh_bus_reset_handler = qla2xxx_eh_bus_reset, .eh_host_reset_handler = qla2xxx_eh_host_reset, @@ -148,6 +146,7 @@ struct scsi_host_template qla24xx_driver_template = { .eh_abort_handler = qla2xxx_eh_abort, .eh_device_reset_handler = qla2xxx_eh_device_reset, + .eh_target_reset_handler = qla2xxx_eh_target_reset, .eh_bus_reset_handler = qla2xxx_eh_bus_reset, .eh_host_reset_handler = qla2xxx_eh_host_reset, @@ -253,9 +252,9 @@ qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str) strcpy(str, "PCIe ("); if (lspeed == 1) - strcat(str, "2.5Gb/s "); + strcat(str, "2.5GT/s "); else if (lspeed == 2) - strcat(str, "5.0Gb/s "); + strcat(str, "5.0GT/s "); else strcat(str, "<unknown> "); snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth); @@ -340,6 +339,8 @@ qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str) strcat(str, "[T10 CRC] "); if (ha->fw_attributes & BIT_5) strcat(str, "[VI] "); + if (ha->fw_attributes & BIT_10) + strcat(str, "[84XX] "); if (ha->fw_attributes & BIT_13) strcat(str, "[Experimental]"); return str; @@ -570,8 +571,6 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *ha) else return_status = QLA_FUNCTION_FAILED; - DEBUG2(printk("%s return_status=%d\n",__func__,return_status)); - return (return_status); } @@ -685,7 +684,6 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld.\n", __func__, ha->host_no, sp, serial)); - DEBUG3(qla2x00_print_scsi_cmd(cmd)); spin_unlock_irqrestore(&pha->hardware_lock, flags); if (ha->isp_ops->abort_command(ha, sp)) { @@ -719,190 +717,122 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) return ret; } -/************************************************************************** -* qla2x00_eh_wait_for_pending_target_commands -* -* Description: -* Waits for all the commands to come back from the specified target. -* -* Input: -* ha - pointer to scsi_qla_host structure. -* t - target -* Returns: -* Either SUCCESS or FAILED. -* -* Note: -**************************************************************************/ +enum nexus_wait_type { + WAIT_HOST = 0, + WAIT_TARGET, + WAIT_LUN, +}; + static int -qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t) +qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha, unsigned int t, + unsigned int l, enum nexus_wait_type type) { - int cnt; - int status; - srb_t *sp; - struct scsi_cmnd *cmd; + int cnt, match, status; + srb_t *sp; unsigned long flags; scsi_qla_host_t *pha = to_qla_parent(ha); - status = 0; - - /* - * Waiting for all commands for the designated target in the active - * array - */ - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - spin_lock_irqsave(&pha->hardware_lock, flags); + status = QLA_SUCCESS; + spin_lock_irqsave(&pha->hardware_lock, flags); + for (cnt = 1; status == QLA_SUCCESS && cnt < MAX_OUTSTANDING_COMMANDS; + cnt++) { sp = pha->outstanding_cmds[cnt]; - if (sp) { - cmd = sp->cmd; - spin_unlock_irqrestore(&pha->hardware_lock, flags); - if (cmd->device->id == t && - ha->vp_idx == sp->ha->vp_idx) { - if (!qla2x00_eh_wait_on_command(ha, cmd)) { - status = 1; - break; - } - } - } else { - spin_unlock_irqrestore(&pha->hardware_lock, flags); + if (!sp) + continue; + if (ha->vp_idx != sp->ha->vp_idx) + continue; + match = 0; + switch (type) { + case WAIT_HOST: + match = 1; + break; + case WAIT_TARGET: + match = sp->cmd->device->id == t; + break; + case WAIT_LUN: + match = (sp->cmd->device->id == t && + sp->cmd->device->lun == l); + break; } + if (!match) + continue; + + spin_unlock_irqrestore(&pha->hardware_lock, flags); + status = qla2x00_eh_wait_on_command(ha, sp->cmd); + spin_lock_irqsave(&pha->hardware_lock, flags); } - return (status); + spin_unlock_irqrestore(&pha->hardware_lock, flags); + + return status; } +static char *reset_errors[] = { + "HBA not online", + "HBA not ready", + "Task management failed", + "Waiting for command completions", +}; -/************************************************************************** -* qla2xxx_eh_device_reset -* -* Description: -* The device reset function will reset the target and abort any -* executing commands. -* -* NOTE: The use of SP is undefined within this context. Do *NOT* -* attempt to use this value, even if you determine it is -* non-null. -* -* Input: -* cmd = Linux SCSI command packet of the command that cause the -* bus device reset. -* -* Returns: -* SUCCESS/FAILURE (defined as macro in scsi.h). -* -**************************************************************************/ static int -qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) +__qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, + struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int)) { scsi_qla_host_t *ha = shost_priv(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; - int ret = FAILED; - unsigned int id, lun; - unsigned long serial; + int err; qla2x00_block_error_handler(cmd); - id = cmd->device->id; - lun = cmd->device->lun; - serial = cmd->serial_number; - if (!fcport) - return ret; + return FAILED; - qla_printk(KERN_INFO, ha, - "scsi(%ld:%d:%d): DEVICE RESET ISSUED.\n", ha->host_no, id, lun); + qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET ISSUED.\n", + ha->host_no, cmd->device->id, cmd->device->lun, name); + err = 0; if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) - goto eh_dev_reset_done; - - if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) { - if (qla2x00_device_reset(ha, fcport) == 0) - ret = SUCCESS; - -#if defined(LOGOUT_AFTER_DEVICE_RESET) - if (ret == SUCCESS) { - if (fcport->flags & FC_FABRIC_DEVICE) { - ha->isp_ops->fabric_logout(ha, fcport->loop_id); - qla2x00_mark_device_lost(ha, fcport, 0, 0); - } - } -#endif - } else { - DEBUG2(printk(KERN_INFO - "%s failed: loop not ready\n",__func__)); - } - - if (ret == FAILED) { - DEBUG3(printk("%s(%ld): device reset failed\n", - __func__, ha->host_no)); - qla_printk(KERN_INFO, ha, "%s: device reset failed\n", - __func__); + goto eh_reset_failed; + err = 1; + if (qla2x00_wait_for_loop_ready(ha) != QLA_SUCCESS) + goto eh_reset_failed; + err = 2; + if (do_reset(fcport, cmd->device->lun) != QLA_SUCCESS) + goto eh_reset_failed; + err = 3; + if (qla2x00_eh_wait_for_pending_commands(ha, cmd->device->id, + cmd->device->lun, type) != QLA_SUCCESS) + goto eh_reset_failed; + + qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n", + ha->host_no, cmd->device->id, cmd->device->lun, name); + + return SUCCESS; + + eh_reset_failed: + qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n", + ha->host_no, cmd->device->id, cmd->device->lun, name, + reset_errors[err]); + return FAILED; +} - goto eh_dev_reset_done; - } +static int +qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) +{ + scsi_qla_host_t *ha = shost_priv(cmd->device->host); - /* Flush outstanding commands. */ - if (qla2x00_eh_wait_for_pending_target_commands(ha, id)) - ret = FAILED; - if (ret == FAILED) { - DEBUG3(printk("%s(%ld): failed while waiting for commands\n", - __func__, ha->host_no)); - qla_printk(KERN_INFO, ha, - "%s: failed while waiting for commands\n", __func__); - } else - qla_printk(KERN_INFO, ha, - "scsi(%ld:%d:%d): DEVICE RESET SUCCEEDED.\n", ha->host_no, - id, lun); - eh_dev_reset_done: - return ret; + return __qla2xxx_eh_generic_reset("DEVICE", WAIT_LUN, cmd, + ha->isp_ops->lun_reset); } -/************************************************************************** -* qla2x00_eh_wait_for_pending_commands -* -* Description: -* Waits for all the commands to come back from the specified host. -* -* Input: -* ha - pointer to scsi_qla_host structure. -* -* Returns: -* 1 : SUCCESS -* 0 : FAILED -* -* Note: -**************************************************************************/ static int -qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha) +qla2xxx_eh_target_reset(struct scsi_cmnd *cmd) { - int cnt; - int status; - srb_t *sp; - struct scsi_cmnd *cmd; - unsigned long flags; - - status = 1; + scsi_qla_host_t *ha = shost_priv(cmd->device->host); - /* - * Waiting for all commands for the designated target in the active - * array - */ - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - spin_lock_irqsave(&ha->hardware_lock, flags); - sp = ha->outstanding_cmds[cnt]; - if (sp) { - cmd = sp->cmd; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - status = qla2x00_eh_wait_on_command(ha, cmd); - if (status == 0) - break; - } - else { - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } - } - return (status); + return __qla2xxx_eh_generic_reset("TARGET", WAIT_TARGET, cmd, + ha->isp_ops->target_reset); } - /************************************************************************** * qla2xxx_eh_bus_reset * @@ -953,7 +883,8 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) goto eh_bus_reset_done; /* Flush outstanding commands. */ - if (!qla2x00_eh_wait_for_pending_commands(pha)) + if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) != + QLA_SUCCESS) ret = FAILED; eh_bus_reset_done: @@ -1024,7 +955,8 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags); /* Waiting for our command in done_queue to be returned to OS.*/ - if (qla2x00_eh_wait_for_pending_commands(pha)) + if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) == + QLA_SUCCESS) ret = SUCCESS; if (ha->parent) @@ -1080,7 +1012,7 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) if (fcport->port_type != FCT_TARGET) continue; - ret = qla2x00_device_reset(ha, fcport); + ret = ha->isp_ops->target_reset(fcport, 0); if (ret != QLA_SUCCESS) { DEBUG2_3(printk("%s(%ld): bus_reset failed: " "target_reset=%d d_id=%x.\n", __func__, @@ -1095,26 +1027,6 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) return QLA_SUCCESS; } -/* - * qla2x00_device_reset - * Issue bus device reset message to the target. - * - * Input: - * ha = adapter block pointer. - * t = SCSI ID. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Context: - * Kernel context. - */ -static int -qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport) -{ - /* Abort Target command will clear Reservation */ - return ha->isp_ops->abort_target(reset_fcport); -} - void qla2x00_abort_all_cmds(scsi_qla_host_t *ha, int res) { @@ -1292,7 +1204,8 @@ static struct isp_operations qla2100_isp_ops = { .enable_intrs = qla2x00_enable_intrs, .disable_intrs = qla2x00_disable_intrs, .abort_command = qla2x00_abort_command, - .abort_target = qla2x00_abort_target, + .target_reset = qla2x00_abort_target, + .lun_reset = qla2x00_lun_reset, .fabric_login = qla2x00_login_fabric, .fabric_logout = qla2x00_fabric_logout, .calc_req_entries = qla2x00_calc_iocbs_32, @@ -1325,7 +1238,8 @@ static struct isp_operations qla2300_isp_ops = { .enable_intrs = qla2x00_enable_intrs, .disable_intrs = qla2x00_disable_intrs, .abort_command = qla2x00_abort_command, - .abort_target = qla2x00_abort_target, + .target_reset = qla2x00_abort_target, + .lun_reset = qla2x00_lun_reset, .fabric_login = qla2x00_login_fabric, .fabric_logout = qla2x00_fabric_logout, .calc_req_entries = qla2x00_calc_iocbs_32, @@ -1358,7 +1272,8 @@ static struct isp_operations qla24xx_isp_ops = { .enable_intrs = qla24xx_enable_intrs, .disable_intrs = qla24xx_disable_intrs, .abort_command = qla24xx_abort_command, - .abort_target = qla24xx_abort_target, + .target_reset = qla24xx_abort_target, + .lun_reset = qla24xx_lun_reset, .fabric_login = qla24xx_login_fabric, .fabric_logout = qla24xx_fabric_logout, .calc_req_entries = NULL, @@ -1391,7 +1306,8 @@ static struct isp_operations qla25xx_isp_ops = { .enable_intrs = qla24xx_enable_intrs, .disable_intrs = qla24xx_disable_intrs, .abort_command = qla24xx_abort_command, - .abort_target = qla24xx_abort_target, + .target_reset = qla24xx_abort_target, + .lun_reset = qla24xx_lun_reset, .fabric_login = qla24xx_login_fabric, .fabric_logout = qla24xx_fabric_logout, .calc_req_entries = NULL, @@ -1464,6 +1380,13 @@ qla2x00_set_isp_flags(scsi_qla_host_t *ha) ha->device_type |= DT_IIDMA; ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; + case PCI_DEVICE_ID_QLOGIC_ISP8432: + ha->device_type |= DT_ISP8432; + ha->device_type |= DT_ZIO_SUPPORTED; + ha->device_type |= DT_FWI2; + ha->device_type |= DT_IIDMA; + ha->fw_srisc_address = RISC_START_ADDRESS_2400; + break; case PCI_DEVICE_ID_QLOGIC_ISP5422: ha->device_type |= DT_ISP5422; ha->device_type |= DT_FWI2; @@ -1587,6 +1510,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) sht = &qla2x00_driver_template; if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 || + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8432 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) { @@ -1677,7 +1601,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (IS_QLA2322(ha) || IS_QLA6322(ha)) ha->optrom_size = OPTROM_SIZE_2322; ha->isp_ops = &qla2300_isp_ops; - } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + } else if (IS_QLA24XX_TYPE(ha)) { host->max_id = MAX_TARGETS_2200; ha->mbx_count = MAILBOX_REGISTER_COUNT; ha->request_q_length = REQUEST_ENTRY_CNT_24XX; @@ -1699,6 +1623,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->gid_list_info_size = 8; ha->optrom_size = OPTROM_SIZE_25XX; ha->isp_ops = &qla25xx_isp_ops; + ha->hw_event_start = PCI_FUNC(pdev->devfn) ? + FA_HW_EVENT1_ADDR: FA_HW_EVENT0_ADDR; } host->can_queue = ha->request_q_length + 128; @@ -1713,6 +1639,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&ha->list); INIT_LIST_HEAD(&ha->fcports); INIT_LIST_HEAD(&ha->vp_list); + INIT_LIST_HEAD(&ha->work_list); set_bit(0, (unsigned long *) ha->vp_idx_map); @@ -1819,6 +1746,8 @@ qla2x00_remove_one(struct pci_dev *pdev) qla2x00_dfs_remove(ha); + qla84xx_put_chip(ha); + qla2x00_free_sysfs_attr(ha); fc_remove_host(ha->host); @@ -2206,6 +2135,97 @@ qla2x00_mem_free(scsi_qla_host_t *ha) kfree(ha->nvram); } +struct qla_work_evt * +qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type, + int locked) +{ + struct qla_work_evt *e; + + e = kzalloc(sizeof(struct qla_work_evt), locked ? GFP_ATOMIC: + GFP_KERNEL); + if (!e) + return NULL; + + INIT_LIST_HEAD(&e->list); + e->type = type; + e->flags = QLA_EVT_FLAG_FREE; + return e; +} + +int +qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked) +{ + unsigned long flags; + + if (!locked) + spin_lock_irqsave(&ha->hardware_lock, flags); + list_add_tail(&e->list, &ha->work_list); + qla2xxx_wake_dpc(ha); + if (!locked) + spin_unlock_irqrestore(&ha->hardware_lock, flags); + return QLA_SUCCESS; +} + +int +qla2x00_post_aen_work(struct scsi_qla_host *ha, enum fc_host_event_code code, + u32 data) +{ + struct qla_work_evt *e; + + e = qla2x00_alloc_work(ha, QLA_EVT_AEN, 1); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.aen.code = code; + e->u.aen.data = data; + return qla2x00_post_work(ha, e, 1); +} + +int +qla2x00_post_hwe_work(struct scsi_qla_host *ha, uint16_t code, uint16_t d1, + uint16_t d2, uint16_t d3) +{ + struct qla_work_evt *e; + + e = qla2x00_alloc_work(ha, QLA_EVT_HWE_LOG, 1); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.hwe.code = code; + e->u.hwe.d1 = d1; + e->u.hwe.d2 = d2; + e->u.hwe.d3 = d3; + return qla2x00_post_work(ha, e, 1); +} + +static void +qla2x00_do_work(struct scsi_qla_host *ha) +{ + struct qla_work_evt *e; + + spin_lock_irq(&ha->hardware_lock); + while (!list_empty(&ha->work_list)) { + e = list_entry(ha->work_list.next, struct qla_work_evt, list); + list_del_init(&e->list); + spin_unlock_irq(&ha->hardware_lock); + + switch (e->type) { + case QLA_EVT_AEN: + fc_host_post_event(ha->host, fc_get_event_number(), + e->u.aen.code, e->u.aen.data); + break; + case QLA_EVT_HWE_LOG: + qla2xxx_hw_event_log(ha, e->u.hwe.code, e->u.hwe.d1, + e->u.hwe.d2, e->u.hwe.d3); + break; + } + if (e->flags & QLA_EVT_FLAG_FREE) + kfree(e); + spin_lock_irq(&ha->hardware_lock); + } + spin_unlock_irq(&ha->hardware_lock); +} + /************************************************************************** * qla2x00_do_dpc * This kernel thread is a task that is schedule by the interrupt handler @@ -2257,6 +2277,8 @@ qla2x00_do_dpc(void *data) continue; } + qla2x00_do_work(ha); + if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) { DEBUG(printk("scsi(%ld): dpc: sched " @@ -2291,12 +2313,6 @@ qla2x00_do_dpc(void *data) if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags)) qla2x00_update_fcports(ha); - if (test_and_clear_bit(LOOP_RESET_NEEDED, &ha->dpc_flags)) { - DEBUG(printk("scsi(%ld): dpc: sched loop_reset()\n", - ha->host_no)); - qla2x00_loop_reset(ha); - } - if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) && (!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) { @@ -2367,19 +2383,6 @@ qla2x00_do_dpc(void *data) ha->host_no)); } - if ((test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags)) && - atomic_read(&ha->loop_state) != LOOP_DOWN) { - - clear_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags); - DEBUG(printk("scsi(%ld): qla2x00_login_retry()\n", - ha->host_no)); - - set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); - - DEBUG(printk("scsi(%ld): qla2x00_login_retry - end\n", - ha->host_no)); - } - if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) { DEBUG(printk("scsi(%ld): qla2x00_loop_resync()\n", @@ -2397,18 +2400,6 @@ qla2x00_do_dpc(void *data) ha->host_no)); } - if (test_and_clear_bit(FCPORT_RESCAN_NEEDED, &ha->dpc_flags)) { - - DEBUG(printk("scsi(%ld): Rescan flagged fcports...\n", - ha->host_no)); - - qla2x00_rescan_fcports(ha); - - DEBUG(printk("scsi(%ld): Rescan flagged fcports..." - "end.\n", - ha->host_no)); - } - if (!ha->interrupts_on) ha->isp_ops->enable_intrs(ha); @@ -2586,7 +2577,8 @@ qla2x00_timer(scsi_qla_host_t *ha) set_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags); start_dpc++; - if (!(ha->device_flags & DFLG_NO_CABLE)) { + if (!(ha->device_flags & DFLG_NO_CABLE) && + !ha->parent) { DEBUG(printk("scsi(%ld): Loop down - " "aborting ISP.\n", ha->host_no)); @@ -2610,10 +2602,8 @@ qla2x00_timer(scsi_qla_host_t *ha) /* Schedule the DPC routine if needed */ if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || - test_bit(LOOP_RESET_NEEDED, &ha->dpc_flags) || test_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags) || start_dpc || - test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) || test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) || test_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags) || test_bit(VP_DPC_NEEDED, &ha->dpc_flags) || @@ -2665,7 +2655,7 @@ qla2x00_request_firmware(scsi_qla_host_t *ha) blob = &qla_fw_blobs[FW_ISP2300]; } else if (IS_QLA2322(ha) || IS_QLA6322(ha)) { blob = &qla_fw_blobs[FW_ISP2322]; - } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + } else if (IS_QLA24XX_TYPE(ha)) { blob = &qla_fw_blobs[FW_ISP24XX]; } else if (IS_QLA25XX(ha)) { blob = &qla_fw_blobs[FW_ISP25XX]; @@ -2815,6 +2805,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6322) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2422) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2432) }, + { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8432) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) }, diff --git a/drivers/scsi/qla2xxx/qla_settings.h b/drivers/scsi/qla2xxx/qla_settings.h index 249e4d90fdc5..2801c2664b40 100644 --- a/drivers/scsi/qla2xxx/qla_settings.h +++ b/drivers/scsi/qla2xxx/qla_settings.h @@ -1,26 +1,12 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ -/* - * Compile time Options: - * 0 - Disable and 1 - Enable - */ -#define DEBUG_QLA2100 0 /* For Debug of qla2x00 */ - -#define USE_ABORT_TGT 1 /* Use Abort Target mbx cmd */ - #define MAX_RETRIES_OF_ISP_ABORT 5 /* Max time to wait for the loop to be in LOOP_READY state */ #define MAX_LOOP_TIMEOUT (60 * 5) -/* - * Some vendor subsystems do not recover properly after a device reset. Define - * the following to force a logout after a successful device reset. - */ -#undef LOGOUT_AFTER_DEVICE_RESET - #include "qla_version.h" diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 26822c8807ee..1728ab3ccb20 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -1,6 +1,6 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ @@ -543,79 +543,174 @@ qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id, } } -static int -qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, - uint32_t dwords) +void +qla2xxx_get_flash_info(scsi_qla_host_t *ha) { - int ret; - uint32_t liter, miter; - uint32_t sec_mask, rest_addr, conf_addr; - uint32_t fdata, findex, cnt; +#define FLASH_BLK_SIZE_32K 0x8000 +#define FLASH_BLK_SIZE_64K 0x10000 + uint16_t cnt, chksum; + uint16_t *wptr; + struct qla_fdt_layout *fdt; uint8_t man_id, flash_id; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - dma_addr_t optrom_dma; - void *optrom = NULL; - uint32_t *s, *d; - ret = QLA_SUCCESS; + if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha)) + return; - /* Prepare burst-capable write on supported ISPs. */ - if (IS_QLA25XX(ha) && !(faddr & 0xfff) && - dwords > OPTROM_BURST_DWORDS) { - optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, - &optrom_dma, GFP_KERNEL); - if (!optrom) { - qla_printk(KERN_DEBUG, ha, - "Unable to allocate memory for optrom burst write " - "(%x KB).\n", OPTROM_BURST_SIZE / 1024); - } + wptr = (uint16_t *)ha->request_ring; + fdt = (struct qla_fdt_layout *)ha->request_ring; + ha->isp_ops->read_optrom(ha, (uint8_t *)ha->request_ring, + FA_FLASH_DESCR_ADDR << 2, OPTROM_BURST_SIZE); + if (*wptr == __constant_cpu_to_le16(0xffff)) + goto no_flash_data; + if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' || + fdt->sig[3] != 'D') + goto no_flash_data; + + for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1; + cnt++) + chksum += le16_to_cpu(*wptr++); + if (chksum) { + DEBUG2(qla_printk(KERN_INFO, ha, "Inconsistent FDT detected: " + "checksum=0x%x id=%c version=0x%x.\n", chksum, fdt->sig[0], + le16_to_cpu(fdt->version))); + DEBUG9(qla2x00_dump_buffer((uint8_t *)fdt, sizeof(*fdt))); + goto no_flash_data; } - qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); - DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, - ha->host_no, man_id, flash_id)); + ha->fdt_odd_index = le16_to_cpu(fdt->man_id) == 0x1f; + ha->fdt_wrt_disable = fdt->wrt_disable_bits; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd); + ha->fdt_block_size = le32_to_cpu(fdt->block_size); + if (fdt->unprotect_sec_cmd) { + ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0300 | + fdt->unprotect_sec_cmd); + ha->fdt_protect_sec_cmd = fdt->protect_sec_cmd ? + flash_conf_to_access_addr(0x0300 | fdt->protect_sec_cmd): + flash_conf_to_access_addr(0x0336); + } - conf_addr = flash_conf_to_access_addr(0x03d8); + DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[FDT]: (0x%x/0x%x) erase=0x%x " + "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", + le16_to_cpu(fdt->man_id), le16_to_cpu(fdt->id), ha->fdt_erase_cmd, + ha->fdt_protect_sec_cmd, ha->fdt_unprotect_sec_cmd, + ha->fdt_odd_index, ha->fdt_wrt_disable, ha->fdt_block_size)); + return; + +no_flash_data: + qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); + ha->fdt_wrt_disable = 0x9c; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x03d8); switch (man_id) { case 0xbf: /* STT flash. */ - if (flash_id == 0x8e) { - rest_addr = 0x3fff; - sec_mask = 0x7c000; - } else { - rest_addr = 0x1fff; - sec_mask = 0x7e000; - } + if (flash_id == 0x8e) + ha->fdt_block_size = FLASH_BLK_SIZE_64K; + else + ha->fdt_block_size = FLASH_BLK_SIZE_32K; + if (flash_id == 0x80) - conf_addr = flash_conf_to_access_addr(0x0352); + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0352); break; case 0x13: /* ST M25P80. */ - rest_addr = 0x3fff; - sec_mask = 0x7c000; + ha->fdt_block_size = FLASH_BLK_SIZE_64K; break; - case 0x1f: // Atmel 26DF081A - rest_addr = 0x3fff; - sec_mask = 0x7c000; - conf_addr = flash_conf_to_access_addr(0x0320); + case 0x1f: /* Atmel 26DF081A. */ + ha->fdt_odd_index = 1; + ha->fdt_block_size = FLASH_BLK_SIZE_64K; + ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0320); + ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0339); + ha->fdt_protect_sec_cmd = flash_conf_to_access_addr(0x0336); break; default: /* Default to 64 kb sector size. */ - rest_addr = 0x3fff; - sec_mask = 0x7c000; + ha->fdt_block_size = FLASH_BLK_SIZE_64K; break; } + DEBUG2(qla_printk(KERN_DEBUG, ha, "Flash[MID]: (0x%x/0x%x) erase=0x%x " + "pro=%x upro=%x idx=%d wrtd=0x%x blk=0x%x.\n", man_id, flash_id, + ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd, + ha->fdt_unprotect_sec_cmd, ha->fdt_odd_index, ha->fdt_wrt_disable, + ha->fdt_block_size)); +} + +static void +qla24xx_unprotect_flash(scsi_qla_host_t *ha) +{ + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + /* Enable flash write. */ WRT_REG_DWORD(®->ctrl_status, RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ + if (!ha->fdt_wrt_disable) + return; + /* Disable flash write-protection. */ qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); /* Some flash parts need an additional zero-write to clear bits.*/ qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); +} + +static void +qla24xx_protect_flash(scsi_qla_host_t *ha) +{ + uint32_t cnt; + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + + if (!ha->fdt_wrt_disable) + goto skip_wrt_protect; + + /* Enable flash write-protection and wait for completion. */ + qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), + ha->fdt_wrt_disable); + for (cnt = 300; cnt && + qla24xx_read_flash_dword(ha, + flash_conf_to_access_addr(0x005)) & BIT_0; + cnt--) { + udelay(10); + } + +skip_wrt_protect: + /* Disable flash write. */ + WRT_REG_DWORD(®->ctrl_status, + RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); + RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ +} + +static int +qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, + uint32_t dwords) +{ + int ret; + uint32_t liter, miter; + uint32_t sec_mask, rest_addr; + uint32_t fdata, findex; + dma_addr_t optrom_dma; + void *optrom = NULL; + uint32_t *s, *d; + + ret = QLA_SUCCESS; + + /* Prepare burst-capable write on supported ISPs. */ + if (IS_QLA25XX(ha) && !(faddr & 0xfff) && + dwords > OPTROM_BURST_DWORDS) { + optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, + &optrom_dma, GFP_KERNEL); + if (!optrom) { + qla_printk(KERN_DEBUG, ha, + "Unable to allocate memory for optrom burst write " + "(%x KB).\n", OPTROM_BURST_SIZE / 1024); + } + } + + rest_addr = (ha->fdt_block_size >> 2) - 1; + sec_mask = 0x80000 - (ha->fdt_block_size >> 2); + + qla24xx_unprotect_flash(ha); for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { - if (man_id == 0x1f) { + if (ha->fdt_odd_index) { findex = faddr << 2; fdata = findex & sec_mask; } else { @@ -625,13 +720,13 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, /* Are we at the beginning of a sector? */ if ((findex & rest_addr) == 0) { - /* Do sector unprotect at 4K boundry for Atmel part. */ - if (man_id == 0x1f) + /* Do sector unprotect. */ + if (ha->fdt_unprotect_sec_cmd) qla24xx_write_flash_dword(ha, - flash_conf_to_access_addr(0x0339), + ha->fdt_unprotect_sec_cmd, (fdata & 0xff00) | ((fdata << 16) & 0xff0000) | ((fdata >> 16) & 0xff)); - ret = qla24xx_write_flash_dword(ha, conf_addr, + ret = qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd, (fdata & 0xff00) |((fdata << 16) & 0xff0000) | ((fdata >> 16) & 0xff)); if (ret != QLA_SUCCESS) { @@ -681,28 +776,16 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, break; } - /* Do sector protect at 4K boundry for Atmel part. */ - if (man_id == 0x1f && + /* Do sector protect. */ + if (ha->fdt_unprotect_sec_cmd && ((faddr & rest_addr) == rest_addr)) qla24xx_write_flash_dword(ha, - flash_conf_to_access_addr(0x0336), + ha->fdt_protect_sec_cmd, (fdata & 0xff00) | ((fdata << 16) & 0xff0000) | ((fdata >> 16) & 0xff)); } - /* Enable flash write-protection and wait for completion. */ - qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0x9c); - for (cnt = 300; cnt && - qla24xx_read_flash_dword(ha, - flash_conf_to_access_addr(0x005)) & BIT_0; - cnt--) { - udelay(10); - } - - /* Disable flash write. */ - WRT_REG_DWORD(®->ctrl_status, - RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); - RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ + qla24xx_protect_flash(ha); if (optrom) dma_free_coherent(&ha->pdev->dev, @@ -2221,3 +2304,107 @@ qla24xx_get_flash_version(scsi_qla_host_t *ha, void *mbuf) return ret; } + +static int +qla2xxx_hw_event_store(scsi_qla_host_t *ha, uint32_t *fdata) +{ + uint32_t d[2], faddr; + + /* Locate first empty entry. */ + for (;;) { + if (ha->hw_event_ptr >= + ha->hw_event_start + FA_HW_EVENT_SIZE) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "HW event -- Log Full!\n")); + return QLA_MEMORY_ALLOC_FAILED; + } + + qla24xx_read_flash_data(ha, d, ha->hw_event_ptr, 2); + faddr = flash_data_to_access_addr(ha->hw_event_ptr); + ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE; + if (d[0] == __constant_cpu_to_le32(0xffffffff) && + d[1] == __constant_cpu_to_le32(0xffffffff)) { + qla24xx_unprotect_flash(ha); + + qla24xx_write_flash_dword(ha, faddr++, + cpu_to_le32(jiffies)); + qla24xx_write_flash_dword(ha, faddr++, 0); + qla24xx_write_flash_dword(ha, faddr++, *fdata++); + qla24xx_write_flash_dword(ha, faddr++, *fdata); + + qla24xx_protect_flash(ha); + break; + } + } + return QLA_SUCCESS; +} + +int +qla2xxx_hw_event_log(scsi_qla_host_t *ha, uint16_t code, uint16_t d1, + uint16_t d2, uint16_t d3) +{ +#define QMARK(a, b, c, d) \ + cpu_to_le32(LSB(a) << 24 | LSB(b) << 16 | LSB(c) << 8 | LSB(d)) + + int rval; + uint32_t marker[2], fdata[4]; + + if (ha->hw_event_start == 0) + return QLA_FUNCTION_FAILED; + + DEBUG2(qla_printk(KERN_WARNING, ha, + "HW event -- code=%x, d1=%x, d2=%x, d3=%x.\n", code, d1, d2, d3)); + + /* If marker not already found, locate or write. */ + if (!ha->flags.hw_event_marker_found) { + /* Create marker. */ + marker[0] = QMARK('L', ha->fw_major_version, + ha->fw_minor_version, ha->fw_subminor_version); + marker[1] = QMARK(QLA_DRIVER_MAJOR_VER, QLA_DRIVER_MINOR_VER, + QLA_DRIVER_PATCH_VER, QLA_DRIVER_BETA_VER); + + /* Locate marker. */ + ha->hw_event_ptr = ha->hw_event_start; + for (;;) { + qla24xx_read_flash_data(ha, fdata, ha->hw_event_ptr, + 4); + if (fdata[0] == __constant_cpu_to_le32(0xffffffff) && + fdata[1] == __constant_cpu_to_le32(0xffffffff)) + break; + ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE; + if (ha->hw_event_ptr >= + ha->hw_event_start + FA_HW_EVENT_SIZE) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "HW event -- Log Full!\n")); + return QLA_MEMORY_ALLOC_FAILED; + } + if (fdata[2] == marker[0] && fdata[3] == marker[1]) { + ha->flags.hw_event_marker_found = 1; + break; + } + } + /* No marker, write it. */ + if (!ha->flags.hw_event_marker_found) { + rval = qla2xxx_hw_event_store(ha, marker); + if (rval != QLA_SUCCESS) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "HW event -- Failed marker write=%x.!\n", + rval)); + return rval; + } + ha->flags.hw_event_marker_found = 1; + } + } + + /* Store error. */ + fdata[0] = cpu_to_le32(code << 16 | d1); + fdata[1] = cpu_to_le32(d2 << 16 | d3); + rval = qla2xxx_hw_event_store(ha, fdata); + if (rval != QLA_SUCCESS) { + DEBUG2(qla_printk(KERN_WARNING, ha, + "HW event -- Failed error write=%x.!\n", + rval)); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index ea08a129fee9..f42f17acf2cf 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -1,15 +1,15 @@ /* * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2005 QLogic Corporation + * Copyright (c) 2003-2008 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */ /* * Driver version */ -#define QLA2XXX_VERSION "8.02.00-k9" +#define QLA2XXX_VERSION "8.02.01-k1" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 2 -#define QLA_DRIVER_PATCH_VER 0 +#define QLA_DRIVER_PATCH_VER 1 #define QLA_DRIVER_BETA_VER 0 diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index fe415ec85655..1b667a70cffa 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -216,6 +216,7 @@ union external_hw_config_reg { #define MBOX_CMD_ABOUT_FW 0x0009 #define MBOX_CMD_PING 0x000B #define MBOX_CMD_LUN_RESET 0x0016 +#define MBOX_CMD_TARGET_WARM_RESET 0x0017 #define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E #define MBOX_CMD_GET_FW_STATUS 0x001F #define MBOX_CMD_SET_ISNS_SERVICE 0x0021 @@ -677,7 +678,8 @@ struct qla4_marker_entry { uint32_t system_defined; /* 04-07 */ uint16_t target; /* 08-09 */ uint16_t modifier; /* 0A-0B */ -#define MM_LUN_RESET 0 +#define MM_LUN_RESET 0 +#define MM_TGT_WARM_RESET 1 uint16_t flags; /* 0C-0D */ uint16_t reserved1; /* 0E-0F */ diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index a3608e028bf6..96ebfb021f6c 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -27,6 +27,8 @@ int qla4xxx_relogin_device(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry); int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, int lun); +int qla4xxx_reset_target(struct scsi_qla_host * ha, + struct ddb_entry * ddb_entry); int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, uint32_t offset, uint32_t len); int qla4xxx_get_firmware_status(struct scsi_qla_host * ha); @@ -68,6 +70,8 @@ int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha); int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha, uint32_t fw_ddb_index, uint32_t state); void qla4xxx_dump_buffer(void *b, uint32_t size); +int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod); extern int ql4xextended_error_logging; extern int ql4xdiscoverywait; diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c index e4461b5d767a..912a67494adf 100644 --- a/drivers/scsi/qla4xxx/ql4_iocb.c +++ b/drivers/scsi/qla4xxx/ql4_iocb.c @@ -66,8 +66,8 @@ static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha, * * This routine issues a marker IOCB. **/ -static int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, int lun) +int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod) { struct qla4_marker_entry *marker_entry; unsigned long flags = 0; @@ -87,7 +87,7 @@ static int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, marker_entry->hdr.entryType = ET_MARKER; marker_entry->hdr.entryCount = 1; marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index); - marker_entry->modifier = cpu_to_le16(MM_LUN_RESET); + marker_entry->modifier = cpu_to_le16(mrkr_mod); int_to_scsilun(lun, &marker_entry->lun); wmb(); @@ -210,14 +210,6 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) /* Get real lun and adapter */ ddb_entry = srb->ddb; - /* Send marker(s) if needed. */ - if (ha->marker_needed == 1) { - if (qla4xxx_send_marker_iocb(ha, ddb_entry, - cmd->device->lun) != QLA_SUCCESS) - return QLA_ERROR; - - ha->marker_needed = 0; - } tot_dsds = 0; /* Acquire hardware specific lock */ diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c index fc84db4069f4..a91a57c57bff 100644 --- a/drivers/scsi/qla4xxx/ql4_isr.c +++ b/drivers/scsi/qla4xxx/ql4_isr.c @@ -11,28 +11,6 @@ #include "ql4_inline.h" /** - * qla2x00_process_completed_request() - Process a Fast Post response. - * @ha: SCSI driver HA context - * @index: SRB index - **/ -static void qla4xxx_process_completed_request(struct scsi_qla_host *ha, - uint32_t index) -{ - struct srb *srb; - - srb = qla4xxx_del_from_active_array(ha, index); - if (srb) { - /* Save ISP completion status */ - srb->cmd->result = DID_OK << 16; - qla4xxx_srb_compl(ha, srb); - } else { - DEBUG2(printk("scsi%ld: Invalid ISP SCSI completion handle = " - "%d\n", ha->host_no, index)); - set_bit(DPC_RESET_HA, &ha->dpc_flags); - } -} - -/** * qla4xxx_status_entry - processes status IOCBs * @ha: Pointer to host adapter structure. * @sts_entry: Pointer to status entry structure. @@ -47,14 +25,6 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, uint32_t residual; uint16_t sensebytecnt; - if (sts_entry->completionStatus == SCS_COMPLETE && - sts_entry->scsiStatus == 0) { - qla4xxx_process_completed_request(ha, - le32_to_cpu(sts_entry-> - handle)); - return; - } - srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle)); if (!srb) { /* FIXMEdg: Don't we need to reset ISP in this case??? */ @@ -62,6 +32,9 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, "handle 0x%x, sp=%p. This cmd may have already " "been completed.\n", ha->host_no, __func__, le32_to_cpu(sts_entry->handle), srb)); + dev_warn(&ha->pdev->dev, "%s invalid status entry:" + " handle=0x%0x\n", __func__, sts_entry->handle); + set_bit(DPC_RESET_HA, &ha->dpc_flags); return; } @@ -88,10 +61,6 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, scsi_status = sts_entry->scsiStatus; switch (sts_entry->completionStatus) { case SCS_COMPLETE: - if (scsi_status == 0) { - cmd->result = DID_OK << 16; - break; - } if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) { cmd->result = DID_ERROR << 16; @@ -100,7 +69,8 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha, if (sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_UNDER) { scsi_set_resid(cmd, residual); - if ((scsi_bufflen(cmd) - residual) < cmd->underflow) { + if (!scsi_status && ((scsi_bufflen(cmd) - residual) < + cmd->underflow)) { cmd->result = DID_ERROR << 16; diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 35cd73c72a68..c577d79bd7e8 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -713,6 +713,45 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, return status; } +/** + * qla4xxx_reset_target - issues target Reset + * @ha: Pointer to host adapter structure. + * @db_entry: Pointer to device database entry + * @un_entry: Pointer to lun entry structure + * + * This routine performs a TARGET RESET on the specified target. + * The caller must ensure that the ddb_entry pointers + * are valid before calling this routine. + **/ +int qla4xxx_reset_target(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry) +{ + uint32_t mbox_cmd[MBOX_REG_COUNT]; + uint32_t mbox_sts[MBOX_REG_COUNT]; + int status = QLA_SUCCESS; + + DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no, + ddb_entry->os_target_id)); + + /* + * Send target reset command to ISP, so that the ISP will return all + * outstanding requests with RESET status + */ + memset(&mbox_cmd, 0, sizeof(mbox_cmd)); + memset(&mbox_sts, 0, sizeof(mbox_sts)); + + mbox_cmd[0] = MBOX_CMD_TARGET_WARM_RESET; + mbox_cmd[1] = ddb_entry->fw_ddb_index; + mbox_cmd[5] = 0x01; /* Immediate Command Enable */ + + qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], + &mbox_sts[0]); + if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE && + mbox_sts[0] != MBOX_STS_COMMAND_ERROR) + status = QLA_ERROR; + + return status; +} int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, uint32_t offset, uint32_t len) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 8b92f348f02c..0c786944d2c2 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -71,6 +71,7 @@ static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session); static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *)); static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); +static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); static int qla4xxx_slave_alloc(struct scsi_device *device); static int qla4xxx_slave_configure(struct scsi_device *device); @@ -84,6 +85,7 @@ static struct scsi_host_template qla4xxx_driver_template = { .queuecommand = qla4xxx_queuecommand, .eh_device_reset_handler = qla4xxx_eh_device_reset, + .eh_target_reset_handler = qla4xxx_eh_target_reset, .eh_host_reset_handler = qla4xxx_eh_host_reset, .slave_configure = qla4xxx_slave_configure, @@ -1482,7 +1484,7 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) } /** - * qla4xxx_eh_wait_for_active_target_commands - wait for active cmds to finish. + * qla4xxx_eh_wait_for_commands - wait for active cmds to finish. * @ha: pointer to to HBA * @t: target id * @l: lun id @@ -1490,20 +1492,22 @@ static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) * This function waits for all outstanding commands to a lun to complete. It * returns 0 if all pending commands are returned and 1 otherwise. **/ -static int qla4xxx_eh_wait_for_active_target_commands(struct scsi_qla_host *ha, - int t, int l) +static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha, + struct scsi_target *stgt, + struct scsi_device *sdev) { int cnt; int status = 0; struct scsi_cmnd *cmd; /* - * Waiting for all commands for the designated target in the active - * array + * Waiting for all commands for the designated target or dev + * in the active array */ for (cnt = 0; cnt < ha->host->can_queue; cnt++) { cmd = scsi_host_find_tag(ha->host, cnt); - if (cmd && cmd->device->id == t && cmd->device->lun == l) { + if (cmd && stgt == scsi_target(cmd->device) && + (!sdev || sdev == cmd->device)) { if (!qla4xxx_eh_wait_on_command(ha, cmd)) { status++; break; @@ -1548,24 +1552,19 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) goto eh_dev_reset_done; } - /* Send marker. */ - ha->marker_needed = 1; - - /* - * If we are coming down the EH path, wait for all commands to complete - * for the device. - */ - if (cmd->device->host->shost_state == SHOST_RECOVERY) { - if (qla4xxx_eh_wait_for_active_target_commands(ha, - cmd->device->id, - cmd->device->lun)){ - dev_info(&ha->pdev->dev, - "DEVICE RESET FAILED - waiting for " - "commands.\n"); - goto eh_dev_reset_done; - } + if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), + cmd->device)) { + dev_info(&ha->pdev->dev, + "DEVICE RESET FAILED - waiting for " + "commands.\n"); + goto eh_dev_reset_done; } + /* Send marker. */ + if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, + MM_LUN_RESET) != QLA_SUCCESS) + goto eh_dev_reset_done; + dev_info(&ha->pdev->dev, "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", ha->host_no, cmd->device->channel, cmd->device->id, @@ -1579,6 +1578,59 @@ eh_dev_reset_done: } /** + * qla4xxx_eh_target_reset - callback for target reset. + * @cmd: Pointer to Linux's SCSI command structure + * + * This routine is called by the Linux OS to reset the target. + **/ +static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) +{ + struct scsi_qla_host *ha = to_qla_host(cmd->device->host); + struct ddb_entry *ddb_entry = cmd->device->hostdata; + int stat; + + if (!ddb_entry) + return FAILED; + + starget_printk(KERN_INFO, scsi_target(cmd->device), + "WARM TARGET RESET ISSUED.\n"); + + DEBUG2(printk(KERN_INFO + "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, " + "to=%x,dpc_flags=%lx, status=%x allowed=%d\n", + ha->host_no, cmd, jiffies, cmd->timeout_per_command / HZ, + ha->dpc_flags, cmd->result, cmd->allowed)); + + stat = qla4xxx_reset_target(ha, ddb_entry); + if (stat != QLA_SUCCESS) { + starget_printk(KERN_INFO, scsi_target(cmd->device), + "WARM TARGET RESET FAILED.\n"); + return FAILED; + } + + if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), + NULL)) { + starget_printk(KERN_INFO, scsi_target(cmd->device), + "WARM TARGET DEVICE RESET FAILED - " + "waiting for commands.\n"); + return FAILED; + } + + /* Send marker. */ + if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, + MM_TGT_WARM_RESET) != QLA_SUCCESS) { + starget_printk(KERN_INFO, scsi_target(cmd->device), + "WARM TARGET DEVICE RESET FAILED - " + "marker iocb failed.\n"); + return FAILED; + } + + starget_printk(KERN_INFO, scsi_target(cmd->device), + "WARM TARGET RESET SUCCEEDED.\n"); + return SUCCESS; +} + +/** * qla4xxx_eh_host_reset - kernel callback * @cmd: Pointer to Linux's SCSI command structure * diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c index 86e13183c9ba..52182a744ba6 100644 --- a/drivers/scsi/raid_class.c +++ b/drivers/scsi/raid_class.c @@ -289,7 +289,7 @@ raid_class_release(struct raid_template *r) { struct raid_internal *i = to_raid_internal(r); - attribute_container_unregister(&i->r.raid_attrs.ac); + BUG_ON(attribute_container_unregister(&i->r.raid_attrs.ac)); kfree(i); } diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index c78b836f59dd..f6980bd9d8f9 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -166,6 +166,51 @@ static struct scsi_host_cmd_pool scsi_cmd_dma_pool = { static DEFINE_MUTEX(host_cmd_pool_mutex); /** + * scsi_pool_alloc_command - internal function to get a fully allocated command + * @pool: slab pool to allocate the command from + * @gfp_mask: mask for the allocation + * + * Returns a fully allocated command (with the allied sense buffer) or + * NULL on failure + */ +static struct scsi_cmnd * +scsi_pool_alloc_command(struct scsi_host_cmd_pool *pool, gfp_t gfp_mask) +{ + struct scsi_cmnd *cmd; + + cmd = kmem_cache_alloc(pool->cmd_slab, gfp_mask | pool->gfp_mask); + if (!cmd) + return NULL; + + memset(cmd, 0, sizeof(*cmd)); + + cmd->sense_buffer = kmem_cache_alloc(pool->sense_slab, + gfp_mask | pool->gfp_mask); + if (!cmd->sense_buffer) { + kmem_cache_free(pool->cmd_slab, cmd); + return NULL; + } + + return cmd; +} + +/** + * scsi_pool_free_command - internal function to release a command + * @pool: slab pool to allocate the command from + * @cmd: command to release + * + * the command must previously have been allocated by + * scsi_pool_alloc_command. + */ +static void +scsi_pool_free_command(struct scsi_host_cmd_pool *pool, + struct scsi_cmnd *cmd) +{ + kmem_cache_free(pool->sense_slab, cmd->sense_buffer); + kmem_cache_free(pool->cmd_slab, cmd); +} + +/** * __scsi_get_command - Allocate a struct scsi_cmnd * @shost: host to transmit command * @gfp_mask: allocation mask @@ -178,20 +223,7 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) struct scsi_cmnd *cmd; unsigned char *buf; - cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab, - gfp_mask | shost->cmd_pool->gfp_mask); - - if (likely(cmd)) { - buf = kmem_cache_alloc(shost->cmd_pool->sense_slab, - gfp_mask | shost->cmd_pool->gfp_mask); - if (likely(buf)) { - memset(cmd, 0, sizeof(*cmd)); - cmd->sense_buffer = buf; - } else { - kmem_cache_free(shost->cmd_pool->cmd_slab, cmd); - cmd = NULL; - } - } + cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask); if (unlikely(!cmd)) { unsigned long flags; @@ -268,11 +300,8 @@ void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd, } spin_unlock_irqrestore(&shost->free_list_lock, flags); - if (likely(cmd != NULL)) { - kmem_cache_free(shost->cmd_pool->sense_slab, - cmd->sense_buffer); - kmem_cache_free(shost->cmd_pool->cmd_slab, cmd); - } + if (likely(cmd != NULL)) + scsi_pool_free_command(shost->cmd_pool, cmd); put_device(dev); } @@ -301,30 +330,16 @@ void scsi_put_command(struct scsi_cmnd *cmd) } EXPORT_SYMBOL(scsi_put_command); -/** - * scsi_setup_command_freelist - Setup the command freelist for a scsi host. - * @shost: host to allocate the freelist for. - * - * Description: The command freelist protects against system-wide out of memory - * deadlock by preallocating one SCSI command structure for each host, so the - * system can always write to a swap file on a device associated with that host. - * - * Returns: Nothing. - */ -int scsi_setup_command_freelist(struct Scsi_Host *shost) +static struct scsi_host_cmd_pool *scsi_get_host_cmd_pool(gfp_t gfp_mask) { - struct scsi_host_cmd_pool *pool; - struct scsi_cmnd *cmd; - - spin_lock_init(&shost->free_list_lock); - INIT_LIST_HEAD(&shost->free_list); - + struct scsi_host_cmd_pool *retval = NULL, *pool; /* * Select a command slab for this host and create it if not * yet existent. */ mutex_lock(&host_cmd_pool_mutex); - pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool); + pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool : + &scsi_cmd_pool; if (!pool->users) { pool->cmd_slab = kmem_cache_create(pool->cmd_name, sizeof(struct scsi_cmnd), 0, @@ -342,37 +357,122 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost) } pool->users++; - shost->cmd_pool = pool; + retval = pool; + fail: mutex_unlock(&host_cmd_pool_mutex); + return retval; +} + +static void scsi_put_host_cmd_pool(gfp_t gfp_mask) +{ + struct scsi_host_cmd_pool *pool; + mutex_lock(&host_cmd_pool_mutex); + pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool : + &scsi_cmd_pool; /* - * Get one backup command for this host. + * This may happen if a driver has a mismatched get and put + * of the command pool; the driver should be implicated in + * the stack trace */ - cmd = kmem_cache_alloc(shost->cmd_pool->cmd_slab, - GFP_KERNEL | shost->cmd_pool->gfp_mask); - if (!cmd) - goto fail2; + BUG_ON(pool->users == 0); - cmd->sense_buffer = kmem_cache_alloc(shost->cmd_pool->sense_slab, - GFP_KERNEL | - shost->cmd_pool->gfp_mask); - if (!cmd->sense_buffer) - goto fail2; - - list_add(&cmd->list, &shost->free_list); - return 0; - - fail2: - if (cmd) - kmem_cache_free(shost->cmd_pool->cmd_slab, cmd); - mutex_lock(&host_cmd_pool_mutex); if (!--pool->users) { kmem_cache_destroy(pool->cmd_slab); kmem_cache_destroy(pool->sense_slab); } - fail: mutex_unlock(&host_cmd_pool_mutex); - return -ENOMEM; +} + +/** + * scsi_allocate_command - get a fully allocated SCSI command + * @gfp_mask: allocation mask + * + * This function is for use outside of the normal host based pools. + * It allocates the relevant command and takes an additional reference + * on the pool it used. This function *must* be paired with + * scsi_free_command which also has the identical mask, otherwise the + * free pool counts will eventually go wrong and you'll trigger a bug. + * + * This function should *only* be used by drivers that need a static + * command allocation at start of day for internal functions. + */ +struct scsi_cmnd *scsi_allocate_command(gfp_t gfp_mask) +{ + struct scsi_host_cmd_pool *pool = scsi_get_host_cmd_pool(gfp_mask); + + if (!pool) + return NULL; + + return scsi_pool_alloc_command(pool, gfp_mask); +} +EXPORT_SYMBOL(scsi_allocate_command); + +/** + * scsi_free_command - free a command allocated by scsi_allocate_command + * @gfp_mask: mask used in the original allocation + * @cmd: command to free + * + * Note: using the original allocation mask is vital because that's + * what determines which command pool we use to free the command. Any + * mismatch will cause the system to BUG eventually. + */ +void scsi_free_command(gfp_t gfp_mask, struct scsi_cmnd *cmd) +{ + struct scsi_host_cmd_pool *pool = scsi_get_host_cmd_pool(gfp_mask); + + /* + * this could trigger if the mask to scsi_allocate_command + * doesn't match this mask. Otherwise we're guaranteed that this + * succeeds because scsi_allocate_command must have taken a reference + * on the pool + */ + BUG_ON(!pool); + + scsi_pool_free_command(pool, cmd); + /* + * scsi_put_host_cmd_pool is called twice; once to release the + * reference we took above, and once to release the reference + * originally taken by scsi_allocate_command + */ + scsi_put_host_cmd_pool(gfp_mask); + scsi_put_host_cmd_pool(gfp_mask); +} +EXPORT_SYMBOL(scsi_free_command); + +/** + * scsi_setup_command_freelist - Setup the command freelist for a scsi host. + * @shost: host to allocate the freelist for. + * + * Description: The command freelist protects against system-wide out of memory + * deadlock by preallocating one SCSI command structure for each host, so the + * system can always write to a swap file on a device associated with that host. + * + * Returns: Nothing. + */ +int scsi_setup_command_freelist(struct Scsi_Host *shost) +{ + struct scsi_cmnd *cmd; + const gfp_t gfp_mask = shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL; + + spin_lock_init(&shost->free_list_lock); + INIT_LIST_HEAD(&shost->free_list); + + shost->cmd_pool = scsi_get_host_cmd_pool(gfp_mask); + + if (!shost->cmd_pool) + return -ENOMEM; + + /* + * Get one backup command for this host. + */ + cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask); + if (!cmd) { + scsi_put_host_cmd_pool(gfp_mask); + return -ENOMEM; + } + list_add(&cmd->list, &shost->free_list); + return 0; } /** @@ -386,17 +486,10 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost) cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list); list_del_init(&cmd->list); - kmem_cache_free(shost->cmd_pool->sense_slab, - cmd->sense_buffer); - kmem_cache_free(shost->cmd_pool->cmd_slab, cmd); + scsi_pool_free_command(shost->cmd_pool, cmd); } - - mutex_lock(&host_cmd_pool_mutex); - if (!--shost->cmd_pool->users) { - kmem_cache_destroy(shost->cmd_pool->cmd_slab); - kmem_cache_destroy(shost->cmd_pool->sense_slab); - } - mutex_unlock(&host_cmd_pool_mutex); + shost->cmd_pool = NULL; + scsi_put_host_cmd_pool(shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL); } #ifdef CONFIG_SCSI_LOGGING diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index d1777a9a9625..07103c399fe0 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -39,16 +39,18 @@ #include <linux/vmalloc.h> #include <linux/moduleparam.h> #include <linux/scatterlist.h> - #include <linux/blkdev.h> -#include "scsi.h" + +#include <scsi/scsi.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsicam.h> +#include <scsi/scsi_eh.h> #include <linux/stat.h> #include "scsi_logging.h" -#include "scsi_debug.h" #define SCSI_DEBUG_VERSION "1.81" static const char * scsi_debug_version_date = "20070104"; @@ -146,7 +148,6 @@ static int scsi_debug_cmnd_count = 0; #define DEV_READONLY(TGT) (0) #define DEV_REMOVEABLE(TGT) (0) -static unsigned int sdebug_store_size; /* in bytes */ static unsigned int sdebug_store_sectors; static sector_t sdebug_capacity; /* in sectors */ @@ -165,6 +166,9 @@ static int sdebug_sectors_per; /* sectors per cylinder */ #define SDEBUG_SENSE_LEN 32 +#define SCSI_DEBUG_CANQUEUE 255 +#define SCSI_DEBUG_MAX_CMD_LEN 16 + struct sdebug_dev_info { struct list_head dev_list; unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */ @@ -202,30 +206,6 @@ struct sdebug_queued_cmd { }; static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; -static struct scsi_host_template sdebug_driver_template = { - .proc_info = scsi_debug_proc_info, - .name = "SCSI DEBUG", - .info = scsi_debug_info, - .slave_alloc = scsi_debug_slave_alloc, - .slave_configure = scsi_debug_slave_configure, - .slave_destroy = scsi_debug_slave_destroy, - .ioctl = scsi_debug_ioctl, - .queuecommand = scsi_debug_queuecommand, - .eh_abort_handler = scsi_debug_abort, - .eh_bus_reset_handler = scsi_debug_bus_reset, - .eh_device_reset_handler = scsi_debug_device_reset, - .eh_host_reset_handler = scsi_debug_host_reset, - .bios_param = scsi_debug_biosparam, - .can_queue = SCSI_DEBUG_CANQUEUE, - .this_id = 7, - .sg_tablesize = 256, - .cmd_per_lun = 16, - .max_sectors = 0xffff, - .unchecked_isa_dma = 0, - .use_clustering = DISABLE_CLUSTERING, - .module = THIS_MODULE, -}; - static unsigned char * fake_storep; /* ramdisk storage */ static int num_aborts = 0; @@ -238,8 +218,6 @@ static DEFINE_RWLOCK(atomic_rw); static char sdebug_proc_name[] = "scsi_debug"; -static int sdebug_driver_probe(struct device *); -static int sdebug_driver_remove(struct device *); static struct bus_type pseudo_lld_bus; static struct device_driver sdebug_driverfs_driver = { @@ -255,94 +233,77 @@ static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x0}; -/* function declarations */ -static int resp_inquiry(struct scsi_cmnd * SCpnt, int target, - struct sdebug_dev_info * devip); -static int resp_requests(struct scsi_cmnd * SCpnt, - struct sdebug_dev_info * devip); -static int resp_start_stop(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip); -static int resp_report_tgtpgs(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip); -static int resp_readcap(struct scsi_cmnd * SCpnt, - struct sdebug_dev_info * devip); -static int resp_readcap16(struct scsi_cmnd * SCpnt, - struct sdebug_dev_info * devip); -static int resp_mode_sense(struct scsi_cmnd * scp, int target, - struct sdebug_dev_info * devip); -static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, - struct sdebug_dev_info * devip); -static int resp_log_sense(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip); -static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, - unsigned int num, struct sdebug_dev_info * devip); -static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, - unsigned int num, struct sdebug_dev_info * devip); -static int resp_report_luns(struct scsi_cmnd * SCpnt, - struct sdebug_dev_info * devip); -static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, - unsigned int num, struct sdebug_dev_info *devip); -static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, - int arr_len); -static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, - int max_arr_len); -static void timer_intr_handler(unsigned long); -static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev); -static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, - int asc, int asq); -static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, - struct sdebug_dev_info * devip); -static int schedule_resp(struct scsi_cmnd * cmnd, - struct sdebug_dev_info * devip, - done_funct_t done, int scsi_result, int delta_jiff); -static void __init sdebug_build_parts(unsigned char * ramp); -static void __init init_all_queued(void); -static void stop_all_queued(void); -static int stop_queued_cmnd(struct scsi_cmnd * cmnd); -static int inquiry_evpd_83(unsigned char * arr, int port_group_id, - int target_dev_id, int dev_id_num, - const char * dev_id_str, int dev_id_str_len); -static int inquiry_evpd_88(unsigned char * arr, int target_dev_id); -static int do_create_driverfs_files(void); -static void do_remove_driverfs_files(void); - static int sdebug_add_adapter(void); static void sdebug_remove_adapter(void); -static void sdebug_max_tgts_luns(void); -static struct device pseudo_primary; -static struct bus_type pseudo_lld_bus; +static void sdebug_max_tgts_luns(void) +{ + struct sdebug_host_info *sdbg_host; + struct Scsi_Host *hpnt; + + spin_lock(&sdebug_host_list_lock); + list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { + hpnt = sdbg_host->shost; + if ((hpnt->this_id >= 0) && + (scsi_debug_num_tgts > hpnt->this_id)) + hpnt->max_id = scsi_debug_num_tgts + 1; + else + hpnt->max_id = scsi_debug_num_tgts; + /* scsi_debug_max_luns; */ + hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; + } + spin_unlock(&sdebug_host_list_lock); +} + +static void mk_sense_buffer(struct sdebug_dev_info *devip, int key, + int asc, int asq) +{ + unsigned char *sbuff; + + sbuff = devip->sense_buff; + memset(sbuff, 0, SDEBUG_SENSE_LEN); + + scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq); + + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: " + "[0x%x,0x%x,0x%x]\n", key, asc, asq); +} static void get_data_transfer_info(unsigned char *cmd, unsigned long long *lba, unsigned int *num) { - int i; - switch (*cmd) { case WRITE_16: case READ_16: - for (*lba = 0, i = 0; i < 8; ++i) { - if (i > 0) - *lba <<= 8; - *lba += cmd[2 + i]; - } - *num = cmd[13] + (cmd[12] << 8) + - (cmd[11] << 16) + (cmd[10] << 24); + *lba = (u64)cmd[9] | (u64)cmd[8] << 8 | + (u64)cmd[7] << 16 | (u64)cmd[6] << 24 | + (u64)cmd[5] << 32 | (u64)cmd[4] << 40 | + (u64)cmd[3] << 48 | (u64)cmd[2] << 56; + + *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 | + (u32)cmd[10] << 24; break; case WRITE_12: case READ_12: - *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); - *num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); + *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | + (u32)cmd[2] << 24; + + *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 | + (u32)cmd[6] << 24; break; case WRITE_10: case READ_10: case XDWRITEREAD_10: - *lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); - *num = cmd[8] + (cmd[7] << 8); + *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | + (u32)cmd[2] << 24; + + *num = (u32)cmd[8] | (u32)cmd[7] << 8; break; case WRITE_6: case READ_6: - *lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); + *lba = (u32)cmd[3] | (u32)cmd[2] << 8 | + (u32)(cmd[1] & 0x1f) << 16; *num = (0 == cmd[4]) ? 256 : cmd[4]; break; default: @@ -350,237 +311,6 @@ static void get_data_transfer_info(unsigned char *cmd, } } -static -int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) -{ - unsigned char *cmd = (unsigned char *) SCpnt->cmnd; - int len, k; - unsigned int num; - unsigned long long lba; - int errsts = 0; - int target = SCpnt->device->id; - struct sdebug_dev_info * devip = NULL; - int inj_recovered = 0; - int inj_transport = 0; - int delay_override = 0; - - if (done == NULL) - return 0; /* assume mid level reprocessing command */ - - scsi_set_resid(SCpnt, 0); - if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { - printk(KERN_INFO "scsi_debug: cmd "); - for (k = 0, len = SCpnt->cmd_len; k < len; ++k) - printk("%02x ", (int)cmd[k]); - printk("\n"); - } - if(target == sdebug_driver_template.this_id) { - printk(KERN_INFO "scsi_debug: initiator's id used as " - "target!\n"); - return schedule_resp(SCpnt, NULL, done, - DID_NO_CONNECT << 16, 0); - } - - if ((SCpnt->device->lun >= scsi_debug_max_luns) && - (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) - return schedule_resp(SCpnt, NULL, done, - DID_NO_CONNECT << 16, 0); - devip = devInfoReg(SCpnt->device); - if (NULL == devip) - return schedule_resp(SCpnt, NULL, done, - DID_NO_CONNECT << 16, 0); - - if ((scsi_debug_every_nth != 0) && - (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) { - scsi_debug_cmnd_count = 0; - if (scsi_debug_every_nth < -1) - scsi_debug_every_nth = -1; - if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) - return 0; /* ignore command causing timeout */ - else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) - inj_recovered = 1; /* to reads and writes below */ - else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) - inj_transport = 1; /* to reads and writes below */ - } - - if (devip->wlun) { - switch (*cmd) { - case INQUIRY: - case REQUEST_SENSE: - case TEST_UNIT_READY: - case REPORT_LUNS: - break; /* only allowable wlun commands */ - default: - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: Opcode: 0x%x " - "not supported for wlun\n", *cmd); - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_OPCODE, 0); - errsts = check_condition_result; - return schedule_resp(SCpnt, devip, done, errsts, - 0); - } - } - - switch (*cmd) { - case INQUIRY: /* mandatory, ignore unit attention */ - delay_override = 1; - errsts = resp_inquiry(SCpnt, target, devip); - break; - case REQUEST_SENSE: /* mandatory, ignore unit attention */ - delay_override = 1; - errsts = resp_requests(SCpnt, devip); - break; - case REZERO_UNIT: /* actually this is REWIND for SSC */ - case START_STOP: - errsts = resp_start_stop(SCpnt, devip); - break; - case ALLOW_MEDIUM_REMOVAL: - if ((errsts = check_readiness(SCpnt, 1, devip))) - break; - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: Medium removal %s\n", - cmd[4] ? "inhibited" : "enabled"); - break; - case SEND_DIAGNOSTIC: /* mandatory */ - errsts = check_readiness(SCpnt, 1, devip); - break; - case TEST_UNIT_READY: /* mandatory */ - delay_override = 1; - errsts = check_readiness(SCpnt, 0, devip); - break; - case RESERVE: - errsts = check_readiness(SCpnt, 1, devip); - break; - case RESERVE_10: - errsts = check_readiness(SCpnt, 1, devip); - break; - case RELEASE: - errsts = check_readiness(SCpnt, 1, devip); - break; - case RELEASE_10: - errsts = check_readiness(SCpnt, 1, devip); - break; - case READ_CAPACITY: - errsts = resp_readcap(SCpnt, devip); - break; - case SERVICE_ACTION_IN: - if (SAI_READ_CAPACITY_16 != cmd[1]) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_OPCODE, 0); - errsts = check_condition_result; - break; - } - errsts = resp_readcap16(SCpnt, devip); - break; - case MAINTENANCE_IN: - if (MI_REPORT_TARGET_PGS != cmd[1]) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_OPCODE, 0); - errsts = check_condition_result; - break; - } - errsts = resp_report_tgtpgs(SCpnt, devip); - break; - case READ_16: - case READ_12: - case READ_10: - case READ_6: - if ((errsts = check_readiness(SCpnt, 0, devip))) - break; - if (scsi_debug_fake_rw) - break; - get_data_transfer_info(cmd, &lba, &num); - errsts = resp_read(SCpnt, lba, num, devip); - if (inj_recovered && (0 == errsts)) { - mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHOLD_EXCEEDED, 0); - errsts = check_condition_result; - } else if (inj_transport && (0 == errsts)) { - mk_sense_buffer(devip, ABORTED_COMMAND, - TRANSPORT_PROBLEM, ACK_NAK_TO); - errsts = check_condition_result; - } - break; - case REPORT_LUNS: /* mandatory, ignore unit attention */ - delay_override = 1; - errsts = resp_report_luns(SCpnt, devip); - break; - case VERIFY: /* 10 byte SBC-2 command */ - errsts = check_readiness(SCpnt, 0, devip); - break; - case WRITE_16: - case WRITE_12: - case WRITE_10: - case WRITE_6: - if ((errsts = check_readiness(SCpnt, 0, devip))) - break; - if (scsi_debug_fake_rw) - break; - get_data_transfer_info(cmd, &lba, &num); - errsts = resp_write(SCpnt, lba, num, devip); - if (inj_recovered && (0 == errsts)) { - mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHOLD_EXCEEDED, 0); - errsts = check_condition_result; - } - break; - case MODE_SENSE: - case MODE_SENSE_10: - errsts = resp_mode_sense(SCpnt, target, devip); - break; - case MODE_SELECT: - errsts = resp_mode_select(SCpnt, 1, devip); - break; - case MODE_SELECT_10: - errsts = resp_mode_select(SCpnt, 0, devip); - break; - case LOG_SENSE: - errsts = resp_log_sense(SCpnt, devip); - break; - case SYNCHRONIZE_CACHE: - delay_override = 1; - errsts = check_readiness(SCpnt, 0, devip); - break; - case WRITE_BUFFER: - errsts = check_readiness(SCpnt, 1, devip); - break; - case XDWRITEREAD_10: - if (!scsi_bidi_cmnd(SCpnt)) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - errsts = check_condition_result; - break; - } - - errsts = check_readiness(SCpnt, 0, devip); - if (errsts) - break; - if (scsi_debug_fake_rw) - break; - get_data_transfer_info(cmd, &lba, &num); - errsts = resp_read(SCpnt, lba, num, devip); - if (errsts) - break; - errsts = resp_write(SCpnt, lba, num, devip); - if (errsts) - break; - errsts = resp_xdwriteread(SCpnt, lba, num, devip); - break; - default: - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " - "supported\n", *cmd); - if ((errsts = check_readiness(SCpnt, 1, devip))) - break; /* Unit attention takes precedence */ - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); - errsts = check_condition_result; - break; - } - return schedule_resp(SCpnt, devip, done, errsts, - (delay_override ? 0 : scsi_debug_delay)); -} - static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) { if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { @@ -613,81 +343,37 @@ static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, } /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ -static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, +static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, int arr_len) { - int k, req_len, act_len, len, active; - void * kaddr; - void * kaddr_off; - struct scatterlist *sg; + int act_len; struct scsi_data_buffer *sdb = scsi_in(scp); if (!sdb->length) return 0; - if (!sdb->table.sgl) - return (DID_ERROR << 16); if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) return (DID_ERROR << 16); - active = 1; - req_len = act_len = 0; - for_each_sg(sdb->table.sgl, sg, sdb->table.nents, k) { - if (active) { - kaddr = (unsigned char *) - kmap_atomic(sg_page(sg), KM_USER0); - if (NULL == kaddr) - return (DID_ERROR << 16); - kaddr_off = (unsigned char *)kaddr + sg->offset; - len = sg->length; - if ((req_len + len) > arr_len) { - active = 0; - len = arr_len - req_len; - } - memcpy(kaddr_off, arr + req_len, len); - kunmap_atomic(kaddr, KM_USER0); - act_len += len; - } - req_len += sg->length; - } + + act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, + arr, arr_len); if (sdb->resid) sdb->resid -= act_len; else - sdb->resid = req_len - act_len; + sdb->resid = scsi_bufflen(scp) - act_len; + return 0; } /* Returns number of bytes fetched into 'arr' or -1 if error. */ -static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, - int max_arr_len) +static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, + int arr_len) { - int k, req_len, len, fin; - void * kaddr; - void * kaddr_off; - struct scatterlist * sg; - - if (0 == scsi_bufflen(scp)) + if (!scsi_bufflen(scp)) return 0; - if (NULL == scsi_sglist(scp)) - return -1; if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) return -1; - req_len = fin = 0; - scsi_for_each_sg(scp, sg, scsi_sg_count(scp), k) { - kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0); - if (NULL == kaddr) - return -1; - kaddr_off = (unsigned char *)kaddr + sg->offset; - len = sg->length; - if ((req_len + len) > max_arr_len) { - len = max_arr_len - req_len; - fin = 1; - } - memcpy(arr + req_len, kaddr_off, len); - kunmap_atomic(kaddr, KM_USER0); - if (fin) - return req_len + len; - req_len += sg->length; - } - return req_len; + + return scsi_sg_copy_to_buffer(scp, arr, arr_len); } @@ -1159,6 +845,14 @@ static int resp_start_stop(struct scsi_cmnd * scp, return 0; } +static sector_t get_sdebug_capacity(void) +{ + if (scsi_debug_virtual_gb > 0) + return 2048 * 1024 * scsi_debug_virtual_gb; + else + return sdebug_store_sectors; +} + #define SDEBUG_READCAP_ARR_SZ 8 static int resp_readcap(struct scsi_cmnd * scp, struct sdebug_dev_info * devip) @@ -1170,11 +864,7 @@ static int resp_readcap(struct scsi_cmnd * scp, if ((errsts = check_readiness(scp, 1, devip))) return errsts; /* following just in case virtual_gb changed */ - if (scsi_debug_virtual_gb > 0) { - sdebug_capacity = 2048 * 1024; - sdebug_capacity *= scsi_debug_virtual_gb; - } else - sdebug_capacity = sdebug_store_sectors; + sdebug_capacity = get_sdebug_capacity(); memset(arr, 0, SDEBUG_READCAP_ARR_SZ); if (sdebug_capacity < 0xffffffff) { capac = (unsigned int)sdebug_capacity - 1; @@ -1207,11 +897,7 @@ static int resp_readcap16(struct scsi_cmnd * scp, alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) + cmd[13]); /* following just in case virtual_gb changed */ - if (scsi_debug_virtual_gb > 0) { - sdebug_capacity = 2048 * 1024; - sdebug_capacity *= scsi_debug_virtual_gb; - } else - sdebug_capacity = sdebug_store_sectors; + sdebug_capacity = get_sdebug_capacity(); memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); capac = sdebug_capacity - 1; for (k = 0; k < 8; ++k, capac >>= 8) @@ -1505,13 +1191,9 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, offset = 8; } ap = arr + offset; - if ((bd_len > 0) && (0 == sdebug_capacity)) { - if (scsi_debug_virtual_gb > 0) { - sdebug_capacity = 2048 * 1024; - sdebug_capacity *= scsi_debug_virtual_gb; - } else - sdebug_capacity = sdebug_store_sectors; - } + if ((bd_len > 0) && (!sdebug_capacity)) + sdebug_capacity = get_sdebug_capacity(); + if (8 == bd_len) { if (sdebug_capacity > 0xfffffffe) { ap[0] = 0xff; @@ -1808,25 +1490,53 @@ static int resp_log_sense(struct scsi_cmnd * scp, min(len, SDEBUG_MAX_INQ_ARR_SZ)); } -static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, - unsigned int num, struct sdebug_dev_info * devip) +static int check_device_access_params(struct sdebug_dev_info *devi, + unsigned long long lba, unsigned int num) { - unsigned long iflags; - unsigned int block, from_bottom; - unsigned long long u; - int ret; - if (lba + num > sdebug_capacity) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, - 0); + mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0); return check_condition_result; } /* transfer length excessive (tie in to block limits VPD page) */ if (num > sdebug_store_sectors) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0); + mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; } + return 0; +} + +static int do_device_access(struct scsi_cmnd *scmd, + struct sdebug_dev_info *devi, + unsigned long long lba, unsigned int num, int write) +{ + int ret; + unsigned int block, rest = 0; + int (*func)(struct scsi_cmnd *, unsigned char *, int); + + func = write ? fetch_to_dev_buffer : fill_from_dev_buffer; + + block = do_div(lba, sdebug_store_sectors); + if (block + num > sdebug_store_sectors) + rest = block + num - sdebug_store_sectors; + + ret = func(scmd, fake_storep + (block * SECT_SIZE), + (num - rest) * SECT_SIZE); + if (!ret && rest) + ret = func(scmd, fake_storep, rest * SECT_SIZE); + + return ret; +} + +static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, + unsigned int num, struct sdebug_dev_info *devip) +{ + unsigned long iflags; + int ret; + + ret = check_device_access_params(devip, lba, num); + if (ret) + return ret; + if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && (lba <= OPT_MEDIUM_ERR_ADDR) && ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { @@ -1845,74 +1555,30 @@ static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, return check_condition_result; } read_lock_irqsave(&atomic_rw, iflags); - if ((lba + num) <= sdebug_store_sectors) - ret = fill_from_dev_buffer(SCpnt, - fake_storep + (lba * SECT_SIZE), - num * SECT_SIZE); - else { - /* modulo when one arg is 64 bits needs do_div() */ - u = lba; - block = do_div(u, sdebug_store_sectors); - from_bottom = 0; - if ((block + num) > sdebug_store_sectors) - from_bottom = (block + num) - sdebug_store_sectors; - ret = fill_from_dev_buffer(SCpnt, - fake_storep + (block * SECT_SIZE), - (num - from_bottom) * SECT_SIZE); - if ((0 == ret) && (from_bottom > 0)) - ret = fill_from_dev_buffer(SCpnt, fake_storep, - from_bottom * SECT_SIZE); - } + ret = do_device_access(SCpnt, devip, lba, num, 0); read_unlock_irqrestore(&atomic_rw, iflags); return ret; } -static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, - unsigned int num, struct sdebug_dev_info * devip) +static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, + unsigned int num, struct sdebug_dev_info *devip) { unsigned long iflags; - unsigned int block, to_bottom; - unsigned long long u; - int res; + int ret; - if (lba + num > sdebug_capacity) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, - 0); - return check_condition_result; - } - /* transfer length excessive (tie in to block limits VPD page) */ - if (num > sdebug_store_sectors) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0); - return check_condition_result; - } + ret = check_device_access_params(devip, lba, num); + if (ret) + return ret; write_lock_irqsave(&atomic_rw, iflags); - if ((lba + num) <= sdebug_store_sectors) - res = fetch_to_dev_buffer(SCpnt, - fake_storep + (lba * SECT_SIZE), - num * SECT_SIZE); - else { - /* modulo when one arg is 64 bits needs do_div() */ - u = lba; - block = do_div(u, sdebug_store_sectors); - to_bottom = 0; - if ((block + num) > sdebug_store_sectors) - to_bottom = (block + num) - sdebug_store_sectors; - res = fetch_to_dev_buffer(SCpnt, - fake_storep + (block * SECT_SIZE), - (num - to_bottom) * SECT_SIZE); - if ((0 == res) && (to_bottom > 0)) - res = fetch_to_dev_buffer(SCpnt, fake_storep, - to_bottom * SECT_SIZE); - } + ret = do_device_access(SCpnt, devip, lba, num, 1); write_unlock_irqrestore(&atomic_rw, iflags); - if (-1 == res) + if (-1 == ret) return (DID_ERROR << 16); - else if ((res < (num * SECT_SIZE)) && + else if ((ret < (num * SECT_SIZE)) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " - " IO sent=%d bytes\n", num * SECT_SIZE, res); + " IO sent=%d bytes\n", num * SECT_SIZE, ret); return 0; } @@ -1987,16 +1653,7 @@ static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, if (!buf) return ret; - offset = 0; - scsi_for_each_sg(scp, sg, scsi_sg_count(scp), i) { - kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0); - if (!kaddr) - goto out; - - memcpy(buf + offset, kaddr + sg->offset, sg->length); - offset += sg->length; - kunmap_atomic(kaddr, KM_USER0); - } + scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); offset = 0; for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) { @@ -2045,7 +1702,73 @@ static void timer_intr_handler(unsigned long indx) spin_unlock_irqrestore(&queued_arr_lock, iflags); } -static int scsi_debug_slave_alloc(struct scsi_device * sdp) + +static struct sdebug_dev_info * +sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags) +{ + struct sdebug_dev_info *devip; + + devip = kzalloc(sizeof(*devip), flags); + if (devip) { + devip->sdbg_host = sdbg_host; + list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); + } + return devip; +} + +static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) +{ + struct sdebug_host_info * sdbg_host; + struct sdebug_dev_info * open_devip = NULL; + struct sdebug_dev_info * devip = + (struct sdebug_dev_info *)sdev->hostdata; + + if (devip) + return devip; + sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); + if (!sdbg_host) { + printk(KERN_ERR "Host info NULL\n"); + return NULL; + } + list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { + if ((devip->used) && (devip->channel == sdev->channel) && + (devip->target == sdev->id) && + (devip->lun == sdev->lun)) + return devip; + else { + if ((!devip->used) && (!open_devip)) + open_devip = devip; + } + } + if (!open_devip) { /* try and make a new one */ + open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); + if (!open_devip) { + printk(KERN_ERR "%s: out of memory at line %d\n", + __FUNCTION__, __LINE__); + return NULL; + } + } + + open_devip->channel = sdev->channel; + open_devip->target = sdev->id; + open_devip->lun = sdev->lun; + open_devip->sdbg_host = sdbg_host; + open_devip->reset = 1; + open_devip->used = 1; + memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); + if (scsi_debug_dsense) + open_devip->sense_buff[0] = 0x72; + else { + open_devip->sense_buff[0] = 0x70; + open_devip->sense_buff[7] = 0xa; + } + if (sdev->lun == SAM2_WLUN_REPORT_LUNS) + open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; + + return open_devip; +} + +static int scsi_debug_slave_alloc(struct scsi_device *sdp) { if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", @@ -2054,9 +1777,9 @@ static int scsi_debug_slave_alloc(struct scsi_device * sdp) return 0; } -static int scsi_debug_slave_configure(struct scsi_device * sdp) +static int scsi_debug_slave_configure(struct scsi_device *sdp) { - struct sdebug_dev_info * devip; + struct sdebug_dev_info *devip; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", @@ -2074,10 +1797,10 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp) return 0; } -static void scsi_debug_slave_destroy(struct scsi_device * sdp) +static void scsi_debug_slave_destroy(struct scsi_device *sdp) { - struct sdebug_dev_info * devip = - (struct sdebug_dev_info *)sdp->hostdata; + struct sdebug_dev_info *devip = + (struct sdebug_dev_info *)sdp->hostdata; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", @@ -2089,84 +1812,44 @@ static void scsi_debug_slave_destroy(struct scsi_device * sdp) } } -static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) +/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */ +static int stop_queued_cmnd(struct scsi_cmnd *cmnd) { - struct sdebug_host_info * sdbg_host; - struct sdebug_dev_info * open_devip = NULL; - struct sdebug_dev_info * devip = - (struct sdebug_dev_info *)sdev->hostdata; + unsigned long iflags; + int k; + struct sdebug_queued_cmd *sqcp; - if (devip) - return devip; - sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata; - if(! sdbg_host) { - printk(KERN_ERR "Host info NULL\n"); - return NULL; - } - list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { - if ((devip->used) && (devip->channel == sdev->channel) && - (devip->target == sdev->id) && - (devip->lun == sdev->lun)) - return devip; - else { - if ((!devip->used) && (!open_devip)) - open_devip = devip; + spin_lock_irqsave(&queued_arr_lock, iflags); + for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { + sqcp = &queued_arr[k]; + if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) { + del_timer_sync(&sqcp->cmnd_timer); + sqcp->in_use = 0; + sqcp->a_cmnd = NULL; + break; } } - if (NULL == open_devip) { /* try and make a new one */ - open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC); - if (NULL == open_devip) { - printk(KERN_ERR "%s: out of memory at line %d\n", - __FUNCTION__, __LINE__); - return NULL; - } - open_devip->sdbg_host = sdbg_host; - list_add_tail(&open_devip->dev_list, - &sdbg_host->dev_info_list); - } - if (open_devip) { - open_devip->channel = sdev->channel; - open_devip->target = sdev->id; - open_devip->lun = sdev->lun; - open_devip->sdbg_host = sdbg_host; - open_devip->reset = 1; - open_devip->used = 1; - memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); - if (scsi_debug_dsense) - open_devip->sense_buff[0] = 0x72; - else { - open_devip->sense_buff[0] = 0x70; - open_devip->sense_buff[7] = 0xa; - } - if (sdev->lun == SAM2_WLUN_REPORT_LUNS) - open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; - return open_devip; - } - return NULL; + spin_unlock_irqrestore(&queued_arr_lock, iflags); + return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0; } -static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, - int asc, int asq) +/* Deletes (stops) timers of all queued commands */ +static void stop_all_queued(void) { - unsigned char * sbuff; + unsigned long iflags; + int k; + struct sdebug_queued_cmd *sqcp; - sbuff = devip->sense_buff; - memset(sbuff, 0, SDEBUG_SENSE_LEN); - if (scsi_debug_dsense) { - sbuff[0] = 0x72; /* descriptor, current */ - sbuff[1] = key; - sbuff[2] = asc; - sbuff[3] = asq; - } else { - sbuff[0] = 0x70; /* fixed, current */ - sbuff[2] = key; - sbuff[7] = 0xa; /* implies 18 byte sense buffer */ - sbuff[12] = asc; - sbuff[13] = asq; + spin_lock_irqsave(&queued_arr_lock, iflags); + for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { + sqcp = &queued_arr[k]; + if (sqcp->in_use && sqcp->a_cmnd) { + del_timer_sync(&sqcp->cmnd_timer); + sqcp->in_use = 0; + sqcp->a_cmnd = NULL; + } } - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: " - "[0x%x,0x%x,0x%x]\n", key, asc, asq); + spin_unlock_irqrestore(&queued_arr_lock, iflags); } static int scsi_debug_abort(struct scsi_cmnd * SCpnt) @@ -2226,7 +1909,7 @@ static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) printk(KERN_INFO "scsi_debug: bus_reset\n"); ++num_bus_resets; if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { - sdbg_host = *(struct sdebug_host_info **) hp->hostdata; + sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); if (sdbg_host) { list_for_each_entry(dev_info, &sdbg_host->dev_info_list, @@ -2256,46 +1939,6 @@ static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) return SUCCESS; } -/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */ -static int stop_queued_cmnd(struct scsi_cmnd * cmnd) -{ - unsigned long iflags; - int k; - struct sdebug_queued_cmd * sqcp; - - spin_lock_irqsave(&queued_arr_lock, iflags); - for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { - sqcp = &queued_arr[k]; - if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) { - del_timer_sync(&sqcp->cmnd_timer); - sqcp->in_use = 0; - sqcp->a_cmnd = NULL; - break; - } - } - spin_unlock_irqrestore(&queued_arr_lock, iflags); - return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0; -} - -/* Deletes (stops) timers of all queued commands */ -static void stop_all_queued(void) -{ - unsigned long iflags; - int k; - struct sdebug_queued_cmd * sqcp; - - spin_lock_irqsave(&queued_arr_lock, iflags); - for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { - sqcp = &queued_arr[k]; - if (sqcp->in_use && sqcp->a_cmnd) { - del_timer_sync(&sqcp->cmnd_timer); - sqcp->in_use = 0; - sqcp->a_cmnd = NULL; - } - } - spin_unlock_irqrestore(&queued_arr_lock, iflags); -} - /* Initializes timers in queued array */ static void __init init_all_queued(void) { @@ -2313,7 +1956,8 @@ static void __init init_all_queued(void) spin_unlock_irqrestore(&queued_arr_lock, iflags); } -static void __init sdebug_build_parts(unsigned char * ramp) +static void __init sdebug_build_parts(unsigned char *ramp, + unsigned long store_size) { struct partition * pp; int starts[SDEBUG_MAX_PARTS + 2]; @@ -2321,7 +1965,7 @@ static void __init sdebug_build_parts(unsigned char * ramp) int heads_by_sects, start_sec, end_sec; /* assume partition table already zeroed */ - if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576)) + if ((scsi_debug_num_parts < 1) || (store_size < 1048576)) return; if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { scsi_debug_num_parts = SDEBUG_MAX_PARTS; @@ -2419,7 +2063,6 @@ static int schedule_resp(struct scsi_cmnd * cmnd, return 0; } } - /* Note: The following macros create attribute files in the /sys/module/scsi_debug/parameters directory. Unfortunately this driver is unaware of a change and cannot trigger auxiliary actions @@ -2736,11 +2379,9 @@ static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp, if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { scsi_debug_virtual_gb = n; - if (scsi_debug_virtual_gb > 0) { - sdebug_capacity = 2048 * 1024; - sdebug_capacity *= scsi_debug_virtual_gb; - } else - sdebug_capacity = sdebug_store_sectors; + + sdebug_capacity = get_sdebug_capacity(); + return count; } return -EINVAL; @@ -2756,21 +2397,10 @@ static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) static ssize_t sdebug_add_host_store(struct device_driver * ddp, const char * buf, size_t count) { - int delta_hosts; - char work[20]; + int delta_hosts; - if (1 != sscanf(buf, "%10s", work)) + if (sscanf(buf, "%d", &delta_hosts) != 1) return -EINVAL; - { /* temporary hack around sscanf() problem with -ve nums */ - int neg = 0; - - if ('-' == *work) - neg = 1; - if (1 != sscanf(work + neg, "%d", &delta_hosts)) - return -EINVAL; - if (neg) - delta_hosts = -delta_hosts; - } if (delta_hosts > 0) { do { sdebug_add_adapter(); @@ -2782,7 +2412,7 @@ static ssize_t sdebug_add_host_store(struct device_driver * ddp, } return count; } -DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, +DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, sdebug_add_host_store); static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp, @@ -2851,22 +2481,29 @@ static void do_remove_driverfs_files(void) driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); } +static void pseudo_0_release(struct device *dev) +{ + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n"); +} + +static struct device pseudo_primary = { + .bus_id = "pseudo_0", + .release = pseudo_0_release, +}; + static int __init scsi_debug_init(void) { - unsigned int sz; + unsigned long sz; int host_to_add; int k; int ret; if (scsi_debug_dev_size_mb < 1) scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ - sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576; - sdebug_store_sectors = sdebug_store_size / SECT_SIZE; - if (scsi_debug_virtual_gb > 0) { - sdebug_capacity = 2048 * 1024; - sdebug_capacity *= scsi_debug_virtual_gb; - } else - sdebug_capacity = sdebug_store_sectors; + sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; + sdebug_store_sectors = sz / SECT_SIZE; + sdebug_capacity = get_sdebug_capacity(); /* play around with geometry, don't waste too much on track 0 */ sdebug_heads = 8; @@ -2885,7 +2522,6 @@ static int __init scsi_debug_init(void) (sdebug_sectors_per * sdebug_heads); } - sz = sdebug_store_size; fake_storep = vmalloc(sz); if (NULL == fake_storep) { printk(KERN_ERR "scsi_debug_init: out of memory, 1\n"); @@ -2893,7 +2529,7 @@ static int __init scsi_debug_init(void) } memset(fake_storep, 0, sz); if (scsi_debug_num_parts > 0) - sdebug_build_parts(fake_storep); + sdebug_build_parts(fake_storep, sz); ret = device_register(&pseudo_primary); if (ret < 0) { @@ -2922,8 +2558,6 @@ static int __init scsi_debug_init(void) init_all_queued(); - sdebug_driver_template.proc_name = sdebug_proc_name; - host_to_add = scsi_debug_add_host; scsi_debug_add_host = 0; @@ -2972,30 +2606,6 @@ static void __exit scsi_debug_exit(void) device_initcall(scsi_debug_init); module_exit(scsi_debug_exit); -static void pseudo_0_release(struct device * dev) -{ - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n"); -} - -static struct device pseudo_primary = { - .bus_id = "pseudo_0", - .release = pseudo_0_release, -}; - -static int pseudo_lld_bus_match(struct device *dev, - struct device_driver *dev_driver) -{ - return 1; -} - -static struct bus_type pseudo_lld_bus = { - .name = "pseudo", - .match = pseudo_lld_bus_match, - .probe = sdebug_driver_probe, - .remove = sdebug_driver_remove, -}; - static void sdebug_release_adapter(struct device * dev) { struct sdebug_host_info *sdbg_host; @@ -3009,8 +2619,7 @@ static int sdebug_add_adapter(void) int k, devs_per_host; int error = 0; struct sdebug_host_info *sdbg_host; - struct sdebug_dev_info *sdbg_devinfo; - struct list_head *lh, *lh_sf; + struct sdebug_dev_info *sdbg_devinfo, *tmp; sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); if (NULL == sdbg_host) { @@ -3023,16 +2632,13 @@ static int sdebug_add_adapter(void) devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; for (k = 0; k < devs_per_host; k++) { - sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL); - if (NULL == sdbg_devinfo) { + sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); + if (!sdbg_devinfo) { printk(KERN_ERR "%s: out of memory at line %d\n", __FUNCTION__, __LINE__); error = -ENOMEM; goto clean; } - sdbg_devinfo->sdbg_host = sdbg_host; - list_add_tail(&sdbg_devinfo->dev_list, - &sdbg_host->dev_info_list); } spin_lock(&sdebug_host_list_lock); @@ -3053,9 +2659,8 @@ static int sdebug_add_adapter(void) return error; clean: - list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { - sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, - dev_list); + list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, + dev_list) { list_del(&sdbg_devinfo->dev_list); kfree(sdbg_devinfo); } @@ -3083,6 +2688,263 @@ static void sdebug_remove_adapter(void) --scsi_debug_add_host; } +static +int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) +{ + unsigned char *cmd = (unsigned char *) SCpnt->cmnd; + int len, k; + unsigned int num; + unsigned long long lba; + int errsts = 0; + int target = SCpnt->device->id; + struct sdebug_dev_info *devip = NULL; + int inj_recovered = 0; + int inj_transport = 0; + int delay_override = 0; + + scsi_set_resid(SCpnt, 0); + if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { + printk(KERN_INFO "scsi_debug: cmd "); + for (k = 0, len = SCpnt->cmd_len; k < len; ++k) + printk("%02x ", (int)cmd[k]); + printk("\n"); + } + + if (target == SCpnt->device->host->hostt->this_id) { + printk(KERN_INFO "scsi_debug: initiator's id used as " + "target!\n"); + return schedule_resp(SCpnt, NULL, done, + DID_NO_CONNECT << 16, 0); + } + + if ((SCpnt->device->lun >= scsi_debug_max_luns) && + (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) + return schedule_resp(SCpnt, NULL, done, + DID_NO_CONNECT << 16, 0); + devip = devInfoReg(SCpnt->device); + if (NULL == devip) + return schedule_resp(SCpnt, NULL, done, + DID_NO_CONNECT << 16, 0); + + if ((scsi_debug_every_nth != 0) && + (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) { + scsi_debug_cmnd_count = 0; + if (scsi_debug_every_nth < -1) + scsi_debug_every_nth = -1; + if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) + return 0; /* ignore command causing timeout */ + else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) + inj_recovered = 1; /* to reads and writes below */ + else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) + inj_transport = 1; /* to reads and writes below */ + } + + if (devip->wlun) { + switch (*cmd) { + case INQUIRY: + case REQUEST_SENSE: + case TEST_UNIT_READY: + case REPORT_LUNS: + break; /* only allowable wlun commands */ + default: + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: Opcode: 0x%x " + "not supported for wlun\n", *cmd); + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_OPCODE, 0); + errsts = check_condition_result; + return schedule_resp(SCpnt, devip, done, errsts, + 0); + } + } + + switch (*cmd) { + case INQUIRY: /* mandatory, ignore unit attention */ + delay_override = 1; + errsts = resp_inquiry(SCpnt, target, devip); + break; + case REQUEST_SENSE: /* mandatory, ignore unit attention */ + delay_override = 1; + errsts = resp_requests(SCpnt, devip); + break; + case REZERO_UNIT: /* actually this is REWIND for SSC */ + case START_STOP: + errsts = resp_start_stop(SCpnt, devip); + break; + case ALLOW_MEDIUM_REMOVAL: + errsts = check_readiness(SCpnt, 1, devip); + if (errsts) + break; + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: Medium removal %s\n", + cmd[4] ? "inhibited" : "enabled"); + break; + case SEND_DIAGNOSTIC: /* mandatory */ + errsts = check_readiness(SCpnt, 1, devip); + break; + case TEST_UNIT_READY: /* mandatory */ + delay_override = 1; + errsts = check_readiness(SCpnt, 0, devip); + break; + case RESERVE: + errsts = check_readiness(SCpnt, 1, devip); + break; + case RESERVE_10: + errsts = check_readiness(SCpnt, 1, devip); + break; + case RELEASE: + errsts = check_readiness(SCpnt, 1, devip); + break; + case RELEASE_10: + errsts = check_readiness(SCpnt, 1, devip); + break; + case READ_CAPACITY: + errsts = resp_readcap(SCpnt, devip); + break; + case SERVICE_ACTION_IN: + if (SAI_READ_CAPACITY_16 != cmd[1]) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_OPCODE, 0); + errsts = check_condition_result; + break; + } + errsts = resp_readcap16(SCpnt, devip); + break; + case MAINTENANCE_IN: + if (MI_REPORT_TARGET_PGS != cmd[1]) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_OPCODE, 0); + errsts = check_condition_result; + break; + } + errsts = resp_report_tgtpgs(SCpnt, devip); + break; + case READ_16: + case READ_12: + case READ_10: + case READ_6: + errsts = check_readiness(SCpnt, 0, devip); + if (errsts) + break; + if (scsi_debug_fake_rw) + break; + get_data_transfer_info(cmd, &lba, &num); + errsts = resp_read(SCpnt, lba, num, devip); + if (inj_recovered && (0 == errsts)) { + mk_sense_buffer(devip, RECOVERED_ERROR, + THRESHOLD_EXCEEDED, 0); + errsts = check_condition_result; + } else if (inj_transport && (0 == errsts)) { + mk_sense_buffer(devip, ABORTED_COMMAND, + TRANSPORT_PROBLEM, ACK_NAK_TO); + errsts = check_condition_result; + } + break; + case REPORT_LUNS: /* mandatory, ignore unit attention */ + delay_override = 1; + errsts = resp_report_luns(SCpnt, devip); + break; + case VERIFY: /* 10 byte SBC-2 command */ + errsts = check_readiness(SCpnt, 0, devip); + break; + case WRITE_16: + case WRITE_12: + case WRITE_10: + case WRITE_6: + errsts = check_readiness(SCpnt, 0, devip); + if (errsts) + break; + if (scsi_debug_fake_rw) + break; + get_data_transfer_info(cmd, &lba, &num); + errsts = resp_write(SCpnt, lba, num, devip); + if (inj_recovered && (0 == errsts)) { + mk_sense_buffer(devip, RECOVERED_ERROR, + THRESHOLD_EXCEEDED, 0); + errsts = check_condition_result; + } + break; + case MODE_SENSE: + case MODE_SENSE_10: + errsts = resp_mode_sense(SCpnt, target, devip); + break; + case MODE_SELECT: + errsts = resp_mode_select(SCpnt, 1, devip); + break; + case MODE_SELECT_10: + errsts = resp_mode_select(SCpnt, 0, devip); + break; + case LOG_SENSE: + errsts = resp_log_sense(SCpnt, devip); + break; + case SYNCHRONIZE_CACHE: + delay_override = 1; + errsts = check_readiness(SCpnt, 0, devip); + break; + case WRITE_BUFFER: + errsts = check_readiness(SCpnt, 1, devip); + break; + case XDWRITEREAD_10: + if (!scsi_bidi_cmnd(SCpnt)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + errsts = check_condition_result; + break; + } + + errsts = check_readiness(SCpnt, 0, devip); + if (errsts) + break; + if (scsi_debug_fake_rw) + break; + get_data_transfer_info(cmd, &lba, &num); + errsts = resp_read(SCpnt, lba, num, devip); + if (errsts) + break; + errsts = resp_write(SCpnt, lba, num, devip); + if (errsts) + break; + errsts = resp_xdwriteread(SCpnt, lba, num, devip); + break; + default: + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " + "supported\n", *cmd); + errsts = check_readiness(SCpnt, 1, devip); + if (errsts) + break; /* Unit attention takes precedence */ + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); + errsts = check_condition_result; + break; + } + return schedule_resp(SCpnt, devip, done, errsts, + (delay_override ? 0 : scsi_debug_delay)); +} + +static struct scsi_host_template sdebug_driver_template = { + .proc_info = scsi_debug_proc_info, + .proc_name = sdebug_proc_name, + .name = "SCSI DEBUG", + .info = scsi_debug_info, + .slave_alloc = scsi_debug_slave_alloc, + .slave_configure = scsi_debug_slave_configure, + .slave_destroy = scsi_debug_slave_destroy, + .ioctl = scsi_debug_ioctl, + .queuecommand = scsi_debug_queuecommand, + .eh_abort_handler = scsi_debug_abort, + .eh_bus_reset_handler = scsi_debug_bus_reset, + .eh_device_reset_handler = scsi_debug_device_reset, + .eh_host_reset_handler = scsi_debug_host_reset, + .bios_param = scsi_debug_biosparam, + .can_queue = SCSI_DEBUG_CANQUEUE, + .this_id = 7, + .sg_tablesize = 256, + .cmd_per_lun = 16, + .max_sectors = 0xffff, + .use_clustering = DISABLE_CLUSTERING, + .module = THIS_MODULE, +}; + static int sdebug_driver_probe(struct device * dev) { int error = 0; @@ -3120,9 +2982,8 @@ static int sdebug_driver_probe(struct device * dev) static int sdebug_driver_remove(struct device * dev) { - struct list_head *lh, *lh_sf; struct sdebug_host_info *sdbg_host; - struct sdebug_dev_info *sdbg_devinfo; + struct sdebug_dev_info *sdbg_devinfo, *tmp; sdbg_host = to_sdebug_host(dev); @@ -3134,9 +2995,8 @@ static int sdebug_driver_remove(struct device * dev) scsi_remove_host(sdbg_host->shost); - list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { - sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, - dev_list); + list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, + dev_list) { list_del(&sdbg_devinfo->dev_list); kfree(sdbg_devinfo); } @@ -3145,20 +3005,15 @@ static int sdebug_driver_remove(struct device * dev) return 0; } -static void sdebug_max_tgts_luns(void) +static int pseudo_lld_bus_match(struct device *dev, + struct device_driver *dev_driver) { - struct sdebug_host_info * sdbg_host; - struct Scsi_Host *hpnt; - - spin_lock(&sdebug_host_list_lock); - list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { - hpnt = sdbg_host->shost; - if ((hpnt->this_id >= 0) && - (scsi_debug_num_tgts > hpnt->this_id)) - hpnt->max_id = scsi_debug_num_tgts + 1; - else - hpnt->max_id = scsi_debug_num_tgts; - hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */ - } - spin_unlock(&sdebug_host_list_lock); + return 1; } + +static struct bus_type pseudo_lld_bus = { + .name = "pseudo", + .match = pseudo_lld_bus_match, + .probe = sdebug_driver_probe, + .remove = sdebug_driver_remove, +}; diff --git a/drivers/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h deleted file mode 100644 index 965dd5e760c1..000000000000 --- a/drivers/scsi/scsi_debug.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _SCSI_DEBUG_H - -#include <linux/types.h> - -static int scsi_debug_slave_alloc(struct scsi_device *); -static int scsi_debug_slave_configure(struct scsi_device *); -static void scsi_debug_slave_destroy(struct scsi_device *); -static int scsi_debug_queuecommand(struct scsi_cmnd *, - void (*done) (struct scsi_cmnd *)); -static int scsi_debug_ioctl(struct scsi_device *, int, void __user *); -static int scsi_debug_biosparam(struct scsi_device *, struct block_device *, - sector_t, int[]); -static int scsi_debug_abort(struct scsi_cmnd *); -static int scsi_debug_bus_reset(struct scsi_cmnd *); -static int scsi_debug_device_reset(struct scsi_cmnd *); -static int scsi_debug_host_reset(struct scsi_cmnd *); -static int scsi_debug_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); -static const char * scsi_debug_info(struct Scsi_Host *); - -#define SCSI_DEBUG_CANQUEUE 255 /* needs to be >= 1 */ - -#define SCSI_DEBUG_MAX_CMD_LEN 16 - -#endif diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 045a0868fc7b..221f31e36d26 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -524,6 +524,41 @@ static int scsi_try_bus_reset(struct scsi_cmnd *scmd) return rtn; } +static void __scsi_report_device_reset(struct scsi_device *sdev, void *data) +{ + sdev->was_reset = 1; + sdev->expecting_cc_ua = 1; +} + +/** + * scsi_try_target_reset - Ask host to perform a target reset + * @scmd: SCSI cmd used to send a target reset + * + * Notes: + * There is no timeout for this operation. if this operation is + * unreliable for a given host, then the host itself needs to put a + * timer on it, and set the host back to a consistent state prior to + * returning. + */ +static int scsi_try_target_reset(struct scsi_cmnd *scmd) +{ + unsigned long flags; + int rtn; + + if (!scmd->device->host->hostt->eh_target_reset_handler) + return FAILED; + + rtn = scmd->device->host->hostt->eh_target_reset_handler(scmd); + if (rtn == SUCCESS) { + spin_lock_irqsave(scmd->device->host->host_lock, flags); + __starget_for_each_device(scsi_target(scmd->device), NULL, + __scsi_report_device_reset); + spin_unlock_irqrestore(scmd->device->host->host_lock, flags); + } + + return rtn; +} + /** * scsi_try_bus_device_reset - Ask host to perform a BDR on a dev * @scmd: SCSI cmd used to send BDR @@ -542,11 +577,8 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd) return FAILED; rtn = scmd->device->host->hostt->eh_device_reset_handler(scmd); - if (rtn == SUCCESS) { - scmd->device->was_reset = 1; - scmd->device->expecting_cc_ua = 1; - } - + if (rtn == SUCCESS) + __scsi_report_device_reset(scmd->device, NULL); return rtn; } @@ -584,8 +616,9 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd) { if (__scsi_try_to_abort_cmd(scmd) != SUCCESS) if (scsi_try_bus_device_reset(scmd) != SUCCESS) - if (scsi_try_bus_reset(scmd) != SUCCESS) - scsi_try_host_reset(scmd); + if (scsi_try_target_reset(scmd) != SUCCESS) + if (scsi_try_bus_reset(scmd) != SUCCESS) + scsi_try_host_reset(scmd); } /** @@ -1060,6 +1093,56 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, } /** + * scsi_eh_target_reset - send target reset if needed + * @shost: scsi host being recovered. + * @work_q: &list_head for pending commands. + * @done_q: &list_head for processed commands. + * + * Notes: + * Try a target reset. + */ +static int scsi_eh_target_reset(struct Scsi_Host *shost, + struct list_head *work_q, + struct list_head *done_q) +{ + struct scsi_cmnd *scmd, *tgtr_scmd, *next; + unsigned int id; + int rtn; + + for (id = 0; id <= shost->max_id; id++) { + tgtr_scmd = NULL; + list_for_each_entry(scmd, work_q, eh_entry) { + if (id == scmd_id(scmd)) { + tgtr_scmd = scmd; + break; + } + } + if (!tgtr_scmd) + continue; + + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending target reset " + "to target %d\n", + current->comm, id)); + rtn = scsi_try_target_reset(tgtr_scmd); + if (rtn == SUCCESS) { + list_for_each_entry_safe(scmd, next, work_q, eh_entry) { + if (id == scmd_id(scmd)) + if (!scsi_device_online(scmd->device) || + !scsi_eh_tur(tgtr_scmd)) + scsi_eh_finish_cmd(scmd, + done_q); + } + } else + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Target reset" + " failed target: " + "%d\n", + current->comm, id)); + } + + return list_empty(work_q); +} + +/** * scsi_eh_bus_reset - send a bus reset * @shost: &scsi host being recovered. * @work_q: &list_head for pending commands. @@ -1447,9 +1530,11 @@ void scsi_eh_ready_devs(struct Scsi_Host *shost, { if (!scsi_eh_stu(shost, work_q, done_q)) if (!scsi_eh_bus_device_reset(shost, work_q, done_q)) - if (!scsi_eh_bus_reset(shost, work_q, done_q)) - if (!scsi_eh_host_reset(work_q, done_q)) - scsi_eh_offline_sdevs(work_q, done_q); + if (!scsi_eh_target_reset(shost, work_q, done_q)) + if (!scsi_eh_bus_reset(shost, work_q, done_q)) + if (!scsi_eh_host_reset(work_q, done_q)) + scsi_eh_offline_sdevs(work_q, + done_q); } EXPORT_SYMBOL_GPL(scsi_eh_ready_devs); @@ -1619,10 +1704,8 @@ void scsi_report_bus_reset(struct Scsi_Host *shost, int channel) struct scsi_device *sdev; __shost_for_each_device(sdev, shost) { - if (channel == sdev_channel(sdev)) { - sdev->was_reset = 1; - sdev->expecting_cc_ua = 1; - } + if (channel == sdev_channel(sdev)) + __scsi_report_device_reset(sdev, NULL); } } EXPORT_SYMBOL(scsi_report_bus_reset); @@ -1655,10 +1738,8 @@ void scsi_report_device_reset(struct Scsi_Host *shost, int channel, int target) __shost_for_each_device(sdev, shost) { if (channel == sdev_channel(sdev) && - target == sdev_id(sdev)) { - sdev->was_reset = 1; - sdev->expecting_cc_ua = 1; - } + target == sdev_id(sdev)) + __scsi_report_device_reset(sdev, NULL); } } EXPORT_SYMBOL(scsi_report_device_reset); @@ -1714,6 +1795,11 @@ scsi_reset_provider(struct scsi_device *dev, int flag) if (rtn == SUCCESS) break; /* FALLTHROUGH */ + case SCSI_TRY_RESET_TARGET: + rtn = scsi_try_target_reset(scmd); + if (rtn == SUCCESS) + break; + /* FALLTHROUGH */ case SCSI_TRY_RESET_BUS: rtn = scsi_try_bus_reset(scmd); if (rtn == SUCCESS) @@ -1907,3 +1993,31 @@ int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, } } EXPORT_SYMBOL(scsi_get_sense_info_fld); + +/** + * scsi_build_sense_buffer - build sense data in a buffer + * @desc: Sense format (non zero == descriptor format, + * 0 == fixed format) + * @buf: Where to build sense data + * @key: Sense key + * @asc: Additional sense code + * @ascq: Additional sense code qualifier + * + **/ +void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq) +{ + if (desc) { + buf[0] = 0x72; /* descriptor, current */ + buf[1] = key; + buf[2] = asc; + buf[3] = ascq; + buf[7] = 0; + } else { + buf[0] = 0x70; /* fixed, current */ + buf[2] = key; + buf[7] = 0xa; + buf[12] = asc; + buf[13] = ascq; + } +} +EXPORT_SYMBOL(scsi_build_sense_buffer); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index f40898dc2d14..67f412bb4974 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -784,7 +784,7 @@ EXPORT_SYMBOL(scsi_release_buffers); * in req->data_len and req->next_rq->data_len. The upper-layer driver can * decide what to do with this information. */ -void scsi_end_bidi_request(struct scsi_cmnd *cmd) +static void scsi_end_bidi_request(struct scsi_cmnd *cmd) { struct request *req = cmd->request; unsigned int dlen = req->data_len; @@ -839,7 +839,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) int this_count = scsi_bufflen(cmd); struct request_queue *q = cmd->device->request_queue; struct request *req = cmd->request; - int clear_errors = 1; + int error = 0; struct scsi_sense_hdr sshdr; int sense_valid = 0; int sense_deferred = 0; @@ -853,7 +853,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) if (blk_pc_request(req)) { /* SG_IO ioctl from block level */ req->errors = result; if (result) { - clear_errors = 0; if (sense_valid && req->sense) { /* * SG_IO wants current and deferred errors @@ -865,6 +864,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) memcpy(req->sense, cmd->sense_buffer, len); req->sense_len = len; } + if (!sense_deferred) + error = -EIO; } if (scsi_bidi_cmnd(cmd)) { /* will also release_buffers */ @@ -885,14 +886,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) "%d bytes done.\n", req->nr_sectors, good_bytes)); - if (clear_errors) - req->errors = 0; - /* A number of bytes were successfully read. If there * are leftovers and there is some kind of error * (result != 0), retry the rest. */ - if (scsi_end_request(cmd, 0, good_bytes, result == 0) == NULL) + if (scsi_end_request(cmd, error, good_bytes, result == 0) == NULL) return; /* good_bytes = 0, or (inclusive) there were leftovers and diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c index a0f308bd145b..ee8496aa0336 100644 --- a/drivers/scsi/scsi_tgt_lib.c +++ b/drivers/scsi/scsi_tgt_lib.c @@ -621,9 +621,7 @@ static int __init scsi_tgt_init(void) { int err; - scsi_tgt_cmd_cache = kmem_cache_create("scsi_tgt_cmd", - sizeof(struct scsi_tgt_cmd), - 0, 0, NULL); + scsi_tgt_cmd_cache = KMEM_CACHE(scsi_tgt_cmd, 0); if (!scsi_tgt_cmd_cache) return -ENOMEM; diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c index 26cfc56c7091..03e359670506 100644 --- a/drivers/scsi/sgiwd93.c +++ b/drivers/scsi/sgiwd93.c @@ -263,10 +263,11 @@ static int __init sgiwd93_probe(struct platform_device *pdev) regs.SASR = wdregs + 3; regs.SCMD = wdregs + 7; - wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_MHZ(20)); + hdata->wh.no_sync = 0; + hdata->wh.fast = 1; + hdata->wh.dma_mode = CTRL_BURST; - if (hdata->wh.no_sync == 0xff) - hdata->wh.no_sync = 0; + wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_MHZ(20)); err = request_irq(irq, sgiwd93_intr, 0, "SGI WD93", host); if (err) { diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 0a52d9d2da2c..df83bea2c620 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support */ -static const char *verstr = "20080221"; +static const char *verstr = "20080224"; #include <linux/module.h> @@ -183,6 +183,7 @@ static int modes_defined; static struct st_buffer *new_tape_buffer(int, int, int); static int enlarge_buffer(struct st_buffer *, int, int); +static void clear_buffer(struct st_buffer *); static void normalize_buffer(struct st_buffer *); static int append_to_buffer(const char __user *, struct st_buffer *, int); static int from_buffer(struct st_buffer *, char __user *, int); @@ -442,6 +443,7 @@ static void st_sleep_done(void *data, char *sense, int result, int resid) memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE); (STp->buffer)->cmdstat.midlevel_result = SRpnt->result = result; + (STp->buffer)->cmdstat.residual = resid; DEB( STp->write_pending = 0; ) if (SRpnt->waiting) @@ -626,7 +628,7 @@ static int cross_eof(struct scsi_tape * STp, int forward) /* Flush the write buffer (never need to write if variable blocksize). */ -static int flush_write_buffer(struct scsi_tape * STp) +static int st_flush_write_buffer(struct scsi_tape * STp) { int offset, transfer, blks; int result; @@ -717,7 +719,7 @@ static int flush_buffer(struct scsi_tape *STp, int seek_next) return 0; STps = &(STp->ps[STp->partition]); if (STps->rw == ST_WRITING) /* Writing */ - return flush_write_buffer(STp); + return st_flush_write_buffer(STp); if (STp->block_size == 0) return 0; @@ -1159,6 +1161,7 @@ static int st_open(struct inode *inode, struct file *filp) goto err_out; } + (STp->buffer)->cleared = 0; (STp->buffer)->writing = 0; (STp->buffer)->syscall_result = 0; @@ -1211,7 +1214,7 @@ static int st_flush(struct file *filp, fl_owner_t id) return 0; if (STps->rw == ST_WRITING && !STp->pos_unknown) { - result = flush_write_buffer(STp); + result = st_flush_write_buffer(STp); if (result != 0 && result != (-ENOSPC)) goto out; } @@ -1432,8 +1435,14 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf, if (STp->block_size) bufsize = STp->block_size > st_fixed_buffer_size ? STp->block_size : st_fixed_buffer_size; - else + else { bufsize = count; + /* Make sure that data from previous user is not leaked even if + HBA does not return correct residual */ + if (is_read && STp->sili && !STbp->cleared) + clear_buffer(STbp); + } + if (bufsize > STbp->buffer_size && !enlarge_buffer(STbp, bufsize, STp->restr_dma)) { printk(KERN_WARNING "%s: Can't allocate %d byte tape buffer.\n", @@ -1783,6 +1792,8 @@ static long read_tape(struct scsi_tape *STp, long count, memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = READ_6; cmd[1] = (STp->block_size != 0); + if (!cmd[1] && STp->sili) + cmd[1] |= 2; cmd[2] = blks >> 16; cmd[3] = blks >> 8; cmd[4] = blks; @@ -1911,8 +1922,11 @@ static long read_tape(struct scsi_tape *STp, long count, } /* End of error handling */ - else /* Read successful */ + else { /* Read successful */ STbp->buffer_bytes = bytes; + if (STp->sili) /* In fixed block mode residual is always zero here */ + STbp->buffer_bytes -= STp->buffer->cmdstat.residual; + } if (STps->drv_block >= 0) { if (STp->block_size == 0) @@ -2090,7 +2104,8 @@ static void st_log_options(struct scsi_tape * STp, struct st_modedef * STm, char name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, STp->scsi2_logical); printk(KERN_INFO - "%s: sysv: %d nowait: %d\n", name, STm->sysv, STp->immediate); + "%s: sysv: %d nowait: %d sili: %d\n", name, STm->sysv, STp->immediate, + STp->sili); printk(KERN_INFO "%s: debugging: %d\n", name, debugging); } @@ -2133,6 +2148,7 @@ static int st_set_options(struct scsi_tape *STp, long options) STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; STp->immediate = (options & MT_ST_NOWAIT) != 0; STm->sysv = (options & MT_ST_SYSV) != 0; + STp->sili = (options & MT_ST_SILI) != 0; DEB( debugging = (options & MT_ST_DEBUGGING) != 0; st_log_options(STp, STm, name); ) } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { @@ -2164,6 +2180,8 @@ static int st_set_options(struct scsi_tape *STp, long options) STp->immediate = value; if ((options & MT_ST_SYSV) != 0) STm->sysv = value; + if ((options & MT_ST_SILI) != 0) + STp->sili = value; DEB( if ((options & MT_ST_DEBUGGING) != 0) debugging = value; @@ -3655,6 +3673,8 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm STbuffer->frp_segs += 1; got += b_size; STbuffer->buffer_size = got; + if (STbuffer->cleared) + memset(page_address(STbuffer->frp[segs].page), 0, b_size); segs++; } STbuffer->b_data = page_address(STbuffer->frp[0].page); @@ -3663,6 +3683,17 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm } +/* Make sure that no data from previous user is in the internal buffer */ +static void clear_buffer(struct st_buffer * st_bp) +{ + int i; + + for (i=0; i < st_bp->frp_segs; i++) + memset(page_address(st_bp->frp[i].page), 0, st_bp->frp[i].length); + st_bp->cleared = 1; +} + + /* Release the extra buffer */ static void normalize_buffer(struct st_buffer * STbuffer) { @@ -3987,6 +4018,7 @@ static int st_probe(struct device *dev) tpnt->two_fm = ST_TWO_FM; tpnt->fast_mteom = ST_FAST_MTEOM; tpnt->scsi2_logical = ST_SCSI2LOGICAL; + tpnt->sili = ST_SILI; tpnt->immediate = ST_NOWAIT; tpnt->default_drvbuffer = 0xff; /* No forced buffering */ tpnt->partition = 0; @@ -4333,6 +4365,46 @@ static ssize_t st_defcompression_show(struct class_device *class_dev, char *buf) CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL); +static ssize_t st_options_show(struct class_device *class_dev, char *buf) +{ + struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev); + struct scsi_tape *STp; + int i, j, options; + ssize_t l = 0; + + for (i=0; i < st_dev_max; i++) { + for (j=0; j < ST_NBR_MODES; j++) + if (&scsi_tapes[i]->modes[j] == STm) + break; + if (j < ST_NBR_MODES) + break; + } + if (i == st_dev_max) + return 0; /* should never happen */ + + STp = scsi_tapes[i]; + + options = STm->do_buffer_writes ? MT_ST_BUFFER_WRITES : 0; + options |= STm->do_async_writes ? MT_ST_ASYNC_WRITES : 0; + options |= STm->do_read_ahead ? MT_ST_READ_AHEAD : 0; + DEB( options |= debugging ? MT_ST_DEBUGGING : 0 ); + options |= STp->two_fm ? MT_ST_TWO_FM : 0; + options |= STp->fast_mteom ? MT_ST_FAST_MTEOM : 0; + options |= STm->defaults_for_writes ? MT_ST_DEF_WRITES : 0; + options |= STp->can_bsr ? MT_ST_CAN_BSR : 0; + options |= STp->omit_blklims ? MT_ST_NO_BLKLIMS : 0; + options |= STp->can_partitions ? MT_ST_CAN_PARTITIONS : 0; + options |= STp->scsi2_logical ? MT_ST_SCSI2LOGICAL : 0; + options |= STm->sysv ? MT_ST_SYSV : 0; + options |= STp->immediate ? MT_ST_NOWAIT : 0; + options |= STp->sili ? MT_ST_SILI : 0; + + l = snprintf(buf, PAGE_SIZE, "0x%08x\n", options); + return l; +} + +CLASS_DEVICE_ATTR(options, S_IRUGO, st_options_show, NULL); + static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) { int i, rew, error; @@ -4370,6 +4442,9 @@ static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) error = class_device_create_file(st_class_member, &class_device_attr_default_compression); if (error) goto out; + error = class_device_create_file(st_class_member, + &class_device_attr_options); + if (error) goto out; if (mode == 0 && rew == 0) { error = sysfs_create_link(&STp->device->sdev_gendev.kobj, diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 5931726fcf93..b92712f95931 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -12,6 +12,7 @@ struct st_cmdstatus { int midlevel_result; struct scsi_sense_hdr sense_hdr; int have_sense; + int residual; u64 uremainder64; u8 flags; u8 remainder_valid; @@ -34,6 +35,7 @@ struct st_request { struct st_buffer { unsigned char dma; /* DMA-able buffer */ unsigned char do_dio; /* direct i/o set up? */ + unsigned char cleared; /* internal buffer cleared after open? */ int buffer_size; int buffer_blocks; int buffer_bytes; @@ -122,6 +124,7 @@ struct scsi_tape { unsigned char try_dio_now; /* try direct i/o before next close? */ unsigned char c_algo; /* compression algorithm */ unsigned char pos_unknown; /* after reset position unknown */ + unsigned char sili; /* use SILI when reading in variable b mode */ int tape_type; int long_timeout; /* timeout for commands known to take long time */ diff --git a/drivers/scsi/st_options.h b/drivers/scsi/st_options.h index b6b5c9c37677..d2f947935554 100644 --- a/drivers/scsi/st_options.h +++ b/drivers/scsi/st_options.h @@ -3,7 +3,7 @@ Copyright 1995-2003 Kai Makisara. - Last modified: Mon Apr 7 22:49:18 2003 by makisara + Last modified: Thu Feb 21 21:47:07 2008 by kai.makisara */ #ifndef _ST_OPTIONS_H @@ -94,6 +94,10 @@ The default is BSD semantics. */ #define ST_SYSV 0 +/* If ST_SILI is non-zero, the SILI bit is set when reading in variable block + mode and the block size is determined using the residual returned by the HBA. */ +#define ST_SILI 0 + /* Time to wait for the drive to become ready if blocking open */ #define ST_BLOCK_SECONDS 120 diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 654430edf74d..f308a0308829 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -33,6 +33,7 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> #include <scsi/scsi_dbg.h> +#include <scsi/scsi_eh.h> #define DRV_NAME "stex" #define ST_DRIVER_VERSION "3.6.0000.1" @@ -362,22 +363,14 @@ static struct status_msg *stex_get_status(struct st_hba *hba) return status; } -static void stex_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) -{ - cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - - cmd->sense_buffer[0] = 0x70; /* fixed format, current */ - cmd->sense_buffer[2] = sk; - cmd->sense_buffer[7] = 18 - 8; /* additional sense length */ - cmd->sense_buffer[12] = asc; - cmd->sense_buffer[13] = ascq; -} - static void stex_invalid_field(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + /* "Invalid field in cbd" */ - stex_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0); + scsi_build_sense_buffer(0, cmd->sense_buffer, ILLEGAL_REQUEST, 0x24, + 0x0); done(cmd); } @@ -426,49 +419,13 @@ static int stex_map_sg(struct st_hba *hba, return 0; } -static void stex_internal_copy(struct scsi_cmnd *cmd, - const void *src, size_t *count, int sg_count, int direction) -{ - size_t lcount; - size_t len; - void *s, *d, *base = NULL; - size_t offset; - - if (*count > scsi_bufflen(cmd)) - *count = scsi_bufflen(cmd); - lcount = *count; - while (lcount) { - len = lcount; - s = (void *)src; - - offset = *count - lcount; - s += offset; - base = scsi_kmap_atomic_sg(scsi_sglist(cmd), - sg_count, &offset, &len); - if (!base) { - *count -= lcount; - return; - } - d = base + offset; - - if (direction == ST_TO_CMD) - memcpy(d, s, len); - else - memcpy(s, d, len); - - lcount -= len; - scsi_kunmap_atomic_sg(base); - } -} - static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb) { struct st_frame *p; size_t count = sizeof(struct st_frame); p = hba->copy_buffer; - stex_internal_copy(ccb->cmd, p, &count, scsi_sg_count(ccb->cmd), - ST_FROM_CMD); + count = scsi_sg_copy_to_buffer(ccb->cmd, p, count); memset(p->base, 0, sizeof(u32)*6); *(unsigned long *)(p->base) = pci_resource_start(hba->pdev, 0); p->rom_addr = 0; @@ -486,8 +443,7 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb) p->subid = hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device; - stex_internal_copy(ccb->cmd, p, &count, scsi_sg_count(ccb->cmd), - ST_TO_CMD); + count = scsi_sg_copy_from_buffer(ccb->cmd, p, count); } static void @@ -554,10 +510,8 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) unsigned char page; page = cmd->cmnd[2] & 0x3f; if (page == 0x8 || page == 0x3f) { - size_t cp_len = sizeof(ms10_caching_page); - stex_internal_copy(cmd, ms10_caching_page, - &cp_len, scsi_sg_count(cmd), - ST_TO_CMD); + scsi_sg_copy_from_buffer(cmd, ms10_caching_page, + sizeof(ms10_caching_page)); cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; done(cmd); } else @@ -586,10 +540,8 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) if (id != host->max_id - 1) break; if (lun == 0 && (cmd->cmnd[1] & INQUIRY_EVPD) == 0) { - size_t cp_len = sizeof(console_inq_page); - stex_internal_copy(cmd, console_inq_page, - &cp_len, scsi_sg_count(cmd), - ST_TO_CMD); + scsi_sg_copy_from_buffer(cmd, (void *)console_inq_page, + sizeof(console_inq_page)); cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; done(cmd); } else @@ -606,8 +558,7 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) ver.signature[0] = PASSTHRU_SIGNATURE; ver.console_id = host->max_id - 1; ver.host_no = hba->host->host_no; - stex_internal_copy(cmd, &ver, &cp_len, - scsi_sg_count(cmd), ST_TO_CMD); + cp_len = scsi_sg_copy_from_buffer(cmd, &ver, cp_len); cmd->result = sizeof(ver) == cp_len ? DID_OK << 16 | COMMAND_COMPLETE << 8 : DID_ERROR << 16 | COMMAND_COMPLETE << 8; @@ -700,15 +651,12 @@ static void stex_copy_data(struct st_ccb *ccb, if (ccb->cmd == NULL) return; - stex_internal_copy(ccb->cmd, - resp->variable, &count, scsi_sg_count(ccb->cmd), ST_TO_CMD); + count = scsi_sg_copy_from_buffer(ccb->cmd, resp->variable, count); } static void stex_ys_commands(struct st_hba *hba, struct st_ccb *ccb, struct status_msg *resp) { - size_t count; - if (ccb->cmd->cmnd[0] == MGT_CMD && resp->scsi_status != SAM_STAT_CHECK_CONDITION) { scsi_set_resid(ccb->cmd, scsi_bufflen(ccb->cmd) - @@ -724,9 +672,8 @@ static void stex_ys_commands(struct st_hba *hba, resp->scsi_status == SAM_STAT_GOOD) { ST_INQ *inq_data; - count = STEX_EXTRA_SIZE; - stex_internal_copy(ccb->cmd, hba->copy_buffer, - &count, scsi_sg_count(ccb->cmd), ST_FROM_CMD); + scsi_sg_copy_to_buffer(ccb->cmd, hba->copy_buffer, + STEX_EXTRA_SIZE); inq_data = (ST_INQ *)hba->copy_buffer; if (inq_data->DeviceTypeQualifier != 0) ccb->srb_status = SRB_STATUS_SELECTION_TIMEOUT; diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c index 02d9727f017a..aaa4fd0dd1b9 100644 --- a/drivers/scsi/sun3_scsi_vme.c +++ b/drivers/scsi/sun3_scsi_vme.c @@ -582,3 +582,4 @@ static struct scsi_host_template driver_template = { #include "scsi_module.c" +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index f286c37da7e0..5fda881c2470 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -1973,10 +1973,7 @@ wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, hostdata->incoming_ptr = 0; hostdata->outgoing_len = 0; hostdata->default_sx_per = DEFAULT_SX_PER; - hostdata->no_sync = 0xff; /* sync defaults to off */ hostdata->no_dma = 0; /* default is DMA enabled */ - hostdata->fast = 0; /* default is Fast SCSI transfers disabled */ - hostdata->dma_mode = CTRL_DMA; /* default is Single Byte DMA */ #ifdef PROC_INTERFACE hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS | |