diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2006-09-17 18:17:19 +0200 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2006-09-17 18:19:31 +0200 |
commit | 9b4f2e9576658c4e52d95dc8d309f51b2e2db096 (patch) | |
tree | 7b1902b0f931783fccc6fee45c6f9c16b4fde5ce /drivers/scsi | |
parent | 3c6c65f5ed5a6d307bd607aecd06d658c0934d88 (diff) | |
parent | 803db244b9f71102e366fd689000c1417b9a7508 (diff) |
ieee1394: merge from Linus
Conflicts: drivers/ieee1394/hosts.c
Patch "lockdep: annotate ieee1394 skb-queue-head locking" was meddling
with patch "ieee1394: fix kerneldoc of hpsb_alloc_host".
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/scsi')
107 files changed, 5505 insertions, 4003 deletions
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index eb7a6a4ded7..657a3ab7539 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -173,6 +173,7 @@ STATIC int NCR_700_bus_reset(struct scsi_cmnd * SCpnt); STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt); STATIC void NCR_700_chip_setup(struct Scsi_Host *host); STATIC void NCR_700_chip_reset(struct Scsi_Host *host); +STATIC int NCR_700_slave_alloc(struct scsi_device *SDpnt); STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt); STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt); static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth); @@ -182,10 +183,6 @@ STATIC struct device_attribute *NCR_700_dev_attrs[]; STATIC struct scsi_transport_template *NCR_700_transport_template = NULL; -struct NCR_700_sense { - unsigned char cmnd[MAX_COMMAND_SIZE]; -}; - static char *NCR_700_phase[] = { "", "after selection", @@ -333,6 +330,7 @@ NCR_700_detect(struct scsi_host_template *tpnt, tpnt->use_clustering = ENABLE_CLUSTERING; tpnt->slave_configure = NCR_700_slave_configure; tpnt->slave_destroy = NCR_700_slave_destroy; + tpnt->slave_alloc = NCR_700_slave_alloc; tpnt->change_queue_depth = NCR_700_change_queue_depth; tpnt->change_queue_type = NCR_700_change_queue_type; @@ -611,9 +609,10 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, struct NCR_700_command_slot *slot = (struct NCR_700_command_slot *)SCp->host_scribble; - NCR_700_unmap(hostdata, SCp, slot); + dma_unmap_single(hostdata->dev, slot->pCmd, + sizeof(SCp->cmnd), DMA_TO_DEVICE); if (slot->flags == NCR_700_FLAG_AUTOSENSE) { - struct NCR_700_sense *sense = SCp->device->hostdata; + char *cmnd = NCR_700_get_sense_cmnd(SCp->device); #ifdef NCR_700_DEBUG printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n", SCp, SCp->cmnd[7], result); @@ -624,10 +623,9 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, /* restore the old result if the request sense was * successful */ if(result == 0) - result = sense->cmnd[7]; + result = cmnd[7]; } else - dma_unmap_single(hostdata->dev, slot->pCmd, - sizeof(SCp->cmnd), DMA_TO_DEVICE); + NCR_700_unmap(hostdata, SCp, slot); free_slot(slot, hostdata); #ifdef NCR_700_DEBUG @@ -969,14 +967,15 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, status_byte(hostdata->status[0]) == COMMAND_TERMINATED) { struct NCR_700_command_slot *slot = (struct NCR_700_command_slot *)SCp->host_scribble; - if(SCp->cmnd[0] == REQUEST_SENSE) { + if(slot->flags == NCR_700_FLAG_AUTOSENSE) { /* OOPS: bad device, returning another * contingent allegiance condition */ scmd_printk(KERN_ERR, SCp, "broken device is looping in contingent allegiance: ignoring\n"); NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]); } else { - struct NCR_700_sense *sense = SCp->device->hostdata; + char *cmnd = + NCR_700_get_sense_cmnd(SCp->device); #ifdef NCR_DEBUG scsi_print_command(SCp); printk(" cmd %p has status %d, requesting sense\n", @@ -994,21 +993,21 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, sizeof(SCp->cmnd), DMA_TO_DEVICE); - sense->cmnd[0] = REQUEST_SENSE; - sense->cmnd[1] = (SCp->device->lun & 0x7) << 5; - sense->cmnd[2] = 0; - sense->cmnd[3] = 0; - sense->cmnd[4] = sizeof(SCp->sense_buffer); - sense->cmnd[5] = 0; + cmnd[0] = REQUEST_SENSE; + cmnd[1] = (SCp->device->lun & 0x7) << 5; + cmnd[2] = 0; + cmnd[3] = 0; + cmnd[4] = sizeof(SCp->sense_buffer); + cmnd[5] = 0; /* Here's a quiet hack: the * REQUEST_SENSE command is six bytes, * so store a flag indicating that * this was an internal sense request * and the original status at the end * of the command */ - sense->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC; - sense->cmnd[7] = hostdata->status[0]; - slot->pCmd = dma_map_single(hostdata->dev, sense->cmnd, sizeof(sense->cmnd), DMA_TO_DEVICE); + cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC; + cmnd[7] = hostdata->status[0]; + slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE); slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE); slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer)); slot->SG[0].pAddr = bS_to_host(slot->dma_handle); @@ -1530,7 +1529,7 @@ NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs) /* clear all the negotiated parameters */ __shost_for_each_device(SDp, host) - SDp->hostdata = NULL; + NCR_700_clear_flag(SDp, ~0); /* clear all the slots and their pending commands */ for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) { @@ -2035,7 +2034,17 @@ NCR_700_set_offset(struct scsi_target *STp, int offset) spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION; } +STATIC int +NCR_700_slave_alloc(struct scsi_device *SDp) +{ + SDp->hostdata = kzalloc(sizeof(struct NCR_700_Device_Parameters), + GFP_KERNEL); + if (!SDp->hostdata) + return -ENOMEM; + + return 0; +} STATIC int NCR_700_slave_configure(struct scsi_device *SDp) @@ -2043,11 +2052,6 @@ NCR_700_slave_configure(struct scsi_device *SDp) struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; - SDp->hostdata = kmalloc(GFP_KERNEL, sizeof(struct NCR_700_sense)); - - if (!SDp->hostdata) - return -ENOMEM; - /* to do here: allocate memory; build a queue_full list */ if(SDp->tagged_supported) { scsi_set_tag_type(SDp, MSG_ORDERED_TAG); diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h index 7f22a06fe5e..97ebe71b701 100644 --- a/drivers/scsi/53c700.h +++ b/drivers/scsi/53c700.h @@ -12,7 +12,7 @@ #include <asm/io.h> #include <scsi/scsi_device.h> - +#include <scsi/scsi_cmnd.h> /* Turn on for general debugging---too verbose for normal use */ #undef NCR_700_DEBUG @@ -76,11 +76,16 @@ struct NCR_700_SG_List { #define SCRIPT_RETURN 0x90080000 }; -/* We use device->hostdata to store negotiated parameters. This is - * supposed to be a pointer to a device private area, but we cannot - * really use it as such since it will never be freed, so just use the - * 32 bits to cram the information. The SYNC negotiation sequence looks - * like: +struct NCR_700_Device_Parameters { + /* space for creating a request sense command. Really, except + * for the annoying SCSI-2 requirement for LUN information in + * cmnd[1], this could be in static storage */ + unsigned char cmnd[MAX_COMMAND_SIZE]; + __u8 depth; +}; + + +/* The SYNC negotiation sequence looks like: * * If DEV_NEGOTIATED_SYNC not set, tack and SDTR message on to the * initial identify for the device and set DEV_BEGIN_SYNC_NEGOTATION @@ -98,19 +103,26 @@ struct NCR_700_SG_List { #define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION (1<<17) #define NCR_700_DEV_PRINT_SYNC_NEGOTIATION (1<<19) +static inline char *NCR_700_get_sense_cmnd(struct scsi_device *SDp) +{ + struct NCR_700_Device_Parameters *hostdata = SDp->hostdata; + + return hostdata->cmnd; +} + static inline void NCR_700_set_depth(struct scsi_device *SDp, __u8 depth) { - long l = (long)SDp->hostdata; + struct NCR_700_Device_Parameters *hostdata = SDp->hostdata; - l &= 0xffff00ff; - l |= 0xff00 & (depth << 8); - SDp->hostdata = (void *)l; + hostdata->depth = depth; } static inline __u8 NCR_700_get_depth(struct scsi_device *SDp) { - return ((((unsigned long)SDp->hostdata) & 0xff00)>>8); + struct NCR_700_Device_Parameters *hostdata = SDp->hostdata; + + return hostdata->depth; } static inline int NCR_700_is_flag_set(struct scsi_device *SDp, __u32 flag) diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c index c690c2b89e4..acf292736b4 100644 --- a/drivers/scsi/53c7xx.c +++ b/drivers/scsi/53c7xx.c @@ -3451,12 +3451,12 @@ create_cmd (Scsi_Cmnd *cmd) { for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4, cmd_dataout += 4, ++i) { u32 vbuf = cmd->use_sg - ? (u32)page_address(((struct scatterlist *)cmd->buffer)[i].page)+ - ((struct scatterlist *)cmd->buffer)[i].offset + ? (u32)page_address(((struct scatterlist *)cmd->request_buffer)[i].page)+ + ((struct scatterlist *)cmd->request_buffer)[i].offset : (u32)(cmd->request_buffer); u32 bbuf = virt_to_bus((void *)vbuf); u32 count = cmd->use_sg ? - ((struct scatterlist *)cmd->buffer)[i].length : + ((struct scatterlist *)cmd->request_buffer)[i].length : cmd->request_bufflen; /* @@ -5417,7 +5417,7 @@ insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) { if ((buffers = cmd->use_sg)) { for (offset = 0, - segment = (struct scatterlist *) cmd->buffer; + segment = (struct scatterlist *) cmd->request_buffer; buffers && !((found = ((ptr >= (char *)page_address(segment->page)+segment->offset) && (ptr < ((char *)page_address(segment->page)+segment->offset+segment->length))))); --buffers, offset += segment->length, ++segment) diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c index 8a4659e9410..bdc6bb262bc 100644 --- a/drivers/scsi/NCR53C9x.c +++ b/drivers/scsi/NCR53C9x.c @@ -911,7 +911,7 @@ static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp) sp->SCp.ptr = (char *) virt_to_phys(sp->request_buffer); } else { - sp->SCp.buffer = (struct scatterlist *) sp->buffer; + sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; sp->SCp.buffers_residual = sp->use_sg - 1; sp->SCp.this_residual = sp->SCp.buffer->length; if (esp->dma_mmu_get_scsi_sgl) @@ -2152,29 +2152,23 @@ static int esp_do_data_finale(struct NCR_ESP *esp, */ static int esp_should_clear_sync(Scsi_Cmnd *sp) { - unchar cmd1 = sp->cmnd[0]; - unchar cmd2 = sp->data_cmnd[0]; + unchar cmd = sp->cmnd[0]; /* These cases are for spinning up a disk and * waiting for that spinup to complete. */ - if(cmd1 == START_STOP || - cmd2 == START_STOP) + if(cmd == START_STOP) return 0; - if(cmd1 == TEST_UNIT_READY || - cmd2 == TEST_UNIT_READY) + if(cmd == TEST_UNIT_READY) return 0; /* One more special case for SCSI tape drives, * this is what is used to probe the device for * completion of a rewind or tape load operation. */ - if(sp->device->type == TYPE_TAPE) { - if(cmd1 == MODE_SENSE || - cmd2 == MODE_SENSE) - return 0; - } + if(sp->device->type == TYPE_TAPE && cmd == MODE_SENSE) + return 0; return 1; } diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c index a06f547e87f..d05681f9d81 100644 --- a/drivers/scsi/NCR_D700.c +++ b/drivers/scsi/NCR_D700.c @@ -114,7 +114,7 @@ MODULE_DESCRIPTION("NCR Dual700 SCSI Driver"); MODULE_LICENSE("GPL"); module_param(NCR_D700, charp, 0); -static __u8 __initdata id_array[2*(MCA_MAX_SLOT_NR + 1)] = +static __u8 __devinitdata id_array[2*(MCA_MAX_SLOT_NR + 1)] = { [0 ... 2*(MCA_MAX_SLOT_NR + 1)-1] = 7 }; #ifdef MODULE @@ -173,7 +173,7 @@ struct NCR_D700_private { char pad; }; -static int +static int __devinit NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq, int slot, u32 region, int differential) { @@ -243,7 +243,7 @@ NCR_D700_intr(int irq, void *data, struct pt_regs *regs) * essentially connectecd to the MCA bus independently, it is easier * to set them up as two separate host adapters, rather than one * adapter with two channels */ -static int +static int __devinit NCR_D700_probe(struct device *dev) { struct NCR_D700_private *p; @@ -329,7 +329,7 @@ NCR_D700_probe(struct device *dev) for (i = 0; i < 2; i++) { int err; - if ((err = NCR_D700_probe_one(p, i, slot, irq, + if ((err = NCR_D700_probe_one(p, i, irq, slot, offset_addr + (0x80 * i), differential)) != 0) printk("D700: SIOP%d: probe failed, error = %d\n", @@ -349,7 +349,7 @@ NCR_D700_probe(struct device *dev) return 0; } -static void +static void __devexit NCR_D700_remove_one(struct Scsi_Host *host) { scsi_remove_host(host); @@ -359,7 +359,7 @@ NCR_D700_remove_one(struct Scsi_Host *host) release_region(host->base, 64); } -static int +static int __devexit NCR_D700_remove(struct device *dev) { struct NCR_D700_private *p = dev_get_drvdata(dev); @@ -380,7 +380,7 @@ static struct mca_driver NCR_D700_driver = { .name = "NCR_D700", .bus = &mca_bus_type, .probe = NCR_D700_probe, - .remove = NCR_D700_remove, + .remove = __devexit_p(NCR_D700_remove), }, }; diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 7cea514e810..1cd3584ba7f 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -92,31 +92,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys); init->AdapterFibsSize = cpu_to_le32(fibsize); init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib)); - /* - * number of 4k pages of host physical memory. The aacraid fw needs - * this number to be less than 4gb worth of pages. num_physpages is in - * system page units. New firmware doesn't have any issues with the - * mapping system, but older Firmware did, and had *troubles* dealing - * with the math overloading past 32 bits, thus we must limit this - * field. - * - * This assumes the memory is mapped zero->n, which isnt - * always true on real computers. It also has some slight problems - * with the GART on x86-64. I've btw never tried DMA from PCI space - * on this platform but don't be surprised if its problematic. - * [AK: something is very very wrong when a driver tests this symbol. - * Someone should figure out what the comment writer really meant here and fix - * the code. Or just remove that bad code. ] - */ -#ifndef CONFIG_IOMMU - if ((num_physpages << (PAGE_SHIFT - 12)) <= AAC_MAX_HOSTPHYSMEMPAGES) { - init->HostPhysMemPages = - cpu_to_le32(num_physpages << (PAGE_SHIFT-12)); - } else -#endif - { - init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES); - } + init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES); init->InitFlags = 0; if (dev->new_comm_interface) { diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 36e63f82d9f..f974869ea32 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -551,6 +551,11 @@ struct aha152x_hostdata { struct aha152x_scdata { Scsi_Cmnd *next; /* next sc in queue */ struct semaphore *sem; /* semaphore to block on */ + unsigned char cmd_len; + unsigned char cmnd[MAX_COMMAND_SIZE]; + unsigned short use_sg; + unsigned request_bufflen; + void *request_buffer; }; @@ -1006,11 +1011,20 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int p return FAILED; } } else { + struct aha152x_scdata *sc; + SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC); if(SCpnt->host_scribble==0) { printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt)); return FAILED; } + + sc = SCDATA(SCpnt); + memcpy(sc->cmnd, SCpnt->cmnd, sizeof(sc->cmnd)); + sc->request_buffer = SCpnt->request_buffer; + sc->request_bufflen = SCpnt->request_bufflen; + sc->use_sg = SCpnt->use_sg; + sc->cmd_len = SCpnt->cmd_len; } SCNEXT(SCpnt) = NULL; @@ -1165,6 +1179,10 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt) DECLARE_MUTEX_LOCKED(sem); struct timer_list timer; int ret, issued, disconnected; + unsigned char old_cmd_len = SCpnt->cmd_len; + unsigned short old_use_sg = SCpnt->use_sg; + void *old_buffer = SCpnt->request_buffer; + unsigned old_bufflen = SCpnt->request_bufflen; unsigned long flags; #if defined(AHA152X_DEBUG) @@ -1198,11 +1216,11 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt) add_timer(&timer); down(&sem); del_timer(&timer); - - SCpnt->cmd_len = SCpnt->old_cmd_len; - SCpnt->use_sg = SCpnt->old_use_sg; - SCpnt->request_buffer = SCpnt->buffer; - SCpnt->request_bufflen = SCpnt->bufflen; + + SCpnt->cmd_len = old_cmd_len; + SCpnt->use_sg = old_use_sg; + SCpnt->request_buffer = old_buffer; + SCpnt->request_bufflen = old_bufflen; DO_LOCK(flags); @@ -1565,6 +1583,9 @@ static void busfree_run(struct Scsi_Host *shpnt) #endif if(DONE_SC->SCp.phase & check_condition) { + struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC; + struct aha152x_scdata *sc = SCDATA(cmd); + #if 0 if(HOSTDATA(shpnt)->debug & debug_eh) { printk(ERR_LEAD "received sense: ", CMDINFO(DONE_SC)); @@ -1573,13 +1594,13 @@ static void busfree_run(struct Scsi_Host *shpnt) #endif /* restore old command */ - memcpy((void *) DONE_SC->cmnd, (void *) DONE_SC->data_cmnd, sizeof(DONE_SC->data_cmnd)); - DONE_SC->request_buffer = DONE_SC->buffer; - DONE_SC->request_bufflen = DONE_SC->bufflen; - DONE_SC->use_sg = DONE_SC->old_use_sg; - DONE_SC->cmd_len = DONE_SC->old_cmd_len; + memcpy(cmd->cmnd, sc->cmnd, sizeof(sc->cmnd)); + cmd->request_buffer = sc->request_buffer; + cmd->request_bufflen = sc->request_bufflen; + cmd->use_sg = sc->use_sg; + cmd->cmd_len = sc->cmd_len; - DONE_SC->SCp.Status = 0x02; + cmd->SCp.Status = 0x02; HOSTDATA(shpnt)->commands--; if (!HOSTDATA(shpnt)->commands) diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 15f6cd4279b..904c25fb4ba 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -940,14 +940,8 @@ static void ahci_host_intr(struct ata_port *ap) return; /* ignore interim PIO setup fis interrupts */ - if (ata_tag_valid(ap->active_tag)) { - struct ata_queued_cmd *qc = - ata_qc_from_tag(ap, ap->active_tag); - - if (qc && qc->tf.protocol == ATA_PROT_PIO && - (status & PORT_IRQ_PIOS_FIS)) - return; - } + if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS)) + return; if (ata_ratelimit()) ata_port_printk(ap, KERN_INFO, "spurious interrupt " @@ -1052,7 +1046,7 @@ static void ahci_thaw(struct ata_port *ap) static void ahci_error_handler(struct ata_port *ap) { - if (!(ap->flags & ATA_FLAG_FROZEN)) { + if (!(ap->pflags & ATA_PFLAG_FROZEN)) { /* restart engine */ ahci_stop_engine(ap); ahci_start_engine(ap); @@ -1323,6 +1317,17 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); + /* JMicron-specific fixup: make sure we're in AHCI mode */ + /* This is protected from races with ata_jmicron by the pci probe + locking */ + if (pdev->vendor == PCI_VENDOR_ID_JMICRON) { + /* AHCI enable, AHCI on function 0 */ + pci_write_config_byte(pdev, 0x41, 0xa1); + /* Function 1 is the PATA controller */ + if (PCI_FUNC(pdev->devfn)) + return -ENODEV; + } + rc = pci_enable_device(pdev); if (rc) return rc; @@ -1378,10 +1383,6 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (have_msi) hpriv->flags |= AHCI_FLAG_MSI; - /* JMicron-specific fixup: make sure we're in AHCI mode */ - if (pdev->vendor == 0x197b) - pci_write_config_byte(pdev, 0x41, 0xa1); - /* initialize adapter */ rc = ahci_host_init(probe_ent); if (rc) diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index eb774569268..df3346b5caf 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -1487,6 +1487,7 @@ typedef enum { } ahd_queue_alg; void ahd_set_tags(struct ahd_softc *ahd, + struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, ahd_queue_alg alg); diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 801fc81d0b2..653818d2f80 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -1090,7 +1090,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) /* Notify XPT */ ahd_send_async(ahd, devinfo.channel, devinfo.target, - CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); + CAM_LUN_WILDCARD, AC_SENT_BDR); /* * Allow the sequencer to continue with @@ -3062,7 +3062,7 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, tinfo->curr.ppr_options = ppr_options; ahd_send_async(ahd, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG); if (bootverbose) { if (offset != 0) { int options; @@ -3184,7 +3184,7 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, tinfo->curr.width = width; ahd_send_async(ahd, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG); if (bootverbose) { printf("%s: target %d using %dbit transfers\n", ahd_name(ahd), devinfo->target, @@ -3211,12 +3211,14 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, * Update the current state of tagged queuing for a given target. */ void -ahd_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - ahd_queue_alg alg) +ahd_set_tags(struct ahd_softc *ahd, struct scsi_cmnd *cmd, + struct ahd_devinfo *devinfo, ahd_queue_alg alg) { - ahd_platform_set_tags(ahd, devinfo, alg); + struct scsi_device *sdev = cmd->device; + + ahd_platform_set_tags(ahd, sdev, devinfo, alg); ahd_send_async(ahd, devinfo->channel, devinfo->target, - devinfo->lun, AC_TRANSFER_NEG, &alg); + devinfo->lun, AC_TRANSFER_NEG); } static void @@ -4746,7 +4748,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) printf("(%s:%c:%d:%d): refuses tagged commands. " "Performing non-tagged I/O\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun); - ahd_set_tags(ahd, devinfo, AHD_QUEUE_NONE); + ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_NONE); mask = ~0x23; } else { printf("(%s:%c:%d:%d): refuses %s tagged commands. " @@ -4754,7 +4756,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun, tag_type == MSG_ORDERED_TASK ? "ordered" : "head of queue"); - ahd_set_tags(ahd, devinfo, AHD_QUEUE_BASIC); + ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_BASIC); mask = ~0x03; } @@ -5098,7 +5100,7 @@ ahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, if (status != CAM_SEL_TIMEOUT) ahd_send_async(ahd, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); + CAM_LUN_WILDCARD, AC_SENT_BDR); if (message != NULL && bootverbose) printf("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd), @@ -7287,7 +7289,7 @@ ahd_reset_cmds_pending(struct ahd_softc *ahd) ahd->flags &= ~AHD_UPDATE_PEND_CMDS; } -void +static void ahd_done_with_status(struct ahd_softc *ahd, struct scb *scb, uint32_t status) { cam_status ostat; @@ -7952,7 +7954,7 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) #endif /* Notify the XPT that a bus reset occurred */ ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); + CAM_LUN_WILDCARD, AC_BUS_RESET); /* * Revert to async/narrow transfers until we renegotiate. diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index e0ccdf36220..998999c0a97 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -243,25 +243,6 @@ ahd_print_path(struct ahd_softc *ahd, struct scb *scb) static uint32_t aic79xx_no_reset; /* - * Certain PCI motherboards will scan PCI devices from highest to lowest, - * others scan from lowest to highest, and they tend to do all kinds of - * strange things when they come into contact with PCI bridge chips. The - * net result of all this is that the PCI card that is actually used to boot - * the machine is very hard to detect. Most motherboards go from lowest - * PCI slot number to highest, and the first SCSI controller found is the - * one you boot from. The only exceptions to this are when a controller - * has its BIOS disabled. So, we by default sort all of our SCSI controllers - * from lowest PCI slot number to highest PCI slot number. We also force - * all controllers with their BIOS disabled to the end of the list. This - * works on *almost* all computers. Where it doesn't work, we have this - * option. Setting this option to non-0 will reverse the order of the sort - * to highest first, then lowest, but will still leave cards with their BIOS - * disabled at the very end. That should fix everyone up unless there are - * really strange cirumstances. - */ -static uint32_t aic79xx_reverse_scan; - -/* * Should we force EXTENDED translation on a controller. * 0 == Use whatever is in the SEEPROM or default to off * 1 == Use whatever is in the SEEPROM or default to on @@ -350,7 +331,6 @@ MODULE_PARM_DESC(aic79xx, " periodically to prevent tag starvation.\n" " This may be required by some older disk\n" " or drives/RAID arrays.\n" -" reverse_scan Sort PCI devices highest Bus/Slot to lowest\n" " tag_info:<tag_str> Set per-target tag depth\n" " global_tag_depth:<int> Global tag depth for all targets on all buses\n" " slewrate:<slewrate_list>Set the signal slew rate (0-15).\n" @@ -484,7 +464,6 @@ ahd_linux_target_alloc(struct scsi_target *starget) struct seeprom_config *sc = ahd->seep_config; unsigned long flags; struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget); - struct ahd_linux_target *targ = scsi_transport_target_data(starget); struct ahd_devinfo devinfo; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; @@ -495,7 +474,6 @@ ahd_linux_target_alloc(struct scsi_target *starget) BUG_ON(*ahd_targp != NULL); *ahd_targp = starget; - memset(targ, 0, sizeof(*targ)); if (sc) { int flags = sc->device_flags[starget->id]; @@ -551,15 +529,11 @@ ahd_linux_slave_alloc(struct scsi_device *sdev) { struct ahd_softc *ahd = *((struct ahd_softc **)sdev->host->hostdata); - struct scsi_target *starget = sdev->sdev_target; - struct ahd_linux_target *targ = scsi_transport_target_data(starget); struct ahd_linux_device *dev; if (bootverbose) printf("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id); - BUG_ON(targ->sdev[sdev->lun] != NULL); - dev = scsi_transport_device_data(sdev); memset(dev, 0, sizeof(*dev)); @@ -576,8 +550,6 @@ ahd_linux_slave_alloc(struct scsi_device *sdev) */ dev->maxtags = 0; - targ->sdev[sdev->lun] = sdev; - return (0); } @@ -599,23 +571,6 @@ ahd_linux_slave_configure(struct scsi_device *sdev) return 0; } -static void -ahd_linux_slave_destroy(struct scsi_device *sdev) -{ - struct ahd_softc *ahd; - struct ahd_linux_device *dev = scsi_transport_device_data(sdev); - struct ahd_linux_target *targ = scsi_transport_target_data(sdev->sdev_target); - - ahd = *((struct ahd_softc **)sdev->host->hostdata); - if (bootverbose) - printf("%s: Slave Destroy %d\n", ahd_name(ahd), sdev->id); - - BUG_ON(dev->active); - - targ->sdev[sdev->lun] = NULL; - -} - #if defined(__i386__) /* * Return the disk geometry for the given SCSI device. @@ -822,7 +777,6 @@ struct scsi_host_template aic79xx_driver_template = { .use_clustering = ENABLE_CLUSTERING, .slave_alloc = ahd_linux_slave_alloc, .slave_configure = ahd_linux_slave_configure, - .slave_destroy = ahd_linux_slave_destroy, .target_alloc = ahd_linux_target_alloc, .target_destroy = ahd_linux_target_destroy, }; @@ -1057,7 +1011,6 @@ aic79xx_setup(char *s) #ifdef AHD_DEBUG { "debug", &ahd_debug }, #endif - { "reverse_scan", &aic79xx_reverse_scan }, { "periodic_otag", &aic79xx_periodic_otag }, { "pci_parity", &aic79xx_pci_parity }, { "seltime", &aic79xx_seltime }, @@ -1249,20 +1202,13 @@ void ahd_platform_free(struct ahd_softc *ahd) { struct scsi_target *starget; - int i, j; + int i; if (ahd->platform_data != NULL) { /* destroy all of the device and target objects */ for (i = 0; i < AHD_NUM_TARGETS; i++) { starget = ahd->platform_data->starget[i]; if (starget != NULL) { - for (j = 0; j < AHD_NUM_LUNS; j++) { - struct ahd_linux_target *targ = - scsi_transport_target_data(starget); - if (targ->sdev[j] == NULL) - continue; - targ->sdev[j] = NULL; - } ahd->platform_data->starget[i] = NULL; } } @@ -1318,20 +1264,13 @@ ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb) } void -ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - ahd_queue_alg alg) +ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, + struct ahd_devinfo *devinfo, ahd_queue_alg alg) { - struct scsi_target *starget; - struct ahd_linux_target *targ; struct ahd_linux_device *dev; - struct scsi_device *sdev; int was_queuing; int now_queuing; - starget = ahd->platform_data->starget[devinfo->target]; - targ = scsi_transport_target_data(starget); - BUG_ON(targ == NULL); - sdev = targ->sdev[devinfo->lun]; if (sdev == NULL) return; @@ -1467,11 +1406,15 @@ ahd_linux_device_queue_depth(struct scsi_device *sdev) tags = ahd_linux_user_tagdepth(ahd, &devinfo); if (tags != 0 && sdev->tagged_supported != 0) { - ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED); + ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_TAGGED); + ahd_send_async(ahd, devinfo.channel, devinfo.target, + devinfo.lun, AC_TRANSFER_NEG); ahd_print_devinfo(ahd, &devinfo); printf("Tagged Queuing enabled. Depth %d\n", tags); } else { - ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE); + ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_NONE); + ahd_send_async(ahd, devinfo.channel, devinfo.target, + devinfo.lun, AC_TRANSFER_NEG); } } @@ -1629,7 +1572,7 @@ ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs) void ahd_send_async(struct ahd_softc *ahd, char channel, - u_int target, u_int lun, ac_code code, void *arg) + u_int target, u_int lun, ac_code code) { switch (code) { case AC_TRANSFER_NEG: @@ -1956,7 +1899,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, } ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); ahd_set_scsi_status(scb, SCSI_STATUS_OK); - ahd_platform_set_tags(ahd, &devinfo, + ahd_platform_set_tags(ahd, sdev, &devinfo, (dev->flags & AHD_DEV_Q_BASIC) ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); break; @@ -1966,7 +1909,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, * as if the target returned BUSY SCSI status. */ dev->openings = 1; - ahd_platform_set_tags(ahd, &devinfo, + ahd_platform_set_tags(ahd, sdev, &devinfo, (dev->flags & AHD_DEV_Q_BASIC) ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); ahd_set_scsi_status(scb, SCSI_STATUS_BUSY); @@ -2778,8 +2721,6 @@ ahd_linux_init(void) if (!ahd_linux_transport_template) return -ENODEV; - scsi_transport_reserve_target(ahd_linux_transport_template, - sizeof(struct ahd_linux_target)); scsi_transport_reserve_device(ahd_linux_transport_template, sizeof(struct ahd_linux_device)); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 92c6154575e..601340d8441 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -93,7 +93,6 @@ #endif /********************************** Misc Macros *******************************/ -#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) #define powerof2(x) ((((x)-1)&(x))==0) /************************* Forward Declarations *******************************/ @@ -262,7 +261,6 @@ typedef enum { AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ } ahd_linux_dev_flags; -struct ahd_linux_target; struct ahd_linux_device { TAILQ_ENTRY(ahd_linux_device) links; @@ -342,12 +340,6 @@ struct ahd_linux_device { #define AHD_OTAG_THRESH 500 }; -struct ahd_linux_target { - struct scsi_device *sdev[AHD_NUM_LUNS]; - struct ahd_transinfo last_tinfo; - struct ahd_softc *ahd; -}; - /********************* Definitions Required by the Core ***********************/ /* * Number of SG segments we require. So long as the S/G segments for @@ -864,7 +856,7 @@ ahd_freeze_scb(struct scb *scb) } } -void ahd_platform_set_tags(struct ahd_softc *ahd, +void ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, struct ahd_devinfo *devinfo, ahd_queue_alg); int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, int lun, u_int tag, @@ -873,7 +865,7 @@ irqreturn_t ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs); void ahd_done(struct ahd_softc*, struct scb*); void ahd_send_async(struct ahd_softc *, char channel, - u_int target, u_int lun, ac_code, void *); + u_int target, u_int lun, ac_code); void ahd_print_path(struct ahd_softc *, struct scb *); #ifdef CONFIG_PCI diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index 24fd59a230b..c5f0ee59150 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -47,7 +47,7 @@ static int copy_info(struct info_str *info, char *fmt, ...); static void ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, u_int our_id, char channel, - u_int target_id, u_int target_offset); + u_int target_id); static void ahd_dump_device_state(struct info_str *info, struct scsi_device *sdev); static int ahd_proc_write_seeprom(struct ahd_softc *ahd, @@ -204,10 +204,8 @@ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo) static void ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, - u_int our_id, char channel, u_int target_id, - u_int target_offset) + u_int our_id, char channel, u_int target_id) { - struct ahd_linux_target *targ; struct scsi_target *starget; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; @@ -218,10 +216,9 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, copy_info(info, "Target %d Negotiation Settings\n", target_id); copy_info(info, "\tUser: "); ahd_format_transinfo(info, &tinfo->user); - starget = ahd->platform_data->starget[target_offset]; + starget = ahd->platform_data->starget[target_id]; if (starget == NULL) return; - targ = scsi_transport_target_data(starget); copy_info(info, "\tGoal: "); ahd_format_transinfo(info, &tinfo->goal); @@ -231,7 +228,7 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, for (lun = 0; lun < AHD_NUM_LUNS; lun++) { struct scsi_device *dev; - dev = targ->sdev[lun]; + dev = scsi_device_lookup_by_target(starget, lun); if (dev == NULL) continue; @@ -355,7 +352,7 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n", ahd->scb_data.numscbs, AHD_NSEG); - max_targ = 15; + max_targ = 16; if (ahd->seep_config == NULL) copy_info(&info, "No Serial EEPROM\n"); @@ -373,12 +370,12 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, copy_info(&info, "\n"); if ((ahd->features & AHD_WIDE) == 0) - max_targ = 7; + max_targ = 8; - for (i = 0; i <= max_targ; i++) { + for (i = 0; i < max_targ; i++) { ahd_dump_target_state(ahd, &info, ahd->our_id, 'A', - /*target_id*/i, /*target_offset*/i); + /*target_id*/i); } retval = info.pos > info.offset ? info.pos - info.offset : 0; done: diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index debf3e2a079..aa4be8a3141 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -353,7 +353,6 @@ MODULE_PARM_DESC(aic7xxx, " periodically to prevent tag starvation.\n" " This may be required by some older disk\n" " drives or RAID arrays.\n" -" reverse_scan Sort PCI devices highest Bus/Slot to lowest\n" " tag_info:<tag_str> Set per-target tag depth\n" " global_tag_depth:<int> Global tag depth for every target\n" " on every bus\n" diff --git a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile index 8c91fda6482..b98c5c1056c 100644 --- a/drivers/scsi/aic7xxx/aicasm/Makefile +++ b/drivers/scsi/aic7xxx/aicasm/Makefile @@ -14,6 +14,8 @@ LIBS= -ldb clean-files:= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) $(PROG) # Override default kernel CFLAGS. This is a userland app. AICASM_CFLAGS:= -I/usr/include -I. +LEX= flex +YACC= bison YFLAGS= -d NOMAN= noman diff --git a/drivers/scsi/arm/Kconfig b/drivers/scsi/arm/Kconfig index 06d7601cdf5..d006a8cb4a7 100644 --- a/drivers/scsi/arm/Kconfig +++ b/drivers/scsi/arm/Kconfig @@ -69,6 +69,7 @@ comment "The following drivers are not fully supported" config SCSI_CUMANA_1 tristate "CumanaSCSI I support (EXPERIMENTAL)" depends on ARCH_ACORN && EXPERIMENTAL && SCSI + select SCSI_SPI_ATTRS help This enables support for the Cumana SCSI I card. If you have an Acorn system with one of these, say Y. If unsure, say N. @@ -76,6 +77,7 @@ config SCSI_CUMANA_1 config SCSI_ECOSCSI tristate "EcoScsi support (EXPERIMENTAL)" depends on ARCH_ACORN && EXPERIMENTAL && (ARCH_ARC || ARCH_A5K) && SCSI + select SCSI_SPI_ATTRS help This enables support for the EcoSCSI card -- a small card that sits in the Econet socket. If you have an Acorn system with one of these, @@ -84,6 +86,7 @@ config SCSI_ECOSCSI config SCSI_OAK1 tristate "Oak SCSI support (EXPERIMENTAL)" depends on ARCH_ACORN && EXPERIMENTAL && SCSI + select SCSI_SPI_ATTRS help This enables support for the Oak SCSI card. If you have an Acorn system with one of these, say Y. If unsure, say N. diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index 3e1053f111d..4cf7afc31cc 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2427,7 +2427,7 @@ int fas216_eh_abort(Scsi_Cmnd *SCpnt) info->stats.aborts += 1; printk(KERN_WARNING "scsi%d: abort command ", info->host->host_no); - __scsi_print_command(SCpnt->data_cmnd); + __scsi_print_command(SCpnt->cmnd); print_debug_list(); fas216_dumpstate(info); diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h index 6dd544a5eb5..8c2600ffc6a 100644 --- a/drivers/scsi/arm/scsi.h +++ b/drivers/scsi/arm/scsi.h @@ -74,7 +74,7 @@ static inline void init_SCp(Scsi_Cmnd *SCpnt) unsigned long len = 0; int buf; - SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer; + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; SCpnt->SCp.ptr = (char *) (page_address(SCpnt->SCp.buffer->page) + diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 94b1261a259..a9bb3cb7e89 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -105,9 +105,6 @@ enum { PIIX_FLAG_SCR = (1 << 26), /* SCR available */ PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */ PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */ - PIIX_FLAG_COMBINED = (1 << 29), /* combined mode possible */ - /* ICH6/7 use different scheme for map value */ - PIIX_FLAG_COMBINED_ICH6 = PIIX_FLAG_COMBINED | (1 << 30), /* combined mode. if set, PATA is channel 0. * if clear, PATA is channel 1. @@ -126,6 +123,8 @@ enum { ich6_sata = 4, ich6_sata_ahci = 5, ich6m_sata_ahci = 6, + ich7m_sata_ahci = 7, + ich8_sata_ahci = 8, /* constants for mapping table */ P0 = 0, /* port 0 */ @@ -141,11 +140,19 @@ enum { struct piix_map_db { const u32 mask; + const u16 port_enable; + const int present_shift; const int map[][4]; }; +struct piix_host_priv { + const int *map; + const struct piix_map_db *map_db; +}; + static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static void piix_host_stop(struct ata_host_set *host_set); static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev); static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev); static void piix_pata_error_handler(struct ata_port *ap); @@ -182,15 +189,15 @@ static const struct pci_device_id piix_pci_tbl[] = { /* 82801GB/GR/GH (ICH7, identical to ICH6) */ { 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci }, /* 2801GBM/GHM (ICH7M, identical to ICH6M) */ - { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci }, + { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7m_sata_ahci }, /* Enterprise Southbridge 2 (where's the datasheet?) */ { 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci }, /* SATA Controller 1 IDE (ICH8, no datasheet yet) */ - { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci }, + { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, /* SATA Controller 2 IDE (ICH8, ditto) */ - { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci }, + { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, /* Mobile SATA Controller IDE (ICH8M, ditto) */ - { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci }, + { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, { } /* terminate list */ }; @@ -254,7 +261,7 @@ static const struct ata_port_operations piix_pata_ops = { .port_start = ata_port_start, .port_stop = ata_port_stop, - .host_stop = ata_host_stop, + .host_stop = piix_host_stop, }; static const struct ata_port_operations piix_sata_ops = { @@ -284,11 +291,13 @@ static const struct ata_port_operations piix_sata_ops = { .port_start = ata_port_start, .port_stop = ata_port_stop, - .host_stop = ata_host_stop, + .host_stop = piix_host_stop, }; -static struct piix_map_db ich5_map_db = { +static const struct piix_map_db ich5_map_db = { .mask = 0x7, + .port_enable = 0x3, + .present_shift = 4, .map = { /* PM PS SM SS MAP */ { P0, NA, P1, NA }, /* 000b */ @@ -302,8 +311,10 @@ static struct piix_map_db ich5_map_db = { }, }; -static struct piix_map_db ich6_map_db = { +static const struct piix_map_db ich6_map_db = { .mask = 0x3, + .port_enable = 0xf, + .present_shift = 4, .map = { /* PM PS SM SS MAP */ { P0, P2, P1, P3 }, /* 00b */ @@ -313,8 +324,10 @@ static struct piix_map_db ich6_map_db = { }, }; -static struct piix_map_db ich6m_map_db = { +static const struct piix_map_db ich6m_map_db = { .mask = 0x3, + .port_enable = 0x5, + .present_shift = 4, .map = { /* PM PS SM SS MAP */ { P0, P2, RV, RV }, /* 00b */ @@ -324,6 +337,47 @@ static struct piix_map_db ich6m_map_db = { }, }; +static const struct piix_map_db ich7m_map_db = { + .mask = 0x3, + .port_enable = 0x5, + .present_shift = 4, + + /* Map 01b isn't specified in the doc but some notebooks use + * it anyway. ATM, the only case spotted carries subsystem ID + * 1025:0107. This is the only difference from ich6m. + */ + .map = { + /* PM PS SM SS MAP */ + { P0, P2, RV, RV }, /* 00b */ + { IDE, IDE, P1, P3 }, /* 01b */ + { P0, P2, IDE, IDE }, /* 10b */ + { RV, RV, RV, RV }, + }, +}; + +static const struct piix_map_db ich8_map_db = { + .mask = 0x3, + .port_enable = 0x3, + .present_shift = 8, + .map = { + /* PM PS SM SS MAP */ + { P0, NA, P1, NA }, /* 00b (hardwired) */ + { RV, RV, RV, RV }, + { RV, RV, RV, RV }, /* 10b (never) */ + { RV, RV, RV, RV }, + }, +}; + +static const struct piix_map_db *piix_map_db_table[] = { + [ich5_sata] = &ich5_map_db, + [esb_sata] = &ich5_map_db, + [ich6_sata] = &ich6_map_db, + [ich6_sata_ahci] = &ich6_map_db, + [ich6m_sata_ahci] = &ich6m_map_db, + [ich7m_sata_ahci] = &ich7m_map_db, + [ich8_sata_ahci] = &ich8_map_db, +}; + static struct ata_port_info piix_port_info[] = { /* piix4_pata */ { @@ -356,63 +410,82 @@ static struct ata_port_info piix_port_info[] = { /* ich5_sata */ { .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED | - PIIX_FLAG_CHECKINTR, + .host_flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR | + PIIX_FLAG_IGNORE_PCS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, - .private_data = &ich5_map_db, }, /* i6300esb_sata */ { .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED | + .host_flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR | PIIX_FLAG_IGNORE_PCS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, - .private_data = &ich5_map_db, }, /* ich6_sata */ { .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 | + .host_flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, - .private_data = &ich6_map_db, }, /* ich6_sata_ahci */ { .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 | + .host_flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR | PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, - .private_data = &ich6_map_db, }, /* ich6m_sata_ahci */ { .sht = &piix_sht, - .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 | + .host_flags = ATA_FLAG_SATA | + PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR | + PIIX_FLAG_AHCI, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, + + /* ich7m_sata_ahci */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | + PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR | + PIIX_FLAG_AHCI, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x7f, /* udma0-6 */ + .port_ops = &piix_sata_ops, + }, + + /* ich8_sata_ahci */ + { + .sht = &piix_sht, + .host_flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR | PIIX_FLAG_AHCI, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &piix_sata_ops, - .private_data = &ich6m_map_db, }, }; @@ -427,6 +500,11 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, piix_pci_tbl); MODULE_VERSION(DRV_VERSION); +static int force_pcs = 0; +module_param(force_pcs, int, 0444); +MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around " + "device mis-detection (0=default, 1=ignore PCS, 2=honor PCS)"); + /** * piix_pata_cbl_detect - Probe host controller cable detect info * @ap: Port for which cable detect info is desired @@ -491,74 +569,83 @@ static void piix_pata_error_handler(struct ata_port *ap) } /** - * piix_sata_prereset - prereset for SATA host controller + * piix_sata_present_mask - determine present mask for SATA host controller * @ap: Target port * - * Reads and configures SATA PCI device's PCI config register - * Port Configuration and Status (PCS) to determine port and - * device availability. Return -ENODEV to skip reset if no - * device is present. + * Reads SATA PCI device's PCI config register Port Configuration + * and Status (PCS) to determine port and device availability. * * LOCKING: * None (inherited from caller). * * RETURNS: - * 0 if device is present, -ENODEV otherwise. + * determined present_mask */ -static int piix_sata_prereset(struct ata_port *ap) +static unsigned int piix_sata_present_mask(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); - const unsigned int *map = ap->host_set->private_data; + struct piix_host_priv *hpriv = ap->host_set->private_data; + const unsigned int *map = hpriv->map; int base = 2 * ap->hard_port_no; unsigned int present_mask = 0; int port, i; - u8 pcs; + u16 pcs; - pci_read_config_byte(pdev, ICH5_PCS, &pcs); + pci_read_config_word(pdev, ICH5_PCS, &pcs); DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base); - /* enable all ports on this ap and wait for them to settle */ - for (i = 0; i < 2; i++) { - port = map[base + i]; - if (port >= 0) - pcs |= 1 << port; - } - - pci_write_config_byte(pdev, ICH5_PCS, pcs); - msleep(100); - - /* let's see which devices are present */ - pci_read_config_byte(pdev, ICH5_PCS, &pcs); - for (i = 0; i < 2; i++) { port = map[base + i]; if (port < 0) continue; - if (ap->flags & PIIX_FLAG_IGNORE_PCS || pcs & 1 << (4 + port)) + if ((ap->flags & PIIX_FLAG_IGNORE_PCS) || + (pcs & 1 << (hpriv->map_db->present_shift + port))) present_mask |= 1 << i; - else - pcs &= ~(1 << port); } - /* disable offline ports on non-AHCI controllers */ - if (!(ap->flags & PIIX_FLAG_AHCI)) - pci_write_config_byte(pdev, ICH5_PCS, pcs); - DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n", ap->id, pcs, present_mask); - if (!present_mask) { - ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n"); - ap->eh_context.i.action &= ~ATA_EH_RESET_MASK; - return 0; + return present_mask; +} + +/** + * piix_sata_softreset - reset SATA host port via ATA SRST + * @ap: port to reset + * @classes: resulting classes of attached devices + * + * Reset SATA host port via ATA SRST. On controllers with + * reliable PCS present bits, the bits are used to determine + * device presence. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +static int piix_sata_softreset(struct ata_port *ap, unsigned int *classes) +{ + unsigned int present_mask; + int i, rc; + + present_mask = piix_sata_present_mask(ap); + + rc = ata_std_softreset(ap, classes); + if (rc) + return rc; + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + if (!(present_mask & (1 << i))) + classes[i] = ATA_DEV_NONE; } - return ata_std_prereset(ap); + return 0; } static void piix_sata_error_handler(struct ata_port *ap) { - ata_bmdma_drive_eh(ap, piix_sata_prereset, ata_std_softreset, NULL, + ata_bmdma_drive_eh(ap, ata_std_prereset, piix_sata_softreset, NULL, ata_std_postreset); } @@ -761,10 +848,40 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev) return no_piix_dma; } +static void __devinit piix_init_pcs(struct pci_dev *pdev, + struct ata_port_info *pinfo, + const struct piix_map_db *map_db) +{ + u16 pcs, new_pcs; + + pci_read_config_word(pdev, ICH5_PCS, &pcs); + + new_pcs = pcs | map_db->port_enable; + + if (new_pcs != pcs) { + DPRINTK("updating PCS from 0x%x to 0x%x\n", pcs, new_pcs); + pci_write_config_word(pdev, ICH5_PCS, new_pcs); + msleep(150); + } + + if (force_pcs == 1) { + dev_printk(KERN_INFO, &pdev->dev, + "force ignoring PCS (0x%x)\n", new_pcs); + pinfo[0].host_flags |= PIIX_FLAG_IGNORE_PCS; + pinfo[1].host_flags |= PIIX_FLAG_IGNORE_PCS; + } else if (force_pcs == 2) { + dev_printk(KERN_INFO, &pdev->dev, + "force honoring PCS (0x%x)\n", new_pcs); + pinfo[0].host_flags &= ~PIIX_FLAG_IGNORE_PCS; + pinfo[1].host_flags &= ~PIIX_FLAG_IGNORE_PCS; + } +} + static void __devinit piix_init_sata_map(struct pci_dev *pdev, - struct ata_port_info *pinfo) + struct ata_port_info *pinfo, + const struct piix_map_db *map_db) { - struct piix_map_db *map_db = pinfo[0].private_data; + struct piix_host_priv *hpriv = pinfo[0].private_data; const unsigned int *map; int i, invalid_map = 0; u8 map_value; @@ -788,6 +905,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, case IDE: WARN_ON((i & 1) || map[i + 1] != IDE); pinfo[i / 2] = piix_port_info[ich5_pata]; + pinfo[i / 2].private_data = hpriv; i++; printk(" IDE IDE"); break; @@ -805,8 +923,8 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, dev_printk(KERN_ERR, &pdev->dev, "invalid MAP value %u\n", map_value); - pinfo[0].private_data = (void *)map; - pinfo[1].private_data = (void *)map; + hpriv->map = map; + hpriv->map_db = map_db; } /** @@ -829,6 +947,7 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) static int printed_version; struct ata_port_info port_info[2]; struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] }; + struct piix_host_priv *hpriv; unsigned long host_flags; if (!printed_version++) @@ -839,8 +958,14 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (!in_module_init) return -ENODEV; + hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; + port_info[0] = piix_port_info[ent->driver_data]; port_info[1] = piix_port_info[ent->driver_data]; + port_info[0].private_data = hpriv; + port_info[1].private_data = hpriv; host_flags = port_info[0].host_flags; @@ -855,8 +980,12 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) } /* Initialize SATA map */ - if (host_flags & ATA_FLAG_SATA) - piix_init_sata_map(pdev, port_info); + if (host_flags & ATA_FLAG_SATA) { + piix_init_sata_map(pdev, port_info, + piix_map_db_table[ent->driver_data]); + piix_init_pcs(pdev, port_info, + piix_map_db_table[ent->driver_data]); + } /* On ICH5, some BIOSen disable the interrupt using the * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3. @@ -879,6 +1008,13 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) return ata_pci_init_one(pdev, ppinfo, 2); } +static void piix_host_stop(struct ata_host_set *host_set) +{ + if (host_set->next == NULL) + kfree(host_set->private_data); + ata_host_stop(host_set); +} + static int __init piix_init(void) { int rc; diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index 007a14e5c3f..e397129c90d 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -507,7 +507,7 @@ static __inline__ void initialize_SCp(Scsi_Cmnd *cmd) */ if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; + cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; cmd->SCp.buffers_residual = cmd->use_sg - 1; cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+ cmd->SCp.buffer->offset; diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 412f8301b75..0ec41f34f46 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -2625,29 +2625,32 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent) unsigned int base_io, tmport, error,n; unsigned char host_id; struct Scsi_Host *shpnt = NULL; - struct atp_unit atp_dev, *p; + struct atp_unit *atpdev, *p; unsigned char setupdata[2][16]; int count = 0; - + + atpdev = kzalloc(sizeof(*atpdev), GFP_KERNEL); + if (!atpdev) + return -ENOMEM; + if (pci_enable_device(pdev)) - return -EIO; + goto err_eio; if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { printk(KERN_INFO "atp870u: use 32bit DMA mask.\n"); } else { printk(KERN_ERR "atp870u: DMA mask required but not available.\n"); - return -EIO; + goto err_eio; } - memset(&atp_dev, 0, sizeof atp_dev); /* * It's probably easier to weed out some revisions like * this than via the PCI device table */ if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) { - error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver); - if (atp_dev.chip_ver < 2) - return -EIO; + error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atpdev->chip_ver); + if (atpdev->chip_ver < 2) + goto err_eio; } switch (ent->device) { @@ -2656,15 +2659,15 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent) case ATP880_DEVID1: case ATP880_DEVID2: case ATP885_DEVID: - atp_dev.chip_ver = 0x04; + atpdev->chip_ver = 0x04; default: break; } base_io = pci_resource_start(pdev, 0); base_io &= 0xfffffff8; - + if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) { - error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver); + error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atpdev->chip_ver); pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803 host_id = inb(base_io + 0x39); @@ -2672,17 +2675,17 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d" " IO:%x, IRQ:%d.\n", count, base_io, pdev->irq); - atp_dev.ioport[0] = base_io + 0x40; - atp_dev.pciport[0] = base_io + 0x28; - atp_dev.dev_id = ent->device; - atp_dev.host_id[0] = host_id; + atpdev->ioport[0] = base_io + 0x40; + atpdev->pciport[0] = base_io + 0x28; + atpdev->dev_id = ent->device; + atpdev->host_id[0] = host_id; tmport = base_io + 0x22; - atp_dev.scam_on = inb(tmport); + atpdev->scam_on = inb(tmport); tmport += 0x13; - atp_dev.global_map[0] = inb(tmport); + atpdev->global_map[0] = inb(tmport); tmport += 0x07; - atp_dev.ultra_map[0] = inw(tmport); + atpdev->ultra_map[0] = inw(tmport); n = 0x3f09; next_fblk_880: @@ -2695,57 +2698,57 @@ next_fblk_880: if (inb(base_io + 0x30) == 0xff) goto flash_ok_880; - atp_dev.sp[0][m++] = inb(base_io + 0x30); - atp_dev.sp[0][m++] = inb(base_io + 0x31); - atp_dev.sp[0][m++] = inb(base_io + 0x32); - atp_dev.sp[0][m++] = inb(base_io + 0x33); + atpdev->sp[0][m++] = inb(base_io + 0x30); + atpdev->sp[0][m++] = inb(base_io + 0x31); + atpdev->sp[0][m++] = inb(base_io + 0x32); + atpdev->sp[0][m++] = inb(base_io + 0x33); outw(n, base_io + 0x34); n += 0x0002; - atp_dev.sp[0][m++] = inb(base_io + 0x30); - atp_dev.sp[0][m++] = inb(base_io + 0x31); - atp_dev.sp[0][m++] = inb(base_io + 0x32); - atp_dev.sp[0][m++] = inb(base_io + 0x33); + atpdev->sp[0][m++] = inb(base_io + 0x30); + atpdev->sp[0][m++] = inb(base_io + 0x31); + atpdev->sp[0][m++] = inb(base_io + 0x32); + atpdev->sp[0][m++] = inb(base_io + 0x33); outw(n, base_io + 0x34); n += 0x0002; - atp_dev.sp[0][m++] = inb(base_io + 0x30); - atp_dev.sp[0][m++] = inb(base_io + 0x31); - atp_dev.sp[0][m++] = inb(base_io + 0x32); - atp_dev.sp[0][m++] = inb(base_io + 0x33); + atpdev->sp[0][m++] = inb(base_io + 0x30); + atpdev->sp[0][m++] = inb(base_io + 0x31); + atpdev->sp[0][m++] = inb(base_io + 0x32); + atpdev->sp[0][m++] = inb(base_io + 0x33); outw(n, base_io + 0x34); n += 0x0002; - atp_dev.sp[0][m++] = inb(base_io + 0x30); - atp_dev.sp[0][m++] = inb(base_io + 0x31); - atp_dev.sp[0][m++] = inb(base_io + 0x32); - atp_dev.sp[0][m++] = inb(base_io + 0x33); + atpdev->sp[0][m++] = inb(base_io + 0x30); + atpdev->sp[0][m++] = inb(base_io + 0x31); + atpdev->sp[0][m++] = inb(base_io + 0x32); + atpdev->sp[0][m++] = inb(base_io + 0x33); n += 0x0018; goto next_fblk_880; flash_ok_880: outw(0, base_io + 0x34); - atp_dev.ultra_map[0] = 0; - atp_dev.async[0] = 0; + atpdev->ultra_map[0] = 0; + atpdev->async[0] = 0; for (k = 0; k < 16; k++) { n = 1; n = n << k; - if (atp_dev.sp[0][k] > 1) { - atp_dev.ultra_map[0] |= n; + if (atpdev->sp[0][k] > 1) { + atpdev->ultra_map[0] |= n; } else { - if (atp_dev.sp[0][k] == 0) - atp_dev.async[0] |= n; + if (atpdev->sp[0][k] == 0) + atpdev->async[0] |= n; } } - atp_dev.async[0] = ~(atp_dev.async[0]); - outb(atp_dev.global_map[0], base_io + 0x35); + atpdev->async[0] = ~(atpdev->async[0]); + outb(atpdev->global_map[0], base_io + 0x35); shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); if (!shpnt) - return -ENOMEM; + goto err_nomem; p = (struct atp_unit *)&shpnt->hostdata; - atp_dev.host = shpnt; - atp_dev.pdev = pdev; + atpdev->host = shpnt; + atpdev->pdev = pdev; pci_set_drvdata(pdev, p); - memcpy(p, &atp_dev, sizeof atp_dev); + memcpy(p, atpdev, sizeof(*atpdev)); if (atp870u_init_tables(shpnt) < 0) { printk(KERN_ERR "Unable to allocate tables for Acard controller\n"); goto unregister; @@ -2798,24 +2801,24 @@ flash_ok_880: printk(KERN_INFO " ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%x, IRQ:%d.\n" , base_io, pdev->irq); - atp_dev.pdev = pdev; - atp_dev.dev_id = ent->device; - atp_dev.baseport = base_io; - atp_dev.ioport[0] = base_io + 0x80; - atp_dev.ioport[1] = base_io + 0xc0; - atp_dev.pciport[0] = base_io + 0x40; - atp_dev.pciport[1] = base_io + 0x50; + atpdev->pdev = pdev; + atpdev->dev_id = ent->device; + atpdev->baseport = base_io; + atpdev->ioport[0] = base_io + 0x80; + atpdev->ioport[1] = base_io + 0xc0; + atpdev->pciport[0] = base_io + 0x40; + atpdev->pciport[1] = base_io + 0x50; shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); if (!shpnt) - return -ENOMEM; + goto err_nomem; p = (struct atp_unit *)&shpnt->hostdata; - atp_dev.host = shpnt; - atp_dev.pdev = pdev; + atpdev->host = shpnt; + atpdev->pdev = pdev; pci_set_drvdata(pdev, p); - memcpy(p, &atp_dev, sizeof(struct atp_unit)); + memcpy(p, atpdev, sizeof(struct atp_unit)); if (atp870u_init_tables(shpnt) < 0) goto unregister; @@ -2974,33 +2977,33 @@ flash_ok_885: printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d " "IO:%x, IRQ:%d.\n", count, base_io, pdev->irq); - atp_dev.ioport[0] = base_io; - atp_dev.pciport[0] = base_io + 0x20; - atp_dev.dev_id = ent->device; + atpdev->ioport[0] = base_io; + atpdev->pciport[0] = base_io + 0x20; + atpdev->dev_id = ent->device; host_id &= 0x07; - atp_dev.host_id[0] = host_id; + atpdev->host_id[0] = host_id; tmport = base_io + 0x22; - atp_dev.scam_on = inb(tmport); + atpdev->scam_on = inb(tmport); tmport += 0x0b; - atp_dev.global_map[0] = inb(tmport++); - atp_dev.ultra_map[0] = inw(tmport); + atpdev->global_map[0] = inb(tmport++); + atpdev->ultra_map[0] = inw(tmport); - if (atp_dev.ultra_map[0] == 0) { - atp_dev.scam_on = 0x00; - atp_dev.global_map[0] = 0x20; - atp_dev.ultra_map[0] = 0xffff; + if (atpdev->ultra_map[0] == 0) { + atpdev->scam_on = 0x00; + atpdev->global_map[0] = 0x20; + atpdev->ultra_map[0] = 0xffff; } shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); if (!shpnt) - return -ENOMEM; + goto err_nomem; p = (struct atp_unit *)&shpnt->hostdata; - atp_dev.host = shpnt; - atp_dev.pdev = pdev; + atpdev->host = shpnt; + atpdev->pdev = pdev; pci_set_drvdata(pdev, p); - memcpy(p, &atp_dev, sizeof atp_dev); + memcpy(p, atpdev, sizeof(*atpdev)); if (atp870u_init_tables(shpnt) < 0) goto unregister; @@ -3010,7 +3013,7 @@ flash_ok_885: } spin_lock_irqsave(shpnt->host_lock, flags); - if (atp_dev.chip_ver > 0x07) { /* check if atp876 chip then enable terminator */ + if (atpdev->chip_ver > 0x07) { /* check if atp876 chip then enable terminator */ tmport = base_io + 0x3e; outb(0x00, tmport); } @@ -3044,7 +3047,7 @@ flash_ok_885: outb((inb(tmport) & 0xef), tmport); tmport++; outb((inb(tmport) | 0x20), tmport); - if (atp_dev.chip_ver == 4) + if (atpdev->chip_ver == 4) shpnt->max_id = 16; else shpnt->max_id = 8; @@ -3093,6 +3096,12 @@ unregister: printk("atp870u_prob:unregister\n"); scsi_host_put(shpnt); return -1; +err_eio: + kfree(atpdev); + return -EIO; +err_nomem: + kfree(atpdev); + return -ENOMEM; } /* The abort command does not leave the device in a clean state where diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index dddd2acce76..61f6024b61b 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -5,6 +5,7 @@ * Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002) * by D. Gilbert and aeb (20020609) * Additions for SPC-3 T10/1416-D Rev 21 22 Sept 2004, D. Gilbert 20041025 + * Update to SPC-4 T10/1713-D Rev 5a, 14 June 2006, D. Gilbert 20060702 */ #include <linux/blkdev.h> @@ -36,55 +37,56 @@ static const char * cdb_byte0_names[] = { /* 00-03 */ "Test Unit Ready", "Rezero Unit/Rewind", NULL, "Request Sense", /* 04-07 */ "Format Unit/Medium", "Read Block Limits", NULL, "Reasssign Blocks", -/* 08-0d */ "Read (6)", NULL, "Write (6)", "Seek (6)", NULL, NULL, +/* 08-0d */ "Read(6)", NULL, "Write(6)", "Seek(6)", NULL, NULL, /* 0e-12 */ NULL, "Read Reverse", "Write Filemarks", "Space", "Inquiry", -/* 13-16 */ "Verify (6)", "Recover Buffered Data", "Mode Select (6)", - "Reserve (6)", -/* 17-1a */ "Release (6)", "Copy", "Erase", "Mode Sense (6)", +/* 13-16 */ "Verify(6)", "Recover Buffered Data", "Mode Select(6)", + "Reserve(6)", +/* 17-1a */ "Release(6)", "Copy", "Erase", "Mode Sense(6)", /* 1b-1d */ "Start/Stop Unit", "Receive Diagnostic", "Send Diagnostic", /* 1e-1f */ "Prevent/Allow Medium Removal", NULL, /* 20-22 */ NULL, NULL, NULL, /* 23-28 */ "Read Format Capacities", "Set Window", - "Read Capacity (10)", NULL, NULL, "Read (10)", -/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase (10)", - "Read updated block", -/* 2e-31 */ "Write Verify (10)", "Verify (10)", "Search High", "Search Equal", + "Read Capacity(10)", NULL, NULL, "Read(10)", +/* 29-2d */ "Read Generation", "Write(10)", "Seek(10)", "Erase(10)", + "Read updated block", +/* 2e-31 */ "Write Verify(10)", "Verify(10)", "Search High", "Search Equal", /* 32-34 */ "Search Low", "Set Limits", "Prefetch/Read Position", -/* 35-37 */ "Synchronize Cache (10)", "Lock/Unlock Cache (10)", +/* 35-37 */ "Synchronize Cache(10)", "Lock/Unlock Cache(10)", "Read Defect Data(10)", /* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", "Read Buffer", -/* 3d-3f */ "Update Block", "Read Long (10)", "Write Long (10)", -/* 40-41 */ "Change Definition", "Write Same (10)", +/* 3d-3f */ "Update Block", "Read Long(10)", "Write Long(10)", +/* 40-41 */ "Change Definition", "Write Same(10)", /* 42-48 */ "Read sub-channel", "Read TOC/PMA/ATIP", "Read density support", - "Play audio (10)", "Get configuration", "Play audio msf", + "Play audio(10)", "Get configuration", "Play audio msf", "Play audio track/index", -/* 49-4f */ "Play track relative (10)", "Get event status notification", +/* 49-4f */ "Play track relative(10)", "Get event status notification", "Pause/resume", "Log Select", "Log Sense", "Stop play/scan", NULL, /* 50-55 */ "Xdwrite", "Xpwrite, Read disk info", "Xdread, Read track info", - "Reserve track", "Send OPC info", "Mode Select (10)", -/* 56-5b */ "Reserve (10)", "Release (10)", "Repair track", "Read master cue", - "Mode Sense (10)", "Close track/session", + "Reserve track", "Send OPC info", "Mode Select(10)", +/* 56-5b */ "Reserve(10)", "Release(10)", "Repair track", "Read master cue", + "Mode Sense(10)", "Close track/session", /* 5c-5f */ "Read buffer capacity", "Send cue sheet", "Persistent reserve in", "Persistent reserve out", /* 60-67 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 68-6f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 70-77 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Variable length", -/* 80-84 */ "Xdwrite (16)", "Rebuild (16)", "Regenerate (16)", "Extended copy", +/* 80-84 */ "Xdwrite(16)", "Rebuild(16)", "Regenerate(16)", "Extended copy", "Receive copy results", -/* 85-89 */ "Memory Export In (16)", "Access control in", "Access control out", - "Read (16)", "Memory Export Out (16)", -/* 8a-8f */ "Write (16)", NULL, "Read attributes", "Write attributes", - "Write and verify (16)", "Verify (16)", -/* 90-94 */ "Pre-fetch (16)", "Synchronize cache (16)", - "Lock/unlock cache (16)", "Write same (16)", NULL, +/* 85-89 */ "ATA command pass through(16)", "Access control in", + "Access control out", "Read(16)", "Memory Export Out(16)", +/* 8a-8f */ "Write(16)", NULL, "Read attributes", "Write attributes", + "Write and verify(16)", "Verify(16)", +/* 90-94 */ "Pre-fetch(16)", "Synchronize cache(16)", + "Lock/unlock cache(16)", "Write same(16)", NULL, /* 95-99 */ NULL, NULL, NULL, NULL, NULL, -/* 9a-9f */ NULL, NULL, NULL, NULL, "Service action in (16)", - "Service action out (16)", -/* a0-a5 */ "Report luns", "Blank", "Send event", "Maintenance in", - "Maintenance out", "Move medium/play audio(12)", +/* 9a-9f */ NULL, NULL, NULL, NULL, "Service action in(16)", + "Service action out(16)", +/* a0-a5 */ "Report luns", "ATA command pass through(12)/Blank", + "Security protocol in", "Maintenance in", "Maintenance out", + "Move medium/play audio(12)", /* a6-a9 */ "Exchange medium", "Move medium attached", "Read(12)", "Play track relative(12)", /* aa-ae */ "Write(12)", NULL, "Erase(12), Get Performance", @@ -92,12 +94,12 @@ static const char * cdb_byte0_names[] = { /* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)", /* b2-b4 */ "Search data low(12)", "Set limits(12)", "Read element status attached", -/* b5-b6 */ "Request volume element address", "Send volume tag, set streaming", +/* b5-b6 */ "Security protocol out", "Send volume tag, set streaming", /* b7-b9 */ "Read defect data(12)", "Read element status", "Read CD msf", /* ba-bc */ "Redundancy group (in), Scan", - "Redundancy group (out), Set cd-rom speed", "Spare in, Play cd", -/* bd-bf */ "Spare out, Mechanism status", "Volume set in, Read cd", - "Volume set out, Send DVD structure", + "Redundancy group (out), Set cd-rom speed", "Spare (in), Play cd", +/* bd-bf */ "Spare (out), Mechanism status", "Volume set (in), Read cd", + "Volume set (out), Send DVD structure", }; struct value_name_pair { @@ -112,6 +114,7 @@ static const struct value_name_pair maint_in_arr[] = { {0xc, "Report supported operation codes"}, {0xd, "Report supported task management functions"}, {0xe, "Report priority"}, + {0xf, "Report timestamp"}, }; #define MAINT_IN_SZ ARRAY_SIZE(maint_in_arr) @@ -120,6 +123,7 @@ static const struct value_name_pair maint_out_arr[] = { {0xa, "Set target port groups"}, {0xb, "Change aliases"}, {0xe, "Set priority"}, + {0xe, "Set timestamp"}, }; #define MAINT_OUT_SZ ARRAY_SIZE(maint_out_arr) @@ -427,6 +431,7 @@ static struct error_info additional[] = {0x001A, "Rewind operation in progress"}, {0x001B, "Set capacity operation in progress"}, {0x001C, "Verify operation in progress"}, + {0x001D, "ATA pass through information available"}, {0x0100, "No index/sector signal"}, @@ -438,7 +443,7 @@ static struct error_info additional[] = {0x0400, "Logical unit not ready, cause not reportable"}, {0x0401, "Logical unit is in process of becoming ready"}, - {0x0402, "Logical unit not ready, initializing cmd. required"}, + {0x0402, "Logical unit not ready, initializing command required"}, {0x0403, "Logical unit not ready, manual intervention required"}, {0x0404, "Logical unit not ready, format in progress"}, {0x0405, "Logical unit not ready, rebuild in progress"}, @@ -478,6 +483,9 @@ static struct error_info additional[] = {0x0B00, "Warning"}, {0x0B01, "Warning - specified temperature exceeded"}, {0x0B02, "Warning - enclosure degraded"}, + {0x0B03, "Warning - background self-test failed"}, + {0x0B04, "Warning - background pre-scan detected medium error"}, + {0x0B05, "Warning - background medium scan detected medium error"}, {0x0C00, "Write error"}, {0x0C01, "Write error - recovered with auto reallocation"}, @@ -493,6 +501,7 @@ static struct error_info additional[] = {0x0C0B, "Auxiliary memory write error"}, {0x0C0C, "Write error - unexpected unsolicited data"}, {0x0C0D, "Write error - not enough unsolicited data"}, + {0x0C0F, "Defects in error window"}, {0x0D00, "Error detected by third party temporary initiator"}, {0x0D01, "Third party device failure"}, @@ -504,11 +513,12 @@ static struct error_info additional[] = {0x0E00, "Invalid information unit"}, {0x0E01, "Information unit too short"}, {0x0E02, "Information unit too long"}, + {0x0E03, "Invalid field in command information unit"}, {0x1000, "Id CRC or ECC error"}, - {0x1001, "Data block guard check failed"}, - {0x1002, "Data block application tag check failed"}, - {0x1003, "Data block reference tag check failed"}, + {0x1001, "Logical block guard check failed"}, + {0x1002, "Logical block application tag check failed"}, + {0x1003, "Logical block reference tag check failed"}, {0x1100, "Unrecovered read error"}, {0x1101, "Read retries exhausted"}, @@ -530,6 +540,7 @@ static struct error_info additional[] = {0x1111, "Read error - loss of streaming"}, {0x1112, "Auxiliary memory read error"}, {0x1113, "Read error - failed retransmission request"}, + {0x1114, "Read error - lba marked bad by application client"}, {0x1200, "Address mark not found for id field"}, @@ -610,11 +621,14 @@ static struct error_info additional[] = {0x2100, "Logical block address out of range"}, {0x2101, "Invalid element address"}, {0x2102, "Invalid address for write"}, + {0x2103, "Invalid write crossing layer jump"}, {0x2200, "Illegal function (use 20 00, 24 00, or 26 00)"}, {0x2400, "Invalid field in cdb"}, {0x2401, "CDB decryption error"}, + {0x2402, "Obsolete"}, + {0x2403, "Obsolete"}, {0x2404, "Security audit value frozen"}, {0x2405, "Security working key frozen"}, {0x2406, "Nonce not unique"}, @@ -637,7 +651,10 @@ static struct error_info additional[] = {0x260C, "Invalid operation for copy source or destination"}, {0x260D, "Copy segment granularity violation"}, {0x260E, "Invalid parameter while port is enabled"}, - {0x260F, "Invalid data-out buffer integrity"}, + {0x260F, "Invalid data-out buffer integrity check value"}, + {0x2610, "Data decryption key fail limit reached"}, + {0x2611, "Incomplete key-associated data set"}, + {0x2612, "Vendor specific key reference not found"}, {0x2700, "Write protected"}, {0x2701, "Hardware write protected"}, @@ -649,6 +666,7 @@ static struct error_info additional[] = {0x2800, "Not ready to ready change, medium may have changed"}, {0x2801, "Import or export element accessed"}, + {0x2802, "Format-layer may have changed"}, {0x2900, "Power on, reset, or bus device reset occurred"}, {0x2901, "Power on occurred"}, @@ -669,6 +687,11 @@ static struct error_info additional[] = {0x2A07, "Implicit asymmetric access state transition failed"}, {0x2A08, "Priority changed"}, {0x2A09, "Capacity data has changed"}, + {0x2A10, "Timestamp changed"}, + {0x2A11, "Data encryption parameters changed by another i_t nexus"}, + {0x2A12, "Data encryption parameters changed by vendor specific " + "event"}, + {0x2A13, "Data encryption key instance counter has changed"}, {0x2B00, "Copy cannot execute since host cannot disconnect"}, @@ -690,6 +713,7 @@ static struct error_info additional[] = {0x2E00, "Insufficient time for operation"}, {0x2F00, "Commands cleared by another initiator"}, + {0x2F01, "Commands cleared by power loss notification"}, {0x3000, "Incompatible medium installed"}, {0x3001, "Cannot read medium - unknown format"}, @@ -702,7 +726,8 @@ static struct error_info additional[] = {0x3008, "Cannot write - application code mismatch"}, {0x3009, "Current session not fixated for append"}, {0x300A, "Cleaning request rejected"}, - {0x300C, "WORM medium, overwrite attempted"}, + {0x300C, "WORM medium - overwrite attempted"}, + {0x300D, "WORM medium - integrity check"}, {0x3010, "Medium not formatted"}, {0x3100, "Medium format corrupted"}, @@ -790,6 +815,9 @@ static struct error_info additional[] = {0x3F0F, "Echo buffer overwritten"}, {0x3F10, "Medium loadable"}, {0x3F11, "Medium auxiliary memory accessible"}, + {0x3F12, "iSCSI IP address added"}, + {0x3F13, "iSCSI IP address removed"}, + {0x3F14, "iSCSI IP address changed"}, /* * {0x40NN, "Ram failure"}, * {0x40NN, "Diagnostic failure on component nn"}, @@ -799,6 +827,7 @@ static struct error_info additional[] = {0x4300, "Message error"}, {0x4400, "Internal target failure"}, + {0x4471, "ATA device failed set features"}, {0x4500, "Select or reselect failure"}, @@ -807,9 +836,10 @@ static struct error_info additional[] = {0x4700, "Scsi parity error"}, {0x4701, "Data phase CRC error detected"}, {0x4702, "Scsi parity error detected during st data phase"}, - {0x4703, "Information unit CRC error detected"}, + {0x4703, "Information unit iuCRC error detected"}, {0x4704, "Asynchronous information protection error detected"}, {0x4705, "Protocol service CRC error"}, + {0x4706, "Phy test function in progress"}, {0x477f, "Some commands cleared by iSCSI Protocol event"}, {0x4800, "Initiator detected error message received"}, @@ -844,6 +874,8 @@ static struct error_info additional[] = {0x5300, "Media load or eject failed"}, {0x5301, "Unload tape failure"}, {0x5302, "Medium removal prevented"}, + {0x5303, "Medium removal prevented by data transfer element"}, + {0x5304, "Medium thread or unthread failure"}, {0x5400, "Scsi to host system interface failure"}, @@ -855,6 +887,7 @@ static struct error_info additional[] = {0x5505, "Insufficient access control resources"}, {0x5506, "Auxiliary memory out of space"}, {0x5507, "Quota error"}, + {0x5508, "Maximum number of supplemental decryption keys exceeded"}, {0x5700, "Unable to recover table-of-contents"}, @@ -1004,6 +1037,7 @@ static struct error_info additional[] = {0x6708, "Assign failure occurred"}, {0x6709, "Multiply assigned logical unit"}, {0x670A, "Set target port groups command failed"}, + {0x670B, "ATA device feature not enabled"}, {0x6800, "Logical unit not configured"}, @@ -1030,6 +1064,8 @@ static struct error_info additional[] = {0x6F03, "Read of scrambled sector without authentication"}, {0x6F04, "Media region code is mismatched to logical unit region"}, {0x6F05, "Drive region must be permanent/region reset count error"}, + {0x6F06, "Insufficient block count for binding nonce recording"}, + {0x6F07, "Conflict in binding nonce recording"}, /* * {0x70NN, "Decompression exception short algorithm id of nn"}, */ @@ -1041,6 +1077,8 @@ static struct error_info additional[] = {0x7203, "Session fixation error - incomplete track in session"}, {0x7204, "Empty or partially written reserved track"}, {0x7205, "No more track reservations allowed"}, + {0x7206, "RMZ extension is not allowed"}, + {0x7207, "No more test zone extensions are allowed"}, {0x7300, "Cd control error"}, {0x7301, "Power calibration area almost full"}, @@ -1049,6 +1087,18 @@ static struct error_info additional[] = {0x7304, "Program memory area update failure"}, {0x7305, "Program memory area is full"}, {0x7306, "RMA/PMA is almost full"}, + {0x7310, "Current power calibration area almost full"}, + {0x7311, "Current power calibration area is full"}, + {0x7317, "RDZ is full"}, + + {0x7400, "Security error"}, + {0x7401, "Unable to decrypt data"}, + {0x7402, "Unencrypted data encountered while decrypting"}, + {0x7403, "Incorrect data encryption key"}, + {0x7404, "Cryptographic integrity validation failed"}, + {0x7405, "Error decrypting data"}, + {0x7471, "Logical unit access not authorized"}, + {0, NULL} }; diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c index 10573c24a50..5630868c1b2 100644 --- a/drivers/scsi/esp.c +++ b/drivers/scsi/esp.c @@ -1146,7 +1146,7 @@ static struct sbus_dev sun4_esp_dev; static int __init esp_sun4_probe(struct scsi_host_template *tpnt) { if (sun4_esp_physaddr) { - memset(&sun4_esp_dev, 0, sizeof(esp_dev)); + memset(&sun4_esp_dev, 0, sizeof(sun4_esp_dev)); sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr; sun4_esp_dev.irqs[0] = 4; sun4_esp_dev.resource[0].start = sun4_esp_physaddr; @@ -1162,6 +1162,7 @@ static int __init esp_sun4_probe(struct scsi_host_template *tpnt) static int __devexit esp_sun4_remove(void) { + struct of_device *dev = &sun4_esp_dev.ofdev; struct esp *esp = dev_get_drvdata(&dev->dev); return esp_remove_common(esp); @@ -1397,7 +1398,7 @@ static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp) sp->SCp.ptr = NULL; } } else { - sp->SCp.buffer = (struct scatterlist *) sp->buffer; + sp->SCp.buffer = (struct scatterlist *) sp->request_buffer; sp->SCp.buffers_residual = sbus_map_sg(esp->sdev, sp->SCp.buffer, sp->use_sg, @@ -1410,7 +1411,7 @@ static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp) static void esp_release_dmabufs(struct esp *esp, struct scsi_cmnd *sp) { if (sp->use_sg) { - sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg, + sbus_unmap_sg(esp->sdev, sp->request_buffer, sp->use_sg, sp->sc_data_direction); } else if (sp->request_bufflen) { sbus_unmap_single(esp->sdev, @@ -2754,18 +2755,15 @@ static int esp_do_data_finale(struct esp *esp) */ static int esp_should_clear_sync(struct scsi_cmnd *sp) { - u8 cmd1 = sp->cmnd[0]; - u8 cmd2 = sp->data_cmnd[0]; + u8 cmd = sp->cmnd[0]; /* These cases are for spinning up a disk and * waiting for that spinup to complete. */ - if (cmd1 == START_STOP || - cmd2 == START_STOP) + if (cmd == START_STOP) return 0; - if (cmd1 == TEST_UNIT_READY || - cmd2 == TEST_UNIT_READY) + if (cmd == TEST_UNIT_READY) return 0; /* One more special case for SCSI tape drives, @@ -2773,8 +2771,7 @@ static int esp_should_clear_sync(struct scsi_cmnd *sp) * completion of a rewind or tape load operation. */ if (sp->device->type == TYPE_TAPE) { - if (cmd1 == MODE_SENSE || - cmd2 == MODE_SENSE) + if (cmd == MODE_SENSE) return 0; } diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index ab2f8b26790..bcb3444f1dc 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -45,10 +45,6 @@ static char driver_name[] = "hptiop"; static const char driver_name_long[] = "RocketRAID 3xxx SATA Controller driver"; static const char driver_ver[] = "v1.0 (060426)"; -static DEFINE_SPINLOCK(hptiop_hba_list_lock); -static LIST_HEAD(hptiop_hba_list); -static int hptiop_cdev_major = -1; - static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag); static void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag); static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg); @@ -577,7 +573,7 @@ static int hptiop_reset_hba(struct hptiop_hba *hba) if (atomic_xchg(&hba->resetting, 1) == 0) { atomic_inc(&hba->reset_count); writel(IOPMU_INBOUND_MSG0_RESET, - &hba->iop->outbound_msgaddr0); + &hba->iop->inbound_msgaddr0); hptiop_pci_posting_flush(hba->iop); } @@ -620,532 +616,11 @@ static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev, return queue_depth; } -struct hptiop_getinfo { - char __user *buffer; - loff_t buflength; - loff_t bufoffset; - loff_t buffillen; - loff_t filpos; -}; - -static void hptiop_copy_mem_info(struct hptiop_getinfo *pinfo, - char *data, int datalen) -{ - if (pinfo->filpos < pinfo->bufoffset) { - if (pinfo->filpos + datalen <= pinfo->bufoffset) { - pinfo->filpos += datalen; - return; - } else { - data += (pinfo->bufoffset - pinfo->filpos); - datalen -= (pinfo->bufoffset - pinfo->filpos); - pinfo->filpos = pinfo->bufoffset; - } - } - - pinfo->filpos += datalen; - if (pinfo->buffillen == pinfo->buflength) - return; - - if (pinfo->buflength - pinfo->buffillen < datalen) - datalen = pinfo->buflength - pinfo->buffillen; - - if (copy_to_user(pinfo->buffer + pinfo->buffillen, data, datalen)) - return; - - pinfo->buffillen += datalen; -} - -static int hptiop_copy_info(struct hptiop_getinfo *pinfo, char *fmt, ...) -{ - va_list args; - char buf[128]; - int len; - - va_start(args, fmt); - len = vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - hptiop_copy_mem_info(pinfo, buf, len); - return len; -} - -static void hptiop_ioctl_done(struct hpt_ioctl_k *arg) -{ - arg->done = NULL; - wake_up(&arg->hba->ioctl_wq); -} - -static void hptiop_do_ioctl(struct hpt_ioctl_k *arg) -{ - struct hptiop_hba *hba = arg->hba; - u32 val; - struct hpt_iop_request_ioctl_command __iomem *req; - int ioctl_retry = 0; - - dprintk("scsi%d: hptiop_do_ioctl\n", hba->host->host_no); - - /* - * check (in + out) buff size from application. - * outbuf must be dword aligned. - */ - if (((arg->inbuf_size + 3) & ~3) + arg->outbuf_size > - hba->max_request_size - - sizeof(struct hpt_iop_request_header) - - 4 * sizeof(u32)) { - dprintk("scsi%d: ioctl buf size (%d/%d) is too large\n", - hba->host->host_no, - arg->inbuf_size, arg->outbuf_size); - arg->result = HPT_IOCTL_RESULT_FAILED; - return; - } - -retry: - spin_lock_irq(hba->host->host_lock); - - val = readl(&hba->iop->inbound_queue); - if (val == IOPMU_QUEUE_EMPTY) { - spin_unlock_irq(hba->host->host_lock); - dprintk("scsi%d: no free req for ioctl\n", hba->host->host_no); - arg->result = -1; - return; - } - - req = (struct hpt_iop_request_ioctl_command __iomem *) - ((unsigned long)hba->iop + val); - - writel(HPT_CTL_CODE_LINUX_TO_IOP(arg->ioctl_code), - &req->ioctl_code); - writel(arg->inbuf_size, &req->inbuf_size); - writel(arg->outbuf_size, &req->outbuf_size); - - /* - * use the buffer on the IOP local memory first, then copy it - * back to host. - * the caller's request buffer shoudl be little-endian. - */ - if (arg->inbuf_size) - memcpy_toio(req->buf, arg->inbuf, arg->inbuf_size); - - /* correct the controller ID for IOP */ - if ((arg->ioctl_code == HPT_IOCTL_GET_CHANNEL_INFO || - arg->ioctl_code == HPT_IOCTL_GET_CONTROLLER_INFO_V2 || - arg->ioctl_code == HPT_IOCTL_GET_CONTROLLER_INFO) - && arg->inbuf_size >= sizeof(u32)) - writel(0, req->buf); - - writel(IOP_REQUEST_TYPE_IOCTL_COMMAND, &req->header.type); - writel(0, &req->header.flags); - writel(offsetof(struct hpt_iop_request_ioctl_command, buf) - + arg->inbuf_size, &req->header.size); - writel((u32)(unsigned long)arg, &req->header.context); - writel(BITS_PER_LONG > 32 ? (u32)((unsigned long)arg>>32) : 0, - &req->header.context_hi32); - writel(IOP_RESULT_PENDING, &req->header.result); - - arg->result = HPT_IOCTL_RESULT_FAILED; - arg->done = hptiop_ioctl_done; - - writel(val, &hba->iop->inbound_queue); - hptiop_pci_posting_flush(hba->iop); - - spin_unlock_irq(hba->host->host_lock); - - wait_event_timeout(hba->ioctl_wq, arg->done == NULL, 60 * HZ); - - if (arg->done != NULL) { - hptiop_reset_hba(hba); - if (ioctl_retry++ < 3) - goto retry; - } - - dprintk("hpt_iop_ioctl %x result %d\n", - arg->ioctl_code, arg->result); -} - -static int __hpt_do_ioctl(struct hptiop_hba *hba, u32 code, void *inbuf, - u32 insize, void *outbuf, u32 outsize) -{ - struct hpt_ioctl_k arg; - arg.hba = hba; - arg.ioctl_code = code; - arg.inbuf = inbuf; - arg.outbuf = outbuf; - arg.inbuf_size = insize; - arg.outbuf_size = outsize; - arg.bytes_returned = NULL; - hptiop_do_ioctl(&arg); - return arg.result; -} - -static inline int hpt_id_valid(__le32 id) -{ - return id != 0 && id != cpu_to_le32(0xffffffff); -} - -static int hptiop_get_controller_info(struct hptiop_hba *hba, - struct hpt_controller_info *pinfo) -{ - int id = 0; - - return __hpt_do_ioctl(hba, HPT_IOCTL_GET_CONTROLLER_INFO, - &id, sizeof(int), pinfo, sizeof(*pinfo)); -} - - -static int hptiop_get_channel_info(struct hptiop_hba *hba, int bus, - struct hpt_channel_info *pinfo) -{ - u32 ids[2]; - - ids[0] = 0; - ids[1] = bus; - return __hpt_do_ioctl(hba, HPT_IOCTL_GET_CHANNEL_INFO, - ids, sizeof(ids), pinfo, sizeof(*pinfo)); - -} - -static int hptiop_get_logical_devices(struct hptiop_hba *hba, - __le32 *pids, int maxcount) -{ - int i; - u32 count = maxcount - 1; - - if (__hpt_do_ioctl(hba, HPT_IOCTL_GET_LOGICAL_DEVICES, - &count, sizeof(u32), - pids, sizeof(u32) * maxcount)) - return -1; - - maxcount = le32_to_cpu(pids[0]); - for (i = 0; i < maxcount; i++) - pids[i] = pids[i+1]; - - return maxcount; -} - -static int hptiop_get_device_info_v3(struct hptiop_hba *hba, __le32 id, - struct hpt_logical_device_info_v3 *pinfo) -{ - return __hpt_do_ioctl(hba, HPT_IOCTL_GET_DEVICE_INFO_V3, - &id, sizeof(u32), - pinfo, sizeof(*pinfo)); -} - -static const char *get_array_status(struct hpt_logical_device_info_v3 *devinfo) -{ - static char s[64]; - u32 flags = le32_to_cpu(devinfo->u.array.flags); - u32 trans_prog = le32_to_cpu(devinfo->u.array.transforming_progress); - u32 reb_prog = le32_to_cpu(devinfo->u.array.rebuilding_progress); - - if (flags & ARRAY_FLAG_DISABLED) - return "Disabled"; - else if (flags & ARRAY_FLAG_TRANSFORMING) - sprintf(s, "Expanding/Migrating %d.%d%%%s%s", - trans_prog / 100, - trans_prog % 100, - (flags & (ARRAY_FLAG_NEEDBUILDING|ARRAY_FLAG_BROKEN))? - ", Critical" : "", - ((flags & ARRAY_FLAG_NEEDINITIALIZING) && - !(flags & ARRAY_FLAG_REBUILDING) && - !(flags & ARRAY_FLAG_INITIALIZING))? - ", Unintialized" : ""); - else if ((flags & ARRAY_FLAG_BROKEN) && - devinfo->u.array.array_type != AT_RAID6) - return "Critical"; - else if (flags & ARRAY_FLAG_REBUILDING) - sprintf(s, - (flags & ARRAY_FLAG_NEEDINITIALIZING)? - "%sBackground initializing %d.%d%%" : - "%sRebuilding %d.%d%%", - (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "", - reb_prog / 100, - reb_prog % 100); - else if (flags & ARRAY_FLAG_VERIFYING) - sprintf(s, "%sVerifying %d.%d%%", - (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "", - reb_prog / 100, - reb_prog % 100); - else if (flags & ARRAY_FLAG_INITIALIZING) - sprintf(s, "%sForground initializing %d.%d%%", - (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "", - reb_prog / 100, - reb_prog % 100); - else if (flags & ARRAY_FLAG_NEEDTRANSFORM) - sprintf(s,"%s%s%s", "Need Expanding/Migrating", - (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "", - ((flags & ARRAY_FLAG_NEEDINITIALIZING) && - !(flags & ARRAY_FLAG_REBUILDING) && - !(flags & ARRAY_FLAG_INITIALIZING))? - ", Unintialized" : ""); - else if (flags & ARRAY_FLAG_NEEDINITIALIZING && - !(flags & ARRAY_FLAG_REBUILDING) && - !(flags & ARRAY_FLAG_INITIALIZING)) - sprintf(s,"%sUninitialized", - (flags & ARRAY_FLAG_BROKEN)? "Critical, " : ""); - else if ((flags & ARRAY_FLAG_NEEDBUILDING) || - (flags & ARRAY_FLAG_BROKEN)) - return "Critical"; - else - return "Normal"; - return s; -} - -static void hptiop_dump_devinfo(struct hptiop_hba *hba, - struct hptiop_getinfo *pinfo, __le32 id, int indent) -{ - struct hpt_logical_device_info_v3 devinfo; - int i; - u64 capacity; - - for (i = 0; i < indent; i++) - hptiop_copy_info(pinfo, "\t"); - - if (hptiop_get_device_info_v3(hba, id, &devinfo)) { - hptiop_copy_info(pinfo, "unknown\n"); - return; - } - - switch (devinfo.type) { - - case LDT_DEVICE: { - struct hd_driveid *driveid; - u32 flags = le32_to_cpu(devinfo.u.device.flags); - - driveid = (struct hd_driveid *)devinfo.u.device.ident; - /* model[] is 40 chars long, but we just want 20 chars here */ - driveid->model[20] = 0; - - if (indent) - if (flags & DEVICE_FLAG_DISABLED) - hptiop_copy_info(pinfo,"Missing\n"); - else - hptiop_copy_info(pinfo, "CH%d %s\n", - devinfo.u.device.path_id + 1, - driveid->model); - else { - capacity = le64_to_cpu(devinfo.capacity) * 512; - do_div(capacity, 1000000); - hptiop_copy_info(pinfo, - "CH%d %s, %lluMB, %s %s%s%s%s\n", - devinfo.u.device.path_id + 1, - driveid->model, - capacity, - (flags & DEVICE_FLAG_DISABLED)? - "Disabled" : "Normal", - devinfo.u.device.read_ahead_enabled? - "[RA]" : "", - devinfo.u.device.write_cache_enabled? - "[WC]" : "", - devinfo.u.device.TCQ_enabled? - "[TCQ]" : "", - devinfo.u.device.NCQ_enabled? - "[NCQ]" : "" - ); - } - break; - } - - case LDT_ARRAY: - if (devinfo.target_id != INVALID_TARGET_ID) - hptiop_copy_info(pinfo, "[DISK %d_%d] ", - devinfo.vbus_id, devinfo.target_id); - - capacity = le64_to_cpu(devinfo.capacity) * 512; - do_div(capacity, 1000000); - hptiop_copy_info(pinfo, "%s (%s), %lluMB, %s\n", - devinfo.u.array.name, - devinfo.u.array.array_type==AT_RAID0? "RAID0" : - devinfo.u.array.array_type==AT_RAID1? "RAID1" : - devinfo.u.array.array_type==AT_RAID5? "RAID5" : - devinfo.u.array.array_type==AT_RAID6? "RAID6" : - devinfo.u.array.array_type==AT_JBOD? "JBOD" : - "unknown", - capacity, - get_array_status(&devinfo)); - for (i = 0; i < devinfo.u.array.ndisk; i++) { - if (hpt_id_valid(devinfo.u.array.members[i])) { - if (cpu_to_le16(1<<i) & - devinfo.u.array.critical_members) - hptiop_copy_info(pinfo, "\t*"); - hptiop_dump_devinfo(hba, pinfo, - devinfo.u.array.members[i], indent+1); - } - else - hptiop_copy_info(pinfo, "\tMissing\n"); - } - if (id == devinfo.u.array.transform_source) { - hptiop_copy_info(pinfo, "\tExpanding/Migrating to:\n"); - hptiop_dump_devinfo(hba, pinfo, - devinfo.u.array.transform_target, indent+1); - } - break; - } -} - static ssize_t hptiop_show_version(struct class_device *class_dev, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", driver_ver); } -static ssize_t hptiop_cdev_read(struct file *filp, char __user *buf, - size_t count, loff_t *ppos) -{ - struct hptiop_hba *hba = filp->private_data; - struct hptiop_getinfo info; - int i, j, ndev; - struct hpt_controller_info con_info; - struct hpt_channel_info chan_info; - __le32 ids[32]; - - info.buffer = buf; - info.buflength = count; - info.bufoffset = ppos ? *ppos : 0; - info.filpos = 0; - info.buffillen = 0; - - if (hptiop_get_controller_info(hba, &con_info)) - return -EIO; - - for (i = 0; i < con_info.num_buses; i++) { - if (hptiop_get_channel_info(hba, i, &chan_info) == 0) { - if (hpt_id_valid(chan_info.devices[0])) - hptiop_dump_devinfo(hba, &info, - chan_info.devices[0], 0); - if (hpt_id_valid(chan_info.devices[1])) - hptiop_dump_devinfo(hba, &info, - chan_info.devices[1], 0); - } - } - - ndev = hptiop_get_logical_devices(hba, ids, - sizeof(ids) / sizeof(ids[0])); - - /* - * if hptiop_get_logical_devices fails, ndev==-1 and it just - * output nothing here - */ - for (j = 0; j < ndev; j++) - hptiop_dump_devinfo(hba, &info, ids[j], 0); - - if (ppos) - *ppos += info.buffillen; - - return info.buffillen; -} - -static int hptiop_cdev_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct hptiop_hba *hba = file->private_data; - struct hpt_ioctl_u ioctl_u; - struct hpt_ioctl_k ioctl_k; - u32 bytes_returned; - int err = -EINVAL; - - if (copy_from_user(&ioctl_u, - (void __user *)arg, sizeof(struct hpt_ioctl_u))) - return -EINVAL; - - if (ioctl_u.magic != HPT_IOCTL_MAGIC) - return -EINVAL; - - ioctl_k.ioctl_code = ioctl_u.ioctl_code; - ioctl_k.inbuf = NULL; - ioctl_k.inbuf_size = ioctl_u.inbuf_size; - ioctl_k.outbuf = NULL; - ioctl_k.outbuf_size = ioctl_u.outbuf_size; - ioctl_k.hba = hba; - ioctl_k.bytes_returned = &bytes_returned; - - /* verify user buffer */ - if ((ioctl_k.inbuf_size && !access_ok(VERIFY_READ, - ioctl_u.inbuf, ioctl_k.inbuf_size)) || - (ioctl_k.outbuf_size && !access_ok(VERIFY_WRITE, - ioctl_u.outbuf, ioctl_k.outbuf_size)) || - (ioctl_u.bytes_returned && !access_ok(VERIFY_WRITE, - ioctl_u.bytes_returned, sizeof(u32))) || - ioctl_k.inbuf_size + ioctl_k.outbuf_size > 0x10000) { - - dprintk("scsi%d: got bad user address\n", hba->host->host_no); - return -EINVAL; - } - - /* map buffer to kernel. */ - if (ioctl_k.inbuf_size) { - ioctl_k.inbuf = kmalloc(ioctl_k.inbuf_size, GFP_KERNEL); - if (!ioctl_k.inbuf) { - dprintk("scsi%d: fail to alloc inbuf\n", - hba->host->host_no); - err = -ENOMEM; - goto err_exit; - } - - if (copy_from_user(ioctl_k.inbuf, - ioctl_u.inbuf, ioctl_k.inbuf_size)) { - goto err_exit; - } - } - - if (ioctl_k.outbuf_size) { - ioctl_k.outbuf = kmalloc(ioctl_k.outbuf_size, GFP_KERNEL); - if (!ioctl_k.outbuf) { - dprintk("scsi%d: fail to alloc outbuf\n", - hba->host->host_no); - err = -ENOMEM; - goto err_exit; - } - } - - hptiop_do_ioctl(&ioctl_k); - - if (ioctl_k.result == HPT_IOCTL_RESULT_OK) { - if (ioctl_k.outbuf_size && - copy_to_user(ioctl_u.outbuf, - ioctl_k.outbuf, ioctl_k.outbuf_size)) - goto err_exit; - - if (ioctl_u.bytes_returned && - copy_to_user(ioctl_u.bytes_returned, - &bytes_returned, sizeof(u32))) - goto err_exit; - - err = 0; - } - -err_exit: - kfree(ioctl_k.inbuf); - kfree(ioctl_k.outbuf); - - return err; -} - -static int hptiop_cdev_open(struct inode *inode, struct file *file) -{ - struct hptiop_hba *hba; - unsigned i = 0, minor = iminor(inode); - int ret = -ENODEV; - - spin_lock(&hptiop_hba_list_lock); - list_for_each_entry(hba, &hptiop_hba_list, link) { - if (i == minor) { - file->private_data = hba; - ret = 0; - goto out; - } - i++; - } - -out: - spin_unlock(&hptiop_hba_list_lock); - return ret; -} - -static struct file_operations hptiop_cdev_fops = { - .owner = THIS_MODULE, - .read = hptiop_cdev_read, - .ioctl = hptiop_cdev_ioctl, - .open = hptiop_cdev_open, -}; - static ssize_t hptiop_show_fw_version(struct class_device *class_dev, char *buf) { struct Scsi_Host *host = class_to_shost(class_dev); @@ -1296,19 +771,13 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev, goto unmap_pci_bar; } - if (scsi_add_host(host, &pcidev->dev)) { - printk(KERN_ERR "scsi%d: scsi_add_host failed\n", - hba->host->host_no); - goto unmap_pci_bar; - } - pci_set_drvdata(pcidev, host); if (request_irq(pcidev->irq, hptiop_intr, IRQF_SHARED, driver_name, hba)) { printk(KERN_ERR "scsi%d: request irq %d failed\n", hba->host->host_no, pcidev->irq); - goto remove_scsi_host; + goto unmap_pci_bar; } /* Allocate request mem */ @@ -1355,9 +824,12 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev, if (hptiop_initialize_iop(hba)) goto free_request_mem; - spin_lock(&hptiop_hba_list_lock); - list_add_tail(&hba->link, &hptiop_hba_list); - spin_unlock(&hptiop_hba_list_lock); + if (scsi_add_host(host, &pcidev->dev)) { + printk(KERN_ERR "scsi%d: scsi_add_host failed\n", + hba->host->host_no); + goto free_request_mem; + } + scsi_scan_host(host); @@ -1372,9 +844,6 @@ free_request_mem: free_request_irq: free_irq(hba->pcidev->irq, hba); -remove_scsi_host: - scsi_remove_host(host); - unmap_pci_bar: iounmap(hba->iop); @@ -1422,10 +891,6 @@ static void hptiop_remove(struct pci_dev *pcidev) scsi_remove_host(host); - spin_lock(&hptiop_hba_list_lock); - list_del_init(&hba->link); - spin_unlock(&hptiop_hba_list_lock); - hptiop_shutdown(pcidev); free_irq(hba->pcidev->irq, hba); @@ -1462,27 +927,12 @@ static struct pci_driver hptiop_pci_driver = { static int __init hptiop_module_init(void) { - int error; - printk(KERN_INFO "%s %s\n", driver_name_long, driver_ver); - - error = pci_register_driver(&hptiop_pci_driver); - if (error < 0) - return error; - - hptiop_cdev_major = register_chrdev(0, "hptiop", &hptiop_cdev_fops); - if (hptiop_cdev_major < 0) { - printk(KERN_WARNING "unable to register hptiop device.\n"); - return hptiop_cdev_major; - } - - return 0; + return pci_register_driver(&hptiop_pci_driver); } static void __exit hptiop_module_exit(void) { - dprintk("hptiop_module_exit\n"); - unregister_chrdev(hptiop_cdev_major, "hptiop"); pci_unregister_driver(&hptiop_pci_driver); } diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 944fc1203eb..669ea4fff16 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -535,6 +535,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, struct ibmvscsi_host_data *hostdata) { u64 *crq_as_u64 = (u64 *) &evt_struct->crq; + int request_status; int rc; /* If we have exhausted our request limit, just fail this request. @@ -542,9 +543,18 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, * (such as task management requests) that the mid layer may think we * can handle more requests (can_queue) when we actually can't */ - if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) && - (atomic_dec_if_positive(&hostdata->request_limit) < 0)) - goto send_error; + if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) { + request_status = + atomic_dec_if_positive(&hostdata->request_limit); + /* If request limit was -1 when we started, it is now even + * less than that + */ + if (request_status < -1) + goto send_error; + /* Otherwise, if we have run out of requests */ + else if (request_status < 0) + goto send_busy; + } /* Copy the IU into the transfer area */ *evt_struct->xfer_iu = evt_struct->iu; @@ -567,11 +577,23 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, return 0; - send_error: + send_busy: unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); free_event_struct(&hostdata->pool, evt_struct); return SCSI_MLQUEUE_HOST_BUSY; + + send_error: + unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); + + if (evt_struct->cmnd != NULL) { + evt_struct->cmnd->result = DID_ERROR << 16; + evt_struct->cmnd_done(evt_struct->cmnd); + } else if (evt_struct->done) + evt_struct->done(evt_struct); + + free_event_struct(&hostdata->pool, evt_struct); + return 0; } /** @@ -1184,27 +1206,37 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, return; case 0xFF: /* Hypervisor telling us the connection is closed */ scsi_block_requests(hostdata->host); + atomic_set(&hostdata->request_limit, 0); if (crq->format == 0x06) { /* We need to re-setup the interpartition connection */ printk(KERN_INFO "ibmvscsi: Re-enabling adapter!\n"); - atomic_set(&hostdata->request_limit, -1); purge_requests(hostdata, DID_REQUEUE); - if (ibmvscsi_reenable_crq_queue(&hostdata->queue, - hostdata) == 0) - if (ibmvscsi_send_crq(hostdata, - 0xC001000000000000LL, 0)) + if ((ibmvscsi_reenable_crq_queue(&hostdata->queue, + hostdata) == 0) || + (ibmvscsi_send_crq(hostdata, + 0xC001000000000000LL, 0))) { + atomic_set(&hostdata->request_limit, + -1); printk(KERN_ERR - "ibmvscsi: transmit error after" + "ibmvscsi: error after" " enable\n"); + } } else { printk(KERN_INFO "ibmvscsi: Virtual adapter failed rc %d!\n", crq->format); - atomic_set(&hostdata->request_limit, -1); purge_requests(hostdata, DID_ERROR); - ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata); + if ((ibmvscsi_reset_crq_queue(&hostdata->queue, + hostdata)) || + (ibmvscsi_send_crq(hostdata, + 0xC001000000000000LL, 0))) { + atomic_set(&hostdata->request_limit, + -1); + printk(KERN_ERR + "ibmvscsi: error after reset\n"); + } } scsi_unblock_requests(hostdata->host); return; @@ -1467,6 +1499,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) struct Scsi_Host *host; struct device *dev = &vdev->dev; unsigned long wait_switch = 0; + int rc; vdev->dev.driver_data = NULL; @@ -1484,8 +1517,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) atomic_set(&hostdata->request_limit, -1); hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */ - if (ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, - max_requests) != 0) { + rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests); + if (rc != 0 && rc != H_RESOURCE) { printk(KERN_ERR "ibmvscsi: couldn't initialize crq\n"); goto init_crq_failed; } @@ -1505,7 +1538,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) * to fail if the other end is not acive. In that case we don't * want to scan */ - if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0) { + if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0 + || rc == H_RESOURCE) { /* * Wait around max init_timeout secs for the adapter to finish * initializing. When we are done initializing, we will have a diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c index 7eed0b09817..6aeb5f003c3 100644 --- a/drivers/scsi/ibmvscsi/iseries_vscsi.c +++ b/drivers/scsi/ibmvscsi/iseries_vscsi.c @@ -81,7 +81,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, int rc; single_host_data = hostdata; - rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, 0); + rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, max_requests); if (rc < 0) { printk("viopath_open failed with rc %d in open_event_path\n", rc); diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c index 1a9992bdfef..ed22b96580c 100644 --- a/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c @@ -208,6 +208,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, int max_requests) { int rc; + int retrc; struct vio_dev *vdev = to_vio_dev(hostdata->dev); queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL); @@ -226,7 +227,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, gather_partition_info(); set_adapter_info(hostdata); - rc = plpar_hcall_norets(H_REG_CRQ, + retrc = rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, queue->msg_token, PAGE_SIZE); if (rc == H_RESOURCE) @@ -237,6 +238,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, if (rc == 2) { /* Adapter is good, but other end is not ready */ printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n"); + retrc = 0; } else if (rc != 0) { printk(KERN_WARNING "ibmvscsi: Error %d opening adapter\n", rc); goto reg_crq_failed; @@ -263,7 +265,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task, (unsigned long)hostdata); - return 0; + return retrc; req_irq_failed: do { diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index f7b5d7372d2..94d1de55607 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -517,7 +517,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) /* No more interrupts */ if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred); - local_irq_enable(); + local_irq_enable_in_hardirq(); if (status.b.check) rq->errors++; idescsi_end_request (drive, 1, 0); diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index b4743a9ecc8..058f094f945 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -43,13 +43,10 @@ #include "iscsi_tcp.h" -#define ISCSI_TCP_VERSION "1.0-595" - MODULE_AUTHOR("Dmitry Yusupov <dmitry_yus@yahoo.com>, " "Alex Aizman <itn780@yahoo.com>"); MODULE_DESCRIPTION("iSCSI/TCP data-path"); MODULE_LICENSE("GPL"); -MODULE_VERSION(ISCSI_TCP_VERSION); /* #define DEBUG_TCP */ #define DEBUG_ASSERT @@ -185,11 +182,19 @@ iscsi_hdr_extract(struct iscsi_tcp_conn *tcp_conn) * must be called with session lock */ static void -__iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) +iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; + struct iscsi_r2t_info *r2t; struct scsi_cmnd *sc; + /* flush ctask's r2t queues */ + while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) { + __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, + sizeof(void*)); + debug_scsi("iscsi_tcp_cleanup_ctask pending r2t dropped\n"); + } + sc = ctask->sc; if (unlikely(!sc)) return; @@ -374,6 +379,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) spin_unlock(&session->lock); return 0; } + rc = __kfifo_get(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); BUG_ON(!rc); @@ -399,7 +405,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) tcp_ctask->exp_r2tsn = r2tsn + 1; tcp_ctask->xmstate |= XMSTATE_SOL_HDR; __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)); - __kfifo_put(conn->xmitqueue, (void*)&ctask, sizeof(void*)); + list_move_tail(&ctask->running, &conn->xmitqueue); scsi_queue_work(session->host, &conn->xmitwork); conn->r2t_pdus_cnt++; @@ -477,6 +483,8 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) case ISCSI_OP_SCSI_DATA_IN: tcp_conn->in.ctask = session->cmds[itt]; rc = iscsi_data_rsp(conn, tcp_conn->in.ctask); + if (rc) + return rc; /* fall through */ case ISCSI_OP_SCSI_CMD_RSP: tcp_conn->in.ctask = session->cmds[itt]; @@ -484,7 +492,7 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) goto copy_hdr; spin_lock(&session->lock); - __iscsi_ctask_cleanup(conn, tcp_conn->in.ctask); + iscsi_tcp_cleanup_ctask(conn, tcp_conn->in.ctask); rc = __iscsi_complete_pdu(conn, hdr, NULL, 0); spin_unlock(&session->lock); break; @@ -500,13 +508,28 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) break; case ISCSI_OP_LOGIN_RSP: case ISCSI_OP_TEXT_RSP: - case ISCSI_OP_LOGOUT_RSP: - case ISCSI_OP_NOOP_IN: case ISCSI_OP_REJECT: case ISCSI_OP_ASYNC_EVENT: + /* + * It is possible that we could get a PDU with a buffer larger + * than 8K, but there are no targets that currently do this. + * For now we fail until we find a vendor that needs it + */ + if (DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH < + tcp_conn->in.datalen) { + printk(KERN_ERR "iscsi_tcp: received buffer of len %u " + "but conn buffer is only %u (opcode %0x)\n", + tcp_conn->in.datalen, + DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, opcode); + rc = ISCSI_ERR_PROTO; + break; + } + if (tcp_conn->in.datalen) goto copy_hdr; /* fall through */ + case ISCSI_OP_LOGOUT_RSP: + case ISCSI_OP_NOOP_IN: case ISCSI_OP_SCSI_TMFUNC_RSP: rc = iscsi_complete_pdu(conn, hdr, NULL, 0); break; @@ -523,7 +546,7 @@ copy_hdr: * skbs to complete the command then we have to copy the header * for later use */ - if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy < + if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy <= (tcp_conn->in.datalen + tcp_conn->in.padding + (conn->datadgst_en ? 4 : 0))) { debug_tcp("Copying header for later use. in.copy %d in.datalen" @@ -614,9 +637,9 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask, * byte counters. **/ static inline int -iscsi_tcp_copy(struct iscsi_tcp_conn *tcp_conn) +iscsi_tcp_copy(struct iscsi_conn *conn) { - void *buf = tcp_conn->data; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; int buf_size = tcp_conn->in.datalen; int buf_left = buf_size - tcp_conn->data_copied; int size = min(tcp_conn->in.copy, buf_left); @@ -627,7 +650,7 @@ iscsi_tcp_copy(struct iscsi_tcp_conn *tcp_conn) BUG_ON(size <= 0); rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset, - (char*)buf + tcp_conn->data_copied, size); + (char*)conn->data + tcp_conn->data_copied, size); BUG_ON(rc); tcp_conn->in.offset += size; @@ -745,10 +768,11 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn) done: /* check for non-exceptional status */ if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) { - debug_scsi("done [sc %lx res %d itt 0x%x]\n", - (long)sc, sc->result, ctask->itt); + debug_scsi("done [sc %lx res %d itt 0x%x flags 0x%x]\n", + (long)sc, sc->result, ctask->itt, + tcp_conn->in.hdr->flags); spin_lock(&conn->session->lock); - __iscsi_ctask_cleanup(conn, ctask); + iscsi_tcp_cleanup_ctask(conn, ctask); __iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0); spin_unlock(&conn->session->lock); } @@ -769,26 +793,25 @@ iscsi_data_recv(struct iscsi_conn *conn) break; case ISCSI_OP_SCSI_CMD_RSP: spin_lock(&conn->session->lock); - __iscsi_ctask_cleanup(conn, tcp_conn->in.ctask); + iscsi_tcp_cleanup_ctask(conn, tcp_conn->in.ctask); spin_unlock(&conn->session->lock); case ISCSI_OP_TEXT_RSP: case ISCSI_OP_LOGIN_RSP: - case ISCSI_OP_NOOP_IN: case ISCSI_OP_ASYNC_EVENT: case ISCSI_OP_REJECT: /* * Collect data segment to the connection's data * placeholder */ - if (iscsi_tcp_copy(tcp_conn)) { + if (iscsi_tcp_copy(conn)) { rc = -EAGAIN; goto exit; } - rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, tcp_conn->data, + rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, conn->data, tcp_conn->in.datalen); if (!rc && conn->datadgst_en && opcode != ISCSI_OP_LOGIN_RSP) - iscsi_recv_digest_update(tcp_conn, tcp_conn->data, + iscsi_recv_digest_update(tcp_conn, conn->data, tcp_conn->in.datalen); break; default: @@ -843,7 +866,7 @@ more: if (rc == -EAGAIN) goto nomore; else { - iscsi_conn_failure(conn, rc); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return 0; } } @@ -897,7 +920,7 @@ more: if (rc) { if (rc == -EAGAIN) goto again; - iscsi_conn_failure(conn, rc); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return 0; } tcp_conn->in.copy -= tcp_conn->in.padding; @@ -1028,9 +1051,8 @@ iscsi_conn_set_callbacks(struct iscsi_conn *conn) } static void -iscsi_conn_restore_callbacks(struct iscsi_conn *conn) +iscsi_conn_restore_callbacks(struct iscsi_tcp_conn *tcp_conn) { - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct sock *sk = tcp_conn->sock->sk; /* restore socket callbacks, see also: iscsi_conn_set_callbacks() */ @@ -1308,7 +1330,7 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) ctask->imm_count - ctask->unsol_count; - debug_scsi("cmd [itt %x total %d imm %d imm_data %d " + debug_scsi("cmd [itt 0x%x total %d imm %d imm_data %d " "r2t_data %d]\n", ctask->itt, ctask->total_length, ctask->imm_count, ctask->unsol_count, tcp_ctask->r2t_data_count); @@ -1636,7 +1658,7 @@ handle_xmstate_sol_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) } solicit_again: /* - * send Data-Out whitnin this R2T sequence. + * send Data-Out within this R2T sequence. */ if (!r2t->data_count) goto data_out_done; @@ -1731,7 +1753,7 @@ handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_data_task *dtask = tcp_ctask->dtask; - int sent, rc; + int sent = 0, rc; tcp_ctask->xmstate &= ~XMSTATE_W_PAD; iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad, @@ -1900,27 +1922,32 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER; /* initial operational parameters */ tcp_conn->hdr_size = sizeof(struct iscsi_hdr); - tcp_conn->data_size = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH; - - /* allocate initial PDU receive place holder */ - if (tcp_conn->data_size <= PAGE_SIZE) - tcp_conn->data = kmalloc(tcp_conn->data_size, GFP_KERNEL); - else - tcp_conn->data = (void*)__get_free_pages(GFP_KERNEL, - get_order(tcp_conn->data_size)); - if (!tcp_conn->data) - goto max_recv_dlenght_alloc_fail; return cls_conn; -max_recv_dlenght_alloc_fail: - kfree(tcp_conn); tcp_conn_alloc_fail: iscsi_conn_teardown(cls_conn); return NULL; } static void +iscsi_tcp_release_conn(struct iscsi_conn *conn) +{ + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + + if (!tcp_conn->sock) + return; + + sock_hold(tcp_conn->sock->sk); + iscsi_conn_restore_callbacks(tcp_conn); + sock_put(tcp_conn->sock->sk); + + sock_release(tcp_conn->sock); + tcp_conn->sock = NULL; + conn->recv_lock = NULL; +} + +static void iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) { struct iscsi_conn *conn = cls_conn->dd_data; @@ -1930,6 +1957,7 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) if (conn->hdrdgst_en || conn->datadgst_en) digest = 1; + iscsi_tcp_release_conn(conn); iscsi_conn_teardown(cls_conn); /* now free tcp_conn */ @@ -1944,15 +1972,18 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) crypto_free_tfm(tcp_conn->data_rx_tfm); } - /* free conn->data, size = MaxRecvDataSegmentLength */ - if (tcp_conn->data_size <= PAGE_SIZE) - kfree(tcp_conn->data); - else - free_pages((unsigned long)tcp_conn->data, - get_order(tcp_conn->data_size)); kfree(tcp_conn); } +static void +iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + + iscsi_conn_stop(cls_conn, flag); + iscsi_tcp_release_conn(conn); +} + static int iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, @@ -2001,52 +2032,6 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, return 0; } -static void -iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) -{ - struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; - struct iscsi_r2t_info *r2t; - - /* flush ctask's r2t queues */ - while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) - __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, - sizeof(void*)); - - __iscsi_ctask_cleanup(conn, ctask); -} - -static void -iscsi_tcp_suspend_conn_rx(struct iscsi_conn *conn) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct sock *sk; - - if (!tcp_conn->sock) - return; - - sk = tcp_conn->sock->sk; - write_lock_bh(&sk->sk_callback_lock); - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); - write_unlock_bh(&sk->sk_callback_lock); -} - -static void -iscsi_tcp_terminate_conn(struct iscsi_conn *conn) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - - if (!tcp_conn->sock) - return; - - sock_hold(tcp_conn->sock->sk); - iscsi_conn_restore_callbacks(conn); - sock_put(tcp_conn->sock->sk); - - sock_release(tcp_conn->sock); - tcp_conn->sock = NULL; - conn->recv_lock = NULL; -} - /* called with host lock */ static void iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask, @@ -2057,6 +2042,7 @@ iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask, iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr, sizeof(struct iscsi_hdr)); tcp_mtask->xmstate = XMSTATE_IMM_HDR; + tcp_mtask->sent = 0; if (mtask->data_count) iscsi_buf_init_iov(&tcp_mtask->sendbuf, (char*)mtask->data, @@ -2130,50 +2116,16 @@ iscsi_r2tpool_free(struct iscsi_session *session) static int iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, - uint32_t value) + char *buf, int buflen) { struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_session *session = conn->session; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + int value; switch(param) { - case ISCSI_PARAM_MAX_RECV_DLENGTH: { - char *saveptr = tcp_conn->data; - gfp_t flags = GFP_KERNEL; - - if (tcp_conn->data_size >= value) { - conn->max_recv_dlength = value; - break; - } - - spin_lock_bh(&session->lock); - if (conn->stop_stage == STOP_CONN_RECOVER) - flags = GFP_ATOMIC; - spin_unlock_bh(&session->lock); - - if (value <= PAGE_SIZE) - tcp_conn->data = kmalloc(value, flags); - else - tcp_conn->data = (void*)__get_free_pages(flags, - get_order(value)); - if (tcp_conn->data == NULL) { - tcp_conn->data = saveptr; - return -ENOMEM; - } - if (tcp_conn->data_size <= PAGE_SIZE) - kfree(saveptr); - else - free_pages((unsigned long)saveptr, - get_order(tcp_conn->data_size)); - conn->max_recv_dlength = value; - tcp_conn->data_size = value; - } - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - conn->max_xmit_dlength = value; - break; case ISCSI_PARAM_HDRDGST_EN: - conn->hdrdgst_en = value; + iscsi_set_param(cls_conn, param, buf, buflen); tcp_conn->hdr_size = sizeof(struct iscsi_hdr); if (conn->hdrdgst_en) { tcp_conn->hdr_size += sizeof(__u32); @@ -2197,7 +2149,7 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, } break; case ISCSI_PARAM_DATADGST_EN: - conn->datadgst_en = value; + iscsi_set_param(cls_conn, param, buf, buflen); if (conn->datadgst_en) { if (!tcp_conn->data_tx_tfm) tcp_conn->data_tx_tfm = @@ -2220,121 +2172,36 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, tcp_conn->sendpage = conn->datadgst_en ? sock_no_sendpage : tcp_conn->sock->ops->sendpage; break; - case ISCSI_PARAM_INITIAL_R2T_EN: - session->initial_r2t_en = value; - break; case ISCSI_PARAM_MAX_R2T: + sscanf(buf, "%d", &value); if (session->max_r2t == roundup_pow_of_two(value)) break; iscsi_r2tpool_free(session); - session->max_r2t = value; + iscsi_set_param(cls_conn, param, buf, buflen); if (session->max_r2t & (session->max_r2t - 1)) session->max_r2t = roundup_pow_of_two(session->max_r2t); if (iscsi_r2tpool_alloc(session)) return -ENOMEM; break; - case ISCSI_PARAM_IMM_DATA_EN: - session->imm_data_en = value; - break; - case ISCSI_PARAM_FIRST_BURST: - session->first_burst = value; - break; - case ISCSI_PARAM_MAX_BURST: - session->max_burst = value; - break; - case ISCSI_PARAM_PDU_INORDER_EN: - session->pdu_inorder_en = value; - break; - case ISCSI_PARAM_DATASEQ_INORDER_EN: - session->dataseq_inorder_en = value; - break; - case ISCSI_PARAM_ERL: - session->erl = value; - break; - case ISCSI_PARAM_IFMARKER_EN: - BUG_ON(value); - session->ifmarker_en = value; - break; - case ISCSI_PARAM_OFMARKER_EN: - BUG_ON(value); - session->ofmarker_en = value; - break; - case ISCSI_PARAM_EXP_STATSN: - conn->exp_statsn = value; - break; default: - break; + return iscsi_set_param(cls_conn, param, buf, buflen); } return 0; } static int -iscsi_session_get_param(struct iscsi_cls_session *cls_session, - enum iscsi_param param, uint32_t *value) -{ - struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); - struct iscsi_session *session = iscsi_hostdata(shost->hostdata); - - switch(param) { - case ISCSI_PARAM_INITIAL_R2T_EN: - *value = session->initial_r2t_en; - break; - case ISCSI_PARAM_MAX_R2T: - *value = session->max_r2t; - break; - case ISCSI_PARAM_IMM_DATA_EN: - *value = session->imm_data_en; - break; - case ISCSI_PARAM_FIRST_BURST: - *value = session->first_burst; - break; - case ISCSI_PARAM_MAX_BURST: - *value = session->max_burst; - break; - case ISCSI_PARAM_PDU_INORDER_EN: - *value = session->pdu_inorder_en; - break; - case ISCSI_PARAM_DATASEQ_INORDER_EN: - *value = session->dataseq_inorder_en; - break; - case ISCSI_PARAM_ERL: - *value = session->erl; - break; - case ISCSI_PARAM_IFMARKER_EN: - *value = session->ifmarker_en; - break; - case ISCSI_PARAM_OFMARKER_EN: - *value = session->ofmarker_en; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int -iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, uint32_t *value) +iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf) { struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct inet_sock *inet; + struct ipv6_pinfo *np; + struct sock *sk; + int len; switch(param) { - case ISCSI_PARAM_MAX_RECV_DLENGTH: - *value = conn->max_recv_dlength; - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - *value = conn->max_xmit_dlength; - break; - case ISCSI_PARAM_HDRDGST_EN: - *value = conn->hdrdgst_en; - break; - case ISCSI_PARAM_DATADGST_EN: - *value = conn->datadgst_en; - break; case ISCSI_PARAM_CONN_PORT: mutex_lock(&conn->xmitmutex); if (!tcp_conn->sock) { @@ -2343,30 +2210,9 @@ iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, } inet = inet_sk(tcp_conn->sock->sk); - *value = be16_to_cpu(inet->dport); + len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport)); mutex_unlock(&conn->xmitmutex); - case ISCSI_PARAM_EXP_STATSN: - *value = conn->exp_statsn; break; - default: - return -EINVAL; - } - - return 0; -} - -static int -iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct sock *sk; - struct inet_sock *inet; - struct ipv6_pinfo *np; - int len = 0; - - switch (param) { case ISCSI_PARAM_CONN_ADDRESS: mutex_lock(&conn->xmitmutex); if (!tcp_conn->sock) { @@ -2388,7 +2234,7 @@ iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn, mutex_unlock(&conn->xmitmutex); break; default: - return -EINVAL; + return iscsi_conn_get_param(cls_conn, param, buf); } return len; @@ -2468,8 +2314,7 @@ static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session) } static struct scsi_host_template iscsi_sht = { - .name = "iSCSI Initiator over TCP/IP, v" - ISCSI_TCP_VERSION, + .name = "iSCSI Initiator over TCP/IP", .queuecommand = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, .can_queue = ISCSI_XMIT_CMDS_MAX - 1, @@ -2501,7 +2346,11 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_ERL | ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS | - ISCSI_EXP_STATSN, + ISCSI_EXP_STATSN | + ISCSI_PERSISTENT_PORT | + ISCSI_PERSISTENT_ADDRESS | + ISCSI_TARGET_NAME | + ISCSI_TPGT, .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, @@ -2514,14 +2363,10 @@ static struct iscsi_transport iscsi_tcp_transport = { .bind_conn = iscsi_tcp_conn_bind, .destroy_conn = iscsi_tcp_conn_destroy, .set_param = iscsi_conn_set_param, - .get_conn_param = iscsi_conn_get_param, - .get_conn_str_param = iscsi_conn_get_str_param, + .get_conn_param = iscsi_tcp_conn_get_param, .get_session_param = iscsi_session_get_param, .start_conn = iscsi_conn_start, - .stop_conn = iscsi_conn_stop, - /* these are called as part of conn recovery */ - .suspend_conn_recv = iscsi_tcp_suspend_conn_rx, - .terminate_conn = iscsi_tcp_terminate_conn, + .stop_conn = iscsi_tcp_conn_stop, /* IO */ .send_pdu = iscsi_conn_send_pdu, .get_stats = iscsi_conn_get_stats, diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index 808302832e6..6a4ee704e46 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h @@ -78,8 +78,6 @@ struct iscsi_tcp_conn { char hdrext[4*sizeof(__u16) + sizeof(__u32)]; int data_copied; - char *data; /* data placeholder */ - int data_size; /* actual recv_dlength */ int stop_stage; /* conn_stop() flag: * * stop to recover, * * stop to terminate */ diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index 3fd8a96f2af..bfac4441d89 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -257,7 +257,7 @@ static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp) static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp) { int sz = sp->use_sg - 1; - struct scatterlist *sg = (struct scatterlist *)sp->buffer; + struct scatterlist *sg = (struct scatterlist *)sp->request_buffer; while(sz >= 0) { vdma_free(sg[sz].dma_address); diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 82caba46429..427b73a3886 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -61,9 +61,9 @@ #include "libata.h" /* debounce timing parameters in msecs { interval, duration, timeout } */ -const unsigned long sata_deb_timing_boot[] = { 5, 100, 2000 }; -const unsigned long sata_deb_timing_eh[] = { 25, 500, 2000 }; -const unsigned long sata_deb_timing_before_fsrst[] = { 100, 2000, 5000 }; +const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 }; +const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 }; +const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 }; static unsigned int ata_dev_init_params(struct ata_device *dev, u16 heads, u16 sectors); @@ -907,7 +907,7 @@ void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data, { int rc; - if (ap->flags & ATA_FLAG_FLUSH_PORT_TASK) + if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK) return; PREPARE_WORK(&ap->port_task, fn, data); @@ -938,7 +938,7 @@ void ata_port_flush_task(struct ata_port *ap) DPRINTK("ENTER\n"); spin_lock_irqsave(ap->lock, flags); - ap->flags |= ATA_FLAG_FLUSH_PORT_TASK; + ap->pflags |= ATA_PFLAG_FLUSH_PORT_TASK; spin_unlock_irqrestore(ap->lock, flags); DPRINTK("flush #1\n"); @@ -957,7 +957,7 @@ void ata_port_flush_task(struct ata_port *ap) } spin_lock_irqsave(ap->lock, flags); - ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK; + ap->pflags &= ~ATA_PFLAG_FLUSH_PORT_TASK; spin_unlock_irqrestore(ap->lock, flags); if (ata_msg_ctl(ap)) @@ -1001,7 +1001,7 @@ unsigned ata_exec_internal(struct ata_device *dev, struct ata_queued_cmd *qc; unsigned int tag, preempted_tag; u32 preempted_sactive, preempted_qc_active; - DECLARE_COMPLETION(wait); + DECLARE_COMPLETION_ONSTACK(wait); unsigned long flags; unsigned int err_mask; int rc; @@ -1009,7 +1009,7 @@ unsigned ata_exec_internal(struct ata_device *dev, spin_lock_irqsave(ap->lock, flags); /* no internal command while frozen */ - if (ap->flags & ATA_FLAG_FROZEN) { + if (ap->pflags & ATA_PFLAG_FROZEN) { spin_unlock_irqrestore(ap->lock, flags); return AC_ERR_SYSTEM; } @@ -1256,10 +1256,15 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, swap_buf_le16(id, ATA_ID_WORDS); /* sanity check */ - if ((class == ATA_DEV_ATA) != (ata_id_is_ata(id) | ata_id_is_cfa(id))) { - rc = -EINVAL; - reason = "device reports illegal type"; - goto err_out; + rc = -EINVAL; + reason = "device reports illegal type"; + + if (class == ATA_DEV_ATA) { + if (!ata_id_is_ata(id) && !ata_id_is_cfa(id)) + goto err_out; + } else { + if (ata_id_is_ata(id)) + goto err_out; } if (post_reset && class == ATA_DEV_ATA) { @@ -1325,6 +1330,19 @@ static void ata_dev_config_ncq(struct ata_device *dev, snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth); } +static void ata_set_port_max_cmd_len(struct ata_port *ap) +{ + int i; + + if (ap->host) { + ap->host->max_cmd_len = 0; + for (i = 0; i < ATA_MAX_DEVICES; i++) + ap->host->max_cmd_len = max_t(unsigned int, + ap->host->max_cmd_len, + ap->device[i].cdb_len); + } +} + /** * ata_dev_configure - Configure the specified ATA/ATAPI device * @dev: Target device to configure @@ -1344,7 +1362,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info) struct ata_port *ap = dev->ap; const u16 *id = dev->id; unsigned int xfer_mask; - int i, rc; + int rc; if (!ata_dev_enabled(dev) && ata_msg_info(ap)) { ata_dev_printk(dev, KERN_INFO, @@ -1404,7 +1422,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info) ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc)); /* print device info to dmesg */ - if (ata_msg_info(ap)) + if (ata_msg_drv(ap) && print_info) ata_dev_printk(dev, KERN_INFO, "ATA-%d, " "max %s, %Lu sectors: %s %s\n", ata_id_major_version(id), @@ -1427,7 +1445,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info) } /* print device info to dmesg */ - if (ata_msg_info(ap)) + if (ata_msg_drv(ap) && print_info) ata_dev_printk(dev, KERN_INFO, "ATA-%d, " "max %s, %Lu sectors: CHS %u/%u/%u\n", ata_id_major_version(id), @@ -1439,7 +1457,7 @@ int ata_dev_configure(struct ata_device *dev, int print_info) if (dev->id[59] & 0x100) { dev->multi_count = dev->id[59] & 0xff; - if (ata_msg_info(ap)) + if (ata_msg_drv(ap) && print_info) ata_dev_printk(dev, KERN_INFO, "ata%u: dev %u multi count %u\n", ap->id, dev->devno, dev->multi_count); @@ -1468,21 +1486,17 @@ int ata_dev_configure(struct ata_device *dev, int print_info) } /* print device info to dmesg */ - if (ata_msg_info(ap)) + if (ata_msg_drv(ap) && print_info) ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n", ata_mode_string(xfer_mask), cdb_intr_string); } - ap->host->max_cmd_len = 0; - for (i = 0; i < ATA_MAX_DEVICES; i++) - ap->host->max_cmd_len = max_t(unsigned int, - ap->host->max_cmd_len, - ap->device[i].cdb_len); + ata_set_port_max_cmd_len(ap); /* limit bridge transfers to udma5, 200 sectors */ if (ata_dev_knobble(dev)) { - if (ata_msg_info(ap)) + if (ata_msg_drv(ap) && print_info) ata_dev_printk(dev, KERN_INFO, "applying bridge limits\n"); dev->udma_mask &= ATA_UDMA5; @@ -2137,7 +2151,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) * return error code and failing device on failure. */ for (i = 0; i < ATA_MAX_DEVICES; i++) { - if (ata_dev_enabled(&ap->device[i])) { + if (ata_dev_ready(&ap->device[i])) { ap->ops->set_mode(ap); break; } @@ -2203,7 +2217,8 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) for (i = 0; i < ATA_MAX_DEVICES; i++) { dev = &ap->device[i]; - if (!ata_dev_enabled(dev)) + /* don't udpate suspended devices' xfer mode */ + if (!ata_dev_ready(dev)) continue; rc = ata_dev_set_mode(dev); @@ -2579,7 +2594,7 @@ static void ata_wait_spinup(struct ata_port *ap) /* first, debounce phy if SATA */ if (ap->cbl == ATA_CBL_SATA) { - rc = sata_phy_debounce(ap, sata_deb_timing_eh); + rc = sata_phy_debounce(ap, sata_deb_timing_hotplug); /* if debounced successfully and offline, no need to wait */ if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap)) @@ -2615,16 +2630,17 @@ static void ata_wait_spinup(struct ata_port *ap) int ata_std_prereset(struct ata_port *ap) { struct ata_eh_context *ehc = &ap->eh_context; - const unsigned long *timing; + const unsigned long *timing = sata_ehc_deb_timing(ehc); int rc; - /* hotplug? */ - if (ehc->i.flags & ATA_EHI_HOTPLUGGED) { - if (ap->flags & ATA_FLAG_HRST_TO_RESUME) - ehc->i.action |= ATA_EH_HARDRESET; - if (ap->flags & ATA_FLAG_SKIP_D2H_BSY) - ata_wait_spinup(ap); - } + /* handle link resume & hotplug spinup */ + if ((ehc->i.flags & ATA_EHI_RESUME_LINK) && + (ap->flags & ATA_FLAG_HRST_TO_RESUME)) + ehc->i.action |= ATA_EH_HARDRESET; + + if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) && + (ap->flags & ATA_FLAG_SKIP_D2H_BSY)) + ata_wait_spinup(ap); /* if we're about to do hardreset, nothing more to do */ if (ehc->i.action & ATA_EH_HARDRESET) @@ -2632,11 +2648,6 @@ int ata_std_prereset(struct ata_port *ap) /* if SATA, resume phy */ if (ap->cbl == ATA_CBL_SATA) { - if (ap->flags & ATA_FLAG_LOADING) - timing = sata_deb_timing_boot; - else - timing = sata_deb_timing_eh; - rc = sata_phy_resume(ap, timing); if (rc && rc != -EOPNOTSUPP) { /* phy resume failed */ @@ -2724,6 +2735,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes) */ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) { + struct ata_eh_context *ehc = &ap->eh_context; + const unsigned long *timing = sata_ehc_deb_timing(ehc); u32 scontrol; int rc; @@ -2738,7 +2751,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol))) return rc; - scontrol = (scontrol & 0x0f0) | 0x302; + scontrol = (scontrol & 0x0f0) | 0x304; if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol))) return rc; @@ -2761,7 +2774,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class) msleep(1); /* bring phy back */ - sata_phy_resume(ap, sata_deb_timing_eh); + sata_phy_resume(ap, timing); /* TODO: phy layer with polling, timeouts, etc. */ if (ata_port_offline(ap)) { @@ -4285,7 +4298,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap) unsigned int i; /* no command while frozen */ - if (unlikely(ap->flags & ATA_FLAG_FROZEN)) + if (unlikely(ap->pflags & ATA_PFLAG_FROZEN)) return NULL; /* the last tag is reserved for internal command. */ @@ -4407,7 +4420,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) * taken care of. */ if (ap->ops->error_handler) { - WARN_ON(ap->flags & ATA_FLAG_FROZEN); + WARN_ON(ap->pflags & ATA_PFLAG_FROZEN); if (unlikely(qc->err_mask)) qc->flags |= ATA_QCFLAG_FAILED; @@ -5001,86 +5014,120 @@ int ata_flush_cache(struct ata_device *dev) return 0; } -static int ata_standby_drive(struct ata_device *dev) +static int ata_host_set_request_pm(struct ata_host_set *host_set, + pm_message_t mesg, unsigned int action, + unsigned int ehi_flags, int wait) { - unsigned int err_mask; + unsigned long flags; + int i, rc; - err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1); - if (err_mask) { - ata_dev_printk(dev, KERN_ERR, "failed to standby drive " - "(err_mask=0x%x)\n", err_mask); - return -EIO; - } + for (i = 0; i < host_set->n_ports; i++) { + struct ata_port *ap = host_set->ports[i]; - return 0; -} + /* Previous resume operation might still be in + * progress. Wait for PM_PENDING to clear. + */ + if (ap->pflags & ATA_PFLAG_PM_PENDING) { + ata_port_wait_eh(ap); + WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING); + } -static int ata_start_drive(struct ata_device *dev) -{ - unsigned int err_mask; + /* request PM ops to EH */ + spin_lock_irqsave(ap->lock, flags); - err_mask = ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE); - if (err_mask) { - ata_dev_printk(dev, KERN_ERR, "failed to start drive " - "(err_mask=0x%x)\n", err_mask); - return -EIO; + ap->pm_mesg = mesg; + if (wait) { + rc = 0; + ap->pm_result = &rc; + } + + ap->pflags |= ATA_PFLAG_PM_PENDING; + ap->eh_info.action |= action; + ap->eh_info.flags |= ehi_flags; + + ata_port_schedule_eh(ap); + + spin_unlock_irqrestore(ap->lock, flags); + + /* wait and check result */ + if (wait) { + ata_port_wait_eh(ap); + WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING); + if (rc) + return rc; + } } return 0; } /** - * ata_device_resume - wakeup a previously suspended devices - * @dev: the device to resume + * ata_host_set_suspend - suspend host_set + * @host_set: host_set to suspend + * @mesg: PM message * - * Kick the drive back into action, by sending it an idle immediate - * command and making sure its transfer mode matches between drive - * and host. + * Suspend @host_set. Actual operation is performed by EH. This + * function requests EH to perform PM operations and waits for EH + * to finish. + * + * LOCKING: + * Kernel thread context (may sleep). * + * RETURNS: + * 0 on success, -errno on failure. */ -int ata_device_resume(struct ata_device *dev) +int ata_host_set_suspend(struct ata_host_set *host_set, pm_message_t mesg) { - struct ata_port *ap = dev->ap; + int i, j, rc; - if (ap->flags & ATA_FLAG_SUSPENDED) { - struct ata_device *failed_dev; + rc = ata_host_set_request_pm(host_set, mesg, 0, ATA_EHI_QUIET, 1); + if (rc) + goto fail; - ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); - ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000); + /* EH is quiescent now. Fail if we have any ready device. + * This happens if hotplug occurs between completion of device + * suspension and here. + */ + for (i = 0; i < host_set->n_ports; i++) { + struct ata_port *ap = host_set->ports[i]; + + for (j = 0; j < ATA_MAX_DEVICES; j++) { + struct ata_device *dev = &ap->device[j]; - ap->flags &= ~ATA_FLAG_SUSPENDED; - while (ata_set_mode(ap, &failed_dev)) - ata_dev_disable(failed_dev); + if (ata_dev_ready(dev)) { + ata_port_printk(ap, KERN_WARNING, + "suspend failed, device %d " + "still active\n", dev->devno); + rc = -EBUSY; + goto fail; + } + } } - if (!ata_dev_enabled(dev)) - return 0; - if (dev->class == ATA_DEV_ATA) - ata_start_drive(dev); + host_set->dev->power.power_state = mesg; return 0; + + fail: + ata_host_set_resume(host_set); + return rc; } /** - * ata_device_suspend - prepare a device for suspend - * @dev: the device to suspend - * @state: target power management state + * ata_host_set_resume - resume host_set + * @host_set: host_set to resume * - * Flush the cache on the drive, if appropriate, then issue a - * standbynow command. + * Resume @host_set. Actual operation is performed by EH. This + * function requests EH to perform PM operations and returns. + * Note that all resume operations are performed parallely. + * + * LOCKING: + * Kernel thread context (may sleep). */ -int ata_device_suspend(struct ata_device *dev, pm_message_t state) +void ata_host_set_resume(struct ata_host_set *host_set) { - struct ata_port *ap = dev->ap; - - if (!ata_dev_enabled(dev)) - return 0; - if (dev->class == ATA_DEV_ATA) - ata_flush_cache(dev); - - if (state.event != PM_EVENT_FREEZE) - ata_standby_drive(dev); - ap->flags |= ATA_FLAG_SUSPENDED; - return 0; + ata_host_set_request_pm(host_set, PMSG_ON, ATA_EH_SOFTRESET, + ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0); + host_set->dev->power.power_state = PMSG_ON; } /** @@ -5143,28 +5190,6 @@ void ata_host_stop (struct ata_host_set *host_set) iounmap(host_set->mmio_base); } - -/** - * ata_host_remove - Unregister SCSI host structure with upper layers - * @ap: Port to unregister - * @do_unregister: 1 if we fully unregister, 0 to just stop the port - * - * LOCKING: - * Inherited from caller. - */ - -static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister) -{ - struct Scsi_Host *sh = ap->host; - - DPRINTK("ENTER\n"); - - if (do_unregister) - scsi_remove_host(sh); - - ap->ops->port_stop(ap); -} - /** * ata_dev_init - Initialize an ata_device structure * @dev: Device structure to initialize @@ -5440,6 +5465,7 @@ int ata_device_add(const struct ata_probe_ent *ent) } if (ap->ops->error_handler) { + struct ata_eh_info *ehi = &ap->eh_info; unsigned long flags; ata_port_probe(ap); @@ -5447,10 +5473,11 @@ int ata_device_add(const struct ata_probe_ent *ent) /* kick EH for boot probing */ spin_lock_irqsave(ap->lock, flags); - ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1; - ap->eh_info.action |= ATA_EH_SOFTRESET; + ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1; + ehi->action |= ATA_EH_SOFTRESET; + ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; - ap->flags |= ATA_FLAG_LOADING; + ap->pflags |= ATA_PFLAG_LOADING; ata_port_schedule_eh(ap); spin_unlock_irqrestore(ap->lock, flags); @@ -5488,8 +5515,11 @@ int ata_device_add(const struct ata_probe_ent *ent) err_out: for (i = 0; i < count; i++) { - ata_host_remove(host_set->ports[i], 1); - scsi_host_put(host_set->ports[i]->host); + struct ata_port *ap = host_set->ports[i]; + if (ap) { + ap->ops->port_stop(ap); + scsi_host_put(ap->host); + } } err_free_ret: kfree(host_set); @@ -5514,11 +5544,11 @@ void ata_port_detach(struct ata_port *ap) int i; if (!ap->ops->error_handler) - return; + goto skip_eh; /* tell EH we're leaving & flush EH */ spin_lock_irqsave(ap->lock, flags); - ap->flags |= ATA_FLAG_UNLOADING; + ap->pflags |= ATA_PFLAG_UNLOADING; spin_unlock_irqrestore(ap->lock, flags); ata_port_wait_eh(ap); @@ -5550,6 +5580,7 @@ void ata_port_detach(struct ata_port *ap) cancel_delayed_work(&ap->hotplug_task); flush_workqueue(ata_aux_wq); + skip_eh: /* remove the associated SCSI host */ scsi_remove_host(ap->host); } @@ -5618,7 +5649,7 @@ int ata_scsi_release(struct Scsi_Host *host) DPRINTK("ENTER\n"); ap->ops->port_disable(ap); - ata_host_remove(ap, 0); + ap->ops->port_stop(ap); DPRINTK("EXIT\n"); return 1; @@ -5723,20 +5754,55 @@ int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits) return (tmp == bits->val) ? 1 : 0; } -int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state) +void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t state) { pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); - return 0; + + if (state.event == PM_EVENT_SUSPEND) { + pci_disable_device(pdev); + pci_set_power_state(pdev, PCI_D3hot); + } } -int ata_pci_device_resume(struct pci_dev *pdev) +void ata_pci_device_do_resume(struct pci_dev *pdev) { pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); pci_enable_device(pdev); pci_set_master(pdev); +} + +int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev); + int rc = 0; + + rc = ata_host_set_suspend(host_set, state); + if (rc) + return rc; + + if (host_set->next) { + rc = ata_host_set_suspend(host_set->next, state); + if (rc) { + ata_host_set_resume(host_set); + return rc; + } + } + + ata_pci_device_do_suspend(pdev, state); + + return 0; +} + +int ata_pci_device_resume(struct pci_dev *pdev) +{ + struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev); + + ata_pci_device_do_resume(pdev); + ata_host_set_resume(host_set); + if (host_set->next) + ata_host_set_resume(host_set->next); + return 0; } #endif /* CONFIG_PCI */ @@ -5842,9 +5908,9 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val, * Do not depend on ABI/API stability. */ -EXPORT_SYMBOL_GPL(sata_deb_timing_boot); -EXPORT_SYMBOL_GPL(sata_deb_timing_eh); -EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst); +EXPORT_SYMBOL_GPL(sata_deb_timing_normal); +EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug); +EXPORT_SYMBOL_GPL(sata_deb_timing_long); EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_device_add); @@ -5916,6 +5982,8 @@ EXPORT_SYMBOL_GPL(sata_scr_write); EXPORT_SYMBOL_GPL(sata_scr_write_flush); EXPORT_SYMBOL_GPL(ata_port_online); EXPORT_SYMBOL_GPL(ata_port_offline); +EXPORT_SYMBOL_GPL(ata_host_set_suspend); +EXPORT_SYMBOL_GPL(ata_host_set_resume); EXPORT_SYMBOL_GPL(ata_id_string); EXPORT_SYMBOL_GPL(ata_id_c_string); EXPORT_SYMBOL_GPL(ata_scsi_simulate); @@ -5930,14 +5998,14 @@ EXPORT_SYMBOL_GPL(ata_pci_host_stop); EXPORT_SYMBOL_GPL(ata_pci_init_native_mode); EXPORT_SYMBOL_GPL(ata_pci_init_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); +EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend); +EXPORT_SYMBOL_GPL(ata_pci_device_do_resume); EXPORT_SYMBOL_GPL(ata_pci_device_suspend); EXPORT_SYMBOL_GPL(ata_pci_device_resume); EXPORT_SYMBOL_GPL(ata_pci_default_filter); EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); #endif /* CONFIG_PCI */ -EXPORT_SYMBOL_GPL(ata_device_suspend); -EXPORT_SYMBOL_GPL(ata_device_resume); EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); EXPORT_SYMBOL_GPL(ata_scsi_device_resume); diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c index bf5a72aca8a..29f59345305 100644 --- a/drivers/scsi/libata-eh.c +++ b/drivers/scsi/libata-eh.c @@ -47,6 +47,8 @@ static void __ata_port_freeze(struct ata_port *ap); static void ata_eh_finish(struct ata_port *ap); +static void ata_eh_handle_port_suspend(struct ata_port *ap); +static void ata_eh_handle_port_resume(struct ata_port *ap); static void ata_ering_record(struct ata_ering *ering, int is_io, unsigned int err_mask) @@ -190,7 +192,6 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd) void ata_scsi_error(struct Scsi_Host *host) { struct ata_port *ap = ata_shost_to_port(host); - spinlock_t *ap_lock = ap->lock; int i, repeat_cnt = ATA_EH_MAX_REPEAT; unsigned long flags; @@ -217,7 +218,7 @@ void ata_scsi_error(struct Scsi_Host *host) struct scsi_cmnd *scmd, *tmp; int nr_timedout = 0; - spin_lock_irqsave(ap_lock, flags); + spin_lock_irqsave(ap->lock, flags); list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) { struct ata_queued_cmd *qc; @@ -256,43 +257,49 @@ void ata_scsi_error(struct Scsi_Host *host) if (nr_timedout) __ata_port_freeze(ap); - spin_unlock_irqrestore(ap_lock, flags); + spin_unlock_irqrestore(ap->lock, flags); } else - spin_unlock_wait(ap_lock); + spin_unlock_wait(ap->lock); repeat: /* invoke error handler */ if (ap->ops->error_handler) { + /* process port resume request */ + ata_eh_handle_port_resume(ap); + /* fetch & clear EH info */ - spin_lock_irqsave(ap_lock, flags); + spin_lock_irqsave(ap->lock, flags); memset(&ap->eh_context, 0, sizeof(ap->eh_context)); ap->eh_context.i = ap->eh_info; memset(&ap->eh_info, 0, sizeof(ap->eh_info)); - ap->flags |= ATA_FLAG_EH_IN_PROGRESS; - ap->flags &= ~ATA_FLAG_EH_PENDING; + ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; + ap->pflags &= ~ATA_PFLAG_EH_PENDING; - spin_unlock_irqrestore(ap_lock, flags); + spin_unlock_irqrestore(ap->lock, flags); - /* invoke EH. if unloading, just finish failed qcs */ - if (!(ap->flags & ATA_FLAG_UNLOADING)) + /* invoke EH, skip if unloading or suspended */ + if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED))) ap->ops->error_handler(ap); else ata_eh_finish(ap); + /* process port suspend request */ + ata_eh_handle_port_suspend(ap); + /* Exception might have happend after ->error_handler * recovered the port but before this point. Repeat * EH in such case. */ - spin_lock_irqsave(ap_lock, flags); + spin_lock_irqsave(ap->lock, flags); - if (ap->flags & ATA_FLAG_EH_PENDING) { + if (ap->pflags & ATA_PFLAG_EH_PENDING) { if (--repeat_cnt) { ata_port_printk(ap, KERN_INFO, "EH pending after completion, " "repeating EH (cnt=%d)\n", repeat_cnt); - spin_unlock_irqrestore(ap_lock, flags); + spin_unlock_irqrestore(ap->lock, flags); goto repeat; } ata_port_printk(ap, KERN_ERR, "EH pending after %d " @@ -302,14 +309,14 @@ void ata_scsi_error(struct Scsi_Host *host) /* this run is complete, make sure EH info is clear */ memset(&ap->eh_info, 0, sizeof(ap->eh_info)); - /* Clear host_eh_scheduled while holding ap_lock such + /* Clear host_eh_scheduled while holding ap->lock such * that if exception occurs after this point but * before EH completion, SCSI midlayer will * re-initiate EH. */ host->host_eh_scheduled = 0; - spin_unlock_irqrestore(ap_lock, flags); + spin_unlock_irqrestore(ap->lock, flags); } else { WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL); ap->ops->eng_timeout(ap); @@ -321,24 +328,23 @@ void ata_scsi_error(struct Scsi_Host *host) scsi_eh_flush_done_q(&ap->eh_done_q); /* clean up */ - spin_lock_irqsave(ap_lock, flags); + spin_lock_irqsave(ap->lock, flags); - if (ap->flags & ATA_FLAG_LOADING) { - ap->flags &= ~ATA_FLAG_LOADING; - } else { - if (ap->flags & ATA_FLAG_SCSI_HOTPLUG) - queue_work(ata_aux_wq, &ap->hotplug_task); - if (ap->flags & ATA_FLAG_RECOVERED) - ata_port_printk(ap, KERN_INFO, "EH complete\n"); - } + if (ap->pflags & ATA_PFLAG_LOADING) + ap->pflags &= ~ATA_PFLAG_LOADING; + else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG) + queue_work(ata_aux_wq, &ap->hotplug_task); - ap->flags &= ~(ATA_FLAG_SCSI_HOTPLUG | ATA_FLAG_RECOVERED); + if (ap->pflags & ATA_PFLAG_RECOVERED) + ata_port_printk(ap, KERN_INFO, "EH complete\n"); + + ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED); /* tell wait_eh that we're done */ - ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS; + ap->pflags &= ~ATA_PFLAG_EH_IN_PROGRESS; wake_up_all(&ap->eh_wait_q); - spin_unlock_irqrestore(ap_lock, flags); + spin_unlock_irqrestore(ap->lock, flags); DPRINTK("EXIT\n"); } @@ -360,7 +366,7 @@ void ata_port_wait_eh(struct ata_port *ap) retry: spin_lock_irqsave(ap->lock, flags); - while (ap->flags & (ATA_FLAG_EH_PENDING | ATA_FLAG_EH_IN_PROGRESS)) { + while (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS)) { prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE); spin_unlock_irqrestore(ap->lock, flags); schedule(); @@ -489,7 +495,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc) WARN_ON(!ap->ops->error_handler); qc->flags |= ATA_QCFLAG_FAILED; - qc->ap->flags |= ATA_FLAG_EH_PENDING; + qc->ap->pflags |= ATA_PFLAG_EH_PENDING; /* The following will fail if timeout has already expired. * ata_scsi_error() takes care of such scmds on EH entry. @@ -513,7 +519,7 @@ void ata_port_schedule_eh(struct ata_port *ap) { WARN_ON(!ap->ops->error_handler); - ap->flags |= ATA_FLAG_EH_PENDING; + ap->pflags |= ATA_PFLAG_EH_PENDING; scsi_schedule_eh(ap->host); DPRINTK("port EH scheduled\n"); @@ -578,7 +584,7 @@ static void __ata_port_freeze(struct ata_port *ap) if (ap->ops->freeze) ap->ops->freeze(ap); - ap->flags |= ATA_FLAG_FROZEN; + ap->pflags |= ATA_PFLAG_FROZEN; DPRINTK("ata%u port frozen\n", ap->id); } @@ -646,7 +652,7 @@ void ata_eh_thaw_port(struct ata_port *ap) spin_lock_irqsave(ap->lock, flags); - ap->flags &= ~ATA_FLAG_FROZEN; + ap->pflags &= ~ATA_PFLAG_FROZEN; if (ap->ops->thaw) ap->ops->thaw(ap); @@ -731,7 +737,7 @@ static void ata_eh_detach_dev(struct ata_device *dev) if (ata_scsi_offline_dev(dev)) { dev->flags |= ATA_DFLAG_DETACHED; - ap->flags |= ATA_FLAG_SCSI_HOTPLUG; + ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; } /* clear per-dev EH actions */ @@ -758,10 +764,29 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, unsigned int action) { unsigned long flags; + struct ata_eh_info *ehi = &ap->eh_info; + struct ata_eh_context *ehc = &ap->eh_context; spin_lock_irqsave(ap->lock, flags); - ata_eh_clear_action(dev, &ap->eh_info, action); - ap->flags |= ATA_FLAG_RECOVERED; + + /* Reset is represented by combination of actions and EHI + * flags. Suck in all related bits before clearing eh_info to + * avoid losing requested action. + */ + if (action & ATA_EH_RESET_MASK) { + ehc->i.action |= ehi->action & ATA_EH_RESET_MASK; + ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK; + + /* make sure all reset actions are cleared & clear EHI flags */ + action |= ATA_EH_RESET_MASK; + ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK; + } + + ata_eh_clear_action(dev, ehi, action); + + if (!(ehc->i.flags & ATA_EHI_QUIET)) + ap->pflags |= ATA_PFLAG_RECOVERED; + spin_unlock_irqrestore(ap->lock, flags); } @@ -780,6 +805,12 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev, static void ata_eh_done(struct ata_port *ap, struct ata_device *dev, unsigned int action) { + /* if reset is complete, clear all reset actions & reset modifier */ + if (action & ATA_EH_RESET_MASK) { + action |= ATA_EH_RESET_MASK; + ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK; + } + ata_eh_clear_action(dev, &ap->eh_context.i, action); } @@ -1027,7 +1058,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap) int tag, rc; /* if frozen, we can't do much */ - if (ap->flags & ATA_FLAG_FROZEN) + if (ap->pflags & ATA_PFLAG_FROZEN) return; /* is it NCQ device error? */ @@ -1266,8 +1297,6 @@ static int ata_eh_speed_down(struct ata_device *dev, int is_io, static void ata_eh_autopsy(struct ata_port *ap) { struct ata_eh_context *ehc = &ap->eh_context; - unsigned int action = ehc->i.action; - struct ata_device *failed_dev = NULL; unsigned int all_err_mask = 0; int tag, is_io = 0; u32 serror; @@ -1275,13 +1304,16 @@ static void ata_eh_autopsy(struct ata_port *ap) DPRINTK("ENTER\n"); + if (ehc->i.flags & ATA_EHI_NO_AUTOPSY) + return; + /* obtain and analyze SError */ rc = sata_scr_read(ap, SCR_ERROR, &serror); if (rc == 0) { ehc->i.serror |= serror; ata_eh_analyze_serror(ap); } else if (rc != -EOPNOTSUPP) - action |= ATA_EH_HARDRESET; + ehc->i.action |= ATA_EH_HARDRESET; /* analyze NCQ failure */ ata_eh_analyze_ncq_error(ap); @@ -1302,7 +1334,7 @@ static void ata_eh_autopsy(struct ata_port *ap) qc->err_mask |= ehc->i.err_mask; /* analyze TF */ - action |= ata_eh_analyze_tf(qc, &qc->result_tf); + ehc->i.action |= ata_eh_analyze_tf(qc, &qc->result_tf); /* DEV errors are probably spurious in case of ATA_BUS error */ if (qc->err_mask & AC_ERR_ATA_BUS) @@ -1316,38 +1348,35 @@ static void ata_eh_autopsy(struct ata_port *ap) /* SENSE_VALID trumps dev/unknown error and revalidation */ if (qc->flags & ATA_QCFLAG_SENSE_VALID) { qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER); - action &= ~ATA_EH_REVALIDATE; + ehc->i.action &= ~ATA_EH_REVALIDATE; } /* accumulate error info */ - failed_dev = qc->dev; + ehc->i.dev = qc->dev; all_err_mask |= qc->err_mask; if (qc->flags & ATA_QCFLAG_IO) is_io = 1; } /* enforce default EH actions */ - if (ap->flags & ATA_FLAG_FROZEN || + if (ap->pflags & ATA_PFLAG_FROZEN || all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT)) - action |= ATA_EH_SOFTRESET; + ehc->i.action |= ATA_EH_SOFTRESET; else if (all_err_mask) - action |= ATA_EH_REVALIDATE; + ehc->i.action |= ATA_EH_REVALIDATE; /* if we have offending qcs and the associated failed device */ - if (failed_dev) { + if (ehc->i.dev) { /* speed down */ - action |= ata_eh_speed_down(failed_dev, is_io, all_err_mask); + ehc->i.action |= ata_eh_speed_down(ehc->i.dev, is_io, + all_err_mask); /* perform per-dev EH action only on the offending device */ - ehc->i.dev_action[failed_dev->devno] |= - action & ATA_EH_PERDEV_MASK; - action &= ~ATA_EH_PERDEV_MASK; + ehc->i.dev_action[ehc->i.dev->devno] |= + ehc->i.action & ATA_EH_PERDEV_MASK; + ehc->i.action &= ~ATA_EH_PERDEV_MASK; } - /* record autopsy result */ - ehc->i.dev = failed_dev; - ehc->i.action = action; - DPRINTK("EXIT\n"); } @@ -1385,7 +1414,7 @@ static void ata_eh_report(struct ata_port *ap) return; frozen = ""; - if (ap->flags & ATA_FLAG_FROZEN) + if (ap->pflags & ATA_PFLAG_FROZEN) frozen = " frozen"; if (ehc->i.dev) { @@ -1465,11 +1494,14 @@ static int ata_eh_reset(struct ata_port *ap, int classify, struct ata_eh_context *ehc = &ap->eh_context; unsigned int *classes = ehc->classes; int tries = ATA_EH_RESET_TRIES; - int verbose = !(ap->flags & ATA_FLAG_LOADING); + int verbose = !(ehc->i.flags & ATA_EHI_QUIET); unsigned int action; ata_reset_fn_t reset; int i, did_followup_srst, rc; + /* about to reset */ + ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); + /* Determine which reset to use and record in ehc->i.action. * prereset() may examine and modify it. */ @@ -1518,8 +1550,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, ata_port_printk(ap, KERN_INFO, "%s resetting port\n", reset == softreset ? "soft" : "hard"); - /* reset */ - ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK); + /* mark that this EH session started with reset */ ehc->i.flags |= ATA_EHI_DID_RESET; rc = ata_do_reset(ap, reset, classes); @@ -1582,7 +1613,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify, postreset(ap, classes); /* reset successful, schedule revalidation */ - ata_eh_done(ap, NULL, ATA_EH_RESET_MASK); + ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK); ehc->i.action |= ATA_EH_REVALIDATE; } @@ -1605,7 +1636,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, dev = &ap->device[i]; action = ata_eh_dev_action(dev); - if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) { + if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) { if (ata_port_offline(ap)) { rc = -EIO; break; @@ -1636,7 +1667,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, } spin_lock_irqsave(ap->lock, flags); - ap->flags |= ATA_FLAG_SCSI_HOTPLUG; + ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG; spin_unlock_irqrestore(ap->lock, flags); } } @@ -1648,6 +1679,164 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, return rc; } +/** + * ata_eh_suspend - handle suspend EH action + * @ap: target host port + * @r_failed_dev: result parameter to indicate failing device + * + * Handle suspend EH action. Disk devices are spinned down and + * other types of devices are just marked suspended. Once + * suspended, no EH action to the device is allowed until it is + * resumed. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise + */ +static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev) +{ + struct ata_device *dev; + int i, rc = 0; + + DPRINTK("ENTER\n"); + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + unsigned long flags; + unsigned int action, err_mask; + + dev = &ap->device[i]; + action = ata_eh_dev_action(dev); + + if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND)) + continue; + + WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED); + + ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND); + + if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) { + /* flush cache */ + rc = ata_flush_cache(dev); + if (rc) + break; + + /* spin down */ + err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1); + if (err_mask) { + ata_dev_printk(dev, KERN_ERR, "failed to " + "spin down (err_mask=0x%x)\n", + err_mask); + rc = -EIO; + break; + } + } + + spin_lock_irqsave(ap->lock, flags); + dev->flags |= ATA_DFLAG_SUSPENDED; + spin_unlock_irqrestore(ap->lock, flags); + + ata_eh_done(ap, dev, ATA_EH_SUSPEND); + } + + if (rc) + *r_failed_dev = dev; + + DPRINTK("EXIT\n"); + return 0; +} + +/** + * ata_eh_prep_resume - prep for resume EH action + * @ap: target host port + * + * Clear SUSPENDED in preparation for scheduled resume actions. + * This allows other parts of EH to access the devices being + * resumed. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +static void ata_eh_prep_resume(struct ata_port *ap) +{ + struct ata_device *dev; + unsigned long flags; + int i; + + DPRINTK("ENTER\n"); + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + unsigned int action; + + dev = &ap->device[i]; + action = ata_eh_dev_action(dev); + + if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME)) + continue; + + spin_lock_irqsave(ap->lock, flags); + dev->flags &= ~ATA_DFLAG_SUSPENDED; + spin_unlock_irqrestore(ap->lock, flags); + } + + DPRINTK("EXIT\n"); +} + +/** + * ata_eh_resume - handle resume EH action + * @ap: target host port + * @r_failed_dev: result parameter to indicate failing device + * + * Handle resume EH action. Target devices are already reset and + * revalidated. Spinning up is the only operation left. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise + */ +static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev) +{ + struct ata_device *dev; + int i, rc = 0; + + DPRINTK("ENTER\n"); + + for (i = 0; i < ATA_MAX_DEVICES; i++) { + unsigned int action, err_mask; + + dev = &ap->device[i]; + action = ata_eh_dev_action(dev); + + if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME)) + continue; + + ata_eh_about_to_do(ap, dev, ATA_EH_RESUME); + + if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) { + err_mask = ata_do_simple_cmd(dev, + ATA_CMD_IDLEIMMEDIATE); + if (err_mask) { + ata_dev_printk(dev, KERN_ERR, "failed to " + "spin up (err_mask=0x%x)\n", + err_mask); + rc = -EIO; + break; + } + } + + ata_eh_done(ap, dev, ATA_EH_RESUME); + } + + if (rc) + *r_failed_dev = dev; + + DPRINTK("EXIT\n"); + return 0; +} + static int ata_port_nr_enabled(struct ata_port *ap) { int i, cnt = 0; @@ -1673,7 +1862,20 @@ static int ata_eh_skip_recovery(struct ata_port *ap) struct ata_eh_context *ehc = &ap->eh_context; int i; - if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap)) + /* skip if all possible devices are suspended */ + for (i = 0; i < ata_port_max_devices(ap); i++) { + struct ata_device *dev = &ap->device[i]; + + if (!(dev->flags & ATA_DFLAG_SUSPENDED)) + break; + } + + if (i == ata_port_max_devices(ap)) + return 1; + + /* thaw frozen port, resume link and recover failed devices */ + if ((ap->pflags & ATA_PFLAG_FROZEN) || + (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap)) return 0; /* skip if class codes for all vacant slots are ATA_DEV_NONE */ @@ -1744,9 +1946,12 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, rc = 0; /* if UNLOADING, finish immediately */ - if (ap->flags & ATA_FLAG_UNLOADING) + if (ap->pflags & ATA_PFLAG_UNLOADING) goto out; + /* prep for resume */ + ata_eh_prep_resume(ap); + /* skip EH if possible. */ if (ata_eh_skip_recovery(ap)) ehc->i.action = 0; @@ -1774,6 +1979,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, if (rc) goto dev_fail; + /* resume devices */ + rc = ata_eh_resume(ap, &dev); + if (rc) + goto dev_fail; + /* configure transfer mode if the port has been reset */ if (ehc->i.flags & ATA_EHI_DID_RESET) { rc = ata_set_mode(ap, &dev); @@ -1783,6 +1993,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, } } + /* suspend devices */ + rc = ata_eh_suspend(ap, &dev); + if (rc) + goto dev_fail; + goto out; dev_fail: @@ -1908,11 +2123,124 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_reset_fn_t softreset, ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) { - if (!(ap->flags & ATA_FLAG_LOADING)) { - ata_eh_autopsy(ap); - ata_eh_report(ap); - } - + ata_eh_autopsy(ap); + ata_eh_report(ap); ata_eh_recover(ap, prereset, softreset, hardreset, postreset); ata_eh_finish(ap); } + +/** + * ata_eh_handle_port_suspend - perform port suspend operation + * @ap: port to suspend + * + * Suspend @ap. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +static void ata_eh_handle_port_suspend(struct ata_port *ap) +{ + unsigned long flags; + int rc = 0; + + /* are we suspending? */ + spin_lock_irqsave(ap->lock, flags); + if (!(ap->pflags & ATA_PFLAG_PM_PENDING) || + ap->pm_mesg.event == PM_EVENT_ON) { + spin_unlock_irqrestore(ap->lock, flags); + return; + } + spin_unlock_irqrestore(ap->lock, flags); + + WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED); + + /* suspend */ + ata_eh_freeze_port(ap); + + if (ap->ops->port_suspend) + rc = ap->ops->port_suspend(ap, ap->pm_mesg); + + /* report result */ + spin_lock_irqsave(ap->lock, flags); + + ap->pflags &= ~ATA_PFLAG_PM_PENDING; + if (rc == 0) + ap->pflags |= ATA_PFLAG_SUSPENDED; + else + ata_port_schedule_eh(ap); + + if (ap->pm_result) { + *ap->pm_result = rc; + ap->pm_result = NULL; + } + + spin_unlock_irqrestore(ap->lock, flags); + + return; +} + +/** + * ata_eh_handle_port_resume - perform port resume operation + * @ap: port to resume + * + * Resume @ap. + * + * This function also waits upto one second until all devices + * hanging off this port requests resume EH action. This is to + * prevent invoking EH and thus reset multiple times on resume. + * + * On DPM resume, where some of devices might not be resumed + * together, this may delay port resume upto one second, but such + * DPM resumes are rare and 1 sec delay isn't too bad. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +static void ata_eh_handle_port_resume(struct ata_port *ap) +{ + unsigned long timeout; + unsigned long flags; + int i, rc = 0; + + /* are we resuming? */ + spin_lock_irqsave(ap->lock, flags); + if (!(ap->pflags & ATA_PFLAG_PM_PENDING) || + ap->pm_mesg.event != PM_EVENT_ON) { + spin_unlock_irqrestore(ap->lock, flags); + return; + } + spin_unlock_irqrestore(ap->lock, flags); + + /* spurious? */ + if (!(ap->pflags & ATA_PFLAG_SUSPENDED)) + goto done; + + if (ap->ops->port_resume) + rc = ap->ops->port_resume(ap); + + /* give devices time to request EH */ + timeout = jiffies + HZ; /* 1s max */ + while (1) { + for (i = 0; i < ATA_MAX_DEVICES; i++) { + struct ata_device *dev = &ap->device[i]; + unsigned int action = ata_eh_dev_action(dev); + + if ((dev->flags & ATA_DFLAG_SUSPENDED) && + !(action & ATA_EH_RESUME)) + break; + } + + if (i == ATA_MAX_DEVICES || time_after(jiffies, timeout)) + break; + msleep(10); + } + + done: + spin_lock_irqsave(ap->lock, flags); + ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED); + if (ap->pm_result) { + *ap->pm_result = rc; + ap->pm_result = NULL; + } + spin_unlock_irqrestore(ap->lock, flags); +} diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 2915bca691e..e92c31d698f 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c @@ -397,20 +397,129 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf) } } -int ata_scsi_device_resume(struct scsi_device *sdev) +/** + * ata_scsi_device_suspend - suspend ATA device associated with sdev + * @sdev: the SCSI device to suspend + * @state: target power management state + * + * Request suspend EH action on the ATA device associated with + * @sdev and wait for the operation to complete. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state) { struct ata_port *ap = ata_shost_to_port(sdev->host); - struct ata_device *dev = __ata_scsi_find_dev(ap, sdev); + struct ata_device *dev = ata_scsi_find_dev(ap, sdev); + unsigned long flags; + unsigned int action; + int rc = 0; + + if (!dev) + goto out; + + spin_lock_irqsave(ap->lock, flags); + + /* wait for the previous resume to complete */ + while (dev->flags & ATA_DFLAG_SUSPENDED) { + spin_unlock_irqrestore(ap->lock, flags); + ata_port_wait_eh(ap); + spin_lock_irqsave(ap->lock, flags); + } + + /* if @sdev is already detached, nothing to do */ + if (sdev->sdev_state == SDEV_OFFLINE || + sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL) + goto out_unlock; + + /* request suspend */ + action = ATA_EH_SUSPEND; + if (state.event != PM_EVENT_SUSPEND) + action |= ATA_EH_PM_FREEZE; + ap->eh_info.dev_action[dev->devno] |= action; + ap->eh_info.flags |= ATA_EHI_QUIET; + ata_port_schedule_eh(ap); + + spin_unlock_irqrestore(ap->lock, flags); + + /* wait for EH to do the job */ + ata_port_wait_eh(ap); + + spin_lock_irqsave(ap->lock, flags); + + /* If @sdev is still attached but the associated ATA device + * isn't suspended, the operation failed. + */ + if (sdev->sdev_state != SDEV_OFFLINE && + sdev->sdev_state != SDEV_CANCEL && sdev->sdev_state != SDEV_DEL && + !(dev->flags & ATA_DFLAG_SUSPENDED)) + rc = -EIO; - return ata_device_resume(dev); + out_unlock: + spin_unlock_irqrestore(ap->lock, flags); + out: + if (rc == 0) + sdev->sdev_gendev.power.power_state = state; + return rc; } -int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state) +/** + * ata_scsi_device_resume - resume ATA device associated with sdev + * @sdev: the SCSI device to resume + * + * Request resume EH action on the ATA device associated with + * @sdev and return immediately. This enables parallel + * wakeup/spinup of devices. + * + * LOCKING: + * Kernel thread context (may sleep). + * + * RETURNS: + * 0. + */ +int ata_scsi_device_resume(struct scsi_device *sdev) { struct ata_port *ap = ata_shost_to_port(sdev->host); - struct ata_device *dev = __ata_scsi_find_dev(ap, sdev); + struct ata_device *dev = ata_scsi_find_dev(ap, sdev); + struct ata_eh_info *ehi = &ap->eh_info; + unsigned long flags; + unsigned int action; - return ata_device_suspend(dev, state); + if (!dev) + goto out; + + spin_lock_irqsave(ap->lock, flags); + + /* if @sdev is already detached, nothing to do */ + if (sdev->sdev_state == SDEV_OFFLINE || + sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL) + goto out_unlock; + + /* request resume */ + action = ATA_EH_RESUME; + if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND) + __ata_ehi_hotplugged(ehi); + else + action |= ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET; + ehi->dev_action[dev->devno] |= action; + + /* We don't want autopsy and verbose EH messages. Disable + * those if we're the only device on this link. + */ + if (ata_port_max_devices(ap) == 1) + ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET; + + ata_port_schedule_eh(ap); + + out_unlock: + spin_unlock_irqrestore(ap->lock, flags); + out: + sdev->sdev_gendev.power.power_state = PMSG_ON; + return 0; } /** @@ -2244,6 +2353,19 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) ata_gen_ata_desc_sense(qc); } + /* SCSI EH automatically locks door if sdev->locked is + * set. Sometimes door lock request continues to + * fail, for example, when no media is present. This + * creates a loop - SCSI EH issues door lock which + * fails and gets invoked again to acquire sense data + * for the failed command. + * + * If door lock fails, always clear sdev->locked to + * avoid this infinite loop. + */ + if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL) + qc->dev->sdev->locked = 0; + qc->scsicmd->result = SAM_STAT_CHECK_CONDITION; qc->scsidone(cmd); ata_qc_free(qc); @@ -2930,7 +3052,7 @@ void ata_scsi_hotplug(void *data) struct ata_port *ap = data; int i; - if (ap->flags & ATA_FLAG_UNLOADING) { + if (ap->pflags & ATA_PFLAG_UNLOADING) { DPRINTK("ENTER/EXIT - unloading\n"); return; } @@ -3011,6 +3133,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, if (dev) { ap->eh_info.probe_mask |= 1 << dev->devno; ap->eh_info.action |= ATA_EH_SOFTRESET; + ap->eh_info.flags |= ATA_EHI_RESUME_LINK; } else rc = -EINVAL; } diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 2673a11a949..5884cd26d53 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -189,6 +189,7 @@ static void iscsi_complete_command(struct iscsi_session *session, { struct scsi_cmnd *sc = ctask->sc; + ctask->state = ISCSI_TASK_COMPLETED; ctask->sc = NULL; list_del_init(&ctask->running); __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); @@ -275,6 +276,25 @@ out: return rc; } +static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) +{ + struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr; + + conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; + conn->tmfrsp_pdus_cnt++; + + if (conn->tmabort_state != TMABORT_INITIAL) + return; + + if (tmf->response == ISCSI_TMF_RSP_COMPLETE) + conn->tmabort_state = TMABORT_SUCCESS; + else if (tmf->response == ISCSI_TMF_RSP_NO_TASK) + conn->tmabort_state = TMABORT_NOT_FOUND; + else + conn->tmabort_state = TMABORT_FAILED; + wake_up(&conn->ehwait); +} + /** * __iscsi_complete_pdu - complete pdu * @conn: iscsi conn @@ -340,6 +360,10 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, switch(opcode) { case ISCSI_OP_LOGOUT_RSP: + if (datalen) { + rc = ISCSI_ERR_PROTO; + break; + } conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; /* fall through */ case ISCSI_OP_LOGIN_RSP: @@ -348,7 +372,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, * login related PDU's exp_statsn is handled in * userspace */ - rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen); + if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) + rc = ISCSI_ERR_CONN_FAILED; list_del(&mtask->running); if (conn->login_mtask != mtask) __kfifo_put(session->mgmtpool.queue, @@ -360,25 +385,17 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, break; } - conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; - conn->tmfrsp_pdus_cnt++; - if (conn->tmabort_state == TMABORT_INITIAL) { - conn->tmabort_state = - ((struct iscsi_tm_rsp *)hdr)-> - response == ISCSI_TMF_RSP_COMPLETE ? - TMABORT_SUCCESS:TMABORT_FAILED; - /* unblock eh_abort() */ - wake_up(&conn->ehwait); - } + iscsi_tmf_rsp(conn, hdr); break; case ISCSI_OP_NOOP_IN: - if (hdr->ttt != ISCSI_RESERVED_TAG) { + if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) { rc = ISCSI_ERR_PROTO; break; } conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; - rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen); + if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) + rc = ISCSI_ERR_CONN_FAILED; list_del(&mtask->running); if (conn->login_mtask != mtask) __kfifo_put(session->mgmtpool.queue, @@ -391,14 +408,21 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, } else if (itt == ISCSI_RESERVED_TAG) { switch(opcode) { case ISCSI_OP_NOOP_IN: - if (!datalen) { - rc = iscsi_check_assign_cmdsn(session, - (struct iscsi_nopin*)hdr); - if (!rc && hdr->ttt != ISCSI_RESERVED_TAG) - rc = iscsi_recv_pdu(conn->cls_conn, - hdr, NULL, 0); - } else + if (datalen) { rc = ISCSI_ERR_PROTO; + break; + } + + rc = iscsi_check_assign_cmdsn(session, + (struct iscsi_nopin*)hdr); + if (rc) + break; + + if (hdr->ttt == ISCSI_RESERVED_TAG) + break; + + if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0)) + rc = ISCSI_ERR_CONN_FAILED; break; case ISCSI_OP_REJECT: /* we need sth like iscsi_reject_rsp()*/ @@ -568,20 +592,24 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) } /* process command queue */ - while (__kfifo_get(conn->xmitqueue, (void*)&conn->ctask, - sizeof(void*))) { + spin_lock_bh(&conn->session->lock); + while (!list_empty(&conn->xmitqueue)) { /* * iscsi tcp may readd the task to the xmitqueue to send * write data */ - spin_lock_bh(&conn->session->lock); - if (list_empty(&conn->ctask->running)) - list_add_tail(&conn->ctask->running, &conn->run_list); + conn->ctask = list_entry(conn->xmitqueue.next, + struct iscsi_cmd_task, running); + conn->ctask->state = ISCSI_TASK_RUNNING; + list_move_tail(conn->xmitqueue.next, &conn->run_list); spin_unlock_bh(&conn->session->lock); + rc = tt->xmit_cmd_task(conn, conn->ctask); if (rc) goto again; + spin_lock_bh(&conn->session->lock); } + spin_unlock_bh(&conn->session->lock); /* done with this ctask */ conn->ctask = NULL; @@ -691,6 +719,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) sc->SCp.phase = session->age; sc->SCp.ptr = (char *)ctask; + ctask->state = ISCSI_TASK_PENDING; ctask->mtask = NULL; ctask->conn = conn; ctask->sc = sc; @@ -700,7 +729,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) session->tt->init_cmd_task(ctask); - __kfifo_put(conn->xmitqueue, (void*)&ctask, sizeof(void*)); + list_add_tail(&ctask->running, &conn->xmitqueue); debug_scsi( "ctask enq [%s cid %d sc %lx itt 0x%x len %d cmdsn %d win %d]\n", sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", @@ -977,31 +1006,27 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc, /* * xmit mutex and session lock must be held */ -#define iscsi_remove_task(tasktype) \ -static struct iscsi_##tasktype * \ -iscsi_remove_##tasktype(struct kfifo *fifo, uint32_t itt) \ -{ \ - int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); \ - struct iscsi_##tasktype *task; \ - \ - debug_scsi("searching %d tasks\n", nr_tasks); \ - \ - for (i = 0; i < nr_tasks; i++) { \ - __kfifo_get(fifo, (void*)&task, sizeof(void*)); \ - debug_scsi("check task %u\n", task->itt); \ - \ - if (task->itt == itt) { \ - debug_scsi("matched task\n"); \ - return task; \ - } \ - \ - __kfifo_put(fifo, (void*)&task, sizeof(void*)); \ - } \ - return NULL; \ -} +static struct iscsi_mgmt_task * +iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt) +{ + int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); + struct iscsi_mgmt_task *task; + + debug_scsi("searching %d tasks\n", nr_tasks); + + for (i = 0; i < nr_tasks; i++) { + __kfifo_get(fifo, (void*)&task, sizeof(void*)); + debug_scsi("check task %u\n", task->itt); -iscsi_remove_task(mgmt_task); -iscsi_remove_task(cmd_task); + if (task->itt == itt) { + debug_scsi("matched task\n"); + return task; + } + + __kfifo_put(fifo, (void*)&task, sizeof(void*)); + } + return NULL; +} static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) { @@ -1027,12 +1052,13 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, { struct scsi_cmnd *sc; - conn->session->tt->cleanup_cmd_task(conn, ctask); - iscsi_ctask_mtask_cleanup(ctask); - sc = ctask->sc; if (!sc) return; + + conn->session->tt->cleanup_cmd_task(conn, ctask); + iscsi_ctask_mtask_cleanup(ctask); + sc->result = err; sc->resid = sc->request_bufflen; iscsi_complete_command(conn->session, ctask); @@ -1043,7 +1069,6 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; struct iscsi_conn *conn = ctask->conn; struct iscsi_session *session = conn->session; - struct iscsi_cmd_task *pending_ctask; int rc; conn->eh_abort_cnt++; @@ -1061,8 +1086,11 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) goto failed; /* ctask completed before time out */ - if (!ctask->sc) - goto success; + if (!ctask->sc) { + spin_unlock_bh(&session->lock); + debug_scsi("sc completed while abort in progress\n"); + goto success_rel_mutex; + } /* what should we do here ? */ if (conn->ctask == ctask) { @@ -1071,17 +1099,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) goto failed; } - /* check for the easy pending cmd abort */ - pending_ctask = iscsi_remove_cmd_task(conn->xmitqueue, ctask->itt); - if (pending_ctask) { - /* iscsi_tcp queues write transfers on the xmitqueue */ - if (list_empty(&pending_ctask->running)) { - debug_scsi("found pending task\n"); - goto success; - } else - __kfifo_put(conn->xmitqueue, (void*)&pending_ctask, - sizeof(void*)); - } + if (ctask->state == ISCSI_TASK_PENDING) + goto success_cleanup; conn->tmabort_state = TMABORT_INITIAL; @@ -1089,25 +1108,31 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) rc = iscsi_exec_abort_task(sc, ctask); spin_lock_bh(&session->lock); - iscsi_ctask_mtask_cleanup(ctask); if (rc || sc->SCp.phase != session->age || session->state != ISCSI_STATE_LOGGED_IN) goto failed; + iscsi_ctask_mtask_cleanup(ctask); - /* ctask completed before tmf abort response */ - if (!ctask->sc) { - debug_scsi("sc completed while abort in progress\n"); - goto success; - } - - if (conn->tmabort_state != TMABORT_SUCCESS) { + switch (conn->tmabort_state) { + case TMABORT_SUCCESS: + goto success_cleanup; + case TMABORT_NOT_FOUND: + if (!ctask->sc) { + /* ctask completed before tmf abort response */ + spin_unlock_bh(&session->lock); + debug_scsi("sc completed while abort in progress\n"); + goto success_rel_mutex; + } + /* fall through */ + default: + /* timedout or failed */ spin_unlock_bh(&session->lock); iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); spin_lock_bh(&session->lock); goto failed; } -success: +success_cleanup: debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); spin_unlock_bh(&session->lock); @@ -1121,6 +1146,7 @@ success: spin_unlock(&session->lock); write_unlock_bh(conn->recv_lock); +success_rel_mutex: mutex_unlock(&conn->xmitmutex); return SUCCESS; @@ -1263,6 +1289,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, if (cmd_task_size) ctask->dd_data = &ctask[1]; ctask->itt = cmd_i; + INIT_LIST_HEAD(&ctask->running); } spin_lock_init(&session->lock); @@ -1282,18 +1309,24 @@ iscsi_session_setup(struct iscsi_transport *iscsit, if (mgmt_task_size) mtask->dd_data = &mtask[1]; mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i; + INIT_LIST_HEAD(&mtask->running); } if (scsi_add_host(shost, NULL)) goto add_host_fail; + if (!try_module_get(iscsit->owner)) + goto cls_session_fail; + cls_session = iscsi_create_session(shost, iscsit, 0); if (!cls_session) - goto cls_session_fail; + goto module_put; *(unsigned long*)shost->hostdata = (unsigned long)cls_session; return cls_session; +module_put: + module_put(iscsit->owner); cls_session_fail: scsi_remove_host(shost); add_host_fail: @@ -1317,14 +1350,18 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) { struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); struct iscsi_session *session = iscsi_hostdata(shost->hostdata); + struct module *owner = cls_session->transport->owner; scsi_remove_host(shost); iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); iscsi_pool_free(&session->cmdpool, (void**)session->cmds); + kfree(session->targetname); + iscsi_destroy_session(cls_session); scsi_host_put(shost); + module_put(owner); } EXPORT_SYMBOL_GPL(iscsi_session_teardown); @@ -1355,12 +1392,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) conn->tmabort_state = TMABORT_INITIAL; INIT_LIST_HEAD(&conn->run_list); INIT_LIST_HEAD(&conn->mgmt_run_list); - - /* initialize general xmit PDU commands queue */ - conn->xmitqueue = kfifo_alloc(session->cmds_max * sizeof(void*), - GFP_KERNEL, NULL); - if (conn->xmitqueue == ERR_PTR(-ENOMEM)) - goto xmitqueue_alloc_fail; + INIT_LIST_HEAD(&conn->xmitqueue); /* initialize general immediate & non-immediate PDU commands queue */ conn->immqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), @@ -1388,7 +1420,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL); if (!data) goto login_mtask_data_alloc_fail; - conn->login_mtask->data = data; + conn->login_mtask->data = conn->data = data; init_timer(&conn->tmabort_timer); mutex_init(&conn->xmitmutex); @@ -1404,8 +1436,6 @@ login_mtask_alloc_fail: mgmtqueue_alloc_fail: kfifo_free(conn->immqueue); immqueue_alloc_fail: - kfifo_free(conn->xmitqueue); -xmitqueue_alloc_fail: iscsi_destroy_conn(cls_conn); return NULL; } @@ -1426,12 +1456,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); mutex_lock(&conn->xmitmutex); - if (conn->c_stage == ISCSI_CONN_INITIAL_STAGE) { - if (session->tt->suspend_conn_recv) - session->tt->suspend_conn_recv(conn); - - session->tt->terminate_conn(conn); - } spin_lock_bh(&session->lock); conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; @@ -1468,7 +1492,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) } spin_lock_bh(&session->lock); - kfree(conn->login_mtask->data); + kfree(conn->data); + kfree(conn->persistent_address); __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, sizeof(void*)); list_del(&conn->item); @@ -1483,7 +1508,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1; spin_unlock_bh(&session->lock); - kfifo_free(conn->xmitqueue); kfifo_free(conn->immqueue); kfifo_free(conn->mgmtqueue); @@ -1566,7 +1590,7 @@ static void fail_all_commands(struct iscsi_conn *conn) struct iscsi_cmd_task *ctask, *tmp; /* flush pending */ - while (__kfifo_get(conn->xmitqueue, (void*)&ctask, sizeof(void*))) { + list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) { debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, ctask->itt); fail_command(conn, ctask, DID_BUS_BUSY << 16); @@ -1609,8 +1633,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); spin_unlock_bh(&session->lock); - if (session->tt->suspend_conn_recv) - session->tt->suspend_conn_recv(conn); + write_lock_bh(conn->recv_lock); + set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); + write_unlock_bh(conn->recv_lock); mutex_lock(&conn->xmitmutex); /* @@ -1629,7 +1654,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, } } - session->tt->terminate_conn(conn); /* * flush queues. */ @@ -1697,6 +1721,185 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session, } EXPORT_SYMBOL_GPL(iscsi_conn_bind); + +int iscsi_set_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf, int buflen) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_session *session = conn->session; + uint32_t value; + + switch(param) { + case ISCSI_PARAM_MAX_RECV_DLENGTH: + sscanf(buf, "%d", &conn->max_recv_dlength); + break; + case ISCSI_PARAM_MAX_XMIT_DLENGTH: + sscanf(buf, "%d", &conn->max_xmit_dlength); + break; + case ISCSI_PARAM_HDRDGST_EN: + sscanf(buf, "%d", &conn->hdrdgst_en); + break; + case ISCSI_PARAM_DATADGST_EN: + sscanf(buf, "%d", &conn->datadgst_en); + break; + case ISCSI_PARAM_INITIAL_R2T_EN: + sscanf(buf, "%d", &session->initial_r2t_en); + break; + case ISCSI_PARAM_MAX_R2T: + sscanf(buf, "%d", &session->max_r2t); + break; + case ISCSI_PARAM_IMM_DATA_EN: + sscanf(buf, "%d", &session->imm_data_en); + break; + case ISCSI_PARAM_FIRST_BURST: + sscanf(buf, "%d", &session->first_burst); + break; + case ISCSI_PARAM_MAX_BURST: + sscanf(buf, "%d", &session->max_burst); + break; + case ISCSI_PARAM_PDU_INORDER_EN: + sscanf(buf, "%d", &session->pdu_inorder_en); + break; + case ISCSI_PARAM_DATASEQ_INORDER_EN: + sscanf(buf, "%d", &session->dataseq_inorder_en); + break; + case ISCSI_PARAM_ERL: + sscanf(buf, "%d", &session->erl); + break; + case ISCSI_PARAM_IFMARKER_EN: + sscanf(buf, "%d", &value); + BUG_ON(value); + break; + case ISCSI_PARAM_OFMARKER_EN: + sscanf(buf, "%d", &value); + BUG_ON(value); + break; + case ISCSI_PARAM_EXP_STATSN: + sscanf(buf, "%u", &conn->exp_statsn); + break; + case ISCSI_PARAM_TARGET_NAME: + /* this should not change between logins */ + if (session->targetname) + break; + + session->targetname = kstrdup(buf, GFP_KERNEL); + if (!session->targetname) + return -ENOMEM; + break; + case ISCSI_PARAM_TPGT: + sscanf(buf, "%d", &session->tpgt); + break; + case ISCSI_PARAM_PERSISTENT_PORT: + sscanf(buf, "%d", &conn->persistent_port); + break; + case ISCSI_PARAM_PERSISTENT_ADDRESS: + /* + * this is the address returned in discovery so it should + * not change between logins. + */ + if (conn->persistent_address) + break; + + conn->persistent_address = kstrdup(buf, GFP_KERNEL); + if (!conn->persistent_address) + return -ENOMEM; + break; + default: + return -ENOSYS; + } + + return 0; +} +EXPORT_SYMBOL_GPL(iscsi_set_param); + +int iscsi_session_get_param(struct iscsi_cls_session *cls_session, + enum iscsi_param param, char *buf) +{ + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + struct iscsi_session *session = iscsi_hostdata(shost->hostdata); + int len; + + switch(param) { + case ISCSI_PARAM_INITIAL_R2T_EN: + len = sprintf(buf, "%d\n", session->initial_r2t_en); + break; + case ISCSI_PARAM_MAX_R2T: + len = sprintf(buf, "%hu\n", session->max_r2t); + break; + case ISCSI_PARAM_IMM_DATA_EN: + len = sprintf(buf, "%d\n", session->imm_data_en); + break; + case ISCSI_PARAM_FIRST_BURST: + len = sprintf(buf, "%u\n", session->first_burst); + break; + case ISCSI_PARAM_MAX_BURST: + len = sprintf(buf, "%u\n", session->max_burst); + break; + case ISCSI_PARAM_PDU_INORDER_EN: + len = sprintf(buf, "%d\n", session->pdu_inorder_en); + break; + case ISCSI_PARAM_DATASEQ_INORDER_EN: + len = sprintf(buf, "%d\n", session->dataseq_inorder_en); + break; + case ISCSI_PARAM_ERL: + len = sprintf(buf, "%d\n", session->erl); + break; + case ISCSI_PARAM_TARGET_NAME: + len = sprintf(buf, "%s\n", session->targetname); + break; + case ISCSI_PARAM_TPGT: + len = sprintf(buf, "%d\n", session->tpgt); + break; + default: + return -ENOSYS; + } + + return len; +} +EXPORT_SYMBOL_GPL(iscsi_session_get_param); + +int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + int len; + + switch(param) { + case ISCSI_PARAM_MAX_RECV_DLENGTH: + len = sprintf(buf, "%u\n", conn->max_recv_dlength); + break; + case ISCSI_PARAM_MAX_XMIT_DLENGTH: + len = sprintf(buf, "%u\n", conn->max_xmit_dlength); + break; + case ISCSI_PARAM_HDRDGST_EN: + len = sprintf(buf, "%d\n", conn->hdrdgst_en); + break; + case ISCSI_PARAM_DATADGST_EN: + len = sprintf(buf, "%d\n", conn->datadgst_en); + break; + case ISCSI_PARAM_IFMARKER_EN: + len = sprintf(buf, "%d\n", conn->ifmarker_en); + break; + case ISCSI_PARAM_OFMARKER_EN: + len = sprintf(buf, "%d\n", conn->ofmarker_en); + break; + case ISCSI_PARAM_EXP_STATSN: + len = sprintf(buf, "%u\n", conn->exp_statsn); + break; + case ISCSI_PARAM_PERSISTENT_PORT: + len = sprintf(buf, "%d\n", conn->persistent_port); + break; + case ISCSI_PARAM_PERSISTENT_ADDRESS: + len = sprintf(buf, "%s\n", conn->persistent_address); + break; + default: + return -ENOSYS; + } + + return len; +} +EXPORT_SYMBOL_GPL(iscsi_conn_get_param); + MODULE_AUTHOR("Mike Christie"); MODULE_DESCRIPTION("iSCSI library functions"); MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 087c44539a1..d44f9aac6b8 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -21,10 +21,12 @@ struct lpfc_sli2_slim; -#define LPFC_MAX_TARGET 256 /* max targets supported */ -#define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els req */ -#define LPFC_MAX_NS_RETRY 3 /* max NameServer retries */ +#define LPFC_MAX_TARGET 256 /* 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 + the NameServer before giving up. */ #define LPFC_DFT_HBA_Q_DEPTH 2048 /* max cmds per hba */ #define LPFC_LC_HBA_Q_DEPTH 1024 /* max cmds per low cost hba */ #define LPFC_LP101_HBA_Q_DEPTH 128 /* max cmds per low cost hba */ @@ -41,7 +43,6 @@ struct lpfc_sli2_slim; (( (u64)(high)<<16 ) << 16)|( (u64)(low)))) /* Provide maximum configuration definitions. */ #define LPFC_DRVR_TIMEOUT 16 /* driver iocb timeout value in sec */ -#define MAX_FCP_TARGET 256 /* max num of FCP targets supported */ #define FC_MAX_ADPTMSG 64 #define MAX_HBAEVT 32 @@ -174,7 +175,6 @@ struct lpfc_hba { dma_addr_t slim2p_mapping; uint16_t pci_cfg_value; - struct semaphore hba_can_block; int32_t hba_state; #define LPFC_STATE_UNKNOWN 0 /* HBA state is unknown */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index b62a72dfab2..d384c16f4a8 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -219,8 +219,18 @@ lpfc_issue_lip(struct Scsi_Host *host) return -ENOMEM; memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); - lpfc_init_link(phba, pmboxq, phba->cfg_topology, phba->cfg_link_speed); - mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); + pmboxq->mb.mbxCommand = MBX_DOWN_LINK; + pmboxq->mb.mbxOwner = OWN_HOST; + + mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2); + + if ((mbxstatus == MBX_SUCCESS) && (pmboxq->mb.mbxStatus == 0)) { + memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); + lpfc_init_link(phba, pmboxq, phba->cfg_topology, + phba->cfg_link_speed); + mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, + phba->fc_ratov * 2); + } if (mbxstatus == MBX_TIMEOUT) pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; @@ -233,51 +243,53 @@ lpfc_issue_lip(struct Scsi_Host *host) return 0; } -static ssize_t -lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf) +static int +lpfc_selective_reset(struct lpfc_hba *phba) { - struct Scsi_Host *host = class_to_shost(cdev); - struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; - return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt); + struct completion online_compl; + int status = 0; + + init_completion(&online_compl); + lpfc_workq_post_event(phba, &status, &online_compl, + LPFC_EVT_OFFLINE); + wait_for_completion(&online_compl); + + if (status != 0) + return -EIO; + + init_completion(&online_compl); + lpfc_workq_post_event(phba, &status, &online_compl, + LPFC_EVT_ONLINE); + wait_for_completion(&online_compl); + + if (status != 0) + return -EIO; + + return 0; } static ssize_t -lpfc_board_online_show(struct class_device *cdev, char *buf) +lpfc_issue_reset(struct class_device *cdev, const char *buf, size_t count) { struct Scsi_Host *host = class_to_shost(cdev); struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; + int status = -EINVAL; - if (phba->fc_flag & FC_OFFLINE_MODE) - return snprintf(buf, PAGE_SIZE, "0\n"); + if (strncmp(buf, "selective", sizeof("selective") - 1) == 0) + status = lpfc_selective_reset(phba); + + if (status == 0) + return strlen(buf); else - return snprintf(buf, PAGE_SIZE, "1\n"); + return status; } static ssize_t -lpfc_board_online_store(struct class_device *cdev, const char *buf, - size_t count) +lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf) { struct Scsi_Host *host = class_to_shost(cdev); struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; - struct completion online_compl; - int val=0, status=0; - - if (sscanf(buf, "%d", &val) != 1) - return -EINVAL; - - init_completion(&online_compl); - - if (val) - lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_ONLINE); - else - lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_OFFLINE); - wait_for_completion(&online_compl); - if (!status) - return strlen(buf); - else - return -EIO; + return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt); } static ssize_t @@ -532,10 +544,9 @@ static CLASS_DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show, NULL); static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show, NULL); -static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR, - lpfc_board_online_show, lpfc_board_online_store); static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR, lpfc_board_mode_show, lpfc_board_mode_store); +static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset); static int lpfc_poll = 0; module_param(lpfc_poll, int, 0); @@ -695,12 +706,12 @@ LPFC_ATTR(discovery_threads, 32, 1, 64, "Maximum number of ELS commands " "during discovery"); /* -# lpfc_max_luns: maximum number of LUNs per target driver will support -# Value range is [1,32768]. Default value is 256. -# NOTE: The SCSI layer will scan each target for this many luns +# lpfc_max_luns: maximum allowed LUN. +# Value range is [0,65535]. Default value is 255. +# NOTE: The SCSI layer might probe all allowed LUN on some old targets. */ -LPFC_ATTR_R(max_luns, 256, 1, 32768, - "Maximum number of LUNs per target driver will support"); +LPFC_ATTR_R(max_luns, 255, 0, 65535, + "Maximum allowed LUN"); /* # lpfc_poll_tmo: .Milliseconds driver will wait between polling FCP ring. @@ -739,8 +750,8 @@ struct class_device_attribute *lpfc_host_attrs[] = { &class_device_attr_lpfc_max_luns, &class_device_attr_nport_evt_cnt, &class_device_attr_management_version, - &class_device_attr_board_online, &class_device_attr_board_mode, + &class_device_attr_issue_reset, &class_device_attr_lpfc_poll, &class_device_attr_lpfc_poll_tmo, NULL, @@ -873,7 +884,7 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count) phba->sysfs_mbox.mbox == NULL ) { sysfs_mbox_idle(phba); spin_unlock_irq(host->host_lock); - return -EINVAL; + return -EAGAIN; } } @@ -989,14 +1000,15 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) spin_unlock_irq(phba->host->host_lock); rc = lpfc_sli_issue_mbox_wait (phba, phba->sysfs_mbox.mbox, - phba->fc_ratov * 2); + lpfc_mbox_tmo_val(phba, + phba->sysfs_mbox.mbox->mb.mbxCommand) * HZ); spin_lock_irq(phba->host->host_lock); } if (rc != MBX_SUCCESS) { sysfs_mbox_idle(phba); spin_unlock_irq(host->host_lock); - return -ENODEV; + return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; } phba->sysfs_mbox.state = SMBOX_READING; } @@ -1005,7 +1017,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) printk(KERN_WARNING "mbox_read: Bad State\n"); sysfs_mbox_idle(phba); spin_unlock_irq(host->host_lock); - return -EINVAL; + return -EAGAIN; } memcpy(buf, (uint8_t *) & phba->sysfs_mbox.mbox->mb + off, count); @@ -1199,8 +1211,10 @@ lpfc_get_stats(struct Scsi_Host *shost) struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; struct lpfc_sli *psli = &phba->sli; struct fc_host_statistics *hs = &phba->link_stats; + struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets; LPFC_MBOXQ_t *pmboxq; MAILBOX_t *pmb; + unsigned long seconds; int rc = 0; pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -1261,22 +1275,103 @@ lpfc_get_stats(struct Scsi_Host *shost) hs->invalid_crc_count = pmb->un.varRdLnk.crcCnt; hs->error_frames = pmb->un.varRdLnk.crcCnt; + hs->link_failure_count -= lso->link_failure_count; + hs->loss_of_sync_count -= lso->loss_of_sync_count; + hs->loss_of_signal_count -= lso->loss_of_signal_count; + hs->prim_seq_protocol_err_count -= lso->prim_seq_protocol_err_count; + hs->invalid_tx_word_count -= lso->invalid_tx_word_count; + hs->invalid_crc_count -= lso->invalid_crc_count; + hs->error_frames -= lso->error_frames; + if (phba->fc_topology == TOPOLOGY_LOOP) { hs->lip_count = (phba->fc_eventTag >> 1); + hs->lip_count -= lso->link_events; hs->nos_count = -1; } else { hs->lip_count = -1; hs->nos_count = (phba->fc_eventTag >> 1); + hs->nos_count -= lso->link_events; } hs->dumped_frames = -1; -/* FIX ME */ - /*hs->SecondsSinceLastReset = (jiffies - lpfc_loadtime) / HZ;*/ + seconds = get_seconds(); + if (seconds < psli->stats_start) + hs->seconds_since_last_reset = seconds + + ((unsigned long)-1 - psli->stats_start); + else + hs->seconds_since_last_reset = seconds - psli->stats_start; return hs; } +static void +lpfc_reset_stats(struct Scsi_Host *shost) +{ + struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; + struct lpfc_sli *psli = &phba->sli; + struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets; + LPFC_MBOXQ_t *pmboxq; + MAILBOX_t *pmb; + int rc = 0; + + pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!pmboxq) + return; + memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); + + pmb = &pmboxq->mb; + pmb->mbxCommand = MBX_READ_STATUS; + pmb->mbxOwner = OWN_HOST; + pmb->un.varWords[0] = 0x1; /* reset request */ + pmboxq->context1 = NULL; + + if ((phba->fc_flag & FC_OFFLINE_MODE) || + (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) + rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); + else + rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); + + if (rc != MBX_SUCCESS) { + if (rc == MBX_TIMEOUT) + pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + else + mempool_free(pmboxq, phba->mbox_mem_pool); + return; + } + + memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); + pmb->mbxCommand = MBX_READ_LNK_STAT; + pmb->mbxOwner = OWN_HOST; + pmboxq->context1 = NULL; + + if ((phba->fc_flag & FC_OFFLINE_MODE) || + (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) + rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); + else + rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); + + if (rc != MBX_SUCCESS) { + if (rc == MBX_TIMEOUT) + pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + else + mempool_free( pmboxq, phba->mbox_mem_pool); + return; + } + + lso->link_failure_count = pmb->un.varRdLnk.linkFailureCnt; + lso->loss_of_sync_count = pmb->un.varRdLnk.lossSyncCnt; + lso->loss_of_signal_count = pmb->un.varRdLnk.lossSignalCnt; + lso->prim_seq_protocol_err_count = pmb->un.varRdLnk.primSeqErrCnt; + lso->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord; + lso->invalid_crc_count = pmb->un.varRdLnk.crcCnt; + lso->error_frames = pmb->un.varRdLnk.crcCnt; + lso->link_events = (phba->fc_eventTag >> 1); + + psli->stats_start = get_seconds(); + + return; +} /* * The LPFC driver treats linkdown handling as target loss events so there @@ -1420,8 +1515,7 @@ struct fc_function_template lpfc_transport_functions = { */ .get_fc_host_stats = lpfc_get_stats, - - /* the LPFC driver doesn't support resetting stats yet */ + .reset_fc_host_stats = lpfc_reset_stats, .dd_fcrport_size = sizeof(struct lpfc_rport_data), .show_rport_maxframe_size = 1, diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index ee22173fce4..2a176467f71 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -127,6 +127,7 @@ void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *); LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *); +int lpfc_mbox_tmo_val(struct lpfc_hba *, int); int lpfc_mem_alloc(struct lpfc_hba *); void lpfc_mem_free(struct lpfc_hba *); @@ -147,6 +148,7 @@ int lpfc_sli_hba_setup(struct lpfc_hba *); int lpfc_sli_hba_down(struct lpfc_hba *); int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); int lpfc_sli_handle_mb_event(struct lpfc_hba *); +int lpfc_sli_flush_mbox_queue(struct lpfc_hba *); int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *, struct lpfc_sli_ring *, uint32_t); void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index b65ee57af53..bbb7310210b 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -131,6 +131,7 @@ lpfc_ct_unsol_event(struct lpfc_hba * phba, } ct_unsol_event_exit_piocbq: + list_del(&head); if (pmbuf) { list_for_each_entry_safe(matp, next_matp, &pmbuf->list, list) { lpfc_mbuf_free(phba, matp->virt, matp->phys); @@ -481,7 +482,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, if (CTrsp->CommandResponse.bits.CmdRsp == be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) { lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0239 NameServer Rsp " + "%d:0208 NameServer Rsp " "Data: x%x\n", phba->brd_no, phba->fc_flag); @@ -588,13 +589,9 @@ lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp) lpfc_decode_firmware_rev(phba, fwrev, 0); - if (phba->Port[0]) { - sprintf(symbp, "Emulex %s Port %s FV%s DV%s", phba->ModelName, - phba->Port, fwrev, lpfc_release_version); - } else { - sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName, - fwrev, lpfc_release_version); - } + sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName, + fwrev, lpfc_release_version); + return; } /* diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 283b7d824c3..3567de61316 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -648,33 +648,32 @@ lpfc_more_plogi(struct lpfc_hba * phba) } static struct lpfc_nodelist * -lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, +lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp, struct lpfc_nodelist *ndlp) { struct lpfc_nodelist *new_ndlp; - struct lpfc_dmabuf *pcmd, *prsp; uint32_t *lp; struct serv_parm *sp; uint8_t name[sizeof (struct lpfc_name)]; uint32_t rc; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - prsp = (struct lpfc_dmabuf *) pcmd->list.next; lp = (uint32_t *) prsp->virt; sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); + memset(name, 0, sizeof (struct lpfc_name)); /* Now we to find out if the NPort we are logging into, matches the WWPN * we have for that ndlp. If not, we have some work to do. */ new_ndlp = lpfc_findnode_wwpn(phba, NLP_SEARCH_ALL, &sp->portName); - memset(name, 0, sizeof (struct lpfc_name)); - rc = memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)); - if (!rc || (new_ndlp == ndlp)) { + if (new_ndlp == ndlp) return ndlp; - } if (!new_ndlp) { + rc = + memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)); + if (!rc) + return ndlp; new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC); if (!new_ndlp) return ndlp; @@ -683,17 +682,21 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, } lpfc_unreg_rpi(phba, new_ndlp); - new_ndlp->nlp_prev_state = ndlp->nlp_state; new_ndlp->nlp_DID = ndlp->nlp_DID; - new_ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_list(phba, new_ndlp, NLP_PLOGI_LIST); + new_ndlp->nlp_prev_state = ndlp->nlp_prev_state; + new_ndlp->nlp_state = ndlp->nlp_state; + lpfc_nlp_list(phba, new_ndlp, ndlp->nlp_flag & NLP_LIST_MASK); /* Move this back to NPR list */ - lpfc_unreg_rpi(phba, ndlp); - ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */ - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); - + if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) { + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + } + else { + lpfc_unreg_rpi(phba, ndlp); + ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */ + ndlp->nlp_state = NLP_STE_NPR_NODE; + lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + } return new_ndlp; } @@ -703,6 +706,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, { IOCB_t *irsp; struct lpfc_nodelist *ndlp; + struct lpfc_dmabuf *prsp; int disc, rc, did, type; @@ -769,7 +773,10 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, } } else { /* Good status, call state machine */ - ndlp = lpfc_plogi_confirm_nport(phba, cmdiocb, ndlp); + prsp = list_entry(((struct lpfc_dmabuf *) + cmdiocb->context2)->list.next, + struct lpfc_dmabuf, list); + ndlp = lpfc_plogi_confirm_nport(phba, prsp, ndlp); rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_PLOGI); } @@ -821,7 +828,7 @@ lpfc_issue_els_plogi(struct lpfc_hba * phba, uint32_t did, uint8_t retry) pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm)); - elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, 0, did, + elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, NULL, did, ELS_CMD_PLOGI); if (!elsiocb) return 1; @@ -1841,9 +1848,12 @@ static void lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb) { + IOCB_t *irsp; struct lpfc_nodelist *ndlp; LPFC_MBOXQ_t *mbox = NULL; + irsp = &rspiocb->iocb; + ndlp = (struct lpfc_nodelist *) cmdiocb->context1; if (cmdiocb->context_un.mbox) mbox = cmdiocb->context_un.mbox; @@ -1886,9 +1896,15 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, mempool_free( mbox, phba->mbox_mem_pool); } else { mempool_free( mbox, phba->mbox_mem_pool); - if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - ndlp = NULL; + /* Do not call NO_LIST for lpfc_els_abort'ed ELS cmds */ + if (!((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && + ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) || + (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) || + (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) { + if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) { + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + ndlp = NULL; + } } } } @@ -2791,8 +2807,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) ndlp = (struct lpfc_nodelist *) pmb->context2; xri = (uint16_t) ((unsigned long)(pmb->context1)); - pmb->context1 = 0; - pmb->context2 = 0; + pmb->context1 = NULL; + pmb->context2 = NULL; if (mb->mbxStatus) { mempool_free( pmb, phba->mbox_mem_pool); @@ -2832,7 +2848,7 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) /* Xmit ELS RPS ACC response tag <ulpIoTag> */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "%d:0128 Xmit ELS RPS ACC response tag x%x " + "%d:0118 Xmit ELS RPS ACC response tag x%x " "Data: x%x x%x x%x x%x x%x\n", phba->brd_no, elsiocb->iocb.ulpIoTag, @@ -2941,7 +2957,7 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize, /* Xmit ELS RPL ACC response tag <ulpIoTag> */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "%d:0128 Xmit ELS RPL ACC response tag x%x " + "%d:0120 Xmit ELS RPL ACC response tag x%x " "Data: x%x x%x x%x x%x x%x\n", phba->brd_no, elsiocb->iocb.ulpIoTag, @@ -3102,7 +3118,7 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist *ndlp, *next_ndlp; /* FAN received */ - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:265 FAN received\n", + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0265 FAN received\n", phba->brd_no); icmd = &cmdiocb->iocb; @@ -3282,10 +3298,9 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) } else lpfc_sli_release_iocbq(phba, piocb); } - if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) { - phba->els_tmofunc.expires = jiffies + HZ * timeout; - add_timer(&phba->els_tmofunc); - } + if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) + mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout); + spin_unlock_irq(phba->host->host_lock); } @@ -3442,6 +3457,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba, if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) { ndlp->nlp_type |= NLP_FABRIC; } + ndlp->nlp_state = NLP_STE_UNUSED_NODE; + lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST); } phba->fc_stat.elsRcvFrame++; @@ -3463,13 +3480,14 @@ lpfc_els_unsol_event(struct lpfc_hba * phba, rjt_err = 1; break; } + ndlp = lpfc_plogi_confirm_nport(phba, mp, ndlp); lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PLOGI); break; case ELS_CMD_FLOGI: phba->fc_stat.elsRcvFLOGI++; lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode); if (newnode) { - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); } break; case ELS_CMD_LOGO: @@ -3492,7 +3510,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba, phba->fc_stat.elsRcvRSCN++; lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode); if (newnode) { - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); } break; case ELS_CMD_ADISC: @@ -3535,28 +3553,28 @@ lpfc_els_unsol_event(struct lpfc_hba * phba, phba->fc_stat.elsRcvLIRR++; lpfc_els_rcv_lirr(phba, elsiocb, ndlp); if (newnode) { - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); } break; case ELS_CMD_RPS: phba->fc_stat.elsRcvRPS++; lpfc_els_rcv_rps(phba, elsiocb, ndlp); if (newnode) { - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); } break; case ELS_CMD_RPL: phba->fc_stat.elsRcvRPL++; lpfc_els_rcv_rpl(phba, elsiocb, ndlp); if (newnode) { - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); } break; case ELS_CMD_RNID: phba->fc_stat.elsRcvRNID++; lpfc_els_rcv_rnid(phba, elsiocb, ndlp); if (newnode) { - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); } break; default: @@ -3568,7 +3586,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba, "%d:0115 Unknown ELS command x%x received from " "NPORT x%x\n", phba->brd_no, cmd, did); if (newnode) { - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); } break; } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index adb086009ae..b2f1552f184 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1084,7 +1084,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba, fc_remote_port_rolechg(rport, rport_ids.roles); if ((rport->scsi_target_id != -1) && - (rport->scsi_target_id < MAX_FCP_TARGET)) { + (rport->scsi_target_id < LPFC_MAX_TARGET)) { ndlp->nlp_sid = rport->scsi_target_id; } @@ -1313,7 +1313,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) if ((rport_add == mapped) && ((!nlp->rport) || (nlp->rport->scsi_target_id == -1) || - (nlp->rport->scsi_target_id >= MAX_FCP_TARGET))) { + (nlp->rport->scsi_target_id >= LPFC_MAX_TARGET))) { nlp->nlp_state = NLP_STE_UNMAPPED_NODE; spin_lock_irq(phba->host->host_lock); nlp->nlp_flag |= NLP_TGT_NO_SCSIID; @@ -1557,6 +1557,8 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; } } + + spin_lock_irq(phba->host->host_lock); list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) && (ndlp == (struct lpfc_nodelist *) mb->context2)) { @@ -1569,6 +1571,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) mempool_free(mb, phba->mbox_mem_pool); } } + spin_unlock_irq(phba->host->host_lock); lpfc_els_abort(phba,ndlp,0); spin_lock_irq(phba->host->host_lock); @@ -1782,7 +1785,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did) /* LOG change to REGLOGIN */ /* FIND node DID reglogin */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID reglogin" + "%d:0901 FIND node DID reglogin" " Data: x%p x%x x%x x%x\n", phba->brd_no, ndlp, ndlp->nlp_DID, @@ -1805,7 +1808,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did) /* LOG change to PRLI */ /* FIND node DID prli */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID prli " + "%d:0902 FIND node DID prli " "Data: x%p x%x x%x x%x\n", phba->brd_no, ndlp, ndlp->nlp_DID, @@ -1828,7 +1831,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did) /* LOG change to NPR */ /* FIND node DID npr */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID npr " + "%d:0903 FIND node DID npr " "Data: x%p x%x x%x x%x\n", phba->brd_no, ndlp, ndlp->nlp_DID, @@ -1851,7 +1854,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did) /* LOG change to UNUSED */ /* FIND node DID unused */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID unused " + "%d:0905 FIND node DID unused " "Data: x%p x%x x%x x%x\n", phba->brd_no, ndlp, ndlp->nlp_DID, @@ -2335,7 +2338,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!initlinkmbox) { lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0226 Device Discovery " + "%d:0206 Device Discovery " "completion error\n", phba->brd_no); phba->hba_state = LPFC_HBA_ERROR; @@ -2365,7 +2368,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) if (!clearlambox) { clrlaerr = 1; lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0226 Device Discovery " + "%d:0207 Device Discovery " "completion error\n", phba->brd_no); phba->hba_state = LPFC_HBA_ERROR; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 5a28d9bf8e4..f6948ffe689 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -71,6 +71,7 @@ lpfc_config_port_prep(struct lpfc_hba * phba) uint16_t offset = 0; static char licensed[56] = "key unlock for use with gnu public licensed code only\0"; + static int init_key = 1; pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmb) { @@ -82,10 +83,13 @@ lpfc_config_port_prep(struct lpfc_hba * phba) phba->hba_state = LPFC_INIT_MBX_CMDS; if (lpfc_is_LC_HBA(phba->pcidev->device)) { - uint32_t *ptext = (uint32_t *) licensed; + if (init_key) { + uint32_t *ptext = (uint32_t *) licensed; - for (i = 0; i < 56; i += sizeof (uint32_t), ptext++) - *ptext = cpu_to_be32(*ptext); + for (i = 0; i < 56; i += sizeof (uint32_t), ptext++) + *ptext = cpu_to_be32(*ptext); + init_key = 0; + } lpfc_read_nv(phba, pmb); memset((char*)mb->un.varRDnvp.rsvd3, 0, @@ -405,19 +409,26 @@ lpfc_config_port_post(struct lpfc_hba * phba) } /* MBOX buffer will be freed in mbox compl */ - i = 0; + return (0); +} + +static int +lpfc_discovery_wait(struct lpfc_hba *phba) +{ + int i = 0; + while ((phba->hba_state != LPFC_HBA_READY) || (phba->num_disc_nodes) || (phba->fc_prli_sent) || ((phba->fc_map_cnt == 0) && (i<2)) || - (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE)) { + (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)) { /* Check every second for 30 retries. */ i++; if (i > 30) { - break; + return -ETIMEDOUT; } if ((i >= 15) && (phba->hba_state <= LPFC_LINK_DOWN)) { /* The link is down. Set linkdown timeout */ - break; + return -ETIMEDOUT; } /* Delay for 1 second to give discovery time to complete. */ @@ -425,12 +436,7 @@ lpfc_config_port_post(struct lpfc_hba * phba) } - /* Since num_disc_nodes keys off of PLOGI, delay a bit to let - * any potential PRLIs to flush thru the SLI sub-system. - */ - msleep(50); - - return (0); + return 0; } /************************************************************************/ @@ -939,12 +945,12 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) "10-port ", "PCIe"}; break; default: - m = (typeof(m)){ 0 }; + m = (typeof(m)){ NULL }; break; } break; default: - m = (typeof(m)){ 0 }; + m = (typeof(m)){ NULL }; break; } @@ -1339,7 +1345,8 @@ lpfc_offline(struct lpfc_hba * phba) struct lpfc_sli_ring *pring; struct lpfc_sli *psli; unsigned long iflag; - int i = 0; + int i; + int cnt = 0; if (!phba) return 0; @@ -1348,20 +1355,31 @@ lpfc_offline(struct lpfc_hba * phba) return 0; psli = &phba->sli; - pring = &psli->ring[psli->fcp_ring]; lpfc_linkdown(phba); + lpfc_sli_flush_mbox_queue(phba); - /* The linkdown event takes 30 seconds to timeout. */ - while (pring->txcmplq_cnt) { - mdelay(10); - if (i++ > 3000) - break; + for (i = 0; i < psli->num_rings; i++) { + pring = &psli->ring[i]; + /* The linkdown event takes 30 seconds to timeout. */ + while (pring->txcmplq_cnt) { + mdelay(10); + if (cnt++ > 3000) { + lpfc_printf_log(phba, + KERN_WARNING, LOG_INIT, + "%d:0466 Outstanding IO when " + "bringing Adapter offline\n", + phba->brd_no); + break; + } + } } + /* stop all timers associated with this hba */ lpfc_stop_timer(phba); phba->work_hba_events = 0; + phba->work_ha = 0; lpfc_printf_log(phba, KERN_WARNING, @@ -1451,7 +1469,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) goto out_put_host; host->unique_id = phba->brd_no; - init_MUTEX(&phba->hba_can_block); INIT_LIST_HEAD(&phba->ctrspbuflist); INIT_LIST_HEAD(&phba->rnidrspbuflist); INIT_LIST_HEAD(&phba->freebufList); @@ -1600,7 +1617,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) goto out_free_iocbq; } - /* We can rely on a queue depth attribute only after SLI HBA setup */ + /* + * Set initial can_queue value since 0 is no longer supported and + * scsi_add_host will fail. This will be adjusted later based on the + * max xri value determined in hba setup. + */ host->can_queue = phba->cfg_hba_queue_depth - 10; /* Tell the midlayer we support 16 byte commands */ @@ -1640,6 +1661,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) goto out_free_irq; } + /* + * hba setup may have changed the hba_queue_depth so we need to adjust + * the value of can_queue. + */ + host->can_queue = phba->cfg_hba_queue_depth - 10; + + lpfc_discovery_wait(phba); + if (phba->cfg_poll & DISABLE_FCP_RING_INT) { spin_lock_irq(phba->host->host_lock); lpfc_poll_start_timer(phba); diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index e42f22aaf71..4d016c2a1b2 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -651,3 +651,19 @@ lpfc_mbox_get(struct lpfc_hba * phba) return mbq; } + +int +lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd) +{ + switch (cmd) { + case MBX_WRITE_NV: /* 0x03 */ + case MBX_UPDATE_CFG: /* 0x1B */ + case MBX_DOWN_LOAD: /* 0x1C */ + case MBX_DEL_LD_ENTRY: /* 0x1D */ + case MBX_LOAD_AREA: /* 0x81 */ + case MBX_FLASH_WR_ULA: /* 0x98 */ + case MBX_LOAD_EXP_ROM: /* 0x9C */ + return LPFC_MBOX_TMO_FLASH_CMD; + } + return LPFC_MBOX_TMO; +} diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 07017658ac5..066292d3995 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -133,6 +133,11 @@ lpfc_mem_free(struct lpfc_hba * phba) pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool); pci_pool_destroy(phba->lpfc_mbuf_pool); + + /* Free the iocb lookup array */ + kfree(psli->iocbq_lookup); + psli->iocbq_lookup = NULL; + } void * diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 27d60ad897c..20449a8dd53 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -179,7 +179,7 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, /* Abort outstanding I/O on NPort <nlp_DID> */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0201 Abort outstanding I/O on NPort x%x " + "%d:0205 Abort outstanding I/O on NPort x%x " "Data: x%x x%x x%x\n", phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); @@ -393,6 +393,20 @@ lpfc_rcv_plogi(struct lpfc_hba * phba, mbox->context2 = ndlp; ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI); + /* + * If there is an outstanding PLOGI issued, abort it before + * sending ACC rsp for received PLOGI. If pending plogi + * is not canceled here, the plogi will be rejected by + * remote port and will be retried. On a configuration with + * single discovery thread, this will cause a huge delay in + * discovery. Also this will cause multiple state machines + * running in parallel for this node. + */ + if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) { + /* software abort outstanding PLOGI */ + lpfc_els_abort(phba, ndlp, 1); + } + lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0); return 1; @@ -1110,6 +1124,17 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba, phba->brd_no, did, mb->mbxStatus, phba->hba_state); + /* + * If RegLogin failed due to lack of HBA resources do not + * retry discovery. + */ + if (mb->mbxStatus == MBXERR_RPI_FULL) { + ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; + ndlp->nlp_state = NLP_STE_UNUSED_NODE; + lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST); + return ndlp->nlp_state; + } + /* Put ndlp in npr list set plogi timer for 1 sec */ mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); spin_lock_irq(phba->host->host_lock); @@ -1590,7 +1615,13 @@ lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba, lpfc_rcv_padisc(phba, ndlp, cmdiocb); - if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { + /* + * Do not start discovery if discovery is about to start + * or discovery in progress for this node. Starting discovery + * here will affect the counting of discovery threads. + */ + if ((!(ndlp->nlp_flag & NLP_DELAY_TMO)) && + (ndlp->nlp_flag & NLP_NPR_2B_DISC)){ if (ndlp->nlp_flag & NLP_NPR_ADISC) { ndlp->nlp_prev_state = NLP_STE_NPR_NODE; ndlp->nlp_state = NLP_STE_ADISC_ISSUE; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 7dc4c2e6bed..a8816a8738f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -21,6 +21,7 @@ #include <linux/pci.h> #include <linux/interrupt.h> +#include <linux/delay.h> #include <scsi/scsi.h> #include <scsi/scsi_device.h> @@ -41,20 +42,6 @@ #define LPFC_ABORT_WAIT 2 -static inline void -lpfc_block_requests(struct lpfc_hba * phba) -{ - down(&phba->hba_can_block); - scsi_block_requests(phba->host); -} - -static inline void -lpfc_unblock_requests(struct lpfc_hba * phba) -{ - scsi_unblock_requests(phba->host); - up(&phba->hba_can_block); -} - /* * This routine allocates a scsi buffer, which contains all the necessary * information needed to initiate a SCSI I/O. The non-DMAable buffer region @@ -167,22 +154,6 @@ static void lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb) { unsigned long iflag = 0; - /* - * There are only two special cases to consider. (1) the scsi command - * requested scatter-gather usage or (2) the scsi command allocated - * a request buffer, but did not request use_sg. There is a third - * case, but it does not require resource deallocation. - */ - if ((psb->seg_cnt > 0) && (psb->pCmd->use_sg)) { - dma_unmap_sg(&phba->pcidev->dev, psb->pCmd->request_buffer, - psb->seg_cnt, psb->pCmd->sc_data_direction); - } else { - if ((psb->nonsg_phys) && (psb->pCmd->request_bufflen)) { - dma_unmap_single(&phba->pcidev->dev, psb->nonsg_phys, - psb->pCmd->request_bufflen, - psb->pCmd->sc_data_direction); - } - } spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag); psb->pCmd = NULL; @@ -296,6 +267,27 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd) } static void +lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb) +{ + /* + * There are only two special cases to consider. (1) the scsi command + * requested scatter-gather usage or (2) the scsi command allocated + * a request buffer, but did not request use_sg. There is a third + * case, but it does not require resource deallocation. + */ + if ((psb->seg_cnt > 0) && (psb->pCmd->use_sg)) { + dma_unmap_sg(&phba->pcidev->dev, psb->pCmd->request_buffer, + psb->seg_cnt, psb->pCmd->sc_data_direction); + } else { + if ((psb->nonsg_phys) && (psb->pCmd->request_bufflen)) { + dma_unmap_single(&phba->pcidev->dev, psb->nonsg_phys, + psb->pCmd->request_bufflen, + psb->pCmd->sc_data_direction); + } + } +} + +static void lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd) { struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; @@ -468,6 +460,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, cmd->scsi_done(cmd); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { + lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); lpfc_release_scsi_buf(phba, lpfc_cmd); return; } @@ -525,6 +518,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } } + lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); lpfc_release_scsi_buf(phba, lpfc_cmd); } @@ -623,6 +617,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd, static int lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, + unsigned int lun, uint8_t task_mgmt_cmd) { struct lpfc_sli *psli; @@ -641,8 +636,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, piocb = &piocbq->iocb; fcp_cmnd = lpfc_cmd->fcp_cmnd; - int_to_scsilun(lpfc_cmd->pCmd->device->lun, - &lpfc_cmd->fcp_cmnd->fcp_lun); + int_to_scsilun(lun, &lpfc_cmd->fcp_cmnd->fcp_lun); fcp_cmnd->fcpCntl2 = task_mgmt_cmd; piocb->ulpCommand = CMD_FCP_ICMND64_CR; @@ -669,14 +663,16 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, static int lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba, - unsigned tgt_id, struct lpfc_rport_data *rdata) + unsigned tgt_id, unsigned int lun, + struct lpfc_rport_data *rdata) { struct lpfc_iocbq *iocbq; struct lpfc_iocbq *iocbqrsp; int ret; lpfc_cmd->rdata = rdata; - ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_TARGET_RESET); + ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, lun, + FCP_TARGET_RESET); if (!ret) return FAILED; @@ -836,6 +832,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) return 0; out_host_busy_free_buf: + lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); lpfc_release_scsi_buf(phba, lpfc_cmd); out_host_busy: return SCSI_MLQUEUE_HOST_BUSY; @@ -845,6 +842,21 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) return 0; } +static void +lpfc_block_error_handler(struct scsi_cmnd *cmnd) +{ + struct Scsi_Host *shost = cmnd->device->host; + struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); + + spin_lock_irq(shost->host_lock); + while (rport->port_state == FC_PORTSTATE_BLOCKED) { + spin_unlock_irq(shost->host_lock); + msleep(1000); + spin_lock_irq(shost->host_lock); + } + spin_unlock_irq(shost->host_lock); + return; +} static int lpfc_abort_handler(struct scsi_cmnd *cmnd) @@ -859,7 +871,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) unsigned int loop_count = 0; int ret = SUCCESS; - lpfc_block_requests(phba); + lpfc_block_error_handler(cmnd); spin_lock_irq(shost->host_lock); lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; @@ -945,7 +957,6 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) cmnd->device->lun, cmnd->serial_number); spin_unlock_irq(shost->host_lock); - lpfc_unblock_requests(phba); return ret; } @@ -963,7 +974,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) int ret = FAILED; int cnt, loopcnt; - lpfc_block_requests(phba); + lpfc_block_error_handler(cmnd); spin_lock_irq(shost->host_lock); /* * If target is not in a MAPPED state, delay the reset until @@ -986,12 +997,12 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) if (lpfc_cmd == NULL) goto out; - lpfc_cmd->pCmd = cmnd; lpfc_cmd->timeout = 60; lpfc_cmd->scsi_hba = phba; lpfc_cmd->rdata = rdata; - ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_LUN_RESET); + ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun, + FCP_LUN_RESET); if (!ret) goto out_free_scsi_buf; @@ -1018,7 +1029,6 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) cmd_status = iocbqrsp->iocb.ulpStatus; lpfc_sli_release_iocbq(phba, iocbqrsp); - lpfc_release_scsi_buf(phba, lpfc_cmd); /* * All outstanding txcmplq I/Os should have been aborted by the device. @@ -1057,6 +1067,8 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) } out_free_scsi_buf: + lpfc_release_scsi_buf(phba, lpfc_cmd); + lpfc_printf_log(phba, KERN_ERR, LOG_FCP, "%d:0713 SCSI layer issued LUN reset (%d, %d) " "Data: x%x x%x x%x\n", @@ -1065,7 +1077,6 @@ out_free_scsi_buf: out: spin_unlock_irq(shost->host_lock); - lpfc_unblock_requests(phba); return ret; } @@ -1080,7 +1091,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) int cnt, loopcnt; struct lpfc_scsi_buf * lpfc_cmd; - lpfc_block_requests(phba); + lpfc_block_error_handler(cmnd); spin_lock_irq(shost->host_lock); lpfc_cmd = lpfc_get_scsi_buf(phba); @@ -1089,7 +1100,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) /* The lpfc_cmd storage is reused. Set all loop invariants. */ lpfc_cmd->timeout = 60; - lpfc_cmd->pCmd = cmnd; lpfc_cmd->scsi_hba = phba; /* @@ -1097,7 +1107,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) * targets known to the driver. Should any target reset * fail, this routine returns failure to the midlayer. */ - for (i = 0; i < MAX_FCP_TARGET; i++) { + for (i = 0; i < LPFC_MAX_TARGET; i++) { /* Search the mapped list for this target ID */ match = 0; list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) { @@ -1109,11 +1119,11 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) if (!match) continue; - ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba, - i, ndlp->rport->dd_data); + ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba, i, cmnd->device->lun, + ndlp->rport->dd_data); if (ret != SUCCESS) { lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "%d:0713 Bus Reset on target %d failed\n", + "%d:0700 Bus Reset on target %d failed\n", phba->brd_no, i); err_count++; } @@ -1163,7 +1173,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) phba->brd_no, ret); out: spin_unlock_irq(shost->host_lock); - lpfc_unblock_requests(phba); return ret; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index bb69a7a1ec5..70f4d5a1348 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -191,35 +191,12 @@ static int lpfc_sli_ringtxcmpl_put(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, struct lpfc_iocbq * piocb) { - uint16_t iotag; - list_add_tail(&piocb->list, &pring->txcmplq); pring->txcmplq_cnt++; if (unlikely(pring->ringno == LPFC_ELS_RING)) mod_timer(&phba->els_tmofunc, jiffies + HZ * (phba->fc_ratov << 1)); - if (pring->fast_lookup) { - /* Setup fast lookup based on iotag for completion */ - iotag = piocb->iocb.ulpIoTag; - if (iotag && (iotag < pring->fast_iotag)) - *(pring->fast_lookup + iotag) = piocb; - else { - - /* Cmd ring <ringno> put: iotag <iotag> greater then - configured max <fast_iotag> wd0 <icmd> */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_SLI, - "%d:0316 Cmd ring %d put: iotag x%x " - "greater then configured max x%x " - "wd0 x%x\n", - phba->brd_no, - pring->ringno, iotag, - pring->fast_iotag, - *(((uint32_t *)(&piocb->iocb)) + 7)); - } - } return (0); } @@ -343,7 +320,8 @@ lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq) kfree(old_arr); return iotag; } - } + } else + spin_unlock_irq(phba->host->host_lock); lpfc_printf_log(phba, KERN_ERR,LOG_SLI, "%d:0318 Failed to allocate IOTAG.last IOTAG is %d\n", @@ -601,7 +579,7 @@ lpfc_sli_handle_mb_event(struct lpfc_hba * phba) /* Stray Mailbox Interrupt, mbxCommand <cmd> mbxStatus <status> */ lpfc_printf_log(phba, - KERN_ERR, + KERN_WARNING, LOG_MBOX | LOG_SLI, "%d:0304 Stray Mailbox Interrupt " "mbxCommand x%x mbxStatus x%x\n", @@ -992,9 +970,11 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba) * resources need to be recovered. */ if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) { - printk(KERN_INFO "%s: IOCB cmd 0x%x processed." - " Skipping completion\n", __FUNCTION__, - irsp->ulpCommand); + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "%d:0314 IOCB cmd 0x%x" + " processed. Skipping" + " completion", phba->brd_no, + irsp->ulpCommand); break; } @@ -1127,7 +1107,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba, if (unlikely(irsp->ulpStatus)) { /* Rsp ring <ringno> error: IOCB */ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "%d:0326 Rsp Ring %d error: IOCB Data: " + "%d:0336 Rsp Ring %d error: IOCB Data: " "x%x x%x x%x x%x x%x x%x x%x x%x\n", phba->brd_no, pring->ringno, irsp->un.ulpWord[0], irsp->un.ulpWord[1], @@ -1145,9 +1125,11 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba, * resources need to be recovered. */ if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) { - printk(KERN_INFO "%s: IOCB cmd 0x%x processed. " - "Skipping completion\n", __FUNCTION__, - irsp->ulpCommand); + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "%d:0333 IOCB cmd 0x%x" + " processed. Skipping" + " completion\n", phba->brd_no, + irsp->ulpCommand); break; } @@ -1178,7 +1160,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba, } else { /* Unknown IOCB command */ lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "%d:0321 Unknown IOCB command " + "%d:0334 Unknown IOCB command " "Data: x%x, x%x x%x x%x x%x\n", phba->brd_no, type, irsp->ulpCommand, irsp->ulpStatus, irsp->ulpIoTag, @@ -1261,7 +1243,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "%d:0312 Ring %d handler: portRspPut %d " + "%d:0303 Ring %d handler: portRspPut %d " "is bigger then rsp ring %d\n", phba->brd_no, pring->ringno, portRspPut, portRspMax); @@ -1406,7 +1388,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "%d:0321 Unknown IOCB command " + "%d:0335 Unknown IOCB command " "Data: x%x x%x x%x x%x\n", phba->brd_no, irsp->ulpCommand, @@ -1422,11 +1404,11 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, next_iocb, &saveq->list, list) { + list_del(&rspiocbp->list); lpfc_sli_release_iocbq(phba, rspiocbp); } } - lpfc_sli_release_iocbq(phba, saveq); } } @@ -1570,8 +1552,8 @@ lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask) void lpfc_reset_barrier(struct lpfc_hba * phba) { - uint32_t * resp_buf; - uint32_t * mbox_buf; + uint32_t __iomem *resp_buf; + uint32_t __iomem *mbox_buf; volatile uint32_t mbox; uint32_t hc_copy; int i; @@ -1587,7 +1569,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba) * Tell the other part of the chip to suspend temporarily all * its DMA activity. */ - resp_buf = (uint32_t *)phba->MBslimaddr; + resp_buf = phba->MBslimaddr; /* Disable the error attention */ hc_copy = readl(phba->HCregaddr); @@ -1605,7 +1587,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba) ((MAILBOX_t *)&mbox)->mbxOwner = OWN_CHIP; writel(BARRIER_TEST_PATTERN, (resp_buf + 1)); - mbox_buf = (uint32_t *)phba->MBslimaddr; + mbox_buf = phba->MBslimaddr; writel(mbox, mbox_buf); for (i = 0; @@ -1734,15 +1716,13 @@ lpfc_sli_brdreset(struct lpfc_hba * phba) phba->fc_myDID = 0; phba->fc_prevDID = 0; - psli->sli_flag = 0; - /* Turn off parity checking and serr during the physical reset */ pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value); pci_write_config_word(phba->pcidev, PCI_COMMAND, (cfg_value & ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + psli->sli_flag &= ~(LPFC_SLI2_ACTIVE | LPFC_PROCESS_LA); /* Now toggle INITFF bit in the Host Control Register */ writel(HC_INITFF, phba->HCregaddr); mdelay(1); @@ -1783,7 +1763,7 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba) /* Restart HBA */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "%d:0328 Restart HBA Data: x%x x%x\n", phba->brd_no, + "%d:0337 Restart HBA Data: x%x x%x\n", phba->brd_no, phba->hba_state, psli->sli_flag); word0 = 0; @@ -1805,7 +1785,7 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba) skip_post = 0; word0 = 0; /* This is really setting up word1 */ } - to_slim = (uint8_t *) phba->MBslimaddr + sizeof (uint32_t); + to_slim = phba->MBslimaddr + sizeof (uint32_t); writel(*(uint32_t *) mb, to_slim); readl(to_slim); /* flush */ @@ -1815,6 +1795,9 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba) spin_unlock_irq(phba->host->host_lock); + memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets)); + psli->stats_start = get_seconds(); + if (skip_post) mdelay(100); else @@ -1925,6 +1908,9 @@ lpfc_sli_hba_setup(struct lpfc_hba * phba) } while (resetcount < 2 && !done) { + spin_lock_irq(phba->host->host_lock); + phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE; + spin_unlock_irq(phba->host->host_lock); phba->hba_state = LPFC_STATE_UNKNOWN; lpfc_sli_brdrestart(phba); msleep(2500); @@ -1932,6 +1918,9 @@ lpfc_sli_hba_setup(struct lpfc_hba * phba) if (rc) break; + spin_lock_irq(phba->host->host_lock); + phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + spin_unlock_irq(phba->host->host_lock); resetcount++; /* Call pre CONFIG_PORT mailbox command initialization. A value of 0 @@ -2217,7 +2206,8 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) return (MBX_NOT_FINISHED); } /* timeout active mbox command */ - mod_timer(&psli->mbox_tmo, jiffies + HZ * LPFC_MBOX_TMO); + mod_timer(&psli->mbox_tmo, (jiffies + + (HZ * lpfc_mbox_tmo_val(phba, mb->mbxCommand)))); } /* Mailbox cmd <cmd> issue */ @@ -2277,7 +2267,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) break; case MBX_POLL: - i = 0; psli->mbox_active = NULL; if (psli->sli_flag & LPFC_SLI2_ACTIVE) { /* First read mbox status word */ @@ -2291,11 +2280,14 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) /* Read the HBA Host Attention Register */ ha_copy = readl(phba->HAregaddr); + i = lpfc_mbox_tmo_val(phba, mb->mbxCommand); + i *= 1000; /* Convert to ms */ + /* Wait for command to complete */ while (((word0 & OWN_CHIP) == OWN_CHIP) || (!(ha_copy & HA_MBATT) && (phba->hba_state > LPFC_WARM_START))) { - if (i++ >= 100) { + if (i-- <= 0) { psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; spin_unlock_irqrestore(phba->host->host_lock, drvr_flag); @@ -2313,7 +2305,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) /* Can be in interrupt context, do not sleep */ /* (or might be called with interrupts disabled) */ - mdelay(i); + mdelay(1); spin_lock_irqsave(phba->host->host_lock, drvr_flag); @@ -2659,8 +2651,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba) INIT_LIST_HEAD(&(pring->txq)); - kfree(pring->fast_lookup); - pring->fast_lookup = NULL; } spin_unlock_irqrestore(phba->host->host_lock, flags); @@ -3030,7 +3020,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba, if (timeleft == 0) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "%d:0329 IOCB wait timeout error - no " + "%d:0338 IOCB wait timeout error - no " "wake response Data x%x\n", phba->brd_no, timeout); retval = IOCB_TIMEDOUT; @@ -3110,6 +3100,24 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq, return retval; } +int +lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba) +{ + int i = 0; + + while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !phba->stopped) { + if (i++ > LPFC_MBOX_TMO * 1000) + return 1; + + if (lpfc_sli_handle_mb_event(phba) == 0) + i = 0; + + msleep(1); + } + + return (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) ? 1 : 0; +} + irqreturn_t lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs) { diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index a52d6c6cf08..e26de680935 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -135,8 +135,6 @@ struct lpfc_sli_ring { uint32_t fast_iotag; /* max fastlookup based iotag */ uint32_t iotag_ctr; /* keeps track of the next iotag to use */ uint32_t iotag_max; /* max iotag value to use */ - struct lpfc_iocbq ** fast_lookup; /* array of IOCB ptrs indexed by - iotag */ struct list_head txq; uint16_t txq_cnt; /* current length of queue */ uint16_t txq_max; /* max length */ @@ -174,6 +172,18 @@ struct lpfc_sli_stat { uint32_t mbox_busy; /* Mailbox cmd busy */ }; +/* Structure to store link status values when port stats are reset */ +struct lpfc_lnk_stat { + uint32_t link_failure_count; + uint32_t loss_of_sync_count; + uint32_t loss_of_signal_count; + uint32_t prim_seq_protocol_err_count; + uint32_t invalid_tx_word_count; + uint32_t invalid_crc_count; + uint32_t error_frames; + uint32_t link_events; +}; + /* Structure used to hold SLI information */ struct lpfc_sli { uint32_t num_rings; @@ -203,6 +213,8 @@ struct lpfc_sli { struct lpfc_iocbq ** iocbq_lookup; /* array to lookup IOCB by IOTAG */ size_t iocbq_lookup_len; /* current lengs of the array */ uint16_t last_iotag; /* last allocated IOTAG */ + unsigned long stats_start; /* in seconds */ + struct lpfc_lnk_stat lnk_stat_offsets; }; /* Given a pointer to the start of the ring, and the slot number of @@ -213,3 +225,9 @@ struct lpfc_sli { #define LPFC_MBOX_TMO 30 /* Sec tmo for outstanding mbox command */ +#define LPFC_MBOX_TMO_FLASH_CMD 300 /* Sec tmo for outstanding FLASH write + * or erase cmds. This is especially + * long because of the potential of + * multiple flash erases that can be + * spawned. + */ diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 6b737568b83..c7091ea29f3 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.1.6" +#define LPFC_DRIVER_VERSION "8.1.9" #define LPFC_DRIVER_NAME "lpfc" diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index 93edaa8696c..89ef34df5a1 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -378,7 +378,7 @@ static void set_dma_cmds(struct fsc_state *state, struct scsi_cmnd *cmd) int nseg; total = 0; - scl = (struct scatterlist *) cmd->buffer; + scl = (struct scatterlist *) cmd->request_buffer; nseg = pci_map_sg(state->pdev, scl, cmd->use_sg, cmd->sc_data_direction); for (i = 0; i < nseg; ++i) { diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h index 4675343228a..8cd0bd1d0f7 100644 --- a/drivers/scsi/megaraid/mega_common.h +++ b/drivers/scsi/megaraid/mega_common.h @@ -37,6 +37,12 @@ #define LSI_MAX_CHANNELS 16 #define LSI_MAX_LOGICAL_DRIVES_64LD (64+1) +#define HBA_SIGNATURE_64_BIT 0x299 +#define PCI_CONF_AMISIG64 0xa4 + +#define MEGA_SCSI_INQ_EVPD 1 +#define MEGA_INVALID_FIELD_IN_CDB 0x24 + /** * scb_t - scsi command control block diff --git a/drivers/scsi/megaraid/megaraid_ioctl.h b/drivers/scsi/megaraid/megaraid_ioctl.h index bdaee144a1c..b8aa34202ec 100644 --- a/drivers/scsi/megaraid/megaraid_ioctl.h +++ b/drivers/scsi/megaraid/megaraid_ioctl.h @@ -132,6 +132,10 @@ typedef struct uioc { /* Driver Data: */ void __user * user_data; uint32_t user_data_len; + + /* 64bit alignment */ + uint32_t pad_for_64bit_align; + mraid_passthru_t __user *user_pthru; mraid_passthru_t *pthru32; diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index 92715130ac0..cd982c877da 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_mbox.c - * Version : v2.20.4.8 (Apr 11 2006) + * Version : v2.20.4.9 (Jul 16 2006) * * Authors: * Atul Mukker <Atul.Mukker@lsil.com> @@ -720,6 +720,7 @@ megaraid_init_mbox(adapter_t *adapter) struct pci_dev *pdev; mraid_device_t *raid_dev; int i; + uint32_t magic64; adapter->ito = MBOX_TIMEOUT; @@ -863,12 +864,33 @@ megaraid_init_mbox(adapter_t *adapter) // Set the DMA mask to 64-bit. All supported controllers as capable of // DMA in this range - if (pci_set_dma_mask(adapter->pdev, DMA_64BIT_MASK) != 0) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid: could not set DMA mask for 64-bit.\n")); + pci_read_config_dword(adapter->pdev, PCI_CONF_AMISIG64, &magic64); + + if (((magic64 == HBA_SIGNATURE_64_BIT) && + ((adapter->pdev->subsystem_device != + PCI_SUBSYS_ID_MEGARAID_SATA_150_6) || + (adapter->pdev->subsystem_device != + PCI_SUBSYS_ID_MEGARAID_SATA_150_4))) || + (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && + adapter->pdev->device == PCI_DEVICE_ID_VERDE) || + (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && + adapter->pdev->device == PCI_DEVICE_ID_DOBSON) || + (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && + adapter->pdev->device == PCI_DEVICE_ID_LINDSAY) || + (adapter->pdev->vendor == PCI_VENDOR_ID_DELL && + adapter->pdev->device == PCI_DEVICE_ID_PERC4_DI_EVERGLADES) || + (adapter->pdev->vendor == PCI_VENDOR_ID_DELL && + adapter->pdev->device == PCI_DEVICE_ID_PERC4E_DI_KOBUK)) { + if (pci_set_dma_mask(adapter->pdev, DMA_64BIT_MASK)) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: DMA mask for 64-bit failed\n")); - goto out_free_sysfs_res; + if (pci_set_dma_mask (adapter->pdev, DMA_32BIT_MASK)) { + con_log(CL_ANN, (KERN_WARNING + "megaraid: 32-bit DMA mask failed\n")); + goto out_free_sysfs_res; + } + } } // setup tasklet for DPC @@ -1622,6 +1644,14 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) rdev->last_disp |= (1L << SCP2CHANNEL(scp)); } + if (scp->cmnd[1] & MEGA_SCSI_INQ_EVPD) { + scp->sense_buffer[0] = 0x70; + scp->sense_buffer[2] = ILLEGAL_REQUEST; + scp->sense_buffer[12] = MEGA_INVALID_FIELD_IN_CDB; + scp->result = CHECK_CONDITION << 1; + return NULL; + } + /* Fall through */ case READ_CAPACITY: diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h index 868fb0ec93e..2b5a3285f79 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.h +++ b/drivers/scsi/megaraid/megaraid_mbox.h @@ -21,8 +21,8 @@ #include "megaraid_ioctl.h" -#define MEGARAID_VERSION "2.20.4.8" -#define MEGARAID_EXT_VERSION "(Release Date: Mon Apr 11 12:27:22 EST 2006)" +#define MEGARAID_VERSION "2.20.4.9" +#define MEGARAID_EXT_VERSION "(Release Date: Sun Jul 16 12:27:22 EST 2006)" /* diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index e8f534fb336..d85b9a8f1b8 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_mm.c - * Version : v2.20.2.6 (Mar 7 2005) + * Version : v2.20.2.7 (Jul 16 2006) * * Common management module */ diff --git a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h index 3d9e67d6849..c8762b2b8ed 100644 --- a/drivers/scsi/megaraid/megaraid_mm.h +++ b/drivers/scsi/megaraid/megaraid_mm.h @@ -27,9 +27,9 @@ #include "megaraid_ioctl.h" -#define LSI_COMMON_MOD_VERSION "2.20.2.6" +#define LSI_COMMON_MOD_VERSION "2.20.2.7" #define LSI_COMMON_MOD_EXT_VERSION \ - "(Release Date: Mon Mar 7 00:01:03 EST 2005)" + "(Release Date: Sun Jul 16 00:01:03 EST 2006)" #define LSI_DBGLVL dbglevel diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index e5c017ccda5..a8c9627a15c 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_sas.c - * Version : v00.00.02.04 + * Version : v00.00.03.01 * * Authors: * Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com> @@ -55,19 +55,25 @@ static struct pci_device_id megasas_pci_table[] = { { PCI_VENDOR_ID_LSI_LOGIC, - PCI_DEVICE_ID_LSI_SAS1064R, // xscale IOP + PCI_DEVICE_ID_LSI_SAS1064R, /* xscale IOP */ PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_LSI_LOGIC, - PCI_DEVICE_ID_LSI_SAS1078R, // ppc IOP + PCI_DEVICE_ID_LSI_SAS1078R, /* ppc IOP */ PCI_ANY_ID, PCI_ANY_ID, }, { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_LSI_VERDE_ZCR, /* xscale IOP, vega */ + PCI_ANY_ID, + PCI_ANY_ID, + }, + { PCI_VENDOR_ID_DELL, - PCI_DEVICE_ID_DELL_PERC5, // xscale IOP + PCI_DEVICE_ID_DELL_PERC5, /* xscale IOP */ PCI_ANY_ID, PCI_ANY_ID, }, @@ -289,9 +295,14 @@ static struct megasas_instance_template megasas_instance_template_ppc = { * @regs: MFI register set */ static inline void -megasas_disable_intr(struct megasas_register_set __iomem * regs) +megasas_disable_intr(struct megasas_instance *instance) { u32 mask = 0x1f; + struct megasas_register_set __iomem *regs = instance->reg_set; + + if(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078R) + mask = 0xffffffff; + writel(mask, ®s->outbound_intr_mask); /* Dummy readl to force pci flush */ @@ -1260,7 +1271,7 @@ megasas_transition_to_ready(struct megasas_instance* instance) /* * Bring it to READY state; assuming max wait 2 secs */ - megasas_disable_intr(instance->reg_set); + megasas_disable_intr(instance); writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell); max_wait = 10; @@ -1757,6 +1768,11 @@ static int megasas_init_mfi(struct megasas_instance *instance) init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info); /* + * disable the intr before firing the init frame to FW + */ + megasas_disable_intr(instance); + + /* * Issue the init frame in polled mode */ if (megasas_issue_polled(instance, cmd)) { @@ -2234,7 +2250,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) megasas_mgmt_info.max_index--; pci_set_drvdata(pdev, NULL); - megasas_disable_intr(instance->reg_set); + megasas_disable_intr(instance); free_irq(instance->pdev->irq, instance); megasas_release_mfi(instance); @@ -2364,7 +2380,7 @@ static void megasas_detach_one(struct pci_dev *pdev) pci_set_drvdata(instance->pdev, NULL); - megasas_disable_intr(instance->reg_set); + megasas_disable_intr(instance); free_irq(instance->pdev->irq, instance); diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 927d6ffef05..3531a14222a 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -18,9 +18,16 @@ /** * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.02.04" -#define MEGASAS_RELDATE "Feb 03, 2006" -#define MEGASAS_EXT_VERSION "Fri Feb 03 14:31:44 PST 2006" +#define MEGASAS_VERSION "00.00.03.01" +#define MEGASAS_RELDATE "May 14, 2006" +#define MEGASAS_EXT_VERSION "Sun May 14 22:49:52 PDT 2006" + +/* + * Device IDs + */ +#define PCI_DEVICE_ID_LSI_SAS1078R 0x0060 +#define PCI_DEVICE_ID_LSI_VERDE_ZCR 0x0413 + /* * ===================================== * MegaRAID SAS MFI firmware definitions @@ -554,7 +561,11 @@ struct megasas_ctrl_info { #define MFI_POLL_TIMEOUT_SECS 10 #define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000 -#define PCI_DEVICE_ID_LSI_SAS1078R 0x00000060 + +/* +* register set for both 1068 and 1078 controllers +* structure extended for 1078 registers +*/ struct megasas_register_set { u32 reserved_0[4]; /*0000h*/ @@ -1150,10 +1161,10 @@ struct compat_megasas_iocpacket { struct compat_iovec sgl[MAX_IOCTL_SGE]; } __attribute__ ((packed)); +#define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket) #endif #define MEGASAS_IOC_FIRMWARE _IOWR('M', 1, struct megasas_iocpacket) -#define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket) #define MEGASAS_IOC_GET_AEN _IOW('M', 3, struct megasas_aen) struct megasas_mgmt_info { diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index c88717727be..5572981a9f9 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1268,7 +1268,7 @@ static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd) if (cmd->use_sg > 0) { int nseg; total = 0; - scl = (struct scatterlist *) cmd->buffer; + scl = (struct scatterlist *) cmd->request_buffer; off = ms->data_ptr; nseg = pci_map_sg(ms->pdev, scl, cmd->use_sg, cmd->sc_data_direction); diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index bd337a91429..bfb4f49e125 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -2866,8 +2866,7 @@ static int nsp32_detect(struct scsi_host_template *sht) */ nsp32_do_bus_reset(data); - ret = request_irq(host->irq, do_nsp32_isr, - IRQF_SHARED | IRQF_SAMPLE_RANDOM, "nsp32", data); + ret = request_irq(host->irq, do_nsp32_isr, IRQF_SHARED, "nsp32", data); if (ret < 0) { nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NinjaSCSI32 " "SCSI PCI controller. Interrupt: %d", host->irq); @@ -2886,12 +2885,19 @@ static int nsp32_detect(struct scsi_host_template *sht) } #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) - scsi_add_host (host, &PCIDEV->dev); + ret = scsi_add_host(host, &PCIDEV->dev); + if (ret) { + nsp32_msg(KERN_ERR, "failed to add scsi host"); + goto free_region; + } scsi_scan_host(host); #endif pci_set_drvdata(PCIDEV, host); return DETECT_OK; + free_region: + release_region(host->io_port, host->n_io_port); + free_irq: free_irq(host->irq, data); diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 7ff5851c040..0d4c04e1f3d 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1623,7 +1623,7 @@ static int nsp_cs_probe(struct pcmcia_device *link) /* Interrupt handler */ link->irq.Handler = &nspintr; link->irq.Instance = info; - link->irq.Attributes |= (IRQF_SHARED | IRQF_SAMPLE_RANDOM); + link->irq.Attributes |= IRQF_SHARED; /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; diff --git a/drivers/scsi/pdc_adma.c b/drivers/scsi/pdc_adma.c index d1f38c32aa1..efc8fff1d25 100644 --- a/drivers/scsi/pdc_adma.c +++ b/drivers/scsi/pdc_adma.c @@ -183,7 +183,8 @@ static struct ata_port_info adma_port_info[] = { { .sht = &adma_ata_sht, .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | - ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO, + ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO | + ATA_FLAG_PIO_POLLING, .pio_mask = 0x10, /* pio4 */ .udma_mask = 0x1f, /* udma0-4 */ .port_ops = &adma_ata_ops, diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c index 7abf64d1bfc..0bd9c60e645 100644 --- a/drivers/scsi/pluto.c +++ b/drivers/scsi/pluto.c @@ -169,8 +169,6 @@ int __init pluto_detect(struct scsi_host_template *tpnt) SCpnt->request->rq_status = RQ_SCSI_BUSY; SCpnt->done = pluto_detect_done; - SCpnt->bufflen = 256; - SCpnt->buffer = fcs[i].inquiry; SCpnt->request_bufflen = 256; SCpnt->request_buffer = fcs[i].inquiry; PLD(("set up %d %08lx\n", i, (long)SCpnt)) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index b818b9bfe67..8953991462d 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4209,7 +4209,7 @@ qla1280_setup(char *s) } -static int +static int __init qla1280_get_token(char *str) { char *sep; diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index e96d58ded57..87f90c4f08e 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -16,15 +16,16 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf, loff_t off, { struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, struct device, kobj))); + char *rbuf = (char *)ha->fw_dump; if (ha->fw_dump_reading == 0) return 0; - if (off > ha->fw_dump_buffer_len) - return 0; - if (off + count > ha->fw_dump_buffer_len) - count = ha->fw_dump_buffer_len - off; + if (off > ha->fw_dump_len) + return 0; + if (off + count > ha->fw_dump_len) + count = ha->fw_dump_len - off; - memcpy(buf, &ha->fw_dump_buffer[off], count); + memcpy(buf, &rbuf[off], count); return (count); } @@ -36,7 +37,6 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off, struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, struct device, kobj))); int reading; - uint32_t dump_size; if (off != 0) return (0); @@ -44,46 +44,27 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off, reading = simple_strtol(buf, NULL, 10); switch (reading) { case 0: - if (ha->fw_dump_reading == 1) { - qla_printk(KERN_INFO, ha, - "Firmware dump cleared on (%ld).\n", ha->host_no); + if (!ha->fw_dump_reading) + break; - vfree(ha->fw_dump_buffer); - ha->fw_dump_buffer = NULL; - ha->fw_dump_reading = 0; - ha->fw_dumped = 0; - } + qla_printk(KERN_INFO, ha, + "Firmware dump cleared on (%ld).\n", ha->host_no); + + ha->fw_dump_reading = 0; + ha->fw_dumped = 0; break; case 1: if (ha->fw_dumped && !ha->fw_dump_reading) { ha->fw_dump_reading = 1; - if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) - dump_size = FW_DUMP_SIZE_24XX; - else { - dump_size = FW_DUMP_SIZE_1M; - if (ha->fw_memory_size < 0x20000) - dump_size = FW_DUMP_SIZE_128K; - else if (ha->fw_memory_size < 0x80000) - dump_size = FW_DUMP_SIZE_512K; - } - ha->fw_dump_buffer = (char *)vmalloc(dump_size); - if (ha->fw_dump_buffer == NULL) { - qla_printk(KERN_WARNING, ha, - "Unable to allocate memory for firmware " - "dump buffer (%d).\n", dump_size); - - ha->fw_dump_reading = 0; - return (count); - } qla_printk(KERN_INFO, ha, - "Firmware dump ready for read on (%ld).\n", + "Raw firmware dump ready for read on (%ld).\n", ha->host_no); - memset(ha->fw_dump_buffer, 0, dump_size); - ha->isp_ops.ascii_fw_dump(ha); - ha->fw_dump_buffer_len = strlen(ha->fw_dump_buffer); } break; + case 2: + qla2x00_alloc_fw_dump(ha); + break; } return (count); } @@ -313,9 +294,6 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj, char *buf, loff_t off, if (!capable(CAP_SYS_ADMIN) || off != 0) return 0; - if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) - return -ENOTSUPP; - /* Read NVRAM. */ spin_lock_irqsave(&ha->hardware_lock, flags); ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->vpd_base, ha->vpd_size); @@ -335,9 +313,6 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj, char *buf, loff_t off, if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size) return 0; - if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) - return -ENOTSUPP; - /* Write NVRAM. */ spin_lock_irqsave(&ha->hardware_lock, flags); ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count); @@ -357,6 +332,53 @@ static struct bin_attribute sysfs_vpd_attr = { .write = qla2x00_sysfs_write_vpd, }; +static ssize_t +qla2x00_sysfs_read_sfp(struct kobject *kobj, char *buf, loff_t off, + size_t count) +{ + struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct device, kobj))); + uint16_t iter, addr, offset; + int rval; + + if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2) + return 0; + + addr = 0xa0; + for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE; + iter++, offset += SFP_BLOCK_SIZE) { + if (iter == 4) { + /* Skip to next device address. */ + addr = 0xa2; + offset = 0; + } + + rval = qla2x00_read_sfp(ha, ha->sfp_data_dma, addr, offset, + SFP_BLOCK_SIZE); + if (rval != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Unable to read SFP data (%x/%x/%x).\n", rval, + addr, offset); + count = 0; + break; + } + memcpy(buf, ha->sfp_data, SFP_BLOCK_SIZE); + buf += SFP_BLOCK_SIZE; + } + + return count; +} + +static struct bin_attribute sysfs_sfp_attr = { + .attr = { + .name = "sfp", + .mode = S_IRUSR | S_IWUSR, + .owner = THIS_MODULE, + }, + .size = SFP_DEV_SIZE * 2, + .read = qla2x00_sysfs_read_sfp, +}; + void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha) { @@ -367,7 +389,12 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha) sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_ctl_attr); - sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_attr); + if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + sysfs_create_bin_file(&host->shost_gendev.kobj, + &sysfs_vpd_attr); + sysfs_create_bin_file(&host->shost_gendev.kobj, + &sysfs_sfp_attr); + } } void @@ -380,7 +407,12 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha) sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_ctl_attr); - sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_attr); + if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + sysfs_remove_bin_file(&host->shost_gendev.kobj, + &sysfs_vpd_attr); + sysfs_remove_bin_file(&host->shost_gendev.kobj, + &sysfs_sfp_attr); + } if (ha->beacon_blink_led == 1) ha->isp_ops.beacon_off(ha); diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 74e54713aa7..f6ed6962bc2 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -8,7 +8,34 @@ #include <linux/delay.h> -static int qla_uprintf(char **, char *, ...); +static inline void +qla2xxx_prep_dump(scsi_qla_host_t *ha, struct qla2xxx_fw_dump *fw_dump) +{ + fw_dump->fw_major_version = htonl(ha->fw_major_version); + fw_dump->fw_minor_version = htonl(ha->fw_minor_version); + fw_dump->fw_subminor_version = htonl(ha->fw_subminor_version); + fw_dump->fw_attributes = htonl(ha->fw_attributes); + + fw_dump->vendor = htonl(ha->pdev->vendor); + fw_dump->device = htonl(ha->pdev->device); + fw_dump->subsystem_vendor = htonl(ha->pdev->subsystem_vendor); + fw_dump->subsystem_device = htonl(ha->pdev->subsystem_device); +} + +static inline void * +qla2xxx_copy_queues(scsi_qla_host_t *ha, void *ptr) +{ + /* Request queue. */ + memcpy(ptr, ha->request_ring, ha->request_q_length * + sizeof(request_t)); + + /* Response queue. */ + ptr += ha->request_q_length * sizeof(request_t); + memcpy(ptr, ha->response_ring, ha->response_q_length * + sizeof(response_t)); + + return ptr + (ha->response_q_length * sizeof(response_t)); +} /** * qla2300_fw_dump() - Dumps binary data from the 2300 firmware. @@ -49,10 +76,11 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) "request...\n", ha->fw_dump); goto qla2300_fw_dump_failed; } - fw = ha->fw_dump; + fw = &ha->fw_dump->isp.isp23; + qla2xxx_prep_dump(ha, ha->fw_dump); rval = QLA_SUCCESS; - fw->hccr = RD_REG_WORD(®->hccr); + fw->hccr = htons(RD_REG_WORD(®->hccr)); /* Pause RISC. */ WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); @@ -73,85 +101,86 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (rval == QLA_SUCCESS) { dmp_reg = (uint16_t __iomem *)(reg + 0); for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) - fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10); for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++) - fw->risc_host_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x40); for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) - fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x40); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->resp_dma_reg) / 2; cnt++) - fw->resp_dma_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->resp_dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x50); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) - fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0); for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) - fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2000); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) - fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2200); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) - fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2400); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) - fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2600); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) - fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2800); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) - fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2A00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) - fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2C00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) - fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2E00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) - fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x10); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) - fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->frame_buf_hdw_reg[cnt] = + htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x20); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) - fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x30); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) - fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); /* Reset RISC. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); @@ -226,7 +255,7 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; - fw->risc_ram[cnt] = mb2; + fw->risc_ram[cnt] = htons(mb2); } else { rval = QLA_FUNCTION_FAILED; } @@ -285,7 +314,7 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; - fw->stack_ram[cnt] = mb2; + fw->stack_ram[cnt] = htons(mb2); } else { rval = QLA_FUNCTION_FAILED; } @@ -345,12 +374,15 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; - fw->data_ram[cnt] = mb2; + fw->data_ram[cnt] = htons(mb2); } else { rval = QLA_FUNCTION_FAILED; } } + if (rval == QLA_SUCCESS) + qla2xxx_copy_queues(ha, &fw->data_ram[cnt]); + if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); @@ -369,193 +401,6 @@ qla2300_fw_dump_failed: } /** - * qla2300_ascii_fw_dump() - Converts a binary firmware dump to ASCII. - * @ha: HA context - */ -void -qla2300_ascii_fw_dump(scsi_qla_host_t *ha) -{ - uint32_t cnt; - char *uiter; - char fw_info[30]; - struct qla2300_fw_dump *fw; - uint32_t data_ram_cnt; - - uiter = ha->fw_dump_buffer; - fw = ha->fw_dump; - - qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number, - ha->isp_ops.fw_version_str(ha, fw_info)); - - qla_uprintf(&uiter, "\n[==>BEG]\n"); - - qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr); - - qla_uprintf(&uiter, "PBIU Registers:"); - for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nReqQ-RspQ-Risc2Host Status registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_host_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_host_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nMailbox Registers:"); - for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nAuto Request Response DMA Registers:"); - for (cnt = 0; cnt < sizeof (fw->resp_dma_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->resp_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nDMA Registers:"); - for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC Hardware Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP0 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP1 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP2 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP3 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP4 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP5 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP6 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP7 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:"); - for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM B0 Registers:"); - for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM B1 Registers:"); - for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nCode RAM Dump:"); - for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%04x: ", cnt + 0x0800); - } - qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\nStack RAM Dump:"); - for (cnt = 0; cnt < sizeof (fw->stack_ram) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%05x: ", cnt + 0x10000); - } - qla_uprintf(&uiter, "%04x ", fw->stack_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\nData RAM Dump:"); - data_ram_cnt = ha->fw_memory_size - 0x11000 + 1; - for (cnt = 0; cnt < data_ram_cnt; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%05x: ", cnt + 0x11000); - } - qla_uprintf(&uiter, "%04x ", fw->data_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump."); -} - -/** * qla2100_fw_dump() - Dumps binary data from the 2100/2200 firmware. * @ha: HA context * @hardware_locked: Called with the hardware_lock @@ -591,10 +436,11 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked) "request...\n", ha->fw_dump); goto qla2100_fw_dump_failed; } - fw = ha->fw_dump; + fw = &ha->fw_dump->isp.isp21; + qla2xxx_prep_dump(ha, ha->fw_dump); rval = QLA_SUCCESS; - fw->hccr = RD_REG_WORD(®->hccr); + fw->hccr = htons(RD_REG_WORD(®->hccr)); /* Pause RISC. */ WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); @@ -608,79 +454,81 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (rval == QLA_SUCCESS) { dmp_reg = (uint16_t __iomem *)(reg + 0); for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) - fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10); for (cnt = 0; cnt < ha->mbx_count; cnt++) { if (cnt == 8) { - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xe0); + dmp_reg = (uint16_t __iomem *) + ((uint8_t __iomem *)reg + 0xe0); } - fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); } dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x20); for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) - fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0); for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) - fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2000); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) - fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2100); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) - fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2200); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) - fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2300); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) - fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2400); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) - fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2500); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) - fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2600); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) - fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2700); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) - fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x10); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) - fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->frame_buf_hdw_reg[cnt] = + htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x20); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) - fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x30); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) - fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); /* Reset the ISP. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); @@ -755,12 +603,15 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; - fw->risc_ram[cnt] = mb2; + fw->risc_ram[cnt] = htons(mb2); } else { rval = QLA_FUNCTION_FAILED; } } + if (rval == QLA_SUCCESS) + qla2xxx_copy_queues(ha, &fw->risc_ram[cnt]); + if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); @@ -778,179 +629,6 @@ qla2100_fw_dump_failed: spin_unlock_irqrestore(&ha->hardware_lock, flags); } -/** - * qla2100_ascii_fw_dump() - Converts a binary firmware dump to ASCII. - * @ha: HA context - */ -void -qla2100_ascii_fw_dump(scsi_qla_host_t *ha) -{ - uint32_t cnt; - char *uiter; - char fw_info[30]; - struct qla2100_fw_dump *fw; - - uiter = ha->fw_dump_buffer; - fw = ha->fw_dump; - - qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number, - ha->isp_ops.fw_version_str(ha, fw_info)); - - qla_uprintf(&uiter, "\n[==>BEG]\n"); - - qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr); - - qla_uprintf(&uiter, "PBIU Registers:"); - for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nMailbox Registers:"); - for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nDMA Registers:"); - for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC Hardware Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP0 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP1 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP2 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP3 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP4 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP5 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP6 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP7 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:"); - for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM B0 Registers:"); - for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM B1 Registers:"); - for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC SRAM:"); - for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%04x: ", cnt + 0x1000); - } - qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump."); - - return; -} - -static int -qla_uprintf(char **uiter, char *fmt, ...) -{ - int iter, len; - char buf[128]; - va_list args; - - va_start(args, fmt); - len = vsprintf(buf, fmt, args); - va_end(args); - - for (iter = 0; iter < len; iter++, *uiter += 1) - *uiter[0] = buf[iter]; - - return (len); -} - - void qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) { @@ -967,6 +645,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) unsigned long flags; struct qla24xx_fw_dump *fw; uint32_t ext_mem_cnt; + void *eft; risc_address = ext_mem_cnt = 0; memset(mb, 0, sizeof(mb)); @@ -987,10 +666,11 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) "request...\n", ha->fw_dump); goto qla24xx_fw_dump_failed; } - fw = ha->fw_dump; + fw = &ha->fw_dump->isp.isp24; + qla2xxx_prep_dump(ha, ha->fw_dump); rval = QLA_SUCCESS; - fw->host_status = RD_REG_DWORD(®->host_status); + fw->host_status = htonl(RD_REG_DWORD(®->host_status)); /* Pause RISC. */ if ((RD_REG_DWORD(®->hccr) & HCCRX_RISC_PAUSE) == 0) { @@ -1012,7 +692,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) /* Host interface registers. */ dmp_reg = (uint32_t __iomem *)(reg + 0); for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) - fw->host_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); /* Disable interrupts. */ WRT_REG_DWORD(®->ictrl, 0); @@ -1024,470 +704,471 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0000000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[0] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[0] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0100000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[1] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[1] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0200000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[2] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[2] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0300000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[3] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[3] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0400000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[4] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[4] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0500000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[5] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[5] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0600000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[6] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[6] = htonl(RD_REG_DWORD(dmp_reg)); /* Mailbox registers. */ mbx_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) - fw->mailbox_reg[cnt] = RD_REG_WORD(mbx_reg++); + fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++)); /* Transfer sequence registers. */ iter_reg = fw->xseq_gp_reg; WRT_REG_DWORD(®->iobase_addr, 0xBF00); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF10); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF20); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF30); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF40); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF50); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF60); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF70); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBFE0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++) - fw->xseq_0_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->xseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBFF0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++) - fw->xseq_1_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); /* Receive sequence registers. */ iter_reg = fw->rseq_gp_reg; WRT_REG_DWORD(®->iobase_addr, 0xFF00); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF10); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF20); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF30); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF40); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF50); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF60); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF70); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFFD0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++) - fw->rseq_0_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->rseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFFE0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++) - fw->rseq_1_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFFF0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++) - fw->rseq_2_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); /* Command DMA registers. */ WRT_REG_DWORD(®->iobase_addr, 0x7100); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++) - fw->cmd_dma_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); /* Queues. */ iter_reg = fw->req0_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7200); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4); for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->resp0_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7300); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4); for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->req1_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7400); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4); for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Transmit DMA registers. */ iter_reg = fw->xmt0_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7600); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7610); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->xmt1_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7620); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7630); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->xmt2_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7640); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7650); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->xmt3_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7660); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7670); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->xmt4_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7680); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7690); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x76A0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++) - fw->xmt_data_dma_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->xmt_data_dma_reg[cnt] = + htonl(RD_REG_DWORD(dmp_reg++)); /* Receive DMA registers. */ iter_reg = fw->rcvt0_data_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7700); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7710); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->rcvt1_data_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7720); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7730); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* RISC registers. */ iter_reg = fw->risc_gp_reg; WRT_REG_DWORD(®->iobase_addr, 0x0F00); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F10); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F20); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F30); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F40); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F50); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F60); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F70); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Local memory controller registers. */ iter_reg = fw->lmc_reg; WRT_REG_DWORD(®->iobase_addr, 0x3000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3010); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3020); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3030); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3040); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3050); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3060); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Fibre Protocol Module registers. */ iter_reg = fw->fpm_hdw_reg; WRT_REG_DWORD(®->iobase_addr, 0x4000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4010); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4020); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4030); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4040); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4050); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4060); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4070); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4080); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4090); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x40A0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x40B0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Frame Buffer registers. */ iter_reg = fw->fb_hdw_reg; WRT_REG_DWORD(®->iobase_addr, 0x6000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6010); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6020); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6030); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6040); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6100); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6130); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6150); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6170); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6190); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x61B0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Reset RISC. */ WRT_REG_DWORD(®->ctrl_status, @@ -1577,7 +1258,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb[0] & MBS_MASK; - fw->code_ram[cnt] = (mb[3] << 16) | mb[2]; + fw->code_ram[cnt] = htonl((mb[3] << 16) | mb[2]); } else { rval = QLA_FUNCTION_FAILED; } @@ -1627,12 +1308,18 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb[0] & MBS_MASK; - fw->ext_mem[cnt] = (mb[3] << 16) | mb[2]; + fw->ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]); } else { rval = QLA_FUNCTION_FAILED; } } + if (rval == QLA_SUCCESS) { + eft = qla2xxx_copy_queues(ha, &fw->ext_mem[cnt]); + if (ha->eft) + memcpy(eft, ha->eft, ntohl(ha->fw_dump->eft_size)); + } + if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); @@ -1650,252 +1337,6 @@ qla24xx_fw_dump_failed: spin_unlock_irqrestore(&ha->hardware_lock, flags); } -void -qla24xx_ascii_fw_dump(scsi_qla_host_t *ha) -{ - uint32_t cnt; - char *uiter; - struct qla24xx_fw_dump *fw; - uint32_t ext_mem_cnt; - - uiter = ha->fw_dump_buffer; - fw = ha->fw_dump; - - qla_uprintf(&uiter, "ISP FW Version %d.%02d.%02d Attributes %04x\n", - ha->fw_major_version, ha->fw_minor_version, - ha->fw_subminor_version, ha->fw_attributes); - - qla_uprintf(&uiter, "\nR2H Status Register\n%04x\n", fw->host_status); - - qla_uprintf(&uiter, "\nHost Interface Registers"); - for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->host_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nShadow Registers"); - for (cnt = 0; cnt < sizeof(fw->shadow_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->shadow_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nMailbox Registers"); - for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->mailbox_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXSEQ GP Registers"); - for (cnt = 0; cnt < sizeof(fw->xseq_gp_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xseq_gp_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXSEQ-0 Registers"); - for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xseq_0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXSEQ-1 Registers"); - for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xseq_1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRSEQ GP Registers"); - for (cnt = 0; cnt < sizeof(fw->rseq_gp_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rseq_gp_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRSEQ-0 Registers"); - for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rseq_0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRSEQ-1 Registers"); - for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rseq_1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRSEQ-2 Registers"); - for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rseq_2_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nCommand DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->cmd_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRequest0 Queue DMA Channel Registers"); - for (cnt = 0; cnt < sizeof(fw->req0_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->req0_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nResponse0 Queue DMA Channel Registers"); - for (cnt = 0; cnt < sizeof(fw->resp0_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->resp0_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRequest1 Queue DMA Channel Registers"); - for (cnt = 0; cnt < sizeof(fw->req1_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->req1_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT0 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt0_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt0_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT1 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt1_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt1_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT2 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt2_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt2_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT3 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt3_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt3_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT4 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt4_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt4_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT Data DMA Common Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt_data_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRCV Thread 0 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->rcvt0_data_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rcvt0_data_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRCV Thread 1 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->rcvt1_data_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rcvt1_data_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP Registers"); - for (cnt = 0; cnt < sizeof(fw->risc_gp_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->risc_gp_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nLMC Registers"); - for (cnt = 0; cnt < sizeof(fw->lmc_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->lmc_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM Hardware Registers"); - for (cnt = 0; cnt < sizeof(fw->fpm_hdw_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->fpm_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFB Hardware Registers"); - for (cnt = 0; cnt < sizeof(fw->fb_hdw_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->fb_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nCode RAM"); - for (cnt = 0; cnt < sizeof (fw->code_ram) / 4; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%08x: ", cnt + 0x20000); - } - qla_uprintf(&uiter, "%08x ", fw->code_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\nExternal Memory"); - ext_mem_cnt = ha->fw_memory_size - 0x100000 + 1; - for (cnt = 0; cnt < ext_mem_cnt; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%08x: ", cnt + 0x100000); - } - qla_uprintf(&uiter, "%08x ", fw->ext_mem[cnt]); - } - - qla_uprintf(&uiter, "\n[<==END] ISP Debug Dump"); -} - - /****************************************************************************/ /* Driver Debug Functions. */ /****************************************************************************/ diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index ab6afeaa2f2..533425338e0 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -37,134 +37,86 @@ /* * Macros use for debugging the driver. */ -#undef ENTER_TRACE -#if defined(ENTER_TRACE) -#define ENTER(x) do { printk("qla2100 : Entering %s()\n", x); } while (0) -#define LEAVE(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0) -#define ENTER_INTR(x) do { printk("qla2100 : Entering %s()\n", x); } while (0) -#define LEAVE_INTR(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0) -#else -#define ENTER(x) do {} while (0) -#define LEAVE(x) do {} while (0) -#define ENTER_INTR(x) do {} while (0) -#define LEAVE_INTR(x) do {} while (0) -#endif -#if DEBUG_QLA2100 -#define DEBUG(x) do {x;} while (0); -#else -#define DEBUG(x) do {} while (0); -#endif +#define DEBUG(x) do { if (extended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_1) -#define DEBUG1(x) do {x;} while (0); +#define DEBUG1(x) do {x;} while (0) #else -#define DEBUG1(x) do {} while (0); +#define DEBUG1(x) do {} while (0) #endif -#if defined(QL_DEBUG_LEVEL_2) -#define DEBUG2(x) do {x;} while (0); -#define DEBUG2_3(x) do {x;} while (0); -#define DEBUG2_3_11(x) do {x;} while (0); -#define DEBUG2_9_10(x) do {x;} while (0); -#define DEBUG2_11(x) do {x;} while (0); -#define DEBUG2_13(x) do {x;} while (0); -#else -#define DEBUG2(x) do {} while (0); -#endif +#define DEBUG2(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_3(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_3_11(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_9_10(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_11(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_13(x) do { if (extended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_3) -#define DEBUG3(x) do {x;} while (0); -#define DEBUG2_3(x) do {x;} while (0); -#define DEBUG2_3_11(x) do {x;} while (0); -#define DEBUG3_11(x) do {x;} while (0); +#define DEBUG3(x) do {x;} while (0) +#define DEBUG3_11(x) do {x;} while (0) #else -#define DEBUG3(x) do {} while (0); - #if !defined(QL_DEBUG_LEVEL_2) - #define DEBUG2_3(x) do {} while (0); - #endif +#define DEBUG3(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_4) -#define DEBUG4(x) do {x;} while (0); +#define DEBUG4(x) do {x;} while (0) #else -#define DEBUG4(x) do {} while (0); +#define DEBUG4(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_5) -#define DEBUG5(x) do {x;} while (0); +#define DEBUG5(x) do {x;} while (0) #else -#define DEBUG5(x) do {} while (0); +#define DEBUG5(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_7) -#define DEBUG7(x) do {x;} while (0); +#define DEBUG7(x) do {x;} while (0) #else -#define DEBUG7(x) do {} while (0); +#define DEBUG7(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_9) -#define DEBUG9(x) do {x;} while (0); -#define DEBUG9_10(x) do {x;} while (0); -#define DEBUG2_9_10(x) do {x;} while (0); +#define DEBUG9(x) do {x;} while (0) +#define DEBUG9_10(x) do {x;} while (0) #else -#define DEBUG9(x) do {} while (0); +#define DEBUG9(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_10) -#define DEBUG10(x) do {x;} while (0); -#define DEBUG2_9_10(x) do {x;} while (0); -#define DEBUG9_10(x) do {x;} while (0); +#define DEBUG10(x) do {x;} while (0) +#define DEBUG9_10(x) do {x;} while (0) #else -#define DEBUG10(x) do {} while (0); - #if !defined(DEBUG2_9_10) - #define DEBUG2_9_10(x) do {} while (0); - #endif +#define DEBUG10(x) do {} while (0) #if !defined(DEBUG9_10) - #define DEBUG9_10(x) do {} while (0); + #define DEBUG9_10(x) do {} while (0) #endif #endif #if defined(QL_DEBUG_LEVEL_11) -#define DEBUG11(x) do{x;} while(0); -#if !defined(DEBUG2_11) -#define DEBUG2_11(x) do{x;} while(0); -#endif -#if !defined(DEBUG2_3_11) -#define DEBUG2_3_11(x) do{x;} while(0); -#endif +#define DEBUG11(x) do{x;} while(0) #if !defined(DEBUG3_11) -#define DEBUG3_11(x) do{x;} while(0); +#define DEBUG3_11(x) do{x;} while(0) #endif #else -#define DEBUG11(x) do{} while(0); - #if !defined(QL_DEBUG_LEVEL_2) - #define DEBUG2_11(x) do{} while(0); - #if !defined(QL_DEBUG_LEVEL_3) - #define DEBUG2_3_11(x) do{} while(0); - #endif - #endif +#define DEBUG11(x) do{} while(0) #if !defined(QL_DEBUG_LEVEL_3) - #define DEBUG3_11(x) do{} while(0); + #define DEBUG3_11(x) do{} while(0) #endif #endif #if defined(QL_DEBUG_LEVEL_12) -#define DEBUG12(x) do {x;} while (0); +#define DEBUG12(x) do {x;} while (0) #else -#define DEBUG12(x) do {} while (0); +#define DEBUG12(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_13) #define DEBUG13(x) do {x;} while (0) -#if !defined(DEBUG2_13) -#define DEBUG2_13(x) do {x;} while(0) -#endif #else #define DEBUG13(x) do {} while (0) -#if !defined(QL_DEBUG_LEVEL_2) -#define DEBUG2_13(x) do {} while(0) -#endif #endif #if defined(QL_DEBUG_LEVEL_14) @@ -176,9 +128,6 @@ /* * Firmware Dump structure definition */ -#define FW_DUMP_SIZE_128K 0xBC000 -#define FW_DUMP_SIZE_512K 0x2FC000 -#define FW_DUMP_SIZE_1M 0x5FC000 struct qla2300_fw_dump { uint16_t hccr; @@ -224,8 +173,6 @@ struct qla2100_fw_dump { uint16_t risc_ram[0xf000]; }; -#define FW_DUMP_SIZE_24XX 0x2B0000 - struct qla24xx_fw_dump { uint32_t host_status; uint32_t host_reg[32]; @@ -257,3 +204,39 @@ struct qla24xx_fw_dump { uint32_t code_ram[0x2000]; uint32_t ext_mem[1]; }; + +#define EFT_NUM_BUFFERS 4 +#define EFT_BYTES_PER_BUFFER 0x4000 +#define EFT_SIZE ((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS)) + +struct qla2xxx_fw_dump { + uint8_t signature[4]; + uint32_t version; + + uint32_t fw_major_version; + uint32_t fw_minor_version; + uint32_t fw_subminor_version; + uint32_t fw_attributes; + + uint32_t vendor; + uint32_t device; + uint32_t subsystem_vendor; + uint32_t subsystem_device; + + uint32_t fixed_size; + uint32_t mem_size; + uint32_t req_q_size; + uint32_t rsp_q_size; + + uint32_t eft_size; + uint32_t eft_addr_l; + uint32_t eft_addr_h; + + uint32_t header_size; + + union { + struct qla2100_fw_dump isp21; + struct qla2300_fw_dump isp23; + struct qla24xx_fw_dump isp24; + } isp; +}; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 6734453ea28..0930260aec2 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -487,6 +487,7 @@ typedef struct { #define MBA_IP_RCV_BUFFER_EMPTY 0x8026 /* IP receive buffer queue empty. */ #define MBA_IP_HDR_DATA_SPLIT 0x8027 /* IP header/data splitting feature */ /* used. */ +#define MBA_TRACE_NOTIFICATION 0x8028 /* Trace/Diagnostic notification. */ #define MBA_POINT_TO_POINT 0x8030 /* Point to point mode. */ #define MBA_CMPLT_1_16BIT 0x8031 /* Completion 1 16bit IOSB. */ #define MBA_CMPLT_2_16BIT 0x8032 /* Completion 2 16bit IOSB. */ @@ -608,7 +609,9 @@ typedef struct { #define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */ #define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */ #define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */ +#define MBC_TRACE_CONTROL 0x27 /* Trace control command. */ #define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */ +#define MBC_READ_SFP 0x31 /* Read SFP Data. */ #define MBC_SET_TIMEOUT_PARAMS 0x32 /* Set FW timeouts. */ #define MBC_MID_INITIALIZE_FIRMWARE 0x48 /* MID Initialize firmware. */ #define MBC_MID_GET_VP_DATABASE 0x49 /* MID Get VP Database. */ @@ -618,6 +621,9 @@ typedef struct { #define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */ #define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */ +#define TC_ENABLE 4 +#define TC_DISABLE 5 + /* Firmware return data sizes */ #define FCAL_MAP_SIZE 128 @@ -1997,7 +2003,6 @@ struct isp_operations { uint32_t); void (*fw_dump) (struct scsi_qla_host *, int); - void (*ascii_fw_dump) (struct scsi_qla_host *); int (*beacon_on) (struct scsi_qla_host *); int (*beacon_off) (struct scsi_qla_host *); @@ -2041,6 +2046,7 @@ typedef struct scsi_qla_host { uint32_t enable_led_scheme :1; uint32_t msi_enabled :1; uint32_t msix_enabled :1; + uint32_t disable_serdes :1; } flags; atomic_t loop_state; @@ -2238,6 +2244,11 @@ typedef struct scsi_qla_host { struct sns_cmd_pkt *sns_cmd; dma_addr_t sns_cmd_dma; +#define SFP_DEV_SIZE 256 +#define SFP_BLOCK_SIZE 64 + void *sfp_data; + dma_addr_t sfp_data_dma; + struct task_struct *dpc_thread; uint8_t dpc_active; /* DPC routine is active */ @@ -2303,11 +2314,12 @@ typedef struct scsi_qla_host { uint16_t fw_seriallink_options24[4]; /* Firmware dump information. */ - void *fw_dump; + struct qla2xxx_fw_dump *fw_dump; + uint32_t fw_dump_len; int fw_dumped; int fw_dump_reading; - char *fw_dump_buffer; - int fw_dump_buffer_len; + dma_addr_t eft_dma; + void *eft; uint8_t host_str[16]; uint32_t pci_attr; diff --git a/drivers/scsi/qla2xxx/qla_devtbl.h b/drivers/scsi/qla2xxx/qla_devtbl.h index a8fc0ffc7fc..dd435410dfa 100644 --- a/drivers/scsi/qla2xxx/qla_devtbl.h +++ b/drivers/scsi/qla2xxx/qla_devtbl.h @@ -1,4 +1,4 @@ -#define QLA_MODEL_NAMES 0x4A +#define QLA_MODEL_NAMES 0x57 /* * Adapter model names and descriptions. @@ -76,6 +76,19 @@ static char *qla2x00_model_name[QLA_MODEL_NAMES*2] = { "QLE2440", "PCI-Express to 4Gb FC, Single Channel", /* 0x145 */ "QLE2464", "PCI-Express to 4Gb FC, Quad Channel", /* 0x146 */ "QLA2440", "PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x147 */ - " ", " ", /* 0x148 */ + "HP AE369A", "PCI-X 2.0 to 4Gb FC, Dual Channel", /* 0x148 */ "QLA2340", "Sun 133MHz PCI-X to 2Gb FC, Single Channel", /* 0x149 */ + " ", " ", /* 0x14a */ + " ", " ", /* 0x14b */ + "QMC2432M", "IBM eServer BC 4Gb FC Expansion Card CFFE", /* 0x14c */ + "QMC2422M", "IBM eServer BC 4Gb FC Expansion Card CFFX", /* 0x14d */ + "QLE220", "Sun PCI-Express to 4Gb FC, Single Channel", /* 0x14e */ + " ", " ", /* 0x14f */ + " ", " ", /* 0x150 */ + " ", " ", /* 0x151 */ + "QME2462", "PCI-Express to 4Gb FC, Dual Channel Mezz HBA", /* 0x152 */ + "QMH2462", "PCI-Express to 4Gb FC, Dual Channel Mezz HBA", /* 0x153 */ + " ", " ", /* 0x154 */ + "QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x155 */ + "QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x156 */ }; diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 3af478663be..a0a722cf423 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -141,7 +141,7 @@ struct nvram_24xx { * BIT 2 = Enable Memory Map BIOS * BIT 3 = Enable Selectable Boot * BIT 4 = Disable RISC code load - * BIT 5 = + * BIT 5 = Disable Serdes * BIT 6 = * BIT 7 = * @@ -278,7 +278,7 @@ struct init_cb_24xx { uint16_t response_q_length; uint16_t request_q_length; - uint16_t link_down_timeout; /* Milliseconds. */ + uint16_t link_down_on_nos; /* Milliseconds. */ uint16_t prio_request_q_length; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 164d53ccbfd..8311ac2b93a 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -31,13 +31,9 @@ extern void qla2x00_update_fw_options(struct scsi_qla_host *); extern void qla24xx_update_fw_options(scsi_qla_host_t *); extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *); extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *); -extern int qla24xx_load_risc_flash(scsi_qla_host_t *, uint32_t *); - -extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t); extern int qla2x00_loop_resync(scsi_qla_host_t *); -extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_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 *); @@ -51,6 +47,8 @@ extern int qla2x00_abort_isp(scsi_qla_host_t *); extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); extern void qla2x00_reg_remote_port(scsi_qla_host_t *, fc_port_t *); +extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *); + /* * Global Data in qla_os.c source file. */ @@ -61,6 +59,8 @@ extern int qlport_down_retry; extern int ql2xplogiabsentdevice; extern int ql2xloginretrycount; extern int ql2xfdmienable; +extern int ql2xallocfwdump; +extern int extended_error_logging; extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); @@ -80,8 +80,6 @@ extern void qla2xxx_wake_dpc(scsi_qla_host_t *); /* * Global Function Prototypes in qla_iocb.c source file. */ -extern void qla2x00_isp_cmd(scsi_qla_host_t *); - extern uint16_t qla2x00_calc_iocbs_32(uint16_t); extern uint16_t qla2x00_calc_iocbs_64(uint16_t); extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t); @@ -204,6 +202,12 @@ qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); extern int qla2x00_stop_firmware(scsi_qla_host_t *); +extern int +qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t); + +extern int +qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); + /* * Global Function Prototypes in qla_isr.c source file. */ @@ -254,9 +258,6 @@ extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *, extern void qla2100_fw_dump(scsi_qla_host_t *, int); extern void qla2300_fw_dump(scsi_qla_host_t *, int); extern void qla24xx_fw_dump(scsi_qla_host_t *, int); -extern void qla2100_ascii_fw_dump(scsi_qla_host_t *); -extern void qla2300_ascii_fw_dump(scsi_qla_host_t *); -extern void qla24xx_ascii_fw_dump(scsi_qla_host_t *); 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 *); @@ -280,13 +281,6 @@ extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); extern int qla2x00_fdmi_register(scsi_qla_host_t *); /* - * Global Function Prototypes in qla_xioctl.c source file. - */ -#define qla2x00_enqueue_aen(ha, cmd, mode) do { } while (0) -#define qla2x00_alloc_ioctl_mem(ha) (0) -#define qla2x00_free_ioctl_mem(ha) do { } while (0) - -/* * Global Function Prototypes in qla_attr.c source file. */ struct class_device_attribute; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 3d4487eac9b..859649160ca 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -39,6 +39,8 @@ static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *, 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); + /****************************************************************************/ /* QLogic ISP2x00 Hardware Support Functions. */ /****************************************************************************/ @@ -89,6 +91,17 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) ha->isp_ops.nvram_config(ha); + if (ha->flags.disable_serdes) { + /* Mask HBA via NVRAM settings? */ + qla_printk(KERN_INFO, ha, "Masking HBA WWPN " + "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n", + ha->port_name[0], ha->port_name[1], + ha->port_name[2], ha->port_name[3], + ha->port_name[4], ha->port_name[5], + ha->port_name[6], ha->port_name[7]); + return QLA_FUNCTION_FAILED; + } + qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n"); retry = 10; @@ -770,29 +783,104 @@ qla24xx_chip_diag(scsi_qla_host_t *ha) return rval; } -static void +void qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) { - uint32_t dump_size = 0; + int rval; + uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size, + eft_size; + dma_addr_t eft_dma; + void *eft; + + if (ha->fw_dump) { + qla_printk(KERN_WARNING, ha, + "Firmware dump previously allocated.\n"); + return; + } ha->fw_dumped = 0; + fixed_size = mem_size = eft_size = 0; if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - dump_size = sizeof(struct qla2100_fw_dump); + fixed_size = sizeof(struct qla2100_fw_dump); } else if (IS_QLA23XX(ha)) { - dump_size = sizeof(struct qla2300_fw_dump); - dump_size += (ha->fw_memory_size - 0x11000) * sizeof(uint16_t); - } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { - dump_size = sizeof(struct qla24xx_fw_dump); - dump_size += (ha->fw_memory_size - 0x100000) * sizeof(uint32_t); + fixed_size = offsetof(struct qla2300_fw_dump, data_ram); + mem_size = (ha->fw_memory_size - 0x11000 + 1) * + sizeof(uint16_t); + } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem); + mem_size = (ha->fw_memory_size - 0x100000 + 1) * + sizeof(uint32_t); + + /* Allocate memory for Extended Trace Buffer. */ + eft = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &eft_dma, + GFP_KERNEL); + if (!eft) { + qla_printk(KERN_WARNING, ha, "Unable to allocate " + "(%d KB) for EFT.\n", EFT_SIZE / 1024); + goto cont_alloc; + } + + rval = qla2x00_trace_control(ha, TC_ENABLE, eft_dma, + EFT_NUM_BUFFERS); + if (rval) { + qla_printk(KERN_WARNING, ha, "Unable to initialize " + "EFT (%d).\n", rval); + dma_free_coherent(&ha->pdev->dev, EFT_SIZE, eft, + eft_dma); + goto cont_alloc; + } + + qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n", + EFT_SIZE / 1024); + + eft_size = EFT_SIZE; + memset(eft, 0, eft_size); + ha->eft_dma = eft_dma; + ha->eft = eft; } +cont_alloc: + req_q_size = ha->request_q_length * sizeof(request_t); + rsp_q_size = ha->response_q_length * sizeof(response_t); + + dump_size = offsetof(struct qla2xxx_fw_dump, isp); + dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + + eft_size; ha->fw_dump = vmalloc(dump_size); - if (ha->fw_dump) - qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware " - "dump...\n", dump_size / 1024); - else + if (!ha->fw_dump) { qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for " "firmware dump!!!\n", dump_size / 1024); + + if (ha->eft) { + dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft, + ha->eft_dma); + ha->eft = NULL; + ha->eft_dma = 0; + } + return; + } + + qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n", + dump_size / 1024); + + ha->fw_dump_len = dump_size; + ha->fw_dump->signature[0] = 'Q'; + ha->fw_dump->signature[1] = 'L'; + ha->fw_dump->signature[2] = 'G'; + ha->fw_dump->signature[3] = 'C'; + ha->fw_dump->version = __constant_htonl(1); + + ha->fw_dump->fixed_size = htonl(fixed_size); + ha->fw_dump->mem_size = htonl(mem_size); + ha->fw_dump->req_q_size = htonl(req_q_size); + ha->fw_dump->rsp_q_size = htonl(rsp_q_size); + + ha->fw_dump->eft_size = htonl(eft_size); + ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma)); + ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma)); + + ha->fw_dump->header_size = + htonl(offsetof(struct qla2xxx_fw_dump, isp)); } /** @@ -810,8 +898,6 @@ qla2x00_resize_request_q(scsi_qla_host_t *ha) dma_addr_t request_dma; request_t *request_ring; - qla2x00_alloc_fw_dump(ha); - /* Valid only on recent ISPs. */ if (IS_QLA2100(ha) || IS_QLA2200(ha)) return; @@ -883,6 +969,9 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) &ha->fw_subminor_version, &ha->fw_attributes, &ha->fw_memory_size); qla2x00_resize_request_q(ha); + + if (ql2xallocfwdump) + qla2x00_alloc_fw_dump(ha); } } else { DEBUG2(printk(KERN_INFO @@ -1186,8 +1275,7 @@ qla2x00_fw_ready(scsi_qla_host_t *ha) rval = QLA_FUNCTION_FAILED; if (atomic_read(&ha->loop_down_timer) && - (fw_state >= FSTATE_LOSS_OF_SYNC || - fw_state == FSTATE_WAIT_AL_PA)) { + fw_state != FSTATE_READY) { /* Loop down. Timeout on min_wait for states * other than Wait for Login. */ @@ -1555,6 +1643,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) /* * Set host adapter parameters. */ + if (nv->host_p[0] & BIT_7) + extended_error_logging = 1; ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0); /* Always load RISC code on non ISP2[12]00 chips. */ if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) @@ -1563,6 +1653,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0); ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0); ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0; + ha->flags.disable_serdes = 0; ha->operating_mode = (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4; @@ -1701,7 +1792,7 @@ qla2x00_rport_del(void *data) * * Returns a pointer to the allocated fcport, or NULL, if none available. */ -fc_port_t * +static fc_port_t * qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags) { fc_port_t *fcport; @@ -2497,7 +2588,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) * Context: * Kernel context. */ -int +static int qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev) { int rval; @@ -2972,6 +3063,7 @@ qla2x00_update_fcports(scsi_qla_host_t *ha) int qla2x00_abort_isp(scsi_qla_host_t *ha) { + int rval; unsigned long flags = 0; uint16_t cnt; srb_t *sp; @@ -3028,6 +3120,16 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) ha->isp_abort_cnt = 0; clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags); + + if (ha->eft) { + rval = qla2x00_trace_control(ha, TC_ENABLE, + ha->eft_dma, EFT_NUM_BUFFERS); + if (rval) { + qla_printk(KERN_WARNING, ha, + "Unable to reinitialize EFT " + "(%d).\n", rval); + } + } } else { /* failed the ISP abort */ ha->flags.online = 1; if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) { @@ -3048,14 +3150,14 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) ha->isp_abort_cnt--; DEBUG(printk("qla%ld: ISP abort - " "retry remaining %d\n", - ha->host_no, ha->isp_abort_cnt);) + ha->host_no, ha->isp_abort_cnt)); status = 1; } } else { ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT; DEBUG(printk("qla2x00(%ld): ISP error recovery " "- retrying (%d) more times\n", - ha->host_no, ha->isp_abort_cnt);) + ha->host_no, ha->isp_abort_cnt)); set_bit(ISP_ABORT_RETRY, &ha->dpc_flags); status = 1; } @@ -3069,7 +3171,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) } else { DEBUG(printk(KERN_INFO "qla2x00_abort_isp(%ld): exiting.\n", - ha->host_no);) + ha->host_no)); } return(status); @@ -3145,7 +3247,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha) clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); if (!(status = qla2x00_fw_ready(ha))) { DEBUG(printk("%s(): Start configure loop, " - "status = %d\n", __func__, status);) + "status = %d\n", __func__, status)); /* Issue a marker after FW becomes ready. */ qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); @@ -3169,7 +3271,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha) DEBUG(printk("%s(): Configure loop done, status = 0x%x\n", __func__, - status);) + status)); } return (status); } @@ -3289,7 +3391,6 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) nv->node_name[6] = 0x55; nv->node_name[7] = 0x86; nv->login_retry_count = __constant_cpu_to_le16(8); - nv->link_down_timeout = __constant_cpu_to_le16(200); nv->interrupt_delay_timer = __constant_cpu_to_le16(0); nv->login_timeout = __constant_cpu_to_le16(0); nv->firmware_options_1 = @@ -3318,7 +3419,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) *dptr1++ = *dptr2++; icb->login_retry_count = nv->login_retry_count; - icb->link_down_timeout = nv->link_down_timeout; + icb->link_down_on_nos = nv->link_down_on_nos; /* Copy 2nd segment. */ dptr1 = (uint8_t *)&icb->interrupt_delay_timer; @@ -3373,6 +3474,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) ha->flags.enable_lip_full_login = 1; ha->flags.enable_target_reset = 1; ha->flags.enable_led_scheme = 0; + ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0; ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) & (BIT_6 | BIT_5 | BIT_4)) >> 4; @@ -3472,7 +3574,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) return (rval); } -int +static int qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr) { int rval; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 8c769cfaa14..c5b3c610a32 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -15,6 +15,7 @@ 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); /** * qla2x00_get_cmd_direction() - Determine control_flag data direction. @@ -470,6 +471,7 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun, mrk24->nport_handle = cpu_to_le16(loop_id); mrk24->lun[1] = LSB(lun); mrk24->lun[2] = MSB(lun); + host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun)); } else { SET_TARGET_ID(ha, mrk->target, loop_id); mrk->lun = cpu_to_le16(lun); @@ -574,7 +576,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha) * * Note: The caller must hold the hardware lock before calling this routine. */ -void +static void qla2x00_isp_cmd(scsi_qla_host_t *ha) { device_reg_t __iomem *reg = ha->iobase; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index b28ac0a27e2..de0613135f7 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -395,10 +395,6 @@ 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; - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_LIP_OCCURRED, NULL); - break; case MBA_LOOP_UP: /* Loop Up Event */ @@ -418,9 +414,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) link_speed); ha->flags.management_server_logged_in = 0; - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_LOOP_UP, NULL); break; case MBA_LOOP_DOWN: /* Loop Down Event */ @@ -439,9 +432,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->link_data_rate = LDR_UNKNOWN; if (ql2xfdmienable) set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_LOOP_DOWN, NULL); break; case MBA_LIP_RESET: /* LIP reset occurred */ @@ -460,10 +450,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->operating_mode = LOOP; ha->flags.management_server_logged_in = 0; - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_LIP_RESET, NULL); - break; case MBA_POINT_TO_POINT: /* Point-to-Point */ @@ -545,9 +531,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_PORT_UPDATE, NULL); break; case MBA_RSCN_UPDATE: /* State Change Registration */ @@ -584,9 +567,6 @@ 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); - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_RSCN_UPDATE, &mb[0]); break; /* case MBA_RIO_RESPONSE: */ @@ -607,6 +587,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) DEBUG2(printk("scsi(%ld): Discard RND Frame -- %04x %04x " "%04x.\n", ha->host_no, mb[1], mb[2], mb[3])); break; + + case MBA_TRACE_NOTIFICATION: + DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n", + ha->host_no, mb[1], mb[2])); + break; } } @@ -1452,8 +1437,8 @@ qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt) 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));) + 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) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index d6cb3bd1a29..879f281e2ea 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -13,13 +13,13 @@ qla2x00_mbx_sem_timeout(unsigned long data) { struct semaphore *sem_ptr = (struct semaphore *)data; - DEBUG11(printk("qla2x00_sem_timeout: entered.\n");) + DEBUG11(printk("qla2x00_sem_timeout: entered.\n")); if (sem_ptr != NULL) { up(sem_ptr); } - DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n");) + DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n")); } /* @@ -61,7 +61,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) rval = QLA_SUCCESS; abort_active = test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); /* * Wait for active mailbox commands to finish by waiting at most tov @@ -72,7 +72,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) if (qla2x00_down_timeout(&ha->mbx_cmd_sem, mcp->tov * HZ)) { /* Timeout occurred. Return error. */ DEBUG2_3_11(printk("%s(%ld): cmd access timeout. " - "Exiting.\n", __func__, ha->host_no);) + "Exiting.\n", __func__, ha->host_no)); return QLA_FUNCTION_TIMEOUT; } } @@ -86,7 +86,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags); DEBUG11(printk("scsi(%ld): prepare to issue mbox cmd=0x%x.\n", - ha->host_no, mcp->mb[0]);) + ha->host_no, mcp->mb[0])); spin_lock_irqsave(&ha->hardware_lock, flags); @@ -131,14 +131,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) /* Unlock mbx registers and wait for interrupt */ DEBUG11(printk("%s(%ld): going to unlock irq & waiting for interrupt. " - "jiffies=%lx.\n", __func__, ha->host_no, jiffies);) + "jiffies=%lx.\n", __func__, ha->host_no, jiffies)); /* Wait for mbx cmd completion until timeout */ if (!abort_active && io_lock_on) { /* sleep on completion semaphore */ DEBUG11(printk("%s(%ld): INTERRUPT MODE. Initializing timer.\n", - __func__, ha->host_no);) + __func__, ha->host_no)); init_timer(&tmp_intr_timer); tmp_intr_timer.data = (unsigned long)&ha->mbx_intr_sem; @@ -147,11 +147,11 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) (void (*)(unsigned long))qla2x00_mbx_sem_timeout; DEBUG11(printk("%s(%ld): Adding timer.\n", __func__, - ha->host_no);) + ha->host_no)); add_timer(&tmp_intr_timer); DEBUG11(printk("%s(%ld): going to unlock & sleep. " - "time=0x%lx.\n", __func__, ha->host_no, jiffies);) + "time=0x%lx.\n", __func__, ha->host_no, jiffies)); set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); @@ -170,14 +170,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) down(&ha->mbx_intr_sem); DEBUG11(printk("%s(%ld): waking up. time=0x%lx\n", __func__, - ha->host_no, jiffies);) + ha->host_no, jiffies)); clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); /* delete the timer */ del_timer(&tmp_intr_timer); } else { DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__, - ha->host_no, command);) + ha->host_no, command)); if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) WRT_REG_DWORD(®->isp24.hccr, HCCRX_SET_HOST_INT); @@ -209,7 +209,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) uint16_t *iptr2; DEBUG3_11(printk("%s(%ld): cmd %x completed.\n", __func__, - ha->host_no, command);) + ha->host_no, command)); /* Got interrupt. Clear the flag. */ ha->flags.mbox_int = 0; @@ -266,7 +266,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) if (!abort_active) { DEBUG11(printk("%s(%ld): checking for additional resp " - "interrupt.\n", __func__, ha->host_no);) + "interrupt.\n", __func__, ha->host_no)); /* polling mode for non isp_abort commands. */ qla2x00_poll(ha); @@ -277,9 +277,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) if (!io_lock_on || (mcp->flags & IOCTL_CMD)) { /* not in dpc. schedule it for dpc to take over. */ DEBUG(printk("%s(%ld): timeout schedule " - "isp_abort_needed.\n", __func__, ha->host_no);) + "isp_abort_needed.\n", __func__, ha->host_no)); DEBUG2_3_11(printk("%s(%ld): timeout schedule " - "isp_abort_needed.\n", __func__, ha->host_no);) + "isp_abort_needed.\n", __func__, ha->host_no)); qla_printk(KERN_WARNING, ha, "Mailbox command timeout occured. Scheduling ISP " "abort.\n"); @@ -288,9 +288,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) } else if (!abort_active) { /* call abort directly since we are in the DPC thread */ DEBUG(printk("%s(%ld): timeout calling abort_isp\n", - __func__, ha->host_no);) + __func__, ha->host_no)); DEBUG2_3_11(printk("%s(%ld): timeout calling " - "abort_isp\n", __func__, ha->host_no);) + "abort_isp\n", __func__, ha->host_no)); qla_printk(KERN_WARNING, ha, "Mailbox command timeout occured. Issuing ISP " "abort.\n"); @@ -303,9 +303,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) } clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); DEBUG(printk("%s(%ld): finished abort_isp\n", __func__, - ha->host_no);) + ha->host_no)); DEBUG2_3_11(printk("%s(%ld): finished abort_isp\n", - __func__, ha->host_no);) + __func__, ha->host_no)); } } @@ -316,9 +316,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) if (rval) { DEBUG2_3_11(printk("%s(%ld): **** FAILED. mbx0=%x, mbx1=%x, " "mbx2=%x, cmd=%x ****\n", __func__, ha->host_no, - mcp->mb[0], mcp->mb[1], mcp->mb[2], command);) + mcp->mb[0], mcp->mb[1], mcp->mb[2], command)); } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return rval; @@ -394,7 +394,7 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); mcp->mb[0] = MBC_EXECUTE_FIRMWARE; mcp->out_mb = MBX_0; @@ -424,10 +424,10 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr) } else { if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { DEBUG11(printk("%s(%ld): done exchanges=%x.\n", - __func__, ha->host_no, mcp->mb[1]);) + __func__, ha->host_no, mcp->mb[1])); } else { DEBUG11(printk("%s(%ld): done.\n", __func__, - ha->host_no);) + ha->host_no)); } } @@ -611,7 +611,7 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", ha->host_no);) + DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", ha->host_no)); mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST; mcp->mb[1] = 0xAAAA; @@ -639,11 +639,11 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha) if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_mbx_reg_test(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_mbx_reg_test(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -671,7 +671,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); mcp->mb[0] = MBC_VERIFY_CHECKSUM; mcp->out_mb = MBX_0; @@ -694,9 +694,9 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr) if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed=%x chk sum=%x.\n", __func__, ha->host_no, rval, (IS_QLA24XX(ha) || IS_QLA54XX(ha) ? - (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1]));) + (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1]))); } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return rval; @@ -743,9 +743,9 @@ qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n", - ha->host_no, rval);) + ha->host_no, rval)); DEBUG2(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { sts_entry_t *sts_entry = (sts_entry_t *) buffer; @@ -781,7 +781,7 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no);) + DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no)); fcport = sp->fcport; @@ -813,11 +813,11 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp) if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("qla2x00_abort_command(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { sp->flags |= SRB_ABORT_PENDING; DEBUG11(printk("qla2x00_abort_command(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -848,7 +848,7 @@ qla2x00_abort_target(fc_port_t *fcport) if (fcport == NULL) return 0; - DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); ha = fcport->ha; mcp->mb[0] = MBC_ABORT_TARGET; @@ -872,11 +872,11 @@ qla2x00_abort_target(fc_port_t *fcport) if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("qla2x00_abort_target(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_abort_target(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -912,7 +912,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_adapter_id(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID; mcp->out_mb = MBX_0; @@ -933,11 +933,11 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_adapter_id(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -968,7 +968,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_retry_cnt(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_GET_RETRY_COUNT; mcp->out_mb = MBX_0; @@ -980,7 +980,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_retry_cnt(%ld): failed = %x.\n", - ha->host_no, mcp->mb[0]);) + ha->host_no, mcp->mb[0])); } else { /* Convert returned data and check our values. */ *r_a_tov = mcp->mb[3] / 2; @@ -992,7 +992,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov, } DEBUG11(printk("qla2x00_get_retry_cnt(%ld): done. mb3=%d " - "ratov=%d.\n", ha->host_no, mcp->mb[3], ratov);) + "ratov=%d.\n", ha->host_no, mcp->mb[3], ratov)); } return rval; @@ -1023,7 +1023,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size) mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_INITIALIZE_FIRMWARE; mcp->mb[2] = MSW(ha->init_cb_dma); @@ -1043,11 +1043,11 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size) /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_init_firmware(%ld): failed=%x " "mb0=%x.\n", - ha->host_no, rval, mcp->mb[0]);) + ha->host_no, rval, mcp->mb[0])); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_init_firmware(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1079,7 +1079,7 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt) struct port_database_24xx *pd24; dma_addr_t pd_dma; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); pd24 = NULL; pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma); @@ -1220,7 +1220,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr) mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_firmware_state(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_GET_FIRMWARE_STATE; mcp->out_mb = MBX_0; @@ -1235,11 +1235,11 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr) if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_firmware_state(%ld): " - "failed=%x.\n", ha->host_no, rval);) + "failed=%x.\n", ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_get_firmware_state(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1272,7 +1272,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_port_name(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_GET_PORT_NAME; mcp->out_mb = MBX_1|MBX_0; @@ -1292,7 +1292,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_port_name(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { if (name != NULL) { /* This function returns name in big endian. */ @@ -1307,7 +1307,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name, } DEBUG11(printk("qla2x00_get_port_name(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1335,7 +1335,7 @@ qla2x00_lip_reset(scsi_qla_host_t *ha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { mcp->mb[0] = MBC_LIP_FULL_LOGIN; @@ -1364,10 +1364,10 @@ qla2x00_lip_reset(scsi_qla_host_t *ha) if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", - __func__, ha->host_no, rval);) + __func__, ha->host_no, rval)); } else { /*EMPTY*/ - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return rval; @@ -1400,10 +1400,10 @@ qla2x00_send_sns(scsi_qla_host_t *ha, dma_addr_t sns_phys_address, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_send_sns(%ld): entered.\n", - ha->host_no);) + ha->host_no)); DEBUG11(printk("qla2x00_send_sns: retry cnt=%d ratov=%d total " - "tov=%d.\n", ha->retry_count, ha->login_timeout, mcp->tov);) + "tov=%d.\n", ha->retry_count, ha->login_timeout, mcp->tov)); mcp->mb[0] = MBC_SEND_SNS_COMMAND; mcp->mb[1] = cmd_size; @@ -1421,12 +1421,12 @@ qla2x00_send_sns(scsi_qla_host_t *ha, dma_addr_t sns_phys_address, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x " - "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);) + "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1])); DEBUG2_3_11(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x " - "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);) + "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1])); } else { /*EMPTY*/ - DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", ha->host_no);) + DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", ha->host_no)); } return rval; @@ -1442,7 +1442,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, dma_addr_t lg_dma; uint32_t iop[2]; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); if (lg == NULL) { @@ -1458,13 +1458,15 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, lg->control_flags = __constant_cpu_to_le16(LCF_COMMAND_PLOGI); if (opt & BIT_0) lg->control_flags |= __constant_cpu_to_le16(LCF_COND_PLOGI); + if (opt & BIT_1) + lg->control_flags |= __constant_cpu_to_le16(LCF_SKIP_PRLI); lg->port_id[0] = al_pa; lg->port_id[1] = area; lg->port_id[2] = domain; rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Login IOCB " - "(%x).\n", __func__, ha->host_no, rval);) + "(%x).\n", __func__, ha->host_no, rval)); } else if (lg->entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- error status (%x).\n", __func__, ha->host_no, @@ -1505,7 +1507,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, break; } } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); iop[0] = le32_to_cpu(lg->io_parameter[0]); @@ -1559,7 +1561,7 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", ha->host_no);) + DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", ha->host_no)); mcp->mb[0] = MBC_LOGIN_FABRIC_PORT; mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; @@ -1604,11 +1606,11 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_login_fabric(%ld): failed=%x " "mb[0]=%x mb[1]=%x mb[2]=%x.\n", ha->host_no, rval, - mcp->mb[0], mcp->mb[1], mcp->mb[2]);) + mcp->mb[0], mcp->mb[1], mcp->mb[2])); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_login_fabric(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1643,7 +1645,7 @@ qla2x00_login_local_device(scsi_qla_host_t *ha, fc_port_t *fcport, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, mb_ret, opt); - DEBUG3(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG3(printk("%s(%ld): entered.\n", __func__, ha->host_no)); mcp->mb[0] = MBC_LOGIN_LOOP_PORT; if (HAS_EXTENDED_IDS(ha)) @@ -1677,13 +1679,13 @@ qla2x00_login_local_device(scsi_qla_host_t *ha, fc_port_t *fcport, DEBUG(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x " "mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval, - mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);) + mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7])); DEBUG2_3(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x " "mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval, - mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);) + mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7])); } else { /*EMPTY*/ - DEBUG3(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG3(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return (rval); @@ -1697,7 +1699,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, struct logio_entry_24xx *lg; dma_addr_t lg_dma; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); if (lg == NULL) { @@ -1718,7 +1720,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB " - "(%x).\n", __func__, ha->host_no, rval);) + "(%x).\n", __func__, ha->host_no, rval)); } else if (lg->entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- error status (%x).\n", __func__, ha->host_no, @@ -1729,10 +1731,10 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, "-- completion status (%x) ioparam=%x/%x.\n", __func__, ha->host_no, le16_to_cpu(lg->comp_status), le32_to_cpu(lg->io_parameter[0]), - le32_to_cpu(lg->io_parameter[1]));) + le32_to_cpu(lg->io_parameter[1]))); } else { /*EMPTY*/ - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } dma_pool_free(ha->s_dma_pool, lg, lg_dma); @@ -1765,7 +1767,7 @@ qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_fabric_logout(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_LOGOUT_FABRIC_PORT; mcp->out_mb = MBX_1|MBX_0; @@ -1785,11 +1787,11 @@ qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_fabric_logout(%ld): failed=%x " - "mbx1=%x.\n", ha->host_no, rval, mcp->mb[1]);) + "mbx1=%x.\n", ha->host_no, rval, mcp->mb[1])); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_fabric_logout(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1818,7 +1820,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha) mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_LIP_FULL_LOGIN; mcp->mb[1] = 0; @@ -1833,11 +1835,11 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha) if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_full_login_lip(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_full_login_lip(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1864,7 +1866,7 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_id_list(%ld): entered.\n", - ha->host_no);) + ha->host_no)); if (id_list == NULL) return QLA_FUNCTION_FAILED; @@ -1893,11 +1895,11 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_id_list(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { *entries = mcp->mb[1]; DEBUG11(printk("qla2x00_get_id_list(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1936,7 +1938,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("%s(%ld): failed = %x.\n", __func__, - ha->host_no, mcp->mb[0]);) + ha->host_no, mcp->mb[0])); } else { DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x " "mb7=%x mb10=%x.\n", __func__, ha->host_no, @@ -2045,7 +2047,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id, link_stat_t *stat_buf; dma_addr_t stat_buf_dma; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); stat_buf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &stat_buf_dma); if (stat_buf == NULL) { @@ -2083,7 +2085,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id, if (rval == QLA_SUCCESS) { if (mcp->mb[0] != MBS_COMMAND_COMPLETE) { DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n", - __func__, ha->host_no, mcp->mb[0]);) + __func__, ha->host_no, mcp->mb[0])); status[0] = mcp->mb[0]; rval = BIT_1; } else { @@ -2108,12 +2110,12 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id, stat_buf->loss_sync_cnt, stat_buf->loss_sig_cnt, stat_buf->prim_seq_err_cnt, stat_buf->inval_xmit_word_cnt, - stat_buf->inval_crc_cnt);) + stat_buf->inval_crc_cnt)); } } else { /* Failed. */ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, - ha->host_no, rval);) + ha->host_no, rval)); rval = BIT_1; } @@ -2132,7 +2134,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords, uint32_t *sbuf, *siter; dma_addr_t sbuf_dma; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); if (dwords > (DMA_POOL_SIZE / 4)) { DEBUG2_3_11(printk("%s(%ld): Unabled to retrieve %d DWORDs " @@ -2196,7 +2198,7 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp) dma_addr_t abt_dma; uint32_t handle; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); fcport = sp->fcport; @@ -2229,7 +2231,7 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp) rval = qla2x00_issue_iocb(ha, abt, abt_dma, 0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue IOCB (%x).\n", - __func__, ha->host_no, rval);) + __func__, ha->host_no, rval)); } else if (abt->entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- error status (%x).\n", __func__, ha->host_no, @@ -2238,10 +2240,10 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp) } else if (abt->nport_handle != __constant_cpu_to_le16(0)) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- completion status (%x).\n", __func__, ha->host_no, - le16_to_cpu(abt->nport_handle));) + le16_to_cpu(abt->nport_handle))); rval = QLA_FUNCTION_FAILED; } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); sp->flags |= SRB_ABORT_PENDING; } @@ -2268,7 +2270,7 @@ qla24xx_abort_target(fc_port_t *fcport) if (fcport == NULL) return 0; - DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); ha = fcport->ha; tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma); @@ -2290,7 +2292,7 @@ qla24xx_abort_target(fc_port_t *fcport) 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);) + "(%x).\n", __func__, ha->host_no, rval)); goto atarget_done; } else if (tsk->p.sts.entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " @@ -2302,7 +2304,7 @@ qla24xx_abort_target(fc_port_t *fcport) __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));) + ha->host_no, le16_to_cpu(tsk->p.sts.comp_status))); rval = QLA_FUNCTION_FAILED; goto atarget_done; } @@ -2311,9 +2313,9 @@ qla24xx_abort_target(fc_port_t *fcport) rval = qla2x00_marker(ha, fcport->loop_id, 0, MK_SYNC_ID); if (rval != 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, rval)); } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } atarget_done: @@ -2460,3 +2462,81 @@ qla2x00_stop_firmware(scsi_qla_host_t *ha) return rval; } + +int +qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma, + uint16_t buffers) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_TRACE_CONTROL; + mcp->mb[1] = ctrl; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + if (ctrl == TC_ENABLE) { + mcp->mb[2] = LSW(eft_dma); + mcp->mb[3] = MSW(eft_dma); + mcp->mb[4] = LSW(MSD(eft_dma)); + mcp->mb[5] = MSW(MSD(eft_dma)); + mcp->mb[6] = buffers; + mcp->mb[7] = buffers; + mcp->out_mb |= MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2; + } + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n", + __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} + +int +qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr, + uint16_t off, uint16_t count) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_READ_SFP; + mcp->mb[1] = addr; + mcp->mb[2] = MSW(sfp_dma); + mcp->mb[3] = LSW(sfp_dma); + mcp->mb[6] = MSW(MSD(sfp_dma)); + mcp->mb[7] = LSW(MSD(sfp_dma)); + mcp->mb[8] = count; + mcp->mb[9] = off; + 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->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, + ha->host_no, rval, mcp->mb[0])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 93062593ebe..65cbe2f5eea 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -39,14 +39,14 @@ MODULE_PARM_DESC(ql2xlogintimeout, int qlport_down_retry = 30; module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(qlport_down_retry, - "Maximum number of command retries to a port that returns" + "Maximum number of command retries to a port that returns " "a PORT-DOWN status."); int ql2xplogiabsentdevice; module_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xplogiabsentdevice, "Option to enable PLOGI to devices that are not present after " - "a Fabric scan. This is needed for several broken switches." + "a Fabric scan. This is needed for several broken switches. " "Default is 0 - no PLOGI. 1 - perfom PLOGI."); int ql2xloginretrycount = 0; @@ -54,6 +54,19 @@ module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xloginretrycount, "Specify an alternate value for the NVRAM login retry count."); +int ql2xallocfwdump = 1; +module_param(ql2xallocfwdump, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xallocfwdump, + "Option to enable allocation of memory for a firmware dump " + "during HBA initialization. Memory allocation requirements " + "vary by ISP type. Default is 1 - allocate memory."); + +int extended_error_logging; +module_param(extended_error_logging, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(extended_error_logging, + "Option to enable extended error logging, " + "Default is 0 - no logging. 1 - log errors."); + static void qla2x00_free_device(scsi_qla_host_t *); static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha); @@ -624,7 +637,7 @@ 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);) + DEBUG3(qla2x00_print_scsi_cmd(cmd)); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (ha->isp_ops.abort_command(ha, sp)) { @@ -731,7 +744,6 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) { scsi_qla_host_t *ha = to_qla_host(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; - srb_t *sp; int ret; unsigned int id, lun; unsigned long serial; @@ -742,8 +754,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) lun = cmd->device->lun; serial = cmd->serial_number; - sp = (srb_t *) CMD_SP(cmd); - if (!sp || !fcport) + if (!fcport) return ret; qla_printk(KERN_INFO, ha, @@ -766,7 +777,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) #endif } else { DEBUG2(printk(KERN_INFO - "%s failed: loop not ready\n",__func__);) + "%s failed: loop not ready\n",__func__)); } if (ret == FAILED) { @@ -862,7 +873,6 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) { scsi_qla_host_t *ha = to_qla_host(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; - srb_t *sp; int ret; unsigned int id, lun; unsigned long serial; @@ -873,8 +883,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) lun = cmd->device->lun; serial = cmd->serial_number; - sp = (srb_t *) CMD_SP(cmd); - if (!sp || !fcport) + if (!fcport) return ret; qla_printk(KERN_INFO, ha, @@ -923,7 +932,6 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) { scsi_qla_host_t *ha = to_qla_host(cmd->device->host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; - srb_t *sp; int ret; unsigned int id, lun; unsigned long serial; @@ -934,8 +942,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) lun = cmd->device->lun; serial = cmd->serial_number; - sp = (srb_t *) CMD_SP(cmd); - if (!sp || !fcport) + if (!fcport) return ret; qla_printk(KERN_INFO, ha, @@ -1021,12 +1028,12 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) /* Empty */ DEBUG2_3(printk("%s(%ld): **** FAILED ****\n", __func__, - ha->host_no);) + ha->host_no)); } else { /* Empty */ DEBUG3(printk("%s(%ld): exiting normally.\n", __func__, - ha->host_no);) + ha->host_no)); } return(status); @@ -1324,7 +1331,8 @@ qla24xx_disable_intrs(scsi_qla_host_t *ha) /* * PCI driver interface */ -static int qla2x00_probe_one(struct pci_dev *pdev) +static int __devinit +qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { int ret = -ENODEV; device_reg_t __iomem *reg; @@ -1405,7 +1413,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev) ha->isp_ops.read_nvram = qla2x00_read_nvram_data; ha->isp_ops.write_nvram = qla2x00_write_nvram_data; ha->isp_ops.fw_dump = qla2100_fw_dump; - ha->isp_ops.ascii_fw_dump = qla2100_ascii_fw_dump; ha->isp_ops.read_optrom = qla2x00_read_optrom_data; ha->isp_ops.write_optrom = qla2x00_write_optrom_data; if (IS_QLA2100(ha)) { @@ -1432,7 +1439,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev) ha->isp_ops.pci_config = qla2300_pci_config; ha->isp_ops.intr_handler = qla2300_intr_handler; ha->isp_ops.fw_dump = qla2300_fw_dump; - ha->isp_ops.ascii_fw_dump = qla2300_ascii_fw_dump; ha->isp_ops.beacon_on = qla2x00_beacon_on; ha->isp_ops.beacon_off = qla2x00_beacon_off; ha->isp_ops.beacon_blink = qla2x00_beacon_blink; @@ -1469,7 +1475,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev) ha->isp_ops.read_nvram = qla24xx_read_nvram_data; ha->isp_ops.write_nvram = qla24xx_write_nvram_data; ha->isp_ops.fw_dump = qla24xx_fw_dump; - ha->isp_ops.ascii_fw_dump = qla24xx_ascii_fw_dump; ha->isp_ops.read_optrom = qla24xx_read_optrom_data; ha->isp_ops.write_optrom = qla24xx_write_optrom_data; ha->isp_ops.beacon_on = qla24xx_beacon_on; @@ -1640,7 +1645,8 @@ probe_out: return ret; } -static void qla2x00_remove_one(struct pci_dev *pdev) +static void __devexit +qla2x00_remove_one(struct pci_dev *pdev) { scsi_qla_host_t *ha; @@ -1678,6 +1684,9 @@ qla2x00_free_device(scsi_qla_host_t *ha) kthread_stop(t); } + if (ha->eft) + qla2x00_trace_control(ha, TC_DISABLE, 0, 0); + /* Stop currently executing firmware. */ qla2x00_stop_firmware(ha); @@ -1899,17 +1908,6 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha) } memset(ha->init_cb, 0, ha->init_cb_size); - /* Allocate ioctl related memory. */ - if (qla2x00_alloc_ioctl_mem(ha)) { - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - ioctl_mem\n"); - - qla2x00_mem_free(ha); - msleep(100); - - continue; - } - if (qla2x00_allocate_sp_pool(ha)) { qla_printk(KERN_WARNING, ha, "Memory Allocation failed - " @@ -1972,6 +1970,26 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha) continue; } memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt)); + + if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + /* + * Get consistent memory allocated for SFP + * block. + */ + ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, + GFP_KERNEL, &ha->sfp_data_dma); + if (ha->sfp_data == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - " + "sfp_data\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + memset(ha->sfp_data, 0, SFP_BLOCK_SIZE); + } } /* Done all allocations without any error. */ @@ -2006,12 +2024,16 @@ qla2x00_mem_free(scsi_qla_host_t *ha) return; } - /* free ioctl memory */ - qla2x00_free_ioctl_mem(ha); - /* free sp pool */ qla2x00_free_sp_pool(ha); + if (ha->fw_dump) { + if (ha->eft) + dma_free_coherent(&ha->pdev->dev, + ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma); + vfree(ha->fw_dump); + } + if (ha->sns_cmd) dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), ha->sns_cmd, ha->sns_cmd_dma); @@ -2020,6 +2042,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha) dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), ha->ct_sns, ha->ct_sns_dma); + if (ha->sfp_data) + dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma); + if (ha->ms_iocb) dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); @@ -2043,6 +2068,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha) (ha->request_q_length + 1) * sizeof(request_t), ha->request_ring, ha->request_dma); + ha->eft = NULL; + ha->eft_dma = 0; ha->sns_cmd = NULL; ha->sns_cmd_dma = 0; ha->ct_sns = NULL; @@ -2071,13 +2098,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha) } INIT_LIST_HEAD(&ha->fcports); - vfree(ha->fw_dump); - vfree(ha->fw_dump_buffer); - ha->fw_dump = NULL; ha->fw_dumped = 0; ha->fw_dump_reading = 0; - ha->fw_dump_buffer = NULL; vfree(ha->optrom_buffer); } @@ -2215,9 +2238,6 @@ qla2x00_do_dpc(void *data) next_loopid = 0; list_for_each_entry(fcport, &ha->fcports, list) { - if (fcport->port_type != FCT_TARGET) - continue; - /* * If the port is not ONLINE then try to login * to it if we haven't run out of retries. @@ -2617,40 +2637,16 @@ static struct pci_device_id qla2xxx_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl); -static int __devinit -qla2xxx_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) -{ - return qla2x00_probe_one(pdev); -} - -static void __devexit -qla2xxx_remove_one(struct pci_dev *pdev) -{ - qla2x00_remove_one(pdev); -} - static struct pci_driver qla2xxx_pci_driver = { .name = QLA2XXX_DRIVER_NAME, .driver = { .owner = THIS_MODULE, }, .id_table = qla2xxx_pci_tbl, - .probe = qla2xxx_probe_one, - .remove = __devexit_p(qla2xxx_remove_one), + .probe = qla2x00_probe_one, + .remove = __devexit_p(qla2x00_remove_one), }; -static inline int -qla2x00_pci_module_init(void) -{ - return pci_module_init(&qla2xxx_pci_driver); -} - -static inline void -qla2x00_pci_module_exit(void) -{ - pci_unregister_driver(&qla2xxx_pci_driver); -} - /** * qla2x00_module_init - Module initialization. **/ @@ -2670,16 +2666,16 @@ qla2x00_module_init(void) /* Derive version string. */ strcpy(qla2x00_version_str, QLA2XXX_VERSION); -#if DEBUG_QLA2100 - strcat(qla2x00_version_str, "-debug"); -#endif + if (extended_error_logging) + strcat(qla2x00_version_str, "-debug"); + qla2xxx_transport_template = fc_attach_transport(&qla2xxx_transport_functions); if (!qla2xxx_transport_template) return -ENODEV; printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n"); - ret = qla2x00_pci_module_init(); + ret = pci_register_driver(&qla2xxx_pci_driver); if (ret) { kmem_cache_destroy(srb_cachep); fc_release_transport(qla2xxx_transport_template); @@ -2693,7 +2689,7 @@ qla2x00_module_init(void) static void __exit qla2x00_module_exit(void) { - qla2x00_pci_module_exit(); + pci_unregister_driver(&qla2xxx_pci_driver); qla2x00_release_firmware(); kmem_cache_destroy(srb_cachep); fc_release_transport(qla2xxx_transport_template); diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 6b315521bd8..971259032ef 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.05-k2" +#define QLA2XXX_VERSION "8.01.07-k1" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 -#define QLA_DRIVER_PATCH_VER 5 +#define QLA_DRIVER_PATCH_VER 7 #define QLA_DRIVER_BETA_VER 0 diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 69e0551a81d..5b2f0741a55 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -874,7 +874,7 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd, if (Cmnd->use_sg) { int sg_count; - sg = (struct scatterlist *) Cmnd->buffer; + sg = (struct scatterlist *) Cmnd->request_buffer; sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, Cmnd->sc_data_direction); ds = cmd->dataseg; @@ -1278,7 +1278,7 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti) if (Cmnd->use_sg) { sbus_unmap_sg(qpti->sdev, - (struct scatterlist *)Cmnd->buffer, + (struct scatterlist *)Cmnd->request_buffer, Cmnd->use_sg, Cmnd->sc_data_direction); } else { diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c index 1053c7c76b7..fa38a413d16 100644 --- a/drivers/scsi/sata_mv.c +++ b/drivers/scsi/sata_mv.c @@ -1961,8 +1961,7 @@ comreset_retry: timeout = jiffies + msecs_to_jiffies(200); do { sata_scr_read(ap, SCR_STATUS, &sstatus); - sstatus &= 0x3; - if ((sstatus == 3) || (sstatus == 0)) + if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0)) break; __msleep(1, can_sleep); diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index 64631bd3895..4776f4e5583 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -269,8 +269,15 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = { { PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20619 }, +/* TODO: remove all associated board_20771 code, as it completely + * duplicates board_2037x code, unless reason for separation can be + * divined. + */ +#if 0 { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20771 }, +#endif + { } /* terminate list */ }; diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index 7aabb45c35e..d0a85073ebf 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -109,6 +109,7 @@ enum { }; static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static int sil_pci_device_resume(struct pci_dev *pdev); static void sil_dev_config(struct ata_port *ap, struct ata_device *dev); static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg); static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); @@ -160,6 +161,8 @@ static struct pci_driver sil_pci_driver = { .id_table = sil_pci_tbl, .probe = sil_init_one, .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = sil_pci_device_resume, }; static struct scsi_host_template sil_sht = { @@ -178,6 +181,8 @@ static struct scsi_host_template sil_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .suspend = ata_scsi_device_suspend, + .resume = ata_scsi_device_resume, }; static const struct ata_port_operations sil_ops = { @@ -370,7 +375,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) * during hardreset makes controllers with broken SIEN * repeat probing needlessly. */ - if (!(ap->flags & ATA_FLAG_FROZEN)) { + if (!(ap->pflags & ATA_PFLAG_FROZEN)) { ata_ehi_hotplugged(&ap->eh_info); ap->eh_info.serror |= serror; } @@ -561,6 +566,52 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev) } } +static void sil_init_controller(struct pci_dev *pdev, + int n_ports, unsigned long host_flags, + void __iomem *mmio_base) +{ + u8 cls; + u32 tmp; + int i; + + /* Initialize FIFO PCI bus arbitration */ + cls = sil_get_device_cache_line(pdev); + if (cls) { + cls >>= 3; + cls++; /* cls = (line_size/8)+1 */ + for (i = 0; i < n_ports; i++) + writew(cls << 8 | cls, + mmio_base + sil_port[i].fifo_cfg); + } else + dev_printk(KERN_WARNING, &pdev->dev, + "cache line size not set. Driver may not function\n"); + + /* Apply R_ERR on DMA activate FIS errata workaround */ + if (host_flags & SIL_FLAG_RERR_ON_DMA_ACT) { + int cnt; + + for (i = 0, cnt = 0; i < n_ports; i++) { + tmp = readl(mmio_base + sil_port[i].sfis_cfg); + if ((tmp & 0x3) != 0x01) + continue; + if (!cnt) + dev_printk(KERN_INFO, &pdev->dev, + "Applying R_ERR on DMA activate " + "FIS errata fix\n"); + writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg); + cnt++; + } + } + + if (n_ports == 4) { + /* flip the magic "make 4 ports work" bit */ + tmp = readl(mmio_base + sil_port[2].bmdma); + if ((tmp & SIL_INTR_STEERING) == 0) + writel(tmp | SIL_INTR_STEERING, + mmio_base + sil_port[2].bmdma); + } +} + static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; @@ -570,8 +621,6 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) int rc; unsigned int i; int pci_dev_busy = 0; - u32 tmp; - u8 cls; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); @@ -630,42 +679,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ata_std_ports(&probe_ent->port[i]); } - /* Initialize FIFO PCI bus arbitration */ - cls = sil_get_device_cache_line(pdev); - if (cls) { - cls >>= 3; - cls++; /* cls = (line_size/8)+1 */ - for (i = 0; i < probe_ent->n_ports; i++) - writew(cls << 8 | cls, - mmio_base + sil_port[i].fifo_cfg); - } else - dev_printk(KERN_WARNING, &pdev->dev, - "cache line size not set. Driver may not function\n"); - - /* Apply R_ERR on DMA activate FIS errata workaround */ - if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) { - int cnt; - - for (i = 0, cnt = 0; i < probe_ent->n_ports; i++) { - tmp = readl(mmio_base + sil_port[i].sfis_cfg); - if ((tmp & 0x3) != 0x01) - continue; - if (!cnt) - dev_printk(KERN_INFO, &pdev->dev, - "Applying R_ERR on DMA activate " - "FIS errata fix\n"); - writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg); - cnt++; - } - } - - if (ent->driver_data == sil_3114) { - /* flip the magic "make 4 ports work" bit */ - tmp = readl(mmio_base + sil_port[2].bmdma); - if ((tmp & SIL_INTR_STEERING) == 0) - writel(tmp | SIL_INTR_STEERING, - mmio_base + sil_port[2].bmdma); - } + sil_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags, + mmio_base); pci_set_master(pdev); @@ -685,6 +700,18 @@ err_out: return rc; } +static int sil_pci_device_resume(struct pci_dev *pdev) +{ + struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev); + + ata_pci_device_do_resume(pdev); + sil_init_controller(pdev, host_set->n_ports, host_set->ports[0]->flags, + host_set->mmio_base); + ata_host_set_resume(host_set); + + return 0; +} + static int __init sil_init(void) { return pci_module_init(&sil_pci_driver); diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index 07a1c6a8a41..3f368c7d3ef 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c @@ -92,6 +92,7 @@ enum { HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */ HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */ HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */ + HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */ /* * Port registers @@ -338,6 +339,7 @@ static int sil24_port_start(struct ata_port *ap); static void sil24_port_stop(struct ata_port *ap); static void sil24_host_stop(struct ata_host_set *host_set); static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +static int sil24_pci_device_resume(struct pci_dev *pdev); static const struct pci_device_id sil24_pci_tbl[] = { { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 }, @@ -353,6 +355,8 @@ static struct pci_driver sil24_pci_driver = { .id_table = sil24_pci_tbl, .probe = sil24_init_one, .remove = ata_pci_remove_one, /* safe? */ + .suspend = ata_pci_device_suspend, + .resume = sil24_pci_device_resume, }; static struct scsi_host_template sil24_sht = { @@ -372,6 +376,8 @@ static struct scsi_host_template sil24_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .suspend = ata_scsi_device_suspend, + .resume = ata_scsi_device_resume, }; static const struct ata_port_operations sil24_ops = { @@ -607,7 +613,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class) /* SStatus oscillates between zero and valid status after * DEV_RST, debounce it. */ - rc = sata_phy_debounce(ap, sata_deb_timing_before_fsrst); + rc = sata_phy_debounce(ap, sata_deb_timing_long); if (rc) { reason = "PHY debouncing failed"; goto err; @@ -988,6 +994,64 @@ static void sil24_host_stop(struct ata_host_set *host_set) kfree(hpriv); } +static void sil24_init_controller(struct pci_dev *pdev, int n_ports, + unsigned long host_flags, + void __iomem *host_base, + void __iomem *port_base) +{ + u32 tmp; + int i; + + /* GPIO off */ + writel(0, host_base + HOST_FLASH_CMD); + + /* clear global reset & mask interrupts during initialization */ + writel(0, host_base + HOST_CTRL); + + /* init ports */ + for (i = 0; i < n_ports; i++) { + void __iomem *port = port_base + i * PORT_REGS_SIZE; + + /* Initial PHY setting */ + writel(0x20c, port + PORT_PHY_CFG); + + /* Clear port RST */ + tmp = readl(port + PORT_CTRL_STAT); + if (tmp & PORT_CS_PORT_RST) { + writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); + tmp = ata_wait_register(port + PORT_CTRL_STAT, + PORT_CS_PORT_RST, + PORT_CS_PORT_RST, 10, 100); + if (tmp & PORT_CS_PORT_RST) + dev_printk(KERN_ERR, &pdev->dev, + "failed to clear port RST\n"); + } + + /* Configure IRQ WoC */ + if (host_flags & SIL24_FLAG_PCIX_IRQ_WOC) + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT); + else + writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); + + /* Zero error counters. */ + writel(0x8000, port + PORT_DECODE_ERR_THRESH); + writel(0x8000, port + PORT_CRC_ERR_THRESH); + writel(0x8000, port + PORT_HSHK_ERR_THRESH); + writel(0x0000, port + PORT_DECODE_ERR_CNT); + writel(0x0000, port + PORT_CRC_ERR_CNT); + writel(0x0000, port + PORT_HSHK_ERR_CNT); + + /* Always use 64bit activation */ + writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); + + /* Clear port multiplier enable and resume bits */ + writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR); + } + + /* Turn on interrupts */ + writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL); +} + static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version = 0; @@ -1042,7 +1106,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - probe_ent->mmio_base = port_base; probe_ent->private_data = hpriv; hpriv->host_base = host_base; @@ -1076,9 +1139,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } } - /* GPIO off */ - writel(0, host_base + HOST_FLASH_CMD); - /* Apply workaround for completion IRQ loss on PCI-X errata */ if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) { tmp = readl(host_base + HOST_CTRL); @@ -1090,56 +1150,18 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC; } - /* clear global reset & mask interrupts during initialization */ - writel(0, host_base + HOST_CTRL); - for (i = 0; i < probe_ent->n_ports; i++) { - void __iomem *port = port_base + i * PORT_REGS_SIZE; - unsigned long portu = (unsigned long)port; + unsigned long portu = + (unsigned long)port_base + i * PORT_REGS_SIZE; probe_ent->port[i].cmd_addr = portu; probe_ent->port[i].scr_addr = portu + PORT_SCONTROL; ata_std_ports(&probe_ent->port[i]); - - /* Initial PHY setting */ - writel(0x20c, port + PORT_PHY_CFG); - - /* Clear port RST */ - tmp = readl(port + PORT_CTRL_STAT); - if (tmp & PORT_CS_PORT_RST) { - writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR); - tmp = ata_wait_register(port + PORT_CTRL_STAT, - PORT_CS_PORT_RST, - PORT_CS_PORT_RST, 10, 100); - if (tmp & PORT_CS_PORT_RST) - dev_printk(KERN_ERR, &pdev->dev, - "failed to clear port RST\n"); - } - - /* Configure IRQ WoC */ - if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) - writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT); - else - writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); - - /* Zero error counters. */ - writel(0x8000, port + PORT_DECODE_ERR_THRESH); - writel(0x8000, port + PORT_CRC_ERR_THRESH); - writel(0x8000, port + PORT_HSHK_ERR_THRESH); - writel(0x0000, port + PORT_DECODE_ERR_CNT); - writel(0x0000, port + PORT_CRC_ERR_CNT); - writel(0x0000, port + PORT_HSHK_ERR_CNT); - - /* Always use 64bit activation */ - writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); - - /* Clear port multiplier enable and resume bits */ - writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR); } - /* Turn on interrupts */ - writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL); + sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->host_flags, + host_base, port_base); pci_set_master(pdev); @@ -1162,6 +1184,25 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return rc; } +static int sil24_pci_device_resume(struct pci_dev *pdev) +{ + struct ata_host_set *host_set = dev_get_drvdata(&pdev->dev); + struct sil24_host_priv *hpriv = host_set->private_data; + + ata_pci_device_do_resume(pdev); + + if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) + writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL); + + sil24_init_controller(pdev, host_set->n_ports, + host_set->ports[0]->flags, + hpriv->host_base, hpriv->port_base); + + ata_host_set_resume(host_set); + + return 0; +} + static int __init sil24_init(void) { return pci_module_init(&sil24_pci_driver); diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index 03baec2191b..a3727af8b9c 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c @@ -74,8 +74,10 @@ enum { static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg); static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); +static void vt6420_error_handler(struct ata_port *ap); static const struct pci_device_id svia_pci_tbl[] = { + { 0x1106, 0x0591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 }, { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 }, { 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 }, @@ -107,7 +109,38 @@ static struct scsi_host_template svia_sht = { .bios_param = ata_std_bios_param, }; -static const struct ata_port_operations svia_sata_ops = { +static const struct ata_port_operations vt6420_sata_ops = { + .port_disable = ata_port_disable, + + .tf_load = ata_tf_load, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = ata_exec_command, + .dev_select = ata_std_dev_select, + + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + .data_xfer = ata_pio_data_xfer, + + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = vt6420_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, + + .irq_handler = ata_interrupt, + .irq_clear = ata_bmdma_irq_clear, + + .port_start = ata_port_start, + .port_stop = ata_port_stop, + .host_stop = ata_host_stop, +}; + +static const struct ata_port_operations vt6421_sata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -141,13 +174,13 @@ static const struct ata_port_operations svia_sata_ops = { .host_stop = ata_host_stop, }; -static struct ata_port_info svia_port_info = { +static struct ata_port_info vt6420_port_info = { .sht = &svia_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = 0x7f, - .port_ops = &svia_sata_ops, + .port_ops = &vt6420_sata_ops, }; MODULE_AUTHOR("Jeff Garzik"); @@ -170,6 +203,81 @@ static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) outl(val, ap->ioaddr.scr_addr + (4 * sc_reg)); } +/** + * vt6420_prereset - prereset for vt6420 + * @ap: target ATA port + * + * SCR registers on vt6420 are pieces of shit and may hang the + * whole machine completely if accessed with the wrong timing. + * To avoid such catastrophe, vt6420 doesn't provide generic SCR + * access operations, but uses SStatus and SControl only during + * boot probing in controlled way. + * + * As the old (pre EH update) probing code is proven to work, we + * strictly follow the access pattern. + * + * LOCKING: + * Kernel thread context (may sleep) + * + * RETURNS: + * 0 on success, -errno otherwise. + */ +static int vt6420_prereset(struct ata_port *ap) +{ + struct ata_eh_context *ehc = &ap->eh_context; + unsigned long timeout = jiffies + (HZ * 5); + u32 sstatus, scontrol; + int online; + + /* don't do any SCR stuff if we're not loading */ + if (!ATA_PFLAG_LOADING) + goto skip_scr; + + /* Resume phy. This is the old resume sequence from + * __sata_phy_reset(). + */ + svia_scr_write(ap, SCR_CONTROL, 0x300); + svia_scr_read(ap, SCR_CONTROL); /* flush */ + + /* wait for phy to become ready, if necessary */ + do { + msleep(200); + if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1) + break; + } while (time_before(jiffies, timeout)); + + /* open code sata_print_link_status() */ + sstatus = svia_scr_read(ap, SCR_STATUS); + scontrol = svia_scr_read(ap, SCR_CONTROL); + + online = (sstatus & 0xf) == 0x3; + + ata_port_printk(ap, KERN_INFO, + "SATA link %s 1.5 Gbps (SStatus %X SControl %X)\n", + online ? "up" : "down", sstatus, scontrol); + + /* SStatus is read one more time */ + svia_scr_read(ap, SCR_STATUS); + + if (!online) { + /* tell EH to bail */ + ehc->i.action &= ~ATA_EH_RESET_MASK; + return 0; + } + + skip_scr: + /* wait for !BSY */ + ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + + return 0; +} + +static void vt6420_error_handler(struct ata_port *ap) +{ + return ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset, + NULL, ata_std_postreset); +} + static const unsigned int svia_bar_sizes[] = { 8, 4, 8, 4, 16, 256 }; @@ -210,7 +318,7 @@ static void vt6421_init_addrs(struct ata_probe_ent *probe_ent, static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev) { struct ata_probe_ent *probe_ent; - struct ata_port_info *ppi = &svia_port_info; + struct ata_port_info *ppi = &vt6420_port_info; probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) @@ -239,7 +347,7 @@ static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev) probe_ent->sht = &svia_sht; probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY; - probe_ent->port_ops = &svia_sata_ops; + probe_ent->port_ops = &vt6421_sata_ops; probe_ent->n_ports = N_PORTS; probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 916fe6fba75..ad37871594f 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -297,7 +297,7 @@ static const struct ata_port_operations vsc_sata_ops = { .bmdma_status = ata_bmdma_status, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, - .data_xfer = ata_pio_data_xfer, + .data_xfer = ata_mmio_data_xfer, .freeze = ata_bmdma_freeze, .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 2ab7df0dcfe..b332caddd5b 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -346,7 +346,7 @@ void scsi_log_send(struct scsi_cmnd *cmd) if (level > 3) { printk(KERN_INFO "buffer = 0x%p, bufflen = %d," " done = 0x%p, queuecommand 0x%p\n", - cmd->buffer, cmd->bufflen, + cmd->request_buffer, cmd->request_bufflen, cmd->done, sdev->host->hostt->queuecommand); @@ -661,11 +661,6 @@ void __scsi_done(struct scsi_cmnd *cmd) */ int scsi_retry_command(struct scsi_cmnd *cmd) { - /* - * Restore the SCSI command state. - */ - scsi_setup_cmd_retry(cmd); - /* * Zero the sense information from the last time we tried * this command. @@ -711,10 +706,6 @@ void scsi_finish_command(struct scsi_cmnd *cmd) "Notifying upper driver of completion " "(result %x)\n", cmd->result)); - /* - * We can get here with use_sg=0, causing a panic in the upper level - */ - cmd->use_sg = cmd->old_use_sg; cmd->done(cmd); } EXPORT_SYMBOL(scsi_finish_command); diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index e1168860045..a80303c6b3f 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -50,18 +50,22 @@ #include "scsi_logging.h" #include "scsi_debug.h" -#define SCSI_DEBUG_VERSION "1.75" -static const char * scsi_debug_version_date = "20050113"; +#define SCSI_DEBUG_VERSION "1.79" +static const char * scsi_debug_version_date = "20060604"; /* Additional Sense Code (ASC) used */ -#define NO_ADDED_SENSE 0x0 +#define NO_ADDITIONAL_SENSE 0x0 +#define LOGICAL_UNIT_NOT_READY 0x4 #define UNRECOVERED_READ_ERR 0x11 +#define PARAMETER_LIST_LENGTH_ERR 0x1a #define INVALID_OPCODE 0x20 #define ADDR_OUT_OF_RANGE 0x21 #define INVALID_FIELD_IN_CDB 0x24 +#define INVALID_FIELD_IN_PARAM_LIST 0x26 #define POWERON_RESET 0x29 #define SAVING_PARAMS_UNSUP 0x39 -#define THRESHHOLD_EXCEEDED 0x5d +#define THRESHOLD_EXCEEDED 0x5d +#define LOW_POWER_COND_ON 0x5e #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */ @@ -80,6 +84,8 @@ static const char * scsi_debug_version_date = "20050113"; #define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */ #define DEF_PTYPE 0 #define DEF_D_SENSE 0 +#define DEF_NO_LUN_0 0 +#define DEF_VIRTUAL_GB 0 /* bit mask values for scsi_debug_opts */ #define SCSI_DEBUG_OPT_NOISE 1 @@ -106,6 +112,7 @@ static const char * scsi_debug_version_date = "20050113"; /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) * or "peripheral device" addressing (value 0) */ #define SAM2_LUN_ADDRESS_METHOD 0 +#define SAM2_WLUN_REPORT_LUNS 0xc101 static int scsi_debug_add_host = DEF_NUM_HOST; static int scsi_debug_delay = DEF_DELAY; @@ -118,13 +125,16 @@ static int scsi_debug_opts = DEF_OPTS; static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ static int scsi_debug_dsense = DEF_D_SENSE; +static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; +static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; static int scsi_debug_cmnd_count = 0; #define DEV_READONLY(TGT) (0) #define DEV_REMOVEABLE(TGT) (0) -static unsigned long sdebug_store_size; /* in bytes */ +static unsigned int sdebug_store_size; /* in bytes */ +static unsigned int sdebug_store_sectors; static sector_t sdebug_capacity; /* in sectors */ /* old BIOS stuff, kernel may get rid of them but some mode sense pages @@ -149,7 +159,9 @@ struct sdebug_dev_info { unsigned int target; unsigned int lun; struct sdebug_host_info *sdbg_host; + unsigned int wlun; char reset; + char stopped; char used; }; @@ -193,11 +205,11 @@ static struct scsi_host_template sdebug_driver_template = { .bios_param = scsi_debug_biosparam, .can_queue = SCSI_DEBUG_CANQUEUE, .this_id = 7, - .sg_tablesize = 64, - .cmd_per_lun = 3, - .max_sectors = 4096, + .sg_tablesize = 256, + .cmd_per_lun = 16, + .max_sectors = 0xffff, .unchecked_isa_dma = 0, - .use_clustering = DISABLE_CLUSTERING, + .use_clustering = ENABLE_CLUSTERING, .module = THIS_MODULE, }; @@ -225,19 +237,32 @@ static struct device_driver sdebug_driverfs_driver = { static const int check_condition_result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; +static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, + 0, 0, 0x2, 0x4b}; +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_readcap(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); -static int resp_mode_sense(struct scsi_cmnd * SCpnt, int target, +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_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, - int num, struct sdebug_dev_info * devip); -static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block, - int num, 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 fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, @@ -248,8 +273,8 @@ 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_reset(struct scsi_cmnd * SCpnt, - struct sdebug_dev_info * devip); +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); @@ -257,9 +282,11 @@ 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 dev_id_num, - const char * dev_id_str, int dev_id_str_len); -static void do_create_driverfs_files(void); +static int inquiry_evpd_83(unsigned char * arr, 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); @@ -274,18 +301,22 @@ static int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) { unsigned char *cmd = (unsigned char *) SCpnt->cmnd; - int block, upper_blk, num, k; + int len, k, j; + unsigned int num; + unsigned long long lba; int errsts = 0; - int target = scmd_id(SCpnt); + int target = SCpnt->device->id; struct sdebug_dev_info * devip = NULL; int inj_recovered = 0; + int delay_override = 0; if (done == NULL) return 0; /* assume mid level reprocessing command */ + SCpnt->resid = 0; if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { printk(KERN_INFO "scsi_debug: cmd "); - for (k = 0, num = SCpnt->cmd_len; k < num; ++k) + for (k = 0, len = SCpnt->cmd_len; k < len; ++k) printk("%02x ", (int)cmd[k]); printk("\n"); } @@ -296,7 +327,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) DID_NO_CONNECT << 16, 0); } - if (SCpnt->device->lun >= scsi_debug_max_luns) + 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); @@ -315,118 +347,150 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) inj_recovered = 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 = check_reset(SCpnt, devip); + errsts = resp_start_stop(SCpnt, devip); break; case ALLOW_MEDIUM_REMOVAL: - if ((errsts = check_reset(SCpnt, devip))) + 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_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case TEST_UNIT_READY: /* mandatory */ - errsts = check_reset(SCpnt, devip); + delay_override = 1; + errsts = check_readiness(SCpnt, 0, devip); break; case RESERVE: - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case RESERVE_10: - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case RELEASE: - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case RELEASE_10: - errsts = check_reset(SCpnt, devip); + 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 READ_16: case READ_12: case READ_10: case READ_6: - if ((errsts = check_reset(SCpnt, devip))) + if ((errsts = check_readiness(SCpnt, 0, devip))) break; - upper_blk = 0; if ((*cmd) == READ_16) { - upper_blk = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - block = cmd[9] + (cmd[8] << 8) + - (cmd[7] << 16) + (cmd[6] << 24); + for (lba = 0, j = 0; j < 8; ++j) { + if (j > 0) + lba <<= 8; + lba += cmd[2 + j]; + } num = cmd[13] + (cmd[12] << 8) + (cmd[11] << 16) + (cmd[10] << 24); } else if ((*cmd) == READ_12) { - block = cmd[5] + (cmd[4] << 8) + + lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); } else if ((*cmd) == READ_10) { - block = cmd[5] + (cmd[4] << 8) + + lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); num = cmd[8] + (cmd[7] << 8); - } else { - block = cmd[3] + (cmd[2] << 8) + + } else { /* READ (6) */ + lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); - num = cmd[4]; + num = (0 == cmd[4]) ? 256 : cmd[4]; } - errsts = resp_read(SCpnt, upper_blk, block, num, devip); + errsts = resp_read(SCpnt, lba, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHHOLD_EXCEEDED, 0); + THRESHOLD_EXCEEDED, 0); 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_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 0, devip); break; case WRITE_16: case WRITE_12: case WRITE_10: case WRITE_6: - if ((errsts = check_reset(SCpnt, devip))) + if ((errsts = check_readiness(SCpnt, 0, devip))) break; - upper_blk = 0; if ((*cmd) == WRITE_16) { - upper_blk = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - block = cmd[9] + (cmd[8] << 8) + - (cmd[7] << 16) + (cmd[6] << 24); + for (lba = 0, j = 0; j < 8; ++j) { + if (j > 0) + lba <<= 8; + lba += cmd[2 + j]; + } num = cmd[13] + (cmd[12] << 8) + (cmd[11] << 16) + (cmd[10] << 24); } else if ((*cmd) == WRITE_12) { - block = cmd[5] + (cmd[4] << 8) + + lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); } else if ((*cmd) == WRITE_10) { - block = cmd[5] + (cmd[4] << 8) + + lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); num = cmd[8] + (cmd[7] << 8); - } else { - block = cmd[3] + (cmd[2] << 8) + + } else { /* WRITE (6) */ + lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); - num = cmd[4]; + num = (0 == cmd[4]) ? 256 : cmd[4]; } - errsts = resp_write(SCpnt, upper_blk, block, num, devip); + errsts = resp_write(SCpnt, lba, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHHOLD_EXCEEDED, 0); + THRESHOLD_EXCEEDED, 0); errsts = check_condition_result; } break; @@ -434,20 +498,31 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) 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: - errsts = check_reset(SCpnt, devip); + delay_override = 1; + errsts = check_readiness(SCpnt, 0, 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_reset(SCpnt, devip))) + 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, scsi_debug_delay); + 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) @@ -459,7 +534,8 @@ static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) /* return -ENOTTY; // correct return but upsets fdisk */ } -static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip) +static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, + struct sdebug_dev_info * devip) { if (devip->reset) { if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) @@ -469,6 +545,14 @@ static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip) mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); return check_condition_result; } + if ((0 == reset_only) && devip->stopped) { + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: Reporting Not " + "ready: initializing command required\n"); + mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY, + 0x2); + return check_condition_result; + } return 0; } @@ -492,7 +576,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, req_len = scp->request_bufflen; act_len = (req_len < arr_len) ? req_len : arr_len; memcpy(scp->request_buffer, arr, act_len); - scp->resid = req_len - act_len; + if (scp->resid) + scp->resid -= act_len; + else + scp->resid = req_len - act_len; return 0; } sgpnt = (struct scatterlist *)scp->request_buffer; @@ -515,7 +602,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, } req_len += sgpnt->length; } - scp->resid = req_len - act_len; + if (scp->resid) + scp->resid -= act_len; + else + scp->resid = req_len - act_len; return 0; } @@ -566,12 +656,14 @@ static const char * inq_vendor_id = "Linux "; static const char * inq_product_id = "scsi_debug "; static const char * inq_product_rev = "0004"; -static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, - const char * dev_id_str, int dev_id_str_len) +static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, + int dev_id_num, const char * dev_id_str, + int dev_id_str_len) { - int num; + int num, port_a; + char b[32]; - /* Two identification descriptors: */ + port_a = target_dev_id + 1; /* T10 vendor identifier field format (faked) */ arr[0] = 0x2; /* ASCII */ arr[1] = 0x1; @@ -582,25 +674,246 @@ static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, num = 8 + 16 + dev_id_str_len; arr[3] = num; num += 4; - /* NAA IEEE registered identifier (faked) */ - arr[num] = 0x1; /* binary */ - arr[num + 1] = 0x3; - arr[num + 2] = 0x0; - arr[num + 3] = 0x8; - arr[num + 4] = 0x51; /* ieee company id=0x123456 (faked) */ - arr[num + 5] = 0x23; - arr[num + 6] = 0x45; - arr[num + 7] = 0x60; - arr[num + 8] = (dev_id_num >> 24); - arr[num + 9] = (dev_id_num >> 16) & 0xff; - arr[num + 10] = (dev_id_num >> 8) & 0xff; - arr[num + 11] = dev_id_num & 0xff; - return num + 12; + if (dev_id_num >= 0) { + /* NAA-5, Logical unit identifier (binary) */ + arr[num++] = 0x1; /* binary (not necessarily sas) */ + arr[num++] = 0x3; /* PIV=0, lu, naa */ + arr[num++] = 0x0; + arr[num++] = 0x8; + arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */ + arr[num++] = 0x33; + arr[num++] = 0x33; + arr[num++] = 0x30; + arr[num++] = (dev_id_num >> 24); + arr[num++] = (dev_id_num >> 16) & 0xff; + arr[num++] = (dev_id_num >> 8) & 0xff; + arr[num++] = dev_id_num & 0xff; + /* Target relative port number */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x94; /* PIV=1, target port, rel port */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x4; /* length */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + arr[num++] = 0x1; /* relative port A */ + } + /* NAA-5, Target port identifier */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x93; /* piv=1, target port, naa */ + arr[num++] = 0x0; + arr[num++] = 0x8; + arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ + arr[num++] = 0x22; + arr[num++] = 0x22; + arr[num++] = 0x20; + arr[num++] = (port_a >> 24); + arr[num++] = (port_a >> 16) & 0xff; + arr[num++] = (port_a >> 8) & 0xff; + arr[num++] = port_a & 0xff; + /* NAA-5, Target device identifier */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0xa3; /* piv=1, target device, naa */ + arr[num++] = 0x0; + arr[num++] = 0x8; + arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ + arr[num++] = 0x22; + arr[num++] = 0x22; + arr[num++] = 0x20; + arr[num++] = (target_dev_id >> 24); + arr[num++] = (target_dev_id >> 16) & 0xff; + arr[num++] = (target_dev_id >> 8) & 0xff; + arr[num++] = target_dev_id & 0xff; + /* SCSI name string: Target device identifier */ + arr[num++] = 0x63; /* proto=sas, UTF-8 */ + arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ + arr[num++] = 0x0; + arr[num++] = 24; + memcpy(arr + num, "naa.52222220", 12); + num += 12; + snprintf(b, sizeof(b), "%08X", target_dev_id); + memcpy(arr + num, b, 8); + num += 8; + memset(arr + num, 0, 4); + num += 4; + return num; +} + + +static unsigned char vpd84_data[] = { +/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, + 0x22,0x22,0x22,0x0,0xbb,0x1, + 0x22,0x22,0x22,0x0,0xbb,0x2, +}; + +static int inquiry_evpd_84(unsigned char * arr) +{ + memcpy(arr, vpd84_data, sizeof(vpd84_data)); + return sizeof(vpd84_data); +} + +static int inquiry_evpd_85(unsigned char * arr) +{ + int num = 0; + const char * na1 = "https://www.kernel.org/config"; + const char * na2 = "http://www.kernel.org/log"; + int plen, olen; + + arr[num++] = 0x1; /* lu, storage config */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + olen = strlen(na1); + plen = olen + 1; + if (plen % 4) + plen = ((plen / 4) + 1) * 4; + arr[num++] = plen; /* length, null termianted, padded */ + memcpy(arr + num, na1, olen); + memset(arr + num + olen, 0, plen - olen); + num += plen; + + arr[num++] = 0x4; /* lu, logging */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + olen = strlen(na2); + plen = olen + 1; + if (plen % 4) + plen = ((plen / 4) + 1) * 4; + arr[num++] = plen; /* length, null terminated, padded */ + memcpy(arr + num, na2, olen); + memset(arr + num + olen, 0, plen - olen); + num += plen; + + return num; +} + +/* SCSI ports VPD page */ +static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) +{ + int num = 0; + int port_a, port_b; + + port_a = target_dev_id + 1; + port_b = port_a + 1; + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + arr[num++] = 0x1; /* relative port 1 (primary) */ + memset(arr + num, 0, 6); + num += 6; + arr[num++] = 0x0; + arr[num++] = 12; /* length tp descriptor */ + /* naa-5 target port identifier (A) */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x93; /* PIV=1, target port, NAA */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x8; /* length */ + arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ + arr[num++] = 0x22; + arr[num++] = 0x22; + arr[num++] = 0x20; + arr[num++] = (port_a >> 24); + arr[num++] = (port_a >> 16) & 0xff; + arr[num++] = (port_a >> 8) & 0xff; + arr[num++] = port_a & 0xff; + + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + arr[num++] = 0x2; /* relative port 2 (secondary) */ + memset(arr + num, 0, 6); + num += 6; + arr[num++] = 0x0; + arr[num++] = 12; /* length tp descriptor */ + /* naa-5 target port identifier (B) */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x93; /* PIV=1, target port, NAA */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x8; /* length */ + arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ + arr[num++] = 0x22; + arr[num++] = 0x22; + arr[num++] = 0x20; + arr[num++] = (port_b >> 24); + arr[num++] = (port_b >> 16) & 0xff; + arr[num++] = (port_b >> 8) & 0xff; + arr[num++] = port_b & 0xff; + + return num; +} + + +static unsigned char vpd89_data[] = { +/* from 4th byte */ 0,0,0,0, +'l','i','n','u','x',' ',' ',' ', +'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', +'1','2','3','4', +0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +0xec,0,0,0, +0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, +0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, +0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, +0x53,0x41, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x10,0x80, +0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, +0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, +0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, +0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, +0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, +0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, +0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, +0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, +0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, +}; + +static int inquiry_evpd_89(unsigned char * arr) +{ + memcpy(arr, vpd89_data, sizeof(vpd89_data)); + return sizeof(vpd89_data); +} + + +static unsigned char vpdb0_data[] = { + /* from 4th byte */ 0,0,0,4, + 0,0,0x4,0, + 0,0,0,64, +}; + +static int inquiry_evpd_b0(unsigned char * arr) +{ + memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); + if (sdebug_store_sectors > 0x400) { + arr[4] = (sdebug_store_sectors >> 24) & 0xff; + arr[5] = (sdebug_store_sectors >> 16) & 0xff; + arr[6] = (sdebug_store_sectors >> 8) & 0xff; + arr[7] = sdebug_store_sectors & 0xff; + } + return sizeof(vpdb0_data); } #define SDEBUG_LONG_INQ_SZ 96 -#define SDEBUG_MAX_INQ_ARR_SZ 128 +#define SDEBUG_MAX_INQ_ARR_SZ 584 static int resp_inquiry(struct scsi_cmnd * scp, int target, struct sdebug_dev_info * devip) @@ -608,64 +921,113 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, unsigned char pq_pdt; unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ]; unsigned char *cmd = (unsigned char *)scp->cmnd; - int alloc_len; + int alloc_len, n; alloc_len = (cmd[3] << 8) + cmd[4]; memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ); - pq_pdt = (scsi_debug_ptype & 0x1f); + if (devip->wlun) + pq_pdt = 0x1e; /* present, wlun */ + else if (scsi_debug_no_lun_0 && (0 == devip->lun)) + pq_pdt = 0x7f; /* not present, no device type */ + else + pq_pdt = (scsi_debug_ptype & 0x1f); arr[0] = pq_pdt; if (0x2 & cmd[1]) { /* CMDDT bit set */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; } else if (0x1 & cmd[1]) { /* EVPD bit set */ - int dev_id_num, len; - char dev_id_str[6]; + int lu_id_num, target_dev_id, len; + char lu_id_str[6]; + int host_no = devip->sdbg_host->shost->host_no; - dev_id_num = ((devip->sdbg_host->shost->host_no + 1) * 2000) + - (devip->target * 1000) + devip->lun; - len = scnprintf(dev_id_str, 6, "%d", dev_id_num); + lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + + (devip->target * 1000) + devip->lun); + target_dev_id = ((host_no + 1) * 2000) + + (devip->target * 1000) - 3; + len = scnprintf(lu_id_str, 6, "%d", lu_id_num); if (0 == cmd[2]) { /* supported vital product data pages */ - arr[3] = 3; - arr[4] = 0x0; /* this page */ - arr[5] = 0x80; /* unit serial number */ - arr[6] = 0x83; /* device identification */ + arr[1] = cmd[2]; /*sanity */ + n = 4; + arr[n++] = 0x0; /* this page */ + arr[n++] = 0x80; /* unit serial number */ + arr[n++] = 0x83; /* device identification */ + arr[n++] = 0x84; /* software interface ident. */ + arr[n++] = 0x85; /* management network addresses */ + arr[n++] = 0x86; /* extended inquiry */ + arr[n++] = 0x87; /* mode page policy */ + arr[n++] = 0x88; /* SCSI ports */ + arr[n++] = 0x89; /* ATA information */ + arr[n++] = 0xb0; /* Block limits (SBC) */ + arr[3] = n - 4; /* number of supported VPD pages */ } else if (0x80 == cmd[2]) { /* unit serial number */ - arr[1] = 0x80; + arr[1] = cmd[2]; /*sanity */ arr[3] = len; - memcpy(&arr[4], dev_id_str, len); + memcpy(&arr[4], lu_id_str, len); } else if (0x83 == cmd[2]) { /* device identification */ - arr[1] = 0x83; - arr[3] = inquiry_evpd_83(&arr[4], dev_id_num, - dev_id_str, len); + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_83(&arr[4], target_dev_id, + lu_id_num, lu_id_str, len); + } else if (0x84 == cmd[2]) { /* Software interface ident. */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_84(&arr[4]); + } else if (0x85 == cmd[2]) { /* Management network addresses */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_85(&arr[4]); + } else if (0x86 == cmd[2]) { /* extended inquiry */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = 0x3c; /* number of following entries */ + arr[4] = 0x0; /* no protection stuff */ + arr[5] = 0x7; /* head of q, ordered + simple q's */ + } else if (0x87 == cmd[2]) { /* mode page policy */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = 0x8; /* number of following entries */ + arr[4] = 0x2; /* disconnect-reconnect mp */ + arr[6] = 0x80; /* mlus, shared */ + arr[8] = 0x18; /* protocol specific lu */ + arr[10] = 0x82; /* mlus, per initiator port */ + } else if (0x88 == cmd[2]) { /* SCSI Ports */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); + } else if (0x89 == cmd[2]) { /* ATA information */ + arr[1] = cmd[2]; /*sanity */ + n = inquiry_evpd_89(&arr[4]); + arr[2] = (n >> 8); + arr[3] = (n & 0xff); + } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_b0(&arr[4]); } else { /* Illegal request, invalid field in cdb */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; } + len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); return fill_from_dev_buffer(scp, arr, - min(alloc_len, SDEBUG_MAX_INQ_ARR_SZ)); + min(len, SDEBUG_MAX_INQ_ARR_SZ)); } /* drops through here for a standard inquiry */ arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ arr[2] = scsi_debug_scsi_level; arr[3] = 2; /* response_data_format==2 */ arr[4] = SDEBUG_LONG_INQ_SZ - 5; - arr[6] = 0x1; /* claim: ADDR16 */ + arr[6] = 0x10; /* claim: MultiP */ /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ - arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */ + arr[7] = 0xa; /* claim: LINKED + CMDQUE */ memcpy(&arr[8], inq_vendor_id, 8); memcpy(&arr[16], inq_product_id, 16); memcpy(&arr[32], inq_product_rev, 4); /* version descriptors (2 bytes each) follow */ - arr[58] = 0x0; arr[59] = 0x40; /* SAM-2 */ - arr[60] = 0x3; arr[61] = 0x0; /* SPC-3 */ + arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */ + arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */ + n = 62; if (scsi_debug_ptype == 0) { - arr[62] = 0x1; arr[63] = 0x80; /* SBC */ + arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */ } else if (scsi_debug_ptype == 1) { - arr[62] = 0x2; arr[63] = 0x00; /* SSC */ + arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ } + arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ return fill_from_dev_buffer(scp, arr, min(alloc_len, SDEBUG_LONG_INQ_SZ)); } @@ -676,46 +1038,141 @@ static int resp_requests(struct scsi_cmnd * scp, unsigned char * sbuff; unsigned char *cmd = (unsigned char *)scp->cmnd; unsigned char arr[SDEBUG_SENSE_LEN]; + int want_dsense; int len = 18; - memset(arr, 0, SDEBUG_SENSE_LEN); + memset(arr, 0, sizeof(arr)); if (devip->reset == 1) - mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0); + mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); + want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense; sbuff = devip->sense_buff; - if ((cmd[1] & 1) && (! scsi_debug_dsense)) { - /* DESC bit set and sense_buff in fixed format */ - arr[0] = 0x72; - arr[1] = sbuff[2]; /* sense key */ - arr[2] = sbuff[12]; /* asc */ - arr[3] = sbuff[13]; /* ascq */ - len = 8; - } else + if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { + if (want_dsense) { + arr[0] = 0x72; + arr[1] = 0x0; /* NO_SENSE in sense_key */ + arr[2] = THRESHOLD_EXCEEDED; + arr[3] = 0xff; /* TEST set and MRIE==6 */ + } else { + arr[0] = 0x70; + arr[2] = 0x0; /* NO_SENSE in sense_key */ + arr[7] = 0xa; /* 18 byte sense buffer */ + arr[12] = THRESHOLD_EXCEEDED; + arr[13] = 0xff; /* TEST set and MRIE==6 */ + } + } else if (devip->stopped) { + if (want_dsense) { + arr[0] = 0x72; + arr[1] = 0x0; /* NO_SENSE in sense_key */ + arr[2] = LOW_POWER_COND_ON; + arr[3] = 0x0; /* TEST set and MRIE==6 */ + } else { + arr[0] = 0x70; + arr[2] = 0x0; /* NO_SENSE in sense_key */ + arr[7] = 0xa; /* 18 byte sense buffer */ + arr[12] = LOW_POWER_COND_ON; + arr[13] = 0x0; /* TEST set and MRIE==6 */ + } + } else { memcpy(arr, sbuff, SDEBUG_SENSE_LEN); - mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0); + if ((cmd[1] & 1) && (! scsi_debug_dsense)) { + /* DESC bit set and sense_buff in fixed format */ + memset(arr, 0, sizeof(arr)); + arr[0] = 0x72; + arr[1] = sbuff[2]; /* sense key */ + arr[2] = sbuff[12]; /* asc */ + arr[3] = sbuff[13]; /* ascq */ + len = 8; + } + } + mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); return fill_from_dev_buffer(scp, arr, len); } +static int resp_start_stop(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + unsigned char *cmd = (unsigned char *)scp->cmnd; + int power_cond, errsts, start; + + if ((errsts = check_readiness(scp, 1, devip))) + return errsts; + power_cond = (cmd[4] & 0xf0) >> 4; + if (power_cond) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, + 0); + return check_condition_result; + } + start = cmd[4] & 1; + if (start == devip->stopped) + devip->stopped = !start; + return 0; +} + #define SDEBUG_READCAP_ARR_SZ 8 static int resp_readcap(struct scsi_cmnd * scp, struct sdebug_dev_info * devip) { unsigned char arr[SDEBUG_READCAP_ARR_SZ]; - unsigned long capac; + unsigned int capac; int errsts; - if ((errsts = check_reset(scp, devip))) + 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; memset(arr, 0, SDEBUG_READCAP_ARR_SZ); - capac = (unsigned long)sdebug_capacity - 1; - arr[0] = (capac >> 24); - arr[1] = (capac >> 16) & 0xff; - arr[2] = (capac >> 8) & 0xff; - arr[3] = capac & 0xff; + if (sdebug_capacity < 0xffffffff) { + capac = (unsigned int)sdebug_capacity - 1; + arr[0] = (capac >> 24); + arr[1] = (capac >> 16) & 0xff; + arr[2] = (capac >> 8) & 0xff; + arr[3] = capac & 0xff; + } else { + arr[0] = 0xff; + arr[1] = 0xff; + arr[2] = 0xff; + arr[3] = 0xff; + } arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; arr[7] = SECT_SIZE_PER(target) & 0xff; return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); } +#define SDEBUG_READCAP16_ARR_SZ 32 +static int resp_readcap16(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + unsigned char *cmd = (unsigned char *)scp->cmnd; + unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; + unsigned long long capac; + int errsts, k, alloc_len; + + if ((errsts = check_readiness(scp, 1, devip))) + return errsts; + 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; + memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); + capac = sdebug_capacity - 1; + for (k = 0; k < 8; ++k, capac >>= 8) + arr[7 - k] = capac & 0xff; + arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff; + arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff; + arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff; + arr[11] = SECT_SIZE_PER(target) & 0xff; + return fill_from_dev_buffer(scp, arr, + min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); +} + /* <<Following mode page info copied from ST318451LW>> */ static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) @@ -771,27 +1228,98 @@ static int resp_caching_pg(unsigned char * p, int pcontrol, int target) static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) { /* Control mode page for mode_sense */ - unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, + unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, + 0, 0, 0, 0}; + unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0x2, 0x4b}; if (scsi_debug_dsense) ctrl_m_pg[2] |= 0x4; + else + ctrl_m_pg[2] &= ~0x4; memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); if (1 == pcontrol) - memset(p + 2, 0, sizeof(ctrl_m_pg) - 2); + memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); + else if (2 == pcontrol) + memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); return sizeof(ctrl_m_pg); } + static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) { /* Informational Exceptions control mode page for mode_sense */ - unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, - 0, 0, 0x0, 0x0}; + unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, + 0, 0, 0x0, 0x0}; + unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, + 0, 0, 0x0, 0x0}; + memcpy(p, iec_m_pg, sizeof(iec_m_pg)); if (1 == pcontrol) - memset(p + 2, 0, sizeof(iec_m_pg) - 2); + memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); + else if (2 == pcontrol) + memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); return sizeof(iec_m_pg); } +static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) +{ /* SAS SSP mode page - short format for mode_sense */ + unsigned char sas_sf_m_pg[] = {0x19, 0x6, + 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; + + memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); + if (1 == pcontrol) + memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); + return sizeof(sas_sf_m_pg); +} + + +static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, + int target_dev_id) +{ /* SAS phy control and discover mode page for mode_sense */ + unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, + 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, + 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, + 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, + 0x2, 0, 0, 0, 0, 0, 0, 0, + 0x88, 0x99, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, + 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, + 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, + 0x3, 0, 0, 0, 0, 0, 0, 0, + 0x88, 0x99, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + int port_a, port_b; + + port_a = target_dev_id + 1; + port_b = port_a + 1; + memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); + p[20] = (port_a >> 24); + p[21] = (port_a >> 16) & 0xff; + p[22] = (port_a >> 8) & 0xff; + p[23] = port_a & 0xff; + p[48 + 20] = (port_b >> 24); + p[48 + 21] = (port_b >> 16) & 0xff; + p[48 + 22] = (port_b >> 8) & 0xff; + p[48 + 23] = port_b & 0xff; + if (1 == pcontrol) + memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); + return sizeof(sas_pcd_m_pg); +} + +static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) +{ /* SAS SSP shared protocol specific port mode subpage */ + unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + + memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); + if (1 == pcontrol) + memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); + return sizeof(sas_sha_m_pg); +} + #define SDEBUG_MAX_MSENSE_SZ 256 static int resp_mode_sense(struct scsi_cmnd * scp, int target, @@ -800,12 +1328,12 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, unsigned char dbd; int pcontrol, pcode, subpcode; unsigned char dev_spec; - int alloc_len, msense_6, offset, len, errsts; + int alloc_len, msense_6, offset, len, errsts, target_dev_id; unsigned char * ap; unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; unsigned char *cmd = (unsigned char *)scp->cmnd; - if ((errsts = check_reset(scp, devip))) + if ((errsts = check_readiness(scp, 1, devip))) return errsts; dbd = cmd[1] & 0x8; pcontrol = (cmd[2] & 0xc0) >> 6; @@ -819,6 +1347,8 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, 0); return check_condition_result; } + target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + + (devip->target * 1000) - 3; dev_spec = DEV_READONLY(target) ? 0x80 : 0x0; if (msense_6) { arr[2] = dev_spec; @@ -829,7 +1359,8 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, } ap = arr + offset; - if (0 != subpcode) { /* TODO: Control Extension page */ + if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { + /* TODO: Control Extension page */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; @@ -855,17 +1386,45 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, len = resp_ctrl_m_pg(ap, pcontrol, target); offset += len; break; + case 0x19: /* if spc==1 then sas phy, control+discover */ + if ((subpcode > 0x2) && (subpcode < 0xff)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + len = 0; + if ((0x0 == subpcode) || (0xff == subpcode)) + len += resp_sas_sf_m_pg(ap + len, pcontrol, target); + if ((0x1 == subpcode) || (0xff == subpcode)) + len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, + target_dev_id); + if ((0x2 == subpcode) || (0xff == subpcode)) + len += resp_sas_sha_m_spg(ap + len, pcontrol); + offset += len; + break; case 0x1c: /* Informational Exceptions Mode page, all devices */ len = resp_iec_m_pg(ap, pcontrol, target); offset += len; break; case 0x3f: /* Read all Mode pages */ - len = resp_err_recov_pg(ap, pcontrol, target); - len += resp_disconnect_pg(ap + len, pcontrol, target); - len += resp_format_pg(ap + len, pcontrol, target); - len += resp_caching_pg(ap + len, pcontrol, target); - len += resp_ctrl_m_pg(ap + len, pcontrol, target); - len += resp_iec_m_pg(ap + len, pcontrol, target); + if ((0 == subpcode) || (0xff == subpcode)) { + len = resp_err_recov_pg(ap, pcontrol, target); + len += resp_disconnect_pg(ap + len, pcontrol, target); + len += resp_format_pg(ap + len, pcontrol, target); + len += resp_caching_pg(ap + len, pcontrol, target); + len += resp_ctrl_m_pg(ap + len, pcontrol, target); + len += resp_sas_sf_m_pg(ap + len, pcontrol, target); + if (0xff == subpcode) { + len += resp_sas_pcd_m_spg(ap + len, pcontrol, + target, target_dev_id); + len += resp_sas_sha_m_spg(ap + len, pcontrol); + } + len += resp_iec_m_pg(ap + len, pcontrol, target); + } else { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } offset += len; break; default: @@ -882,71 +1441,274 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); } -static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, - int num, struct sdebug_dev_info * devip) +#define SDEBUG_MAX_MSELECT_SZ 512 + +static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, + struct sdebug_dev_info * devip) +{ + int pf, sp, ps, md_len, bd_len, off, spf, pg_len; + int param_len, res, errsts, mpage; + unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; + unsigned char *cmd = (unsigned char *)scp->cmnd; + + if ((errsts = check_readiness(scp, 1, devip))) + return errsts; + memset(arr, 0, sizeof(arr)); + pf = cmd[1] & 0x10; + sp = cmd[1] & 0x1; + param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]); + if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + res = fetch_to_dev_buffer(scp, arr, param_len); + if (-1 == res) + return (DID_ERROR << 16); + else if ((res < param_len) && + (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) + printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, " + " IO sent=%d bytes\n", param_len, res); + md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); + bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); + if ((md_len > 2) || (0 != bd_len)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_PARAM_LIST, 0); + return check_condition_result; + } + off = bd_len + (mselect6 ? 4 : 8); + mpage = arr[off] & 0x3f; + ps = !!(arr[off] & 0x80); + if (ps) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_PARAM_LIST, 0); + return check_condition_result; + } + spf = !!(arr[off] & 0x40); + pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) : + (arr[off + 1] + 2); + if ((pg_len + off) > param_len) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + PARAMETER_LIST_LENGTH_ERR, 0); + return check_condition_result; + } + switch (mpage) { + case 0xa: /* Control Mode page */ + if (ctrl_m_pg[1] == arr[off + 1]) { + memcpy(ctrl_m_pg + 2, arr + off + 2, + sizeof(ctrl_m_pg) - 2); + scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4); + return 0; + } + break; + case 0x1c: /* Informational Exceptions Mode page */ + if (iec_m_pg[1] == arr[off + 1]) { + memcpy(iec_m_pg + 2, arr + off + 2, + sizeof(iec_m_pg) - 2); + return 0; + } + break; + default: + break; + } + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_PARAM_LIST, 0); + return check_condition_result; +} + +static int resp_temp_l_pg(unsigned char * arr) +{ + unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, + 0x0, 0x1, 0x3, 0x2, 0x0, 65, + }; + + memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); + return sizeof(temp_l_pg); +} + +static int resp_ie_l_pg(unsigned char * arr) +{ + unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, + }; + + memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); + if (iec_m_pg[2] & 0x4) { /* TEST bit set */ + arr[4] = THRESHOLD_EXCEEDED; + arr[5] = 0xff; + } + return sizeof(ie_l_pg); +} + +#define SDEBUG_MAX_LSENSE_SZ 512 + +static int resp_log_sense(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + int ppc, sp, pcontrol, pcode, alloc_len, errsts, len, n; + unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; + unsigned char *cmd = (unsigned char *)scp->cmnd; + + if ((errsts = check_readiness(scp, 1, devip))) + return errsts; + memset(arr, 0, sizeof(arr)); + ppc = cmd[1] & 0x2; + sp = cmd[1] & 0x1; + if (ppc || sp) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + pcontrol = (cmd[2] & 0xc0) >> 6; + pcode = cmd[2] & 0x3f; + alloc_len = (cmd[7] << 8) + cmd[8]; + arr[0] = pcode; + switch (pcode) { + case 0x0: /* Supported log pages log page */ + n = 4; + arr[n++] = 0x0; /* this page */ + arr[n++] = 0xd; /* Temperature */ + arr[n++] = 0x2f; /* Informational exceptions */ + arr[3] = n - 4; + break; + case 0xd: /* Temperature log page */ + arr[3] = resp_temp_l_pg(arr + 4); + break; + case 0x2f: /* Informational exceptions log page */ + arr[3] = resp_ie_l_pg(arr + 4); + break; + default: + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); + return fill_from_dev_buffer(scp, arr, + 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) { unsigned long iflags; + unsigned int block, from_bottom; + unsigned long long u; int ret; - if (upper_blk || (block + num > sdebug_capacity)) { + 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; + } if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && - (block <= OPT_MEDIUM_ERR_ADDR) && - ((block + num) > OPT_MEDIUM_ERR_ADDR)) { + (lba <= OPT_MEDIUM_ERR_ADDR) && + ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { + /* claim unrecoverable read error */ mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); - /* claim unrecoverable read error */ + /* set info field and valid bit for fixed descriptor */ + if (0x70 == (devip->sense_buff[0] & 0x7f)) { + devip->sense_buff[0] |= 0x80; /* Valid bit */ + ret = OPT_MEDIUM_ERR_ADDR; + devip->sense_buff[3] = (ret >> 24) & 0xff; + devip->sense_buff[4] = (ret >> 16) & 0xff; + devip->sense_buff[5] = (ret >> 8) & 0xff; + devip->sense_buff[6] = ret & 0xff; + } return check_condition_result; } read_lock_irqsave(&atomic_rw, iflags); - ret = fill_from_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE), - num * SECT_SIZE); + 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); + } read_unlock_irqrestore(&atomic_rw, iflags); return ret; } -static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block, - 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; - if (upper_blk || (block + num > sdebug_capacity)) { + 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; + } write_lock_irqsave(&atomic_rw, iflags); - res = fetch_to_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE), - num * SECT_SIZE); + 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); + } write_unlock_irqrestore(&atomic_rw, iflags); if (-1 == res) return (DID_ERROR << 16); else if ((res < (num * SECT_SIZE)) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) - printk(KERN_INFO "scsi_debug: write: cdb indicated=%d, " + printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " " IO sent=%d bytes\n", num * SECT_SIZE, res); return 0; } -#define SDEBUG_RLUN_ARR_SZ 128 +#define SDEBUG_RLUN_ARR_SZ 256 static int resp_report_luns(struct scsi_cmnd * scp, struct sdebug_dev_info * devip) { unsigned int alloc_len; - int lun_cnt, i, upper; + int lun_cnt, i, upper, num, n, wlun, lun; unsigned char *cmd = (unsigned char *)scp->cmnd; int select_report = (int)cmd[2]; struct scsi_lun *one_lun; unsigned char arr[SDEBUG_RLUN_ARR_SZ]; + unsigned char * max_addr; alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); - if ((alloc_len < 16) || (select_report > 2)) { + if ((alloc_len < 4) || (select_report > 2)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; @@ -954,18 +1716,37 @@ static int resp_report_luns(struct scsi_cmnd * scp, /* can produce response with up to 16k luns (lun 0 to lun 16383) */ memset(arr, 0, SDEBUG_RLUN_ARR_SZ); lun_cnt = scsi_debug_max_luns; - arr[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff; - arr[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff; - lun_cnt = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / - sizeof(struct scsi_lun)), lun_cnt); + if (1 == select_report) + lun_cnt = 0; + else if (scsi_debug_no_lun_0 && (lun_cnt > 0)) + --lun_cnt; + wlun = (select_report > 0) ? 1 : 0; + num = lun_cnt + wlun; + arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; + arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; + n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / + sizeof(struct scsi_lun)), num); + if (n < num) { + wlun = 0; + lun_cnt = n; + } one_lun = (struct scsi_lun *) &arr[8]; - for (i = 0; i < lun_cnt; i++) { - upper = (i >> 8) & 0x3f; + max_addr = arr + SDEBUG_RLUN_ARR_SZ; + for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0); + ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); + i++, lun++) { + upper = (lun >> 8) & 0x3f; if (upper) one_lun[i].scsi_lun[0] = (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); - one_lun[i].scsi_lun[1] = i & 0xff; + one_lun[i].scsi_lun[1] = lun & 0xff; } + if (wlun) { + one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff; + one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff; + i++; + } + alloc_len = (unsigned char *)(one_lun + i) - arr; return fill_from_dev_buffer(scp, arr, min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); } @@ -1001,7 +1782,8 @@ static void timer_intr_handler(unsigned long indx) static int scsi_debug_slave_alloc(struct scsi_device * sdp) { if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_alloc\n"); + printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", + sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); return 0; } @@ -1010,7 +1792,8 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp) struct sdebug_dev_info * devip; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_configure\n"); + printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", + sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; devip = devInfoReg(sdp); @@ -1018,6 +1801,7 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp) if (sdp->host->cmd_per_lun) scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, sdp->host->cmd_per_lun); + blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); return 0; } @@ -1027,7 +1811,8 @@ static void scsi_debug_slave_destroy(struct scsi_device * sdp) (struct sdebug_dev_info *)sdp->hostdata; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_destroy\n"); + printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", + sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); if (devip) { /* make this slot avaliable for re-use */ devip->used = 0; @@ -1084,6 +1869,8 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) 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; @@ -1272,7 +2059,7 @@ static void __init sdebug_build_parts(unsigned char * ramp) printk(KERN_WARNING "scsi_debug:build_parts: reducing " "partitions to %d\n", SDEBUG_MAX_PARTS); } - num_sectors = (int)(sdebug_store_size / SECT_SIZE); + num_sectors = (int)sdebug_store_sectors; sectors_per_part = (num_sectors - sdebug_sectors_per) / scsi_debug_num_parts; heads_by_sects = sdebug_heads * sdebug_sectors_per; @@ -1315,9 +2102,9 @@ static int schedule_resp(struct scsi_cmnd * cmnd, if (scsi_result) { struct scsi_device * sdp = cmnd->device; - sdev_printk(KERN_INFO, sdp, - "non-zero result=0x%x\n", - scsi_result); + printk(KERN_INFO "scsi_debug: <%u %u %u %u> " + "non-zero result=0x%x\n", sdp->host->host_no, + sdp->channel, sdp->id, sdp->lun, scsi_result); } } if (cmnd && devip) { @@ -1364,21 +2151,19 @@ static int schedule_resp(struct scsi_cmnd * cmnd, } } -/* Set 'perm' (4th argument) to 0 to disable module_param's definition - * of sysfs parameters (which module_param doesn't yet support). - * Sysfs parameters defined explicitly below. - */ -module_param_named(add_host, scsi_debug_add_host, int, 0); /* perm=0644 */ -module_param_named(delay, scsi_debug_delay, int, 0); /* perm=0644 */ -module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, 0); -module_param_named(dsense, scsi_debug_dsense, int, 0); -module_param_named(every_nth, scsi_debug_every_nth, int, 0); -module_param_named(max_luns, scsi_debug_max_luns, int, 0); -module_param_named(num_parts, scsi_debug_num_parts, int, 0); -module_param_named(num_tgts, scsi_debug_num_tgts, int, 0); -module_param_named(opts, scsi_debug_opts, int, 0); /* perm=0644 */ -module_param_named(ptype, scsi_debug_ptype, int, 0); -module_param_named(scsi_level, scsi_debug_scsi_level, int, 0); +module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); +module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); +module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); +module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); +module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); +module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); +module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); +module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); +module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); +module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); +module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); +module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); +module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); MODULE_DESCRIPTION("SCSI debug adapter driver"); @@ -1387,15 +2172,17 @@ MODULE_VERSION(SCSI_DEBUG_VERSION); MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); -MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs"); -MODULE_PARM_DESC(dsense, "use descriptor sense format(def: fixed)"); +MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); +MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)"); -MODULE_PARM_DESC(max_luns, "number of SCSI LUNs per target to simulate"); +MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); +MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); -MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate"); -MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->..."); +MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); +MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->... (def=0)"); MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); +MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); static char sdebug_info[256]; @@ -1547,6 +2334,24 @@ static ssize_t sdebug_dsense_store(struct device_driver * ddp, DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, sdebug_dsense_store); +static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); +} +static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp, + const char * buf, size_t count) +{ + int n; + + if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { + scsi_debug_no_lun_0 = n; + return count; + } + return -EINVAL; +} +DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show, + sdebug_no_lun_0_store); + static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) { return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); @@ -1622,6 +2427,29 @@ static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) } DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL); +static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb); +} +static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp, + const char * buf, size_t count) +{ + int n; + + 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; + return count; + } + return -EINVAL; +} +DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show, + sdebug_virtual_gb_store); + static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) { return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); @@ -1659,19 +2487,22 @@ static ssize_t sdebug_add_host_store(struct device_driver * ddp, DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, sdebug_add_host_store); -static void do_create_driverfs_files(void) +static int do_create_driverfs_files(void) { - driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); - driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); - driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); - driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); - driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); - driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); - driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); - driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); - driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); - driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); - driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); + int ret; + + ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); + ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); + return ret; } static void do_remove_driverfs_files(void) @@ -1691,14 +2522,20 @@ static void do_remove_driverfs_files(void) static int __init scsi_debug_init(void) { - unsigned long sz; + unsigned int 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 long)scsi_debug_dev_size_mb * 1048576; - sdebug_capacity = sdebug_store_size / SECT_SIZE; + 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; /* play around with geometry, don't waste too much on track 0 */ sdebug_heads = 8; @@ -1727,12 +2564,32 @@ static int __init scsi_debug_init(void) if (scsi_debug_num_parts > 0) sdebug_build_parts(fake_storep); - init_all_queued(); + ret = device_register(&pseudo_primary); + if (ret < 0) { + printk(KERN_WARNING "scsi_debug: device_register error: %d\n", + ret); + goto free_vm; + } + ret = bus_register(&pseudo_lld_bus); + if (ret < 0) { + printk(KERN_WARNING "scsi_debug: bus_register error: %d\n", + ret); + goto dev_unreg; + } + ret = driver_register(&sdebug_driverfs_driver); + if (ret < 0) { + printk(KERN_WARNING "scsi_debug: driver_register error: %d\n", + ret); + goto bus_unreg; + } + ret = do_create_driverfs_files(); + if (ret < 0) { + printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n", + ret); + goto del_files; + } - device_register(&pseudo_primary); - bus_register(&pseudo_lld_bus); - driver_register(&sdebug_driverfs_driver); - do_create_driverfs_files(); + init_all_queued(); sdebug_driver_template.proc_name = (char *)sdebug_proc_name; @@ -1752,6 +2609,18 @@ static int __init scsi_debug_init(void) scsi_debug_add_host); } return 0; + +del_files: + do_remove_driverfs_files(); + driver_unregister(&sdebug_driverfs_driver); +bus_unreg: + bus_unregister(&pseudo_lld_bus); +dev_unreg: + device_unregister(&pseudo_primary); +free_vm: + vfree(fake_storep); + + return ret; } static void __exit scsi_debug_exit(void) @@ -1812,7 +2681,7 @@ static int sdebug_add_adapter(void) struct sdebug_dev_info *sdbg_devinfo; struct list_head *lh, *lh_sf; - sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL); + sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); if (NULL == sdbg_host) { printk(KERN_ERR "%s: out of memory at line %d\n", @@ -1824,7 +2693,7 @@ 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); + sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL); if (NULL == sdbg_devinfo) { printk(KERN_ERR "%s: out of memory at line %d\n", __FUNCTION__, __LINE__); @@ -1905,7 +2774,7 @@ static int sdebug_driver_probe(struct device * dev) hpnt->max_id = scsi_debug_num_tgts + 1; else hpnt->max_id = scsi_debug_num_tgts; - hpnt->max_lun = scsi_debug_max_luns; + hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ error = scsi_add_host(hpnt, &sdbg_host->dev); if (error) { @@ -1959,7 +2828,7 @@ static void sdebug_max_tgts_luns(void) hpnt->max_id = scsi_debug_num_tgts + 1; else hpnt->max_id = scsi_debug_num_tgts; - hpnt->max_lun = scsi_debug_max_luns; + hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */ } spin_unlock(&sdebug_host_list_lock); } diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index fb5cb4c9ac6..3d0429bc14a 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -162,7 +162,7 @@ static struct { {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN}, {"HITACHI", "OPEN-E", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN}, {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */ - {"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP XP Arrays */ + {"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */ {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN}, {"HP", "HSV100", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, {"HP", "C1557A", NULL, BLIST_FORCELUN}, diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 6a7a60fc0a4..3d355d05461 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -460,19 +460,71 @@ static void scsi_eh_done(struct scsi_cmnd *scmd) * Return value: * SUCCESS or FAILED or NEEDS_RETRY **/ -static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout) +static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, + int cmnd_size, int timeout, int copy_sense) { struct scsi_device *sdev = scmd->device; struct Scsi_Host *shost = sdev->host; - DECLARE_COMPLETION(done); + int old_result = scmd->result; + DECLARE_COMPLETION_ONSTACK(done); unsigned long timeleft; unsigned long flags; + unsigned char old_cmnd[MAX_COMMAND_SIZE]; + enum dma_data_direction old_data_direction; + unsigned short old_use_sg; + unsigned char old_cmd_len; + unsigned old_bufflen; + void *old_buffer; int rtn; + /* + * We need saved copies of a number of fields - this is because + * error handling may need to overwrite these with different values + * to run different commands, and once error handling is complete, + * we will need to restore these values prior to running the actual + * command. + */ + old_buffer = scmd->request_buffer; + old_bufflen = scmd->request_bufflen; + memcpy(old_cmnd, scmd->cmnd, sizeof(scmd->cmnd)); + old_data_direction = scmd->sc_data_direction; + old_cmd_len = scmd->cmd_len; + old_use_sg = scmd->use_sg; + + memset(scmd->cmnd, 0, sizeof(scmd->cmnd)); + memcpy(scmd->cmnd, cmnd, cmnd_size); + + if (copy_sense) { + int gfp_mask = GFP_ATOMIC; + + if (shost->hostt->unchecked_isa_dma) + gfp_mask |= __GFP_DMA; + + scmd->sc_data_direction = DMA_FROM_DEVICE; + scmd->request_bufflen = 252; + scmd->request_buffer = kzalloc(scmd->request_bufflen, gfp_mask); + if (!scmd->request_buffer) + return FAILED; + } else { + scmd->request_buffer = NULL; + scmd->request_bufflen = 0; + scmd->sc_data_direction = DMA_NONE; + } + + scmd->underflow = 0; + scmd->use_sg = 0; + scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); + if (sdev->scsi_level <= SCSI_2) scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) | (sdev->lun << 5 & 0xe0); + /* + * Zero the sense buffer. The scsi spec mandates that any + * untransferred sense data should be interpreted as being zero. + */ + memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); + shost->eh_action = &done; spin_lock_irqsave(shost->host_lock, flags); @@ -522,6 +574,29 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout) rtn = FAILED; } + + /* + * Last chance to have valid sense data. + */ + if (copy_sense) { + if (!SCSI_SENSE_VALID(scmd)) { + memcpy(scmd->sense_buffer, scmd->request_buffer, + sizeof(scmd->sense_buffer)); + } + kfree(scmd->request_buffer); + } + + + /* + * Restore original data + */ + scmd->request_buffer = old_buffer; + scmd->request_bufflen = old_bufflen; + memcpy(scmd->cmnd, old_cmnd, sizeof(scmd->cmnd)); + scmd->sc_data_direction = old_data_direction; + scmd->cmd_len = old_cmd_len; + scmd->use_sg = old_use_sg; + scmd->result = old_result; return rtn; } @@ -537,56 +612,9 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout) static int scsi_request_sense(struct scsi_cmnd *scmd) { static unsigned char generic_sense[6] = - {REQUEST_SENSE, 0, 0, 0, 252, 0}; - unsigned char *scsi_result; - int saved_result; - int rtn; - - memcpy(scmd->cmnd, generic_sense, sizeof(generic_sense)); - - scsi_result = kmalloc(252, GFP_ATOMIC | ((scmd->device->host->hostt->unchecked_isa_dma) ? __GFP_DMA : 0)); + {REQUEST_SENSE, 0, 0, 0, 252, 0}; - - if (unlikely(!scsi_result)) { - printk(KERN_ERR "%s: cannot allocate scsi_result.\n", - __FUNCTION__); - return FAILED; - } - - /* - * zero the sense buffer. some host adapters automatically always - * request sense, so it is not a good idea that - * scmd->request_buffer and scmd->sense_buffer point to the same - * address (db). 0 is not a valid sense code. - */ - memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); - memset(scsi_result, 0, 252); - - saved_result = scmd->result; - scmd->request_buffer = scsi_result; - scmd->request_bufflen = 252; - scmd->use_sg = 0; - scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); - scmd->sc_data_direction = DMA_FROM_DEVICE; - scmd->underflow = 0; - - rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT); - - /* last chance to have valid sense data */ - if(!SCSI_SENSE_VALID(scmd)) { - memcpy(scmd->sense_buffer, scmd->request_buffer, - sizeof(scmd->sense_buffer)); - } - - kfree(scsi_result); - - /* - * when we eventually call scsi_finish, we really wish to complete - * the original request, so let's restore the original data. (db) - */ - scsi_setup_cmd_retry(scmd); - scmd->result = saved_result; - return rtn; + return scsi_send_eh_cmnd(scmd, generic_sense, 6, SENSE_TIMEOUT, 1); } /** @@ -605,12 +633,6 @@ void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q) { scmd->device->host->host_failed--; scmd->eh_eflags = 0; - - /* - * set this back so that the upper level can correctly free up - * things. - */ - scsi_setup_cmd_retry(scmd); list_move_tail(&scmd->eh_entry, done_q); } EXPORT_SYMBOL(scsi_eh_finish_cmd); @@ -715,47 +737,23 @@ static int scsi_eh_tur(struct scsi_cmnd *scmd) { static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; int retry_cnt = 1, rtn; - int saved_result; retry_tur: - memcpy(scmd->cmnd, tur_command, sizeof(tur_command)); - - /* - * zero the sense buffer. the scsi spec mandates that any - * untransferred sense data should be interpreted as being zero. - */ - memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); + rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, SENSE_TIMEOUT, 0); - saved_result = scmd->result; - scmd->request_buffer = NULL; - scmd->request_bufflen = 0; - scmd->use_sg = 0; - scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); - scmd->underflow = 0; - scmd->sc_data_direction = DMA_NONE; - - rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT); - - /* - * when we eventually call scsi_finish, we really wish to complete - * the original request, so let's restore the original data. (db) - */ - scsi_setup_cmd_retry(scmd); - scmd->result = saved_result; - - /* - * hey, we are done. let's look to see what happened. - */ SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n", __FUNCTION__, scmd, rtn)); - if (rtn == SUCCESS) - return 0; - else if (rtn == NEEDS_RETRY) { + + switch (rtn) { + case NEEDS_RETRY: if (retry_cnt--) goto retry_tur; + /*FALLTHRU*/ + case SUCCESS: return 0; + default: + return 1; } - return 1; } /** @@ -837,44 +835,16 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd) static int scsi_eh_try_stu(struct scsi_cmnd *scmd) { static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0}; - int rtn; - int saved_result; - - if (!scmd->device->allow_restart) - return 1; - memcpy(scmd->cmnd, stu_command, sizeof(stu_command)); - - /* - * zero the sense buffer. the scsi spec mandates that any - * untransferred sense data should be interpreted as being zero. - */ - memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); - - saved_result = scmd->result; - scmd->request_buffer = NULL; - scmd->request_bufflen = 0; - scmd->use_sg = 0; - scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); - scmd->underflow = 0; - scmd->sc_data_direction = DMA_NONE; + if (scmd->device->allow_restart) { + int rtn; - rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT); - - /* - * when we eventually call scsi_finish, we really wish to complete - * the original request, so let's restore the original data. (db) - */ - scsi_setup_cmd_retry(scmd); - scmd->result = saved_result; + rtn = scsi_send_eh_cmnd(scmd, stu_command, 6, + START_UNIT_TIMEOUT, 0); + if (rtn == SUCCESS) + return 0; + } - /* - * hey, we are done. let's look to see what happened. - */ - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n", - __FUNCTION__, scmd, rtn)); - if (rtn == SUCCESS) - return 0; return 1; } @@ -1672,7 +1642,9 @@ int scsi_reset_provider(struct scsi_device *dev, int flag) { struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL); + struct Scsi_Host *shost = dev->host; struct request req; + unsigned long flags; int rtn; scmd->request = &req; @@ -1682,8 +1654,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag) scmd->scsi_done = scsi_reset_provider_done_command; scmd->done = NULL; - scmd->buffer = NULL; - scmd->bufflen = 0; scmd->request_buffer = NULL; scmd->request_bufflen = 0; @@ -1699,6 +1669,10 @@ scsi_reset_provider(struct scsi_device *dev, int flag) */ scmd->pid = 0; + spin_lock_irqsave(shost->host_lock, flags); + shost->tmf_in_progress = 1; + spin_unlock_irqrestore(shost->host_lock, flags); + switch (flag) { case SCSI_TRY_RESET_DEVICE: rtn = scsi_try_bus_device_reset(scmd); @@ -1717,6 +1691,22 @@ scsi_reset_provider(struct scsi_device *dev, int flag) rtn = FAILED; } + spin_lock_irqsave(shost->host_lock, flags); + shost->tmf_in_progress = 0; + spin_unlock_irqrestore(shost->host_lock, flags); + + /* + * be sure to wake up anyone who was sleeping or had their queue + * suspended while we performed the TMF. + */ + SCSI_LOG_ERROR_RECOVERY(3, + printk("%s: waking up host to restart after TMF\n", + __FUNCTION__)); + + wake_up(&shost->host_wait); + + scsi_run_host_queues(shost); + scsi_next_command(scmd); return rtn; } diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index a89c4115cfb..32293f45166 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -110,11 +110,8 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, sshdr.asc, sshdr.ascq); break; case NOT_READY: /* This happens if there is no disc in drive */ - if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) { - printk(KERN_INFO "Device not ready. Make sure" - " there is a disc in the drive.\n"); + if (sdev->removable) break; - } case UNIT_ATTENTION: if (sdev->removable) { sdev->changed = 1; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 3d04a9f386a..077c1c69121 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -436,60 +436,16 @@ EXPORT_SYMBOL_GPL(scsi_execute_async); * * Arguments: cmd - command that is ready to be queued. * - * Returns: Nothing - * * Notes: This function has the job of initializing a number of * fields related to error handling. Typically this will * be called once for each command, as required. */ -static int scsi_init_cmd_errh(struct scsi_cmnd *cmd) +static void scsi_init_cmd_errh(struct scsi_cmnd *cmd) { cmd->serial_number = 0; - memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer); - if (cmd->cmd_len == 0) cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); - - /* - * We need saved copies of a number of fields - this is because - * error handling may need to overwrite these with different values - * to run different commands, and once error handling is complete, - * we will need to restore these values prior to running the actual - * command. - */ - cmd->old_use_sg = cmd->use_sg; - cmd->old_cmd_len = cmd->cmd_len; - cmd->sc_old_data_direction = cmd->sc_data_direction; - cmd->old_underflow = cmd->underflow; - memcpy(cmd->data_cmnd, cmd->cmnd, sizeof(cmd->cmnd)); - cmd->buffer = cmd->request_buffer; - cmd->bufflen = cmd->request_bufflen; - - return 1; -} - -/* - * Function: scsi_setup_cmd_retry() - * - * Purpose: Restore the command state for a retry - * - * Arguments: cmd - command to be restored - * - * Returns: Nothing - * - * Notes: Immediately prior to retrying a command, we need - * to restore certain fields that we saved above. - */ -void scsi_setup_cmd_retry(struct scsi_cmnd *cmd) -{ - memcpy(cmd->cmnd, cmd->data_cmnd, sizeof(cmd->data_cmnd)); - cmd->request_buffer = cmd->buffer; - cmd->request_bufflen = cmd->bufflen; - cmd->use_sg = cmd->old_use_sg; - cmd->cmd_len = cmd->old_cmd_len; - cmd->sc_data_direction = cmd->sc_old_data_direction; - cmd->underflow = cmd->old_underflow; } void scsi_device_unbusy(struct scsi_device *sdev) @@ -807,22 +763,13 @@ static void scsi_free_sgtable(struct scatterlist *sgl, int index) */ static void scsi_release_buffers(struct scsi_cmnd *cmd) { - struct request *req = cmd->request; - - /* - * Free up any indirection buffers we allocated for DMA purposes. - */ if (cmd->use_sg) scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len); - else if (cmd->request_buffer != req->buffer) - kfree(cmd->request_buffer); /* * Zero these out. They now point to freed memory, and it is * dangerous to hang onto the pointers. */ - cmd->buffer = NULL; - cmd->bufflen = 0; cmd->request_buffer = NULL; cmd->request_bufflen = 0; } @@ -855,11 +802,10 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd) * b) We can just use scsi_requeue_command() here. This would * be used if we just wanted to retry, for example. */ -void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, - unsigned int block_bytes) +void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) { int result = cmd->result; - int this_count = cmd->bufflen; + int this_count = cmd->request_bufflen; request_queue_t *q = cmd->device->request_queue; struct request *req = cmd->request; int clear_errors = 1; @@ -867,28 +813,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, int sense_valid = 0; int sense_deferred = 0; - /* - * Free up any indirection buffers we allocated for DMA purposes. - * For the case of a READ, we need to copy the data out of the - * bounce buffer and into the real buffer. - */ - if (cmd->use_sg) - scsi_free_sgtable(cmd->buffer, cmd->sglist_len); - else if (cmd->buffer != req->buffer) { - if (rq_data_dir(req) == READ) { - unsigned long flags; - char *to = bio_kmap_irq(req->bio, &flags); - memcpy(to, cmd->buffer, cmd->bufflen); - bio_kunmap_irq(to, &flags); - } - kfree(cmd->buffer); - } + scsi_release_buffers(cmd); if (result) { sense_valid = scsi_command_normalize_sense(cmd, &sshdr); if (sense_valid) sense_deferred = scsi_sense_is_deferred(&sshdr); } + if (blk_pc_request(req)) { /* SG_IO ioctl from block level */ req->errors = result; if (result) { @@ -909,99 +841,73 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, } /* - * Zero these out. They now point to freed memory, and it is - * dangerous to hang onto the pointers. - */ - cmd->buffer = NULL; - cmd->bufflen = 0; - cmd->request_buffer = NULL; - cmd->request_bufflen = 0; - - /* * Next deal with any sectors which we were able to correctly * handle. */ - if (good_bytes >= 0) { - SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d bytes done.\n", - req->nr_sectors, good_bytes)); - SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg)); + SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, " + "%d bytes done.\n", + req->nr_sectors, good_bytes)); + SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg)); - if (clear_errors) - req->errors = 0; - /* - * If multiple sectors are requested in one buffer, then - * they will have been finished off by the first command. - * If not, then we have a multi-buffer command. - * - * If block_bytes != 0, it means we had a medium error - * of some sort, and that we want to mark some number of - * sectors as not uptodate. Thus we want to inhibit - * requeueing right here - we will requeue down below - * when we handle the bad sectors. - */ + if (clear_errors) + req->errors = 0; - /* - * If the command completed without error, then either - * finish off the rest of the command, or start a new one. - */ - if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL) - return; - } - /* - * Now, if we were good little boys and girls, Santa left us a request - * sense buffer. We can extract information from this, so we - * can choose a block to remap, etc. + /* 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, 1, good_bytes, result == 0) == NULL) + return; + + /* good_bytes = 0, or (inclusive) there were leftovers and + * result = 0, so scsi_end_request couldn't retry. */ if (sense_valid && !sense_deferred) { switch (sshdr.sense_key) { case UNIT_ATTENTION: if (cmd->device->removable) { - /* detected disc change. set a bit + /* Detected disc change. Set a bit * and quietly refuse further access. */ cmd->device->changed = 1; - scsi_end_request(cmd, 0, - this_count, 1); + scsi_end_request(cmd, 0, this_count, 1); return; } else { - /* - * Must have been a power glitch, or a - * bus reset. Could not have been a - * media change, so we just retry the - * request and see what happens. - */ + /* Must have been a power glitch, or a + * bus reset. Could not have been a + * media change, so we just retry the + * request and see what happens. + */ scsi_requeue_command(q, cmd); return; } break; case ILLEGAL_REQUEST: - /* - * If we had an ILLEGAL REQUEST returned, then we may - * have performed an unsupported command. The only - * thing this should be would be a ten byte read where - * only a six byte read was supported. Also, on a - * system where READ CAPACITY failed, we may have read - * past the end of the disk. - */ + /* If we had an ILLEGAL REQUEST returned, then + * we may have performed an unsupported + * command. The only thing this should be + * would be a ten byte read where only a six + * byte read was supported. Also, on a system + * where READ CAPACITY failed, we may have + * read past the end of the disk. + */ if ((cmd->device->use_10_for_rw && sshdr.asc == 0x20 && sshdr.ascq == 0x00) && (cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == WRITE_10)) { cmd->device->use_10_for_rw = 0; - /* - * This will cause a retry with a 6-byte - * command. + /* This will cause a retry with a + * 6-byte command. */ scsi_requeue_command(q, cmd); - result = 0; + return; } else { scsi_end_request(cmd, 0, this_count, 1); return; } break; case NOT_READY: - /* - * If the device is in the process of becoming + /* If the device is in the process of becoming * ready, or has a temporary blockage, retry. */ if (sshdr.asc == 0x04) { @@ -1021,7 +927,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, } if (!(req->flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, - "Device not ready: "); + "Device not ready: "); scsi_print_sense_hdr("", &sshdr); } scsi_end_request(cmd, 0, this_count, 1); @@ -1029,21 +935,21 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, case VOLUME_OVERFLOW: if (!(req->flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, - "Volume overflow, CDB: "); - __scsi_print_command(cmd->data_cmnd); + "Volume overflow, CDB: "); + __scsi_print_command(cmd->cmnd); scsi_print_sense("", cmd); } - scsi_end_request(cmd, 0, block_bytes, 1); + /* See SSC3rXX or current. */ + scsi_end_request(cmd, 0, this_count, 1); return; default: break; } - } /* driver byte != 0 */ + } if (host_byte(result) == DID_RESET) { - /* - * Third party bus reset or reset for error - * recovery reasons. Just retry the request - * and see what happens. + /* Third party bus reset or reset for error recovery + * reasons. Just retry the request and see what + * happens. */ scsi_requeue_command(q, cmd); return; @@ -1051,21 +957,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, if (result) { if (!(req->flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, - "SCSI error: return code = 0x%x\n", result); - + "SCSI error: return code = 0x%08x\n", + result); if (driver_byte(result) & DRIVER_SENSE) scsi_print_sense("", cmd); } - /* - * Mark a single buffer as not uptodate. Queue the remainder. - * We sometimes get this cruft in the event that a medium error - * isn't properly reported. - */ - block_bytes = req->hard_cur_sectors << 9; - if (!block_bytes) - block_bytes = req->data_len; - scsi_end_request(cmd, 0, block_bytes, 1); } + scsi_end_request(cmd, 0, this_count, !result); } EXPORT_SYMBOL(scsi_io_completion); @@ -1169,7 +1067,7 @@ static void scsi_blk_pc_done(struct scsi_cmnd *cmd) * successfully. Since this is a REQ_BLOCK_PC command the * caller should check the request's errors value */ - scsi_io_completion(cmd, cmd->bufflen, 0); + scsi_io_completion(cmd, cmd->request_bufflen); } static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd) @@ -2050,6 +1948,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) switch (oldstate) { case SDEV_CREATED: case SDEV_RUNNING: + case SDEV_QUIESCE: case SDEV_OFFLINE: case SDEV_BLOCK: break; @@ -2060,6 +1959,9 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) case SDEV_DEL: switch (oldstate) { + case SDEV_CREATED: + case SDEV_RUNNING: + case SDEV_OFFLINE: case SDEV_CANCEL: break; default: diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 015c90cf3ab..ae24c85aaee 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -57,7 +57,6 @@ extern int scsi_eh_scmd_add(struct scsi_cmnd *, int); /* scsi_lib.c */ extern int scsi_maybe_unblock_host(struct scsi_device *sdev); -extern void scsi_setup_cmd_retry(struct scsi_cmnd *cmd); extern void scsi_device_unbusy(struct scsi_device *sdev); extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason); extern void scsi_next_command(struct scsi_cmnd *cmd); @@ -116,7 +115,7 @@ extern struct bus_type scsi_bus_type; * classes. */ -#define SCSI_DEVICE_BLOCK_MAX_TIMEOUT (HZ*60) +#define SCSI_DEVICE_BLOCK_MAX_TIMEOUT 600 /* units in seconds */ extern int scsi_internal_device_block(struct scsi_device *sdev); extern int scsi_internal_device_unblock(struct scsi_device *sdev); diff --git a/drivers/scsi/scsi_sas_internal.h b/drivers/scsi/scsi_sas_internal.h index d76e6e3d8ca..e1edab45a37 100644 --- a/drivers/scsi/scsi_sas_internal.h +++ b/drivers/scsi/scsi_sas_internal.h @@ -2,7 +2,8 @@ #define _SCSI_SAS_INTERNAL_H #define SAS_HOST_ATTRS 0 -#define SAS_PORT_ATTRS 17 +#define SAS_PHY_ATTRS 17 +#define SAS_PORT_ATTRS 1 #define SAS_RPORT_ATTRS 7 #define SAS_END_DEV_ATTRS 3 #define SAS_EXPANDER_ATTRS 7 @@ -13,12 +14,14 @@ struct sas_internal { struct sas_domain_function_template *dft; struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS]; - struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS]; + struct class_device_attribute private_phy_attrs[SAS_PHY_ATTRS]; + struct class_device_attribute private_port_attrs[SAS_PORT_ATTRS]; struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS]; struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS]; struct class_device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS]; struct transport_container phy_attr_cont; + struct transport_container port_attr_cont; struct transport_container rphy_attr_cont; struct transport_container end_dev_attr_cont; struct transport_container expander_attr_cont; @@ -28,7 +31,8 @@ struct sas_internal { * needed by scsi_sysfs.c */ struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1]; - struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1]; + struct class_device_attribute *phy_attrs[SAS_PHY_ATTRS + 1]; + struct class_device_attribute *port_attrs[SAS_PORT_ATTRS + 1]; struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1]; struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1]; struct class_device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1]; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 1341608e9e3..1bd92b9b46d 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -809,6 +809,7 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) static inline void scsi_destroy_sdev(struct scsi_device *sdev) { + scsi_device_set_state(sdev, SDEV_DEL); if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); transport_destroy_device(&sdev->sdev_gendev); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index f2db7a41cf1..b03aa85108e 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -368,7 +368,7 @@ static DECLARE_TRANSPORT_CLASS(fc_rport_class, * should insulate the loss of a remote port. * The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT. */ -static unsigned int fc_dev_loss_tmo = SCSI_DEVICE_BLOCK_MAX_TIMEOUT; +static unsigned int fc_dev_loss_tmo = 60; /* seconds */ module_param_named(dev_loss_tmo, fc_dev_loss_tmo, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(dev_loss_tmo, @@ -1284,7 +1284,9 @@ EXPORT_SYMBOL(fc_release_transport); * @work: Work to queue for execution. * * Return value: - * 0 on success / != 0 for error + * 1 - work queued for execution + * 0 - work is already queued + * -EINVAL - work queue doesn't exist **/ static int fc_queue_work(struct Scsi_Host *shost, struct work_struct *work) @@ -1434,8 +1436,6 @@ fc_starget_delete(void *data) struct Scsi_Host *shost = rport_to_shost(rport); unsigned long flags; - scsi_target_unblock(&rport->dev); - spin_lock_irqsave(shost->host_lock, flags); if (rport->flags & FC_RPORT_DEVLOSS_PENDING) { spin_unlock_irqrestore(shost->host_lock, flags); @@ -1476,7 +1476,8 @@ fc_rport_final_delete(void *data) transport_remove_device(dev); device_del(dev); transport_destroy_device(dev); - put_device(&shost->shost_gendev); + put_device(&shost->shost_gendev); /* for fc_host->rport list */ + put_device(dev); /* for self-reference */ } @@ -1537,13 +1538,13 @@ fc_rport_create(struct Scsi_Host *shost, int channel, else rport->scsi_target_id = -1; list_add_tail(&rport->peers, &fc_host->rports); - get_device(&shost->shost_gendev); + get_device(&shost->shost_gendev); /* for fc_host->rport list */ spin_unlock_irqrestore(shost->host_lock, flags); dev = &rport->dev; - device_initialize(dev); - dev->parent = get_device(&shost->shost_gendev); + device_initialize(dev); /* takes self reference */ + dev->parent = get_device(&shost->shost_gendev); /* parent reference */ dev->release = fc_rport_dev_release; sprintf(dev->bus_id, "rport-%d:%d-%d", shost->host_no, channel, rport->number); @@ -1567,10 +1568,9 @@ fc_rport_create(struct Scsi_Host *shost, int channel, delete_rport: transport_destroy_device(dev); - put_device(dev->parent); spin_lock_irqsave(shost->host_lock, flags); list_del(&rport->peers); - put_device(&shost->shost_gendev); + put_device(&shost->shost_gendev); /* for fc_host->rport list */ spin_unlock_irqrestore(shost->host_lock, flags); put_device(dev->parent); kfree(rport); @@ -1707,6 +1707,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, spin_unlock_irqrestore(shost->host_lock, flags); + scsi_target_unblock(&rport->dev); + return rport; } } @@ -1762,9 +1764,10 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, /* initiate a scan of the target */ rport->flags |= FC_RPORT_SCAN_PENDING; scsi_queue_work(shost, &rport->scan_work); - } - - spin_unlock_irqrestore(shost->host_lock, flags); + spin_unlock_irqrestore(shost->host_lock, flags); + scsi_target_unblock(&rport->dev); + } else + spin_unlock_irqrestore(shost->host_lock, flags); return rport; } @@ -1938,6 +1941,7 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) rport->flags |= FC_RPORT_SCAN_PENDING; scsi_queue_work(shost, &rport->scan_work); spin_unlock_irqrestore(shost->host_lock, flags); + scsi_target_unblock(&rport->dev); } } EXPORT_SYMBOL(fc_remote_port_rolechg); @@ -1970,8 +1974,9 @@ fc_timeout_deleted_rport(void *data) dev_printk(KERN_ERR, &rport->dev, "blocked FC remote port time out: no longer" " a FCP target, removing starget\n"); - fc_queue_work(shost, &rport->stgt_delete_work); spin_unlock_irqrestore(shost->host_lock, flags); + scsi_target_unblock(&rport->dev); + fc_queue_work(shost, &rport->stgt_delete_work); return; } @@ -2035,17 +2040,15 @@ fc_timeout_deleted_rport(void *data) * went away and didn't come back - we'll remove * all attached scsi devices. */ - fc_queue_work(shost, &rport->stgt_delete_work); - spin_unlock_irqrestore(shost->host_lock, flags); + + scsi_target_unblock(&rport->dev); + fc_queue_work(shost, &rport->stgt_delete_work); } /** * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. * - * Will unblock the target (in case it went away and has now come back), - * then invoke a scan. - * * @data: remote port to be scanned. **/ static void @@ -2057,7 +2060,6 @@ fc_scsi_scan_rport(void *data) if ((rport->port_state == FC_PORTSTATE_ONLINE) && (rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { - scsi_target_unblock(&rport->dev); scsi_scan_target(&rport->dev, rport->channel, rport->scsi_target_id, SCAN_WILD_CARD, 1); } diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 5569fdcfd62..2ecd1418857 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -34,6 +34,7 @@ #define ISCSI_SESSION_ATTRS 11 #define ISCSI_CONN_ATTRS 11 #define ISCSI_HOST_ATTRS 0 +#define ISCSI_TRANSPORT_VERSION "1.1-646" struct iscsi_internal { int daemon_pid; @@ -228,14 +229,11 @@ static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid) static void iscsi_session_release(struct device *dev) { struct iscsi_cls_session *session = iscsi_dev_to_session(dev); - struct iscsi_transport *transport = session->transport; struct Scsi_Host *shost; shost = iscsi_session_to_shost(session); scsi_host_put(shost); - kfree(session->targetname); kfree(session); - module_put(transport->owner); } static int iscsi_is_session_dev(const struct device *dev) @@ -251,10 +249,9 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, mutex_lock(&ihost->mutex); list_for_each_entry(session, &ihost->sessions, host_list) { - if ((channel == SCAN_WILD_CARD || - channel == session->channel) && + if ((channel == SCAN_WILD_CARD || channel == 0) && (id == SCAN_WILD_CARD || id == session->target_id)) - scsi_scan_target(&session->dev, session->channel, + scsi_scan_target(&session->dev, 0, session->target_id, lun, 1); } mutex_unlock(&ihost->mutex); @@ -291,80 +288,92 @@ void iscsi_block_session(struct iscsi_cls_session *session) } EXPORT_SYMBOL_GPL(iscsi_block_session); -/** - * iscsi_create_session - create iscsi class session - * @shost: scsi host - * @transport: iscsi transport - * - * This can be called from a LLD or iscsi_transport. - **/ struct iscsi_cls_session * -iscsi_create_session(struct Scsi_Host *shost, - struct iscsi_transport *transport, int channel) +iscsi_alloc_session(struct Scsi_Host *shost, + struct iscsi_transport *transport) { - struct iscsi_host *ihost; struct iscsi_cls_session *session; - int err; - - if (!try_module_get(transport->owner)) - return NULL; session = kzalloc(sizeof(*session) + transport->sessiondata_size, GFP_KERNEL); if (!session) - goto module_put; + return NULL; + session->transport = transport; session->recovery_tmo = 120; INIT_WORK(&session->recovery_work, session_recovery_timedout, session); INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); + /* this is released in the dev's release function */ + scsi_host_get(shost); + session->dev.parent = &shost->shost_gendev; + session->dev.release = iscsi_session_release; + device_initialize(&session->dev); if (transport->sessiondata_size) session->dd_data = &session[1]; + return session; +} +EXPORT_SYMBOL_GPL(iscsi_alloc_session); - /* this is released in the dev's release function */ - scsi_host_get(shost); - ihost = shost->shost_data; +int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) +{ + struct Scsi_Host *shost = iscsi_session_to_shost(session); + struct iscsi_host *ihost; + int err; + ihost = shost->shost_data; session->sid = iscsi_session_nr++; - session->channel = channel; - session->target_id = ihost->next_target_id++; + session->target_id = target_id; snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", session->sid); - session->dev.parent = &shost->shost_gendev; - session->dev.release = iscsi_session_release; - err = device_register(&session->dev); + err = device_add(&session->dev); if (err) { dev_printk(KERN_ERR, &session->dev, "iscsi: could not " "register session's dev\n"); - goto free_session; + goto release_host; } transport_register_device(&session->dev); mutex_lock(&ihost->mutex); list_add(&session->host_list, &ihost->sessions); mutex_unlock(&ihost->mutex); + return 0; - return session; - -free_session: - kfree(session); -module_put: - module_put(transport->owner); - return NULL; +release_host: + scsi_host_put(shost); + return err; } - -EXPORT_SYMBOL_GPL(iscsi_create_session); +EXPORT_SYMBOL_GPL(iscsi_add_session); /** - * iscsi_destroy_session - destroy iscsi session - * @session: iscsi_session + * iscsi_create_session - create iscsi class session + * @shost: scsi host + * @transport: iscsi transport * - * Can be called by a LLD or iscsi_transport. There must not be - * any running connections. + * This can be called from a LLD or iscsi_transport. **/ -int iscsi_destroy_session(struct iscsi_cls_session *session) +struct iscsi_cls_session * +iscsi_create_session(struct Scsi_Host *shost, + struct iscsi_transport *transport, + unsigned int target_id) +{ + struct iscsi_cls_session *session; + + session = iscsi_alloc_session(shost, transport); + if (!session) + return NULL; + + if (iscsi_add_session(session, target_id)) { + iscsi_free_session(session); + return NULL; + } + return session; +} +EXPORT_SYMBOL_GPL(iscsi_create_session); + +void iscsi_remove_session(struct iscsi_cls_session *session) { struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_host *ihost = shost->shost_data; @@ -376,19 +385,88 @@ int iscsi_destroy_session(struct iscsi_cls_session *session) list_del(&session->host_list); mutex_unlock(&ihost->mutex); + scsi_remove_target(&session->dev); + transport_unregister_device(&session->dev); - device_unregister(&session->dev); - return 0; + device_del(&session->dev); +} +EXPORT_SYMBOL_GPL(iscsi_remove_session); + +void iscsi_free_session(struct iscsi_cls_session *session) +{ + put_device(&session->dev); } +EXPORT_SYMBOL_GPL(iscsi_free_session); + +/** + * iscsi_destroy_session - destroy iscsi session + * @session: iscsi_session + * + * Can be called by a LLD or iscsi_transport. There must not be + * any running connections. + **/ +int iscsi_destroy_session(struct iscsi_cls_session *session) +{ + iscsi_remove_session(session); + iscsi_free_session(session); + return 0; +} EXPORT_SYMBOL_GPL(iscsi_destroy_session); +static void mempool_zone_destroy(struct mempool_zone *zp) +{ + mempool_destroy(zp->pool); + kfree(zp); +} + +static void* +mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data) +{ + struct mempool_zone *zone = pool_data; + + return alloc_skb(zone->size, gfp_mask); +} + +static void +mempool_zone_free_skb(void *element, void *pool_data) +{ + kfree_skb(element); +} + +static struct mempool_zone * +mempool_zone_init(unsigned max, unsigned size, unsigned hiwat) +{ + struct mempool_zone *zp; + + zp = kzalloc(sizeof(*zp), GFP_KERNEL); + if (!zp) + return NULL; + + zp->size = size; + zp->hiwat = hiwat; + INIT_LIST_HEAD(&zp->freequeue); + spin_lock_init(&zp->freelock); + atomic_set(&zp->allocated, 0); + + zp->pool = mempool_create(max, mempool_zone_alloc_skb, + mempool_zone_free_skb, zp); + if (!zp->pool) { + kfree(zp); + return NULL; + } + + return zp; +} + static void iscsi_conn_release(struct device *dev) { struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); struct device *parent = conn->dev.parent; - kfree(conn->persistent_address); + mempool_zone_destroy(conn->z_pdu); + mempool_zone_destroy(conn->z_error); + kfree(conn); put_device(parent); } @@ -398,6 +476,31 @@ static int iscsi_is_conn_dev(const struct device *dev) return dev->release == iscsi_conn_release; } +static int iscsi_create_event_pools(struct iscsi_cls_conn *conn) +{ + conn->z_pdu = mempool_zone_init(Z_MAX_PDU, + NLMSG_SPACE(sizeof(struct iscsi_uevent) + + sizeof(struct iscsi_hdr) + + DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH), + Z_HIWAT_PDU); + if (!conn->z_pdu) { + dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " + "pdu zone for new conn\n"); + return -ENOMEM; + } + + conn->z_error = mempool_zone_init(Z_MAX_ERROR, + NLMSG_SPACE(sizeof(struct iscsi_uevent)), + Z_HIWAT_ERROR); + if (!conn->z_error) { + dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " + "error zone for new conn\n"); + mempool_zone_destroy(conn->z_pdu); + return -ENOMEM; + } + return 0; +} + /** * iscsi_create_conn - create iscsi class connection * @session: iscsi cls session @@ -430,9 +533,12 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) conn->transport = transport; conn->cid = cid; + if (iscsi_create_event_pools(conn)) + goto free_conn; + /* this is released in the dev's release function */ if (!get_device(&session->dev)) - goto free_conn; + goto free_conn_pools; snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u", session->sid, cid); @@ -449,6 +555,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) release_parent_ref: put_device(&session->dev); +free_conn_pools: + free_conn: kfree(conn); return NULL; @@ -496,20 +604,6 @@ static inline struct list_head *skb_to_lh(struct sk_buff *skb) return (struct list_head *)&skb->cb; } -static void* -mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data) -{ - struct mempool_zone *zone = pool_data; - - return alloc_skb(zone->size, gfp_mask); -} - -static void -mempool_zone_free_skb(void *element, void *pool_data) -{ - kfree_skb(element); -} - static void mempool_zone_complete(struct mempool_zone *zone) { @@ -529,37 +623,6 @@ mempool_zone_complete(struct mempool_zone *zone) spin_unlock_irqrestore(&zone->freelock, flags); } -static struct mempool_zone * -mempool_zone_init(unsigned max, unsigned size, unsigned hiwat) -{ - struct mempool_zone *zp; - - zp = kzalloc(sizeof(*zp), GFP_KERNEL); - if (!zp) - return NULL; - - zp->size = size; - zp->hiwat = hiwat; - INIT_LIST_HEAD(&zp->freequeue); - spin_lock_init(&zp->freelock); - atomic_set(&zp->allocated, 0); - - zp->pool = mempool_create(max, mempool_zone_alloc_skb, - mempool_zone_free_skb, zp); - if (!zp->pool) { - kfree(zp); - return NULL; - } - - return zp; -} - -static void mempool_zone_destroy(struct mempool_zone *zp) -{ - mempool_destroy(zp->pool); - kfree(zp); -} - static struct sk_buff* mempool_zone_get_skb(struct mempool_zone *zone) { @@ -572,6 +635,27 @@ mempool_zone_get_skb(struct mempool_zone *zone) } static int +iscsi_broadcast_skb(struct mempool_zone *zone, struct sk_buff *skb, gfp_t gfp) +{ + unsigned long flags; + int rc; + + skb_get(skb); + rc = netlink_broadcast(nls, skb, 0, 1, gfp); + if (rc < 0) { + mempool_free(skb, zone->pool); + printk(KERN_ERR "iscsi: can not broadcast skb (%d)\n", rc); + return rc; + } + + spin_lock_irqsave(&zone->freelock, flags); + INIT_LIST_HEAD(skb_to_lh(skb)); + list_add(skb_to_lh(skb), &zone->freequeue); + spin_unlock_irqrestore(&zone->freelock, flags); + return 0; +} + +static int iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb, int pid) { unsigned long flags; @@ -666,7 +750,7 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) ev->r.connerror.cid = conn->cid; ev->r.connerror.sid = iscsi_conn_get_sid(conn); - iscsi_unicast_skb(conn->z_error, skb, priv->daemon_pid); + iscsi_broadcast_skb(conn->z_error, skb, GFP_ATOMIC); dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", error); @@ -767,6 +851,131 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) return err; } +/** + * iscsi_if_destroy_session_done - send session destr. completion event + * @conn: last connection for session + * + * This is called by HW iscsi LLDs to notify userpsace that its HW has + * removed a session. + **/ +int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn) +{ + struct iscsi_internal *priv; + struct iscsi_cls_session *session; + struct Scsi_Host *shost; + struct iscsi_uevent *ev; + struct sk_buff *skb; + struct nlmsghdr *nlh; + unsigned long flags; + int rc, len = NLMSG_SPACE(sizeof(*ev)); + + priv = iscsi_if_transport_lookup(conn->transport); + if (!priv) + return -EINVAL; + + session = iscsi_dev_to_session(conn->dev.parent); + shost = iscsi_session_to_shost(session); + + mempool_zone_complete(conn->z_pdu); + + skb = mempool_zone_get_skb(conn->z_pdu); + if (!skb) { + dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " + "session creation event\n"); + return -ENOMEM; + } + + nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); + ev = NLMSG_DATA(nlh); + ev->transport_handle = iscsi_handle(conn->transport); + ev->type = ISCSI_KEVENT_DESTROY_SESSION; + ev->r.d_session.host_no = shost->host_no; + ev->r.d_session.sid = session->sid; + + /* + * this will occur if the daemon is not up, so we just warn + * the user and when the daemon is restarted it will handle it + */ + rc = iscsi_broadcast_skb(conn->z_pdu, skb, GFP_KERNEL); + if (rc < 0) + dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " + "session destruction event. Check iscsi daemon\n"); + + spin_lock_irqsave(&sesslock, flags); + list_del(&session->sess_list); + spin_unlock_irqrestore(&sesslock, flags); + + spin_lock_irqsave(&connlock, flags); + conn->active = 0; + list_del(&conn->conn_list); + spin_unlock_irqrestore(&connlock, flags); + + return rc; +} +EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done); + +/** + * iscsi_if_create_session_done - send session creation completion event + * @conn: leading connection for session + * + * This is called by HW iscsi LLDs to notify userpsace that its HW has + * created a session or a existing session is back in the logged in state. + **/ +int iscsi_if_create_session_done(struct iscsi_cls_conn *conn) +{ + struct iscsi_internal *priv; + struct iscsi_cls_session *session; + struct Scsi_Host *shost; + struct iscsi_uevent *ev; + struct sk_buff *skb; + struct nlmsghdr *nlh; + unsigned long flags; + int rc, len = NLMSG_SPACE(sizeof(*ev)); + + priv = iscsi_if_transport_lookup(conn->transport); + if (!priv) + return -EINVAL; + + session = iscsi_dev_to_session(conn->dev.parent); + shost = iscsi_session_to_shost(session); + + mempool_zone_complete(conn->z_pdu); + + skb = mempool_zone_get_skb(conn->z_pdu); + if (!skb) { + dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " + "session creation event\n"); + return -ENOMEM; + } + + nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); + ev = NLMSG_DATA(nlh); + ev->transport_handle = iscsi_handle(conn->transport); + ev->type = ISCSI_UEVENT_CREATE_SESSION; + ev->r.c_session_ret.host_no = shost->host_no; + ev->r.c_session_ret.sid = session->sid; + + /* + * this will occur if the daemon is not up, so we just warn + * the user and when the daemon is restarted it will handle it + */ + rc = iscsi_broadcast_skb(conn->z_pdu, skb, GFP_KERNEL); + if (rc < 0) + dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " + "session creation event. Check iscsi daemon\n"); + + spin_lock_irqsave(&sesslock, flags); + list_add(&session->sess_list, &sesslist); + spin_unlock_irqrestore(&sesslock, flags); + + spin_lock_irqsave(&connlock, flags); + list_add(&conn->conn_list, &connlist); + conn->active = 1; + spin_unlock_irqrestore(&connlock, flags); + return rc; +} +EXPORT_SYMBOL_GPL(iscsi_if_create_session_done); + static int iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) { @@ -812,26 +1021,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) return -ENOMEM; } - conn->z_pdu = mempool_zone_init(Z_MAX_PDU, - NLMSG_SPACE(sizeof(struct iscsi_uevent) + - sizeof(struct iscsi_hdr) + - DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH), - Z_HIWAT_PDU); - if (!conn->z_pdu) { - dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " - "pdu zone for new conn\n"); - goto destroy_conn; - } - - conn->z_error = mempool_zone_init(Z_MAX_ERROR, - NLMSG_SPACE(sizeof(struct iscsi_uevent)), - Z_HIWAT_ERROR); - if (!conn->z_error) { - dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " - "error zone for new conn\n"); - goto free_pdu_pool; - } - ev->r.c_conn_ret.sid = session->sid; ev->r.c_conn_ret.cid = conn->cid; @@ -841,13 +1030,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) spin_unlock_irqrestore(&connlock, flags); return 0; - -free_pdu_pool: - mempool_zone_destroy(conn->z_pdu); -destroy_conn: - if (transport->destroy_conn) - transport->destroy_conn(conn->dd_data); - return -ENOMEM; } static int @@ -855,7 +1037,6 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev { unsigned long flags; struct iscsi_cls_conn *conn; - struct mempool_zone *z_error, *z_pdu; conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid); if (!conn) @@ -865,35 +1046,18 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev list_del(&conn->conn_list); spin_unlock_irqrestore(&connlock, flags); - z_pdu = conn->z_pdu; - z_error = conn->z_error; - if (transport->destroy_conn) transport->destroy_conn(conn); - - mempool_zone_destroy(z_pdu); - mempool_zone_destroy(z_error); - return 0; } -static void -iscsi_copy_param(struct iscsi_uevent *ev, uint32_t *value, char *data) -{ - if (ev->u.set_param.len != sizeof(uint32_t)) - BUG(); - memcpy(value, data, min_t(uint32_t, sizeof(uint32_t), - ev->u.set_param.len)); -} - static int iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) { char *data = (char*)ev + sizeof(*ev); struct iscsi_cls_conn *conn; struct iscsi_cls_session *session; - int err = 0; - uint32_t value = 0; + int err = 0, value = 0; session = iscsi_session_lookup(ev->u.set_param.sid); conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid); @@ -902,42 +1066,13 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) switch (ev->u.set_param.param) { case ISCSI_PARAM_SESS_RECOVERY_TMO: - iscsi_copy_param(ev, &value, data); + sscanf(data, "%d", &value); if (value != 0) session->recovery_tmo = value; break; - case ISCSI_PARAM_TARGET_NAME: - /* this should not change between logins */ - if (session->targetname) - return 0; - - session->targetname = kstrdup(data, GFP_KERNEL); - if (!session->targetname) - return -ENOMEM; - break; - case ISCSI_PARAM_TPGT: - iscsi_copy_param(ev, &value, data); - session->tpgt = value; - break; - case ISCSI_PARAM_PERSISTENT_PORT: - iscsi_copy_param(ev, &value, data); - conn->persistent_port = value; - break; - case ISCSI_PARAM_PERSISTENT_ADDRESS: - /* - * this is the address returned in discovery so it should - * not change between logins. - */ - if (conn->persistent_address) - return 0; - - conn->persistent_address = kstrdup(data, GFP_KERNEL); - if (!conn->persistent_address) - return -ENOMEM; - break; default: - iscsi_copy_param(ev, &value, data); - err = transport->set_param(conn, ev->u.set_param.param, value); + err = transport->set_param(conn, ev->u.set_param.param, + data, ev->u.set_param.len); } return err; @@ -978,6 +1113,21 @@ iscsi_if_transport_ep(struct iscsi_transport *transport, } static int +iscsi_tgt_dscvr(struct iscsi_transport *transport, + struct iscsi_uevent *ev) +{ + struct sockaddr *dst_addr; + + if (!transport->tgt_dscvr) + return -EINVAL; + + dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); + return transport->tgt_dscvr(ev->u.tgt_dscvr.type, + ev->u.tgt_dscvr.host_no, + ev->u.tgt_dscvr.enable, dst_addr); +} + +static int iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { int err = 0; @@ -1065,6 +1215,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type); break; + case ISCSI_UEVENT_TGT_DSCVR: + err = iscsi_tgt_dscvr(transport, ev); + break; default: err = -EINVAL; break; @@ -1147,49 +1300,31 @@ struct class_device_attribute class_device_attr_##_prefix##_##_name = \ /* * iSCSI connection attrs */ -#define iscsi_conn_int_attr_show(param, format) \ -static ssize_t \ -show_conn_int_param_##param(struct class_device *cdev, char *buf) \ -{ \ - uint32_t value = 0; \ - struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ - struct iscsi_transport *t = conn->transport; \ - \ - t->get_conn_param(conn, param, &value); \ - return snprintf(buf, 20, format"\n", value); \ -} - -#define iscsi_conn_int_attr(field, param, format) \ - iscsi_conn_int_attr_show(param, format) \ -static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_int_param_##param, \ - NULL); - -iscsi_conn_int_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH, "%u"); -iscsi_conn_int_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH, "%u"); -iscsi_conn_int_attr(header_digest, ISCSI_PARAM_HDRDGST_EN, "%d"); -iscsi_conn_int_attr(data_digest, ISCSI_PARAM_DATADGST_EN, "%d"); -iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d"); -iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d"); -iscsi_conn_int_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT, "%d"); -iscsi_conn_int_attr(port, ISCSI_PARAM_CONN_PORT, "%d"); -iscsi_conn_int_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN, "%u"); - -#define iscsi_conn_str_attr_show(param) \ +#define iscsi_conn_attr_show(param) \ static ssize_t \ -show_conn_str_param_##param(struct class_device *cdev, char *buf) \ +show_conn_param_##param(struct class_device *cdev, char *buf) \ { \ struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ struct iscsi_transport *t = conn->transport; \ - return t->get_conn_str_param(conn, param, buf); \ + return t->get_conn_param(conn, param, buf); \ } -#define iscsi_conn_str_attr(field, param) \ - iscsi_conn_str_attr_show(param) \ -static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_str_param_##param, \ +#define iscsi_conn_attr(field, param) \ + iscsi_conn_attr_show(param) \ +static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_param_##param, \ NULL); -iscsi_conn_str_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); -iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS); +iscsi_conn_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH); +iscsi_conn_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH); +iscsi_conn_attr(header_digest, ISCSI_PARAM_HDRDGST_EN); +iscsi_conn_attr(data_digest, ISCSI_PARAM_DATADGST_EN); +iscsi_conn_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN); +iscsi_conn_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN); +iscsi_conn_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT); +iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT); +iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN); +iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); +iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS); #define iscsi_cdev_to_session(_cdev) \ iscsi_dev_to_session(_cdev->dev) @@ -1197,61 +1332,36 @@ iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS); /* * iSCSI session attrs */ -#define iscsi_session_int_attr_show(param, format) \ -static ssize_t \ -show_session_int_param_##param(struct class_device *cdev, char *buf) \ -{ \ - uint32_t value = 0; \ - struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ - struct iscsi_transport *t = session->transport; \ - \ - t->get_session_param(session, param, &value); \ - return snprintf(buf, 20, format"\n", value); \ -} - -#define iscsi_session_int_attr(field, param, format) \ - iscsi_session_int_attr_show(param, format) \ -static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_int_param_##param, \ - NULL); - -iscsi_session_int_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, "%d"); -iscsi_session_int_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, "%hu"); -iscsi_session_int_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, "%d"); -iscsi_session_int_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, "%u"); -iscsi_session_int_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, "%u"); -iscsi_session_int_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, "%d"); -iscsi_session_int_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, "%d"); -iscsi_session_int_attr(erl, ISCSI_PARAM_ERL, "%d"); -iscsi_session_int_attr(tpgt, ISCSI_PARAM_TPGT, "%d"); - -#define iscsi_session_str_attr_show(param) \ +#define iscsi_session_attr_show(param) \ static ssize_t \ -show_session_str_param_##param(struct class_device *cdev, char *buf) \ +show_session_param_##param(struct class_device *cdev, char *buf) \ { \ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ struct iscsi_transport *t = session->transport; \ - return t->get_session_str_param(session, param, buf); \ + return t->get_session_param(session, param, buf); \ } -#define iscsi_session_str_attr(field, param) \ - iscsi_session_str_attr_show(param) \ -static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_str_param_##param, \ +#define iscsi_session_attr(field, param) \ + iscsi_session_attr_show(param) \ +static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \ NULL); -iscsi_session_str_attr(targetname, ISCSI_PARAM_TARGET_NAME); +iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME); +iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN); +iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T); +iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN); +iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST); +iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST); +iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN); +iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN); +iscsi_session_attr(erl, ISCSI_PARAM_ERL); +iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT); -/* - * Private session and conn attrs. userspace uses several iscsi values - * to identify each session between reboots. Some of these values may not - * be present in the iscsi_transport/LLD driver becuase userspace handles - * login (and failback for login redirect) so for these type of drivers - * the class manages the attrs and values for the iscsi_transport/LLD - */ #define iscsi_priv_session_attr_show(field, format) \ static ssize_t \ -show_priv_session_##field(struct class_device *cdev, char *buf) \ +show_priv_session_##field(struct class_device *cdev, char *buf) \ { \ - struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ + struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\ return sprintf(buf, format"\n", session->field); \ } @@ -1259,31 +1369,15 @@ show_priv_session_##field(struct class_device *cdev, char *buf) \ iscsi_priv_session_attr_show(field, format) \ static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \ NULL) -iscsi_priv_session_attr(targetname, "%s"); -iscsi_priv_session_attr(tpgt, "%d"); iscsi_priv_session_attr(recovery_tmo, "%d"); -#define iscsi_priv_conn_attr_show(field, format) \ -static ssize_t \ -show_priv_conn_##field(struct class_device *cdev, char *buf) \ -{ \ - struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ - return sprintf(buf, format"\n", conn->field); \ -} - -#define iscsi_priv_conn_attr(field, format) \ - iscsi_priv_conn_attr_show(field, format) \ -static ISCSI_CLASS_ATTR(priv_conn, field, S_IRUGO, show_priv_conn_##field, \ - NULL) -iscsi_priv_conn_attr(persistent_address, "%s"); -iscsi_priv_conn_attr(persistent_port, "%d"); - #define SETUP_PRIV_SESSION_RD_ATTR(field) \ do { \ priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \ count++; \ } while (0) + #define SETUP_SESSION_RD_ATTR(field, param_flag) \ do { \ if (tt->param_mask & param_flag) { \ @@ -1292,12 +1386,6 @@ do { \ } \ } while (0) -#define SETUP_PRIV_CONN_RD_ATTR(field) \ -do { \ - priv->conn_attrs[count] = &class_device_attr_priv_conn_##field; \ - count++; \ -} while (0) - #define SETUP_CONN_RD_ATTR(field, param_flag) \ do { \ if (tt->param_mask & param_flag) { \ @@ -1388,6 +1476,7 @@ iscsi_register_transport(struct iscsi_transport *tt) if (!priv) return NULL; INIT_LIST_HEAD(&priv->list); + priv->daemon_pid = -1; priv->iscsi_transport = tt; priv->t.user_scan = iscsi_user_scan; @@ -1424,16 +1513,8 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS); SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT); SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN); - - if (tt->param_mask & ISCSI_PERSISTENT_ADDRESS) - SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); - else - SETUP_PRIV_CONN_RD_ATTR(persistent_address); - - if (tt->param_mask & ISCSI_PERSISTENT_PORT) - SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT); - else - SETUP_PRIV_CONN_RD_ATTR(persistent_port); + SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); + SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT); BUG_ON(count > ISCSI_CONN_ATTRS); priv->conn_attrs[count] = NULL; @@ -1453,18 +1534,10 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN); SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN); SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL); + SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME); + SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT); SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); - if (tt->param_mask & ISCSI_TARGET_NAME) - SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME); - else - SETUP_PRIV_SESSION_RD_ATTR(targetname); - - if (tt->param_mask & ISCSI_TPGT) - SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT); - else - SETUP_PRIV_SESSION_RD_ATTR(tpgt); - BUG_ON(count > ISCSI_SESSION_ATTRS); priv->session_attrs[count] = NULL; @@ -1541,6 +1614,9 @@ static __init int iscsi_transport_init(void) { int err; + printk(KERN_INFO "Loading iSCSI transport class v%s.", + ISCSI_TRANSPORT_VERSION); + err = class_register(&iscsi_transport_class); if (err) return err; @@ -1606,3 +1682,4 @@ MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, " "Alex Aizman <itn780@yahoo.com>"); MODULE_DESCRIPTION("iSCSI Transport Interface"); MODULE_LICENSE("GPL"); +MODULE_VERSION(ISCSI_TRANSPORT_VERSION); diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 1fe6b2d0185..5a625c3fdda 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -41,6 +41,7 @@ struct sas_host_attrs { struct mutex lock; u32 next_target_id; u32 next_expander_id; + int next_port_id; }; #define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) @@ -146,6 +147,7 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev, mutex_init(&sas_host->lock); sas_host->next_target_id = 0; sas_host->next_expander_id = 0; + sas_host->next_port_id = 0; return 0; } @@ -174,12 +176,29 @@ static int sas_host_match(struct attribute_container *cont, static int do_sas_phy_delete(struct device *dev, void *data) { - if (scsi_is_sas_phy(dev)) + int pass = (int)(unsigned long)data; + + if (pass == 0 && scsi_is_sas_port(dev)) + sas_port_delete(dev_to_sas_port(dev)); + else if (pass == 1 && scsi_is_sas_phy(dev)) sas_phy_delete(dev_to_phy(dev)); return 0; } /** + * sas_remove_children -- tear down a devices SAS data structures + * @dev: device belonging to the sas object + * + * Removes all SAS PHYs and remote PHYs for a given object + */ +void sas_remove_children(struct device *dev) +{ + device_for_each_child(dev, (void *)0, do_sas_phy_delete); + device_for_each_child(dev, (void *)1, do_sas_phy_delete); +} +EXPORT_SYMBOL(sas_remove_children); + +/** * sas_remove_host -- tear down a Scsi_Host's SAS data structures * @shost: Scsi Host that is torn down * @@ -188,13 +207,13 @@ static int do_sas_phy_delete(struct device *dev, void *data) */ void sas_remove_host(struct Scsi_Host *shost) { - device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete); + sas_remove_children(&shost->shost_gendev); } EXPORT_SYMBOL(sas_remove_host); /* - * SAS Port attributes + * SAS Phy attributes */ #define sas_phy_show_simple(field, name, format_string, cast) \ @@ -310,7 +329,7 @@ sas_phy_protocol_attr(identify.target_port_protocols, sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", unsigned long long); sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); -sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8); +//sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int); sas_phy_linkspeed_attr(negotiated_linkrate); sas_phy_linkspeed_attr(minimum_linkrate_hw); sas_phy_linkspeed_attr(minimum_linkrate); @@ -378,9 +397,10 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number) device_initialize(&phy->dev); phy->dev.parent = get_device(parent); phy->dev.release = sas_phy_release; + INIT_LIST_HEAD(&phy->port_siblings); if (scsi_is_sas_expander_device(parent)) { struct sas_rphy *rphy = dev_to_rphy(parent); - sprintf(phy->dev.bus_id, "phy-%d-%d:%d", shost->host_no, + sprintf(phy->dev.bus_id, "phy-%d:%d:%d", shost->host_no, rphy->scsi_target_id, number); } else sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number); @@ -440,8 +460,8 @@ sas_phy_delete(struct sas_phy *phy) { struct device *dev = &phy->dev; - if (phy->rphy) - sas_rphy_delete(phy->rphy); + /* this happens if the phy is still part of a port when deleted */ + BUG_ON(!list_empty(&phy->port_siblings)); transport_remove_device(dev); device_del(dev); @@ -464,6 +484,310 @@ int scsi_is_sas_phy(const struct device *dev) EXPORT_SYMBOL(scsi_is_sas_phy); /* + * SAS Port attributes + */ +#define sas_port_show_simple(field, name, format_string, cast) \ +static ssize_t \ +show_sas_port_##name(struct class_device *cdev, char *buf) \ +{ \ + struct sas_port *port = transport_class_to_sas_port(cdev); \ + \ + return snprintf(buf, 20, format_string, cast port->field); \ +} + +#define sas_port_simple_attr(field, name, format_string, type) \ + sas_port_show_simple(field, name, format_string, (type)) \ +static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL) + +sas_port_simple_attr(num_phys, num_phys, "%d\n", int); + +static DECLARE_TRANSPORT_CLASS(sas_port_class, + "sas_port", NULL, NULL, NULL); + +static int sas_port_match(struct attribute_container *cont, struct device *dev) +{ + struct Scsi_Host *shost; + struct sas_internal *i; + + if (!scsi_is_sas_port(dev)) + return 0; + shost = dev_to_shost(dev->parent); + + if (!shost->transportt) + return 0; + if (shost->transportt->host_attrs.ac.class != + &sas_host_class.class) + return 0; + + i = to_sas_internal(shost->transportt); + return &i->port_attr_cont.ac == cont; +} + + +static void sas_port_release(struct device *dev) +{ + struct sas_port *port = dev_to_sas_port(dev); + + BUG_ON(!list_empty(&port->phy_list)); + + put_device(dev->parent); + kfree(port); +} + +static void sas_port_create_link(struct sas_port *port, + struct sas_phy *phy) +{ + sysfs_create_link(&port->dev.kobj, &phy->dev.kobj, phy->dev.bus_id); + sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port"); +} + +static void sas_port_delete_link(struct sas_port *port, + struct sas_phy *phy) +{ + sysfs_remove_link(&port->dev.kobj, phy->dev.bus_id); + sysfs_remove_link(&phy->dev.kobj, "port"); +} + +/** sas_port_alloc - allocate and initialize a SAS port structure + * + * @parent: parent device + * @port_id: port number + * + * Allocates a SAS port structure. It will be added to the device tree + * below the device specified by @parent which must be either a Scsi_Host + * or a sas_expander_device. + * + * Returns %NULL on error + */ +struct sas_port *sas_port_alloc(struct device *parent, int port_id) +{ + struct Scsi_Host *shost = dev_to_shost(parent); + struct sas_port *port; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return NULL; + + port->port_identifier = port_id; + + device_initialize(&port->dev); + + port->dev.parent = get_device(parent); + port->dev.release = sas_port_release; + + mutex_init(&port->phy_list_mutex); + INIT_LIST_HEAD(&port->phy_list); + + if (scsi_is_sas_expander_device(parent)) { + struct sas_rphy *rphy = dev_to_rphy(parent); + sprintf(port->dev.bus_id, "port-%d:%d:%d", shost->host_no, + rphy->scsi_target_id, port->port_identifier); + } else + sprintf(port->dev.bus_id, "port-%d:%d", shost->host_no, + port->port_identifier); + + transport_setup_device(&port->dev); + + return port; +} +EXPORT_SYMBOL(sas_port_alloc); + +/** sas_port_alloc_num - allocate and initialize a SAS port structure + * + * @parent: parent device + * + * Allocates a SAS port structure and a number to go with it. This + * interface is really for adapters where the port number has no + * meansing, so the sas class should manage them. It will be added to + * the device tree below the device specified by @parent which must be + * either a Scsi_Host or a sas_expander_device. + * + * Returns %NULL on error + */ +struct sas_port *sas_port_alloc_num(struct device *parent) +{ + int index; + struct Scsi_Host *shost = dev_to_shost(parent); + struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); + + /* FIXME: use idr for this eventually */ + mutex_lock(&sas_host->lock); + if (scsi_is_sas_expander_device(parent)) { + struct sas_rphy *rphy = dev_to_rphy(parent); + struct sas_expander_device *exp = rphy_to_expander_device(rphy); + + index = exp->next_port_id++; + } else + index = sas_host->next_port_id++; + mutex_unlock(&sas_host->lock); + return sas_port_alloc(parent, index); +} +EXPORT_SYMBOL(sas_port_alloc_num); + +/** + * sas_port_add - add a SAS port to the device hierarchy + * + * @port: port to be added + * + * publishes a port to the rest of the system + */ +int sas_port_add(struct sas_port *port) +{ + int error; + + /* No phys should be added until this is made visible */ + BUG_ON(!list_empty(&port->phy_list)); + + error = device_add(&port->dev); + + if (error) + return error; + + transport_add_device(&port->dev); + transport_configure_device(&port->dev); + + return 0; +} +EXPORT_SYMBOL(sas_port_add); + +/** + * sas_port_free -- free a SAS PORT + * @port: SAS PORT to free + * + * Frees the specified SAS PORT. + * + * Note: + * This function must only be called on a PORT that has not + * sucessfully been added using sas_port_add(). + */ +void sas_port_free(struct sas_port *port) +{ + transport_destroy_device(&port->dev); + put_device(&port->dev); +} +EXPORT_SYMBOL(sas_port_free); + +/** + * sas_port_delete -- remove SAS PORT + * @port: SAS PORT to remove + * + * Removes the specified SAS PORT. If the SAS PORT has an + * associated phys, unlink them from the port as well. + */ +void sas_port_delete(struct sas_port *port) +{ + struct device *dev = &port->dev; + struct sas_phy *phy, *tmp_phy; + + if (port->rphy) { + sas_rphy_delete(port->rphy); + port->rphy = NULL; + } + + mutex_lock(&port->phy_list_mutex); + list_for_each_entry_safe(phy, tmp_phy, &port->phy_list, + port_siblings) { + sas_port_delete_link(port, phy); + list_del_init(&phy->port_siblings); + } + mutex_unlock(&port->phy_list_mutex); + + if (port->is_backlink) { + struct device *parent = port->dev.parent; + + sysfs_remove_link(&port->dev.kobj, parent->bus_id); + port->is_backlink = 0; + } + + transport_remove_device(dev); + device_del(dev); + transport_destroy_device(dev); + put_device(dev); +} +EXPORT_SYMBOL(sas_port_delete); + +/** + * scsi_is_sas_port -- check if a struct device represents a SAS port + * @dev: device to check + * + * Returns: + * %1 if the device represents a SAS Port, %0 else + */ +int scsi_is_sas_port(const struct device *dev) +{ + return dev->release == sas_port_release; +} +EXPORT_SYMBOL(scsi_is_sas_port); + +/** + * sas_port_add_phy - add another phy to a port to form a wide port + * @port: port to add the phy to + * @phy: phy to add + * + * When a port is initially created, it is empty (has no phys). All + * ports must have at least one phy to operated, and all wide ports + * must have at least two. The current code makes no difference + * between ports and wide ports, but the only object that can be + * connected to a remote device is a port, so ports must be formed on + * all devices with phys if they're connected to anything. + */ +void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy) +{ + mutex_lock(&port->phy_list_mutex); + if (unlikely(!list_empty(&phy->port_siblings))) { + /* make sure we're already on this port */ + struct sas_phy *tmp; + + list_for_each_entry(tmp, &port->phy_list, port_siblings) + if (tmp == phy) + break; + /* If this trips, you added a phy that was already + * part of a different port */ + if (unlikely(tmp != phy)) { + dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n", phy->dev.bus_id); + BUG(); + } + } else { + sas_port_create_link(port, phy); + list_add_tail(&phy->port_siblings, &port->phy_list); + port->num_phys++; + } + mutex_unlock(&port->phy_list_mutex); +} +EXPORT_SYMBOL(sas_port_add_phy); + +/** + * sas_port_delete_phy - remove a phy from a port or wide port + * @port: port to remove the phy from + * @phy: phy to remove + * + * This operation is used for tearing down ports again. It must be + * done to every port or wide port before calling sas_port_delete. + */ +void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy) +{ + mutex_lock(&port->phy_list_mutex); + sas_port_delete_link(port, phy); + list_del_init(&phy->port_siblings); + port->num_phys--; + mutex_unlock(&port->phy_list_mutex); +} +EXPORT_SYMBOL(sas_port_delete_phy); + +void sas_port_mark_backlink(struct sas_port *port) +{ + struct device *parent = port->dev.parent->parent->parent; + + if (port->is_backlink) + return; + port->is_backlink = 1; + sysfs_create_link(&port->dev.kobj, &parent->kobj, + parent->bus_id); + +} +EXPORT_SYMBOL(sas_port_mark_backlink); + +/* * SAS remote PHY attributes. */ @@ -767,7 +1091,7 @@ static void sas_rphy_initialize(struct sas_rphy *rphy) * Returns: * SAS PHY allocated or %NULL if the allocation failed. */ -struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent) +struct sas_rphy *sas_end_device_alloc(struct sas_port *parent) { struct Scsi_Host *shost = dev_to_shost(&parent->dev); struct sas_end_device *rdev; @@ -780,8 +1104,13 @@ struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent) device_initialize(&rdev->rphy.dev); rdev->rphy.dev.parent = get_device(&parent->dev); rdev->rphy.dev.release = sas_end_device_release; - sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d-%d", - shost->host_no, parent->port_identifier, parent->number); + if (scsi_is_sas_expander_device(parent->dev.parent)) { + struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent); + sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d:%d", + shost->host_no, rphy->scsi_target_id, parent->port_identifier); + } else + sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d", + shost->host_no, parent->port_identifier); rdev->rphy.identify.device_type = SAS_END_DEVICE; sas_rphy_initialize(&rdev->rphy); transport_setup_device(&rdev->rphy.dev); @@ -798,7 +1127,7 @@ EXPORT_SYMBOL(sas_end_device_alloc); * Returns: * SAS PHY allocated or %NULL if the allocation failed. */ -struct sas_rphy *sas_expander_alloc(struct sas_phy *parent, +struct sas_rphy *sas_expander_alloc(struct sas_port *parent, enum sas_device_type type) { struct Scsi_Host *shost = dev_to_shost(&parent->dev); @@ -837,7 +1166,7 @@ EXPORT_SYMBOL(sas_expander_alloc); */ int sas_rphy_add(struct sas_rphy *rphy) { - struct sas_phy *parent = dev_to_phy(rphy->dev.parent); + struct sas_port *parent = dev_to_sas_port(rphy->dev.parent); struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); struct sas_identify *identify = &rphy->identify; @@ -865,7 +1194,7 @@ int sas_rphy_add(struct sas_rphy *rphy) if (identify->device_type == SAS_END_DEVICE && rphy->scsi_target_id != -1) { - scsi_scan_target(&rphy->dev, parent->port_identifier, + scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id, ~0, 0); } @@ -910,7 +1239,7 @@ void sas_rphy_delete(struct sas_rphy *rphy) { struct device *dev = &rphy->dev; - struct sas_phy *parent = dev_to_phy(dev->parent); + struct sas_port *parent = dev_to_sas_port(dev->parent); struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); @@ -920,7 +1249,7 @@ sas_rphy_delete(struct sas_rphy *rphy) break; case SAS_EDGE_EXPANDER_DEVICE: case SAS_FANOUT_EXPANDER_DEVICE: - device_for_each_child(dev, NULL, do_sas_phy_delete); + sas_remove_children(dev); break; default: break; @@ -967,15 +1296,13 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel, mutex_lock(&sas_host->lock); list_for_each_entry(rphy, &sas_host->rphy_list, list) { - struct sas_phy *parent = dev_to_phy(rphy->dev.parent); - if (rphy->identify.device_type != SAS_END_DEVICE || rphy->scsi_target_id == -1) continue; - if ((channel == SCAN_WILD_CARD || channel == parent->port_identifier) && + if ((channel == SCAN_WILD_CARD || channel == 0) && (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) { - scsi_scan_target(&rphy->dev, parent->port_identifier, + scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id, lun, 1); } } @@ -1003,16 +1330,19 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel, #define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \ SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func) -#define SETUP_PORT_ATTRIBUTE(field) \ +#define SETUP_PHY_ATTRIBUTE(field) \ SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1) -#define SETUP_OPTIONAL_PORT_ATTRIBUTE(field, func) \ +#define SETUP_PORT_ATTRIBUTE(field) \ + SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1) + +#define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func) \ SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func) -#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \ +#define SETUP_PHY_ATTRIBUTE_WRONLY(field) \ SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1) -#define SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(field, func) \ +#define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \ SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func) #define SETUP_END_DEV_ATTRIBUTE(field) \ @@ -1048,6 +1378,11 @@ sas_attach_transport(struct sas_function_template *ft) i->phy_attr_cont.ac.match = sas_phy_match; transport_container_register(&i->phy_attr_cont); + i->port_attr_cont.ac.class = &sas_port_class.class; + i->port_attr_cont.ac.attrs = &i->port_attrs[0]; + i->port_attr_cont.ac.match = sas_port_match; + transport_container_register(&i->port_attr_cont); + i->rphy_attr_cont.ac.class = &sas_rphy_class.class; i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0]; i->rphy_attr_cont.ac.match = sas_rphy_match; @@ -1066,30 +1401,35 @@ sas_attach_transport(struct sas_function_template *ft) i->f = ft; count = 0; + SETUP_PORT_ATTRIBUTE(num_phys); i->host_attrs[count] = NULL; count = 0; - SETUP_PORT_ATTRIBUTE(initiator_port_protocols); - SETUP_PORT_ATTRIBUTE(target_port_protocols); - SETUP_PORT_ATTRIBUTE(device_type); - SETUP_PORT_ATTRIBUTE(sas_address); - SETUP_PORT_ATTRIBUTE(phy_identifier); - SETUP_PORT_ATTRIBUTE(port_identifier); - SETUP_PORT_ATTRIBUTE(negotiated_linkrate); - SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw); - SETUP_PORT_ATTRIBUTE(minimum_linkrate); - SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw); - SETUP_PORT_ATTRIBUTE(maximum_linkrate); - - SETUP_PORT_ATTRIBUTE(invalid_dword_count); - SETUP_PORT_ATTRIBUTE(running_disparity_error_count); - SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count); - SETUP_PORT_ATTRIBUTE(phy_reset_problem_count); - SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(link_reset, phy_reset); - SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(hard_reset, phy_reset); + SETUP_PHY_ATTRIBUTE(initiator_port_protocols); + SETUP_PHY_ATTRIBUTE(target_port_protocols); + SETUP_PHY_ATTRIBUTE(device_type); + SETUP_PHY_ATTRIBUTE(sas_address); + SETUP_PHY_ATTRIBUTE(phy_identifier); + //SETUP_PHY_ATTRIBUTE(port_identifier); + SETUP_PHY_ATTRIBUTE(negotiated_linkrate); + SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw); + SETUP_PHY_ATTRIBUTE(minimum_linkrate); + SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw); + SETUP_PHY_ATTRIBUTE(maximum_linkrate); + + SETUP_PHY_ATTRIBUTE(invalid_dword_count); + SETUP_PHY_ATTRIBUTE(running_disparity_error_count); + SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count); + SETUP_PHY_ATTRIBUTE(phy_reset_problem_count); + SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset); + SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset); i->phy_attrs[count] = NULL; count = 0; + SETUP_PORT_ATTRIBUTE(num_phys); + i->port_attrs[count] = NULL; + + count = 0; SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols); SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols); SETUP_RPORT_ATTRIBUTE(rphy_device_type); @@ -1131,6 +1471,7 @@ void sas_release_transport(struct scsi_transport_template *t) transport_container_unregister(&i->t.host_attrs); transport_container_unregister(&i->phy_attr_cont); + transport_container_unregister(&i->port_attr_cont); transport_container_unregister(&i->rphy_attr_cont); transport_container_unregister(&i->end_dev_attr_cont); transport_container_unregister(&i->expander_attr_cont); @@ -1149,9 +1490,12 @@ static __init int sas_transport_init(void) error = transport_class_register(&sas_phy_class); if (error) goto out_unregister_transport; - error = transport_class_register(&sas_rphy_class); + error = transport_class_register(&sas_port_class); if (error) goto out_unregister_phy; + error = transport_class_register(&sas_rphy_class); + if (error) + goto out_unregister_port; error = transport_class_register(&sas_end_dev_class); if (error) goto out_unregister_rphy; @@ -1165,6 +1509,8 @@ static __init int sas_transport_init(void) transport_class_unregister(&sas_end_dev_class); out_unregister_rphy: transport_class_unregister(&sas_rphy_class); + out_unregister_port: + transport_class_unregister(&sas_port_class); out_unregister_phy: transport_class_unregister(&sas_phy_class); out_unregister_transport: @@ -1178,6 +1524,7 @@ static void __exit sas_transport_exit(void) { transport_class_unregister(&sas_host_class); transport_class_unregister(&sas_phy_class); + transport_class_unregister(&sas_port_class); transport_class_unregister(&sas_rphy_class); transport_class_unregister(&sas_end_dev_class); transport_class_unregister(&sas_expander_class); diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index b78354fc4b1..cd68a66c7bb 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -57,6 +57,7 @@ EXPORT_SYMBOL(scsi_bios_ptable); int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip) { unsigned char *p; + u64 capacity64 = capacity; /* Suppress gcc warning */ int ret; p = scsi_bios_ptable(bdev); @@ -68,7 +69,7 @@ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip) (unsigned int *)ip + 0, (unsigned int *)ip + 1); kfree(p); - if (ret == -1) { + if (ret == -1 && capacity64 < (1ULL << 32)) { /* pick some standard mapping with at most 1024 cylinders, and at most 62 sectors per track - this works up to 7905 MB */ diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index ea38757d12e..98bd3aab973 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -207,6 +207,23 @@ static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf, return count; } +static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf, + size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(cdev); + struct scsi_device *sdp = sdkp->device; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (sdp->type != TYPE_DISK) + return -EINVAL; + + sdp->allow_restart = simple_strtoul(buf, NULL, 10); + + return count; +} + static ssize_t sd_show_cache_type(struct class_device *cdev, char *buf) { struct scsi_disk *sdkp = to_scsi_disk(cdev); @@ -222,10 +239,19 @@ static ssize_t sd_show_fua(struct class_device *cdev, char *buf) return snprintf(buf, 20, "%u\n", sdkp->DPOFUA); } +static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(cdev); + + return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart); +} + static struct class_device_attribute sd_disk_attrs[] = { __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, sd_store_cache_type), __ATTR(FUA, S_IRUGO, sd_show_fua, NULL), + __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart, + sd_store_allow_restart), __ATTR_NULL, }; @@ -476,8 +502,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) SCpnt->cmnd[4] = (unsigned char) this_count; SCpnt->cmnd[5] = 0; } - SCpnt->request_bufflen = SCpnt->bufflen = - this_count * sdp->sector_size; + SCpnt->request_bufflen = this_count * sdp->sector_size; /* * We shouldn't disconnect in the middle of a sector, so with a dumb @@ -890,11 +915,10 @@ static struct block_device_operations sd_fops = { static void sd_rw_intr(struct scsi_cmnd * SCpnt) { int result = SCpnt->result; - int this_count = SCpnt->request_bufflen; - int good_bytes = (result == 0 ? this_count : 0); - sector_t block_sectors = 1; - u64 first_err_block; - sector_t error_sector; + unsigned int xfer_size = SCpnt->request_bufflen; + unsigned int good_bytes = result ? 0 : xfer_size; + u64 start_lba = SCpnt->request->sector; + u64 bad_lba; struct scsi_sense_hdr sshdr; int sense_valid = 0; int sense_deferred = 0; @@ -905,7 +929,6 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) if (sense_valid) sense_deferred = scsi_sense_is_deferred(&sshdr); } - #ifdef CONFIG_SCSI_LOGGING SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", SCpnt->request->rq_disk->disk_name, result)); @@ -915,89 +938,72 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) sshdr.sense_key, sshdr.asc, sshdr.ascq)); } #endif - /* - Handle MEDIUM ERRORs that indicate partial success. Since this is a - relatively rare error condition, no care is taken to avoid - unnecessary additional work such as memcpy's that could be avoided. - */ - if (driver_byte(result) != 0 && - sense_valid && !sense_deferred) { - switch (sshdr.sense_key) { - case MEDIUM_ERROR: - if (!blk_fs_request(SCpnt->request)) - break; - info_valid = scsi_get_sense_info_fld( - SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE, - &first_err_block); - /* - * May want to warn and skip if following cast results - * in actual truncation (if sector_t < 64 bits) - */ - error_sector = (sector_t)first_err_block; - if (SCpnt->request->bio != NULL) - block_sectors = bio_sectors(SCpnt->request->bio); - switch (SCpnt->device->sector_size) { - case 1024: - error_sector <<= 1; - if (block_sectors < 2) - block_sectors = 2; - break; - case 2048: - error_sector <<= 2; - if (block_sectors < 4) - block_sectors = 4; - break; - case 4096: - error_sector <<=3; - if (block_sectors < 8) - block_sectors = 8; - break; - case 256: - error_sector >>= 1; - break; - default: - break; - } + if (driver_byte(result) != DRIVER_SENSE && + (!sense_valid || sense_deferred)) + goto out; - error_sector &= ~(block_sectors - 1); - good_bytes = (error_sector - SCpnt->request->sector) << 9; - if (good_bytes < 0 || good_bytes >= this_count) - good_bytes = 0; + switch (sshdr.sense_key) { + case HARDWARE_ERROR: + case MEDIUM_ERROR: + if (!blk_fs_request(SCpnt->request)) + goto out; + info_valid = scsi_get_sense_info_fld(SCpnt->sense_buffer, + SCSI_SENSE_BUFFERSIZE, + &bad_lba); + if (!info_valid) + goto out; + if (xfer_size <= SCpnt->device->sector_size) + goto out; + switch (SCpnt->device->sector_size) { + case 256: + start_lba <<= 1; break; - - case RECOVERED_ERROR: /* an error occurred, but it recovered */ - case NO_SENSE: /* LLDD got sense data */ - /* - * Inform the user, but make sure that it's not treated - * as a hard error. - */ - scsi_print_sense("sd", SCpnt); - SCpnt->result = 0; - memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - good_bytes = this_count; + case 512: break; - - case ILLEGAL_REQUEST: - if (SCpnt->device->use_10_for_rw && - (SCpnt->cmnd[0] == READ_10 || - SCpnt->cmnd[0] == WRITE_10)) - SCpnt->device->use_10_for_rw = 0; - if (SCpnt->device->use_10_for_ms && - (SCpnt->cmnd[0] == MODE_SENSE_10 || - SCpnt->cmnd[0] == MODE_SELECT_10)) - SCpnt->device->use_10_for_ms = 0; + case 1024: + start_lba >>= 1; + break; + case 2048: + start_lba >>= 2; + break; + case 4096: + start_lba >>= 3; break; - default: + /* Print something here with limiting frequency. */ + goto out; break; } + /* This computation should always be done in terms of + * the resolution of the device's medium. + */ + good_bytes = (bad_lba - start_lba)*SCpnt->device->sector_size; + break; + case RECOVERED_ERROR: + case NO_SENSE: + /* Inform the user, but make sure that it's not treated + * as a hard error. + */ + scsi_print_sense("sd", SCpnt); + SCpnt->result = 0; + memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); + good_bytes = xfer_size; + break; + case ILLEGAL_REQUEST: + if (SCpnt->device->use_10_for_rw && + (SCpnt->cmnd[0] == READ_10 || + SCpnt->cmnd[0] == WRITE_10)) + SCpnt->device->use_10_for_rw = 0; + if (SCpnt->device->use_10_for_ms && + (SCpnt->cmnd[0] == MODE_SENSE_10 || + SCpnt->cmnd[0] == MODE_SELECT_10)) + SCpnt->device->use_10_for_ms = 0; + break; + default: + break; } - /* - * This calls the generic completion function, now that we know - * how many actual sectors finished, and how many sectors we need - * to say have failed. - */ - scsi_io_completion(SCpnt, good_bytes, block_sectors << 9); + out: + scsi_io_completion(SCpnt, good_bytes); } static int media_not_present(struct scsi_disk *sdkp, diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index 3f312a84c6a..2679ea8bff1 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -1002,7 +1002,7 @@ connect_loop: } #endif - buffer = (struct scatterlist *) SCint->buffer; + buffer = (struct scatterlist *) SCint->request_buffer; len = buffer->length; data = page_address(buffer->page) + buffer->offset; } else { diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 4e607d3065b..34f9343ed0a 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -18,8 +18,8 @@ * */ -static int sg_version_num = 30533; /* 2 digits for each component */ -#define SG_VERSION_STR "3.5.33" +static int sg_version_num = 30534; /* 2 digits for each component */ +#define SG_VERSION_STR "3.5.34" /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: @@ -60,7 +60,7 @@ static int sg_version_num = 30533; /* 2 digits for each component */ #ifdef CONFIG_SCSI_PROC_FS #include <linux/proc_fs.h> -static char *sg_version_date = "20050908"; +static char *sg_version_date = "20060818"; static int sg_proc_init(void); static void sg_proc_cleanup(void); @@ -1164,7 +1164,7 @@ sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type) len = vma->vm_end - sa; len = (len < sg->length) ? len : sg->length; if (offset < len) { - page = sg->page; + page = virt_to_page(page_address(sg->page) + offset); get_page(page); /* increment page count */ break; } @@ -1401,6 +1401,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) Sg_device *sdp = NULL; struct cdev * cdev = NULL; int error, k; + unsigned long iflags; disk = alloc_disk(1); if (!disk) { @@ -1428,7 +1429,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1); if (error) - goto out; + goto cdev_add_err; sdp->cdev = cdev; if (sg_sysfs_valid) { @@ -1455,6 +1456,13 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) return 0; +cdev_add_err: + write_lock_irqsave(&sg_dev_arr_lock, iflags); + kfree(sg_dev_arr[k]); + sg_dev_arr[k] = NULL; + sg_nr_dev--; + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); + out: put_disk(disk); if (cdev) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index ebf6579ed69..fae6e95a629 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -292,7 +292,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt) * how many actual sectors finished, and how many sectors we need * to say have failed. */ - scsi_io_completion(SCpnt, good_bytes, block_sectors << 9); + scsi_io_completion(SCpnt, good_bytes); } static int sr_init_command(struct scsi_cmnd * SCpnt) @@ -360,7 +360,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt) "mismatch count %d, bytes %d\n", size, SCpnt->request_bufflen); if (SCpnt->request_bufflen > size) - SCpnt->request_bufflen = SCpnt->bufflen = size; + SCpnt->request_bufflen = size; } } @@ -387,8 +387,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt) if (this_count > 0xffff) { this_count = 0xffff; - SCpnt->request_bufflen = SCpnt->bufflen = - this_count * s_size; + SCpnt->request_bufflen = this_count * s_size; } SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index b5218fc0ac8..7f669b60067 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -368,7 +368,7 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2], SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]); if (cmdstatp->have_sense) - __scsi_print_sense("st", SRpnt->sense, SCSI_SENSE_BUFFERSIZE); + __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE); } ) /* end DEB */ if (!debugging) { /* Abnormal conditions for tape */ if (!cmdstatp->have_sense) @@ -384,9 +384,8 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) scode != VOLUME_OVERFLOW && SRpnt->cmd[0] != MODE_SENSE && SRpnt->cmd[0] != TEST_UNIT_READY) { - printk(KERN_WARNING "%s: Error with sense data: ", name); - __scsi_print_sense("st", SRpnt->sense, - SCSI_SENSE_BUFFERSIZE); + + __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE); } } @@ -3599,7 +3598,6 @@ static struct st_buffer * tb->use_sg = max_sg; tb->frp = (struct st_buf_fragment *)(&(tb->sg[0]) + max_sg); - tb->in_use = 1; tb->dma = need_dma; tb->buffer_size = got; diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 411209048d7..05a5cae126e 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -31,7 +31,6 @@ struct st_request { /* The tape buffer descriptor. */ struct st_buffer { - unsigned char in_use; unsigned char dma; /* DMA-able buffer */ unsigned char do_dio; /* direct i/o set up? */ int buffer_size; diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c index 2ebe0d66389..2f8073b73bf 100644 --- a/drivers/scsi/sun3_NCR5380.c +++ b/drivers/scsi/sun3_NCR5380.c @@ -517,7 +517,7 @@ static __inline__ void initialize_SCp(Scsi_Cmnd *cmd) */ if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; + cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; cmd->SCp.buffers_residual = cmd->use_sg - 1; cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index 1f328cae5c0..6b60536ac92 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -347,7 +347,7 @@ static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp) static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp) { int sz = sp->use_sg - 1; - struct scatterlist *sg = (struct scatterlist *)sp->buffer; + struct scatterlist *sg = (struct scatterlist *)sp->request_buffer; while(sz >= 0) { dvma_unmap((char *)sg[sz].dma_address); diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 8c505076c0e..739d3ef46a4 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -2084,7 +2084,7 @@ static struct pci_device_id sym2_id_table[] __devinitdata = { { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C860, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1510, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_SCSI<<8, 0xffff00, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C896, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C895, diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index 680f38ab60d..2083454db51 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -373,7 +373,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd, */ if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; + cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; cmd->SCp.buffers_residual = cmd->use_sg - 1; cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset; |