diff options
Diffstat (limited to 'drivers/scsi')
218 files changed, 11616 insertions, 12657 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 61da513fc0ed..90cf4691b8c3 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -99,28 +99,6 @@ config CHR_DEV_ST To compile this driver as a module, choose M here and read <file:Documentation/scsi/scsi.txt>. The module will be called st. -config CHR_DEV_OSST - tristate "SCSI OnStream SC-x0 tape support" - depends on SCSI - ---help--- - The OnStream SC-x0 SCSI tape drives cannot be driven by the - standard st driver, but instead need this special osst driver and - use the /dev/osstX char device nodes (major 206). Via usb-storage, - you may be able to drive the USB-x0 and DI-x0 drives as well. - Note that there is also a second generation of OnStream - tape drives (ADR-x0) that supports the standard SCSI-2 commands for - tapes (QIC-157) and can be driven by the standard driver st. - For more information, you may have a look at the SCSI-HOWTO - <http://www.tldp.org/docs.html#howto> and - <file:Documentation/scsi/osst.txt> in the kernel source. - More info on the OnStream driver may be found on - <http://sourceforge.net/projects/osst/> - Please also have a look at the standard st docu, as most of it - applies to osst as well. - - To compile this driver as a module, choose M here and read - <file:Documentation/scsi/scsi.txt>. The module will be called osst. - config BLK_DEV_SR tristate "SCSI CDROM support" depends on SCSI && BLK_DEV @@ -183,7 +161,7 @@ config CHR_DEV_SCH If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/kbuild/modules.txt> and + say M here and read <file:Documentation/kbuild/modules.rst> and <file:Documentation/scsi/scsi.txt>. The module will be called ch.o. If unsure, say N. @@ -664,6 +642,41 @@ config SCSI_DMX3191D To compile this driver as a module, choose M here: the module will be called dmx3191d. +config SCSI_FDOMAIN + tristate + depends on SCSI + +config SCSI_FDOMAIN_PCI + tristate "Future Domain TMC-3260/AHA-2920A PCI SCSI support" + depends on PCI && SCSI + select SCSI_FDOMAIN + help + This is support for Future Domain's PCI SCSI host adapters (TMC-3260) + and other adapters with PCI bus based on the Future Domain chipsets + (Adaptec AHA-2920A). + + NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip + and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI + controller support"). This Future Domain driver works with the older + Adaptec AHA-2920A boards with a Future Domain chip on them. + + To compile this driver as a module, choose M here: the + module will be called fdomain_pci. + +config SCSI_FDOMAIN_ISA + tristate "Future Domain 16xx ISA SCSI support" + depends on ISA && SCSI + select CHECK_SIGNATURE + select SCSI_FDOMAIN + help + This is support for Future Domain's 16-bit SCSI host adapters + (TMC-1660/1680, TMC-1650/1670, TMC-1610M/MER/MEX) and other adapters + with ISA bus based on the Future Domain chipsets (Quantum ISA-200S, + ISA-250MG; and at least one IBM board). + + To compile this driver as a module, choose M here: the + module will be called fdomain_isa. + config SCSI_GDTH tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support" depends on PCI && SCSI @@ -885,7 +898,7 @@ config SCSI_SNI_53C710 config 53C700_LE_ON_BE bool - depends on SCSI_LASI700 + depends on SCSI_LASI700 || SCSI_SNI_53C710 default y config SCSI_STEX @@ -1474,7 +1487,7 @@ config ZFCP This driver is also available as a module. This module will be called zfcp. If you want to compile it as a module, say M here - and read <file:Documentation/kbuild/modules.txt>. + and read <file:Documentation/kbuild/modules.rst>. config SCSI_PMCRAID tristate "PMC SIERRA Linux MaxRAID adapter support" @@ -1510,10 +1523,10 @@ config SCSI_VIRTIO source "drivers/scsi/csiostor/Kconfig" -endif # SCSI_LOWLEVEL - source "drivers/scsi/pcmcia/Kconfig" +endif # SCSI_LOWLEVEL + source "drivers/scsi/device_handler/Kconfig" endmenu diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 8826111fdf4a..c00e3dd57990 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -76,6 +76,9 @@ obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/ obj-$(CONFIG_SCSI_PM8001) += pm8001/ obj-$(CONFIG_SCSI_ISCI) += isci/ obj-$(CONFIG_SCSI_IPS) += ips.o +obj-$(CONFIG_SCSI_FDOMAIN) += fdomain.o +obj-$(CONFIG_SCSI_FDOMAIN_PCI) += fdomain_pci.o +obj-$(CONFIG_SCSI_FDOMAIN_ISA) += fdomain_isa.o obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o @@ -143,7 +146,6 @@ obj-$(CONFIG_SCSI_WD719X) += wd719x.o obj-$(CONFIG_ARM) += arm/ obj-$(CONFIG_CHR_DEV_ST) += st.o -obj-$(CONFIG_CHR_DEV_OSST) += osst.o obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o @@ -183,7 +185,7 @@ zalon7xx-objs := zalon.o ncr53c8xx.o # Files generated that shall be removed upon make clean clean-files := 53c700_d.h 53c700_u.h scsi_devinfo_tbl.c -$(obj)/53c700.o $(MODVERDIR)/$(obj)/53c700.ver: $(obj)/53c700_d.h +$(obj)/53c700.o: $(obj)/53c700_d.h $(obj)/scsi_sysfs.o: $(obj)/scsi_devinfo_tbl.c diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index fe0535affc14..536426f25e86 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -149,12 +149,10 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd) if (scsi_bufflen(cmd)) { cmd->SCp.buffer = scsi_sglist(cmd); - cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; } else { cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; cmd->SCp.ptr = NULL; cmd->SCp.this_residual = 0; } @@ -163,6 +161,17 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd) cmd->SCp.Message = 0; } +static inline void advance_sg_buffer(struct scsi_cmnd *cmd) +{ + struct scatterlist *s = cmd->SCp.buffer; + + if (!cmd->SCp.this_residual && s && !sg_is_last(s)) { + cmd->SCp.buffer = sg_next(s); + cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); + cmd->SCp.this_residual = cmd->SCp.buffer->length; + } +} + /** * NCR5380_poll_politely2 - wait for two chip register values * @hostdata: host private data @@ -709,6 +718,8 @@ static void NCR5380_main(struct work_struct *work) NCR5380_information_transfer(instance); done = 0; } + if (!hostdata->connected) + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); spin_unlock_irq(&hostdata->lock); if (!done) cond_resched(); @@ -1110,8 +1121,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) spin_lock_irq(&hostdata->lock); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); NCR5380_reselect(instance); - if (!hostdata->connected) - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); shost_printk(KERN_ERR, instance, "reselection after won arbitration?\n"); goto out; } @@ -1119,7 +1128,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) if (err < 0) { spin_lock_irq(&hostdata->lock); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); /* Can't touch cmd if it has been reclaimed by the scsi ML */ if (!hostdata->selecting) @@ -1157,7 +1165,6 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) if (err < 0) { shost_printk(KERN_ERR, instance, "select: REQ timeout\n"); NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); goto out; } if (!hostdata->selecting) { @@ -1672,12 +1679,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) sun3_dma_setup_done != cmd) { int count; - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - } + advance_sg_buffer(cmd); count = sun3scsi_dma_xfer_len(hostdata, cmd); @@ -1727,15 +1729,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) * scatter-gather list, move onto the next one. */ - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - dsprintk(NDEBUG_INFORMATION, instance, "%d bytes and %d buffers left\n", - cmd->SCp.this_residual, - cmd->SCp.buffers_residual); - } + advance_sg_buffer(cmd); + dsprintk(NDEBUG_INFORMATION, instance, + "this residual %d, sg ents %d\n", + cmd->SCp.this_residual, + sg_nents(cmd->SCp.buffer)); /* * The preferred transfer method is going to be @@ -1763,10 +1761,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) scmd_printk(KERN_INFO, cmd, "switching to slow handshake\n"); cmd->device->borken = 1; - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - /* XXX - need to source or sink data here, as appropriate */ + do_reset(instance); + bus_reset_cleanup(instance); } } else { /* Transfer a small chunk so that the @@ -1826,9 +1822,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) */ NCR5380_write(TARGET_COMMAND_REG, 0); - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - maybe_release_dma_irq(instance); return; case MESSAGE_REJECT: @@ -1860,8 +1853,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) */ NCR5380_write(TARGET_COMMAND_REG, 0); - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); #ifdef SUN3_SCSI_VME dregs->csr |= CSR_DMA_ENABLE; #endif @@ -1964,7 +1955,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) cmd->result = DID_ERROR << 16; complete_cmd(instance, cmd); maybe_release_dma_irq(instance); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); return; } msgout = NOP; @@ -2136,12 +2126,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) if (sun3_dma_setup_done != tmp) { int count; - if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) { - ++tmp->SCp.buffer; - --tmp->SCp.buffers_residual; - tmp->SCp.this_residual = tmp->SCp.buffer->length; - tmp->SCp.ptr = sg_virt(tmp->SCp.buffer); - } + advance_sg_buffer(tmp); count = sun3scsi_dma_xfer_len(hostdata, tmp); diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index efca509b92b0..5935fd6d1a05 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -235,7 +235,7 @@ struct NCR5380_cmd { #define NCR5380_PIO_CHUNK_SIZE 256 /* Time limit (ms) to poll registers when IRQs are disabled, e.g. during PDMA */ -#define NCR5380_REG_POLL_TIME 15 +#define NCR5380_REG_POLL_TIME 10 static inline struct scsi_cmnd *NCR5380_to_scmd(struct NCR5380_cmd *ncmd_ptr) { diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 644f7f5c61a2..4a858789e6c5 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -27,7 +27,6 @@ #include <linux/moduleparam.h> #include <linux/pci.h> #include <linux/aer.h> -#include <linux/pci-aspm.h> #include <linux/slab.h> #include <linux/mutex.h> #include <linux/spinlock.h> diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 926311c792d5..a242a62caaa1 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -7710,7 +7710,7 @@ adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp, sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */ return ADV_SUCCESS; } - slp++; + slp = sg_next(slp); } sg_block->sg_cnt = NO_OF_SG_PER_BLOCK; prev_sg_block = sg_block; diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 88c649b3ef61..eb466c2e1839 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -937,7 +937,6 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, SCp.ptr : buffer pointer SCp.this_residual : buffer length SCp.buffer : next buffer - SCp.buffers_residual : left buffers in list SCp.phase : current state of the command */ if ((phase & resetting) || !scsi_sglist(SCpnt)) { @@ -945,13 +944,11 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, SCpnt->SCp.this_residual = 0; scsi_set_resid(SCpnt, 0); SCpnt->SCp.buffer = NULL; - SCpnt->SCp.buffers_residual = 0; } else { scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); SCpnt->SCp.buffer = scsi_sglist(SCpnt); SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer); SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1; } DO_LOCK(flags); @@ -2019,10 +2016,9 @@ static void datai_run(struct Scsi_Host *shpnt) } if (CURRENT_SC->SCp.this_residual == 0 && - CURRENT_SC->SCp.buffers_residual > 0) { + !sg_is_last(CURRENT_SC->SCp.buffer)) { /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer); CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer); CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; } @@ -2125,10 +2121,10 @@ static void datao_run(struct Scsi_Host *shpnt) CMD_INC_RESID(CURRENT_SC, -2 * data_count); } - if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) { + if (CURRENT_SC->SCp.this_residual == 0 && + !sg_is_last(CURRENT_SC->SCp.buffer)) { /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.buffer = sg_next(CURRENT_SC->SCp.buffer); CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer); CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; } @@ -2147,22 +2143,26 @@ static void datao_run(struct Scsi_Host *shpnt) static void datao_end(struct Scsi_Host *shpnt) { if(TESTLO(DMASTAT, DFIFOEMP)) { - int data_count = (DATA_LEN - scsi_get_resid(CURRENT_SC)) - - GETSTCNT(); + u32 datao_cnt = GETSTCNT(); + int datao_out = DATA_LEN - scsi_get_resid(CURRENT_SC); + int done; + struct scatterlist *sg = scsi_sglist(CURRENT_SC); - CMD_INC_RESID(CURRENT_SC, data_count); + CMD_INC_RESID(CURRENT_SC, datao_out - datao_cnt); - data_count -= CURRENT_SC->SCp.ptr - - SG_ADDRESS(CURRENT_SC->SCp.buffer); - while(data_count>0) { - CURRENT_SC->SCp.buffer--; - CURRENT_SC->SCp.buffers_residual++; - data_count -= CURRENT_SC->SCp.buffer->length; + done = scsi_bufflen(CURRENT_SC) - scsi_get_resid(CURRENT_SC); + /* Locate the first SG entry not yet sent */ + while (done > 0 && !sg_is_last(sg)) { + if (done < sg->length) + break; + done -= sg->length; + sg = sg_next(sg); } - CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) - - data_count; - CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + - data_count; + + CURRENT_SC->SCp.buffer = sg; + CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) + done; + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length - + done; } SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); @@ -2490,7 +2490,7 @@ static void get_command(struct seq_file *m, struct scsi_cmnd * ptr) seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |", scsi_get_resid(ptr), ptr->SCp.this_residual, - ptr->SCp.buffers_residual); + sg_nents(ptr->SCp.buffer) - 1); if (ptr->SCp.phase & not_issued) seq_puts(m, "not issued|"); diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg index ba0b411d03e2..00fde2243e48 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.reg +++ b/drivers/scsi/aic7xxx/aic7xxx.reg @@ -1666,7 +1666,7 @@ scratch_ram { size 6 /* * These are reserved registers in the card's scratch ram on the 2742. - * The EISA configuraiton chip is mapped here. On Rev E. of the + * The EISA configuration chip is mapped here. On Rev E. of the * aic7770, the sequencer can use this area for scratch, but the * host cannot directly access these registers. On later chips, this * area can be read and written by both the host and the sequencer. diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c index 730b35e7c1ba..604a5331f639 100644 --- a/drivers/scsi/aic94xx/aic94xx_dev.c +++ b/drivers/scsi/aic94xx/aic94xx_dev.c @@ -170,9 +170,7 @@ static int asd_init_target_ddb(struct domain_device *dev) } } else { flags |= CONCURRENT_CONN_SUPP; - if (!dev->parent && - (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || - dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)) + if (!dev->parent && dev_is_expander(dev->dev_type)) asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN, 4); else diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 261d8e495fed..f5781e31f57c 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -565,8 +565,7 @@ static void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha) if (asd_ha->hw_prof.scb_ext) asd_free_coherent(asd_ha, asd_ha->hw_prof.scb_ext); - if (asd_ha->hw_prof.ddb_bitmap) - kfree(asd_ha->hw_prof.ddb_bitmap); + kfree(asd_ha->hw_prof.ddb_bitmap); asd_ha->hw_prof.ddb_bitmap = NULL; for (i = 0; i < ASD_MAX_PHYS; i++) { @@ -641,12 +640,10 @@ Err: static void asd_destroy_global_caches(void) { - if (asd_dma_token_cache) - kmem_cache_destroy(asd_dma_token_cache); + kmem_cache_destroy(asd_dma_token_cache); asd_dma_token_cache = NULL; - if (asd_ascb_cache) - kmem_cache_destroy(asd_ascb_cache); + kmem_cache_destroy(asd_ascb_cache); asd_ascb_cache = NULL; } diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index aea4fd73c862..6c68c2303638 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -603,6 +603,7 @@ static void fas216_handlesync(FAS216_Info *info, char *msg) msgqueue_flush(&info->scsi.msgs); msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); info->scsi.phase = PHASE_MSGOUT_EXPECT; + /* fall through */ case async: dev->period = info->ifcfg.asyncperiod / 4; @@ -915,6 +916,7 @@ static void fas216_disconnect_intr(FAS216_Info *info) fas216_done(info, DID_ABORT); break; } + /* else, fall through */ default: /* huh? */ printk(KERN_ERR "scsi%d.%c: unexpected disconnect in phase %s\n", @@ -1411,6 +1413,8 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out -> Status */ case STATE(STAT_STATUS, PHASE_DATAIN): /* Data In -> Status */ fas216_stoptransfer(info); + /* fall through */ + case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status */ case STATE(STAT_STATUS, PHASE_MSGOUT): /* Message Out -> Status */ case STATE(STAT_STATUS, PHASE_COMMAND): /* Command -> Status */ @@ -1422,6 +1426,8 @@ static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigne case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out -> Message In */ case STATE(STAT_MESGIN, PHASE_DATAIN): /* Data In -> Message In */ fas216_stoptransfer(info); + /* fall through */ + case STATE(STAT_MESGIN, PHASE_COMMAND): /* Command -> Message In */ case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In */ case STATE(STAT_MESGIN, PHASE_MSGOUT): /* Message Out -> Message In */ @@ -1575,6 +1581,7 @@ static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned fas216_message(info); break; } + /* else, fall through */ default: fas216_log(info, 0, "internal phase %s for function done?" @@ -1957,6 +1964,7 @@ static void fas216_kick(FAS216_Info *info) switch (where_from) { case TYPE_QUEUE: fas216_allocate_tag(info, SCpnt); + /* fall through */ case TYPE_OTHER: fas216_start_command(info, SCpnt); break; diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index b2014cb96f58..22f06be2606f 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -536,7 +536,7 @@ bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port, struct device *dev) { struct bfad_im_port_pointer *im_portp; - int error = 1; + int error; mutex_lock(&bfad_mutex); error = idr_alloc(&bfad_im_port_index, im_port, 0, 0, GFP_KERNEL); diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 901a31632493..3b84db8d13a9 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -66,7 +66,7 @@ #include "bnx2fc_constants.h" #define BNX2FC_NAME "bnx2fc" -#define BNX2FC_VERSION "2.11.8" +#define BNX2FC_VERSION "2.12.10" #define PFX "bnx2fc: " @@ -75,8 +75,9 @@ #define BNX2X_DOORBELL_PCI_BAR 2 #define BNX2FC_MAX_BD_LEN 0xffff -#define BNX2FC_BD_SPLIT_SZ 0x8000 -#define BNX2FC_MAX_BDS_PER_CMD 256 +#define BNX2FC_BD_SPLIT_SZ 0xffff +#define BNX2FC_MAX_BDS_PER_CMD 255 +#define BNX2FC_FW_MAX_BDS_PER_CMD 255 #define BNX2FC_SQ_WQES_MAX 256 @@ -433,8 +434,10 @@ struct bnx2fc_cmd { void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg); struct bnx2fc_els_cb_arg *cb_arg; struct delayed_work timeout_work; /* timer for ULP timeouts */ - struct completion tm_done; - int wait_for_comp; + struct completion abts_done; + struct completion cleanup_done; + int wait_for_abts_comp; + int wait_for_cleanup_comp; u16 xid; struct fcoe_err_report_entry err_entry; struct fcoe_task_ctx_entry *task; @@ -455,6 +458,7 @@ struct bnx2fc_cmd { #define BNX2FC_FLAG_ELS_TIMEOUT 0xb #define BNX2FC_FLAG_CMD_LOST 0xc #define BNX2FC_FLAG_SRR_SENT 0xd +#define BNX2FC_FLAG_ISSUE_CLEANUP_REQ 0xe u8 rec_retry; u8 srr_retry; u32 srr_offset; diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c index 76e65a32f38c..754f2e82d955 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_els.c +++ b/drivers/scsi/bnx2fc/bnx2fc_els.c @@ -610,7 +610,6 @@ int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req) rc = bnx2fc_initiate_els(tgt, ELS_REC, &rec, sizeof(rec), bnx2fc_rec_compl, cb_arg, r_a_tov); -rec_err: if (rc) { BNX2FC_IO_DBG(orig_io_req, "REC failed - release\n"); spin_lock_bh(&tgt->tgt_lock); @@ -618,6 +617,7 @@ rec_err: spin_unlock_bh(&tgt->tgt_lock); kfree(cb_arg); } +rec_err: return rc; } @@ -654,7 +654,6 @@ int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl) rc = bnx2fc_initiate_els(tgt, ELS_SRR, &srr, sizeof(srr), bnx2fc_srr_compl, cb_arg, r_a_tov); -srr_err: if (rc) { BNX2FC_IO_DBG(orig_io_req, "SRR failed - release\n"); spin_lock_bh(&tgt->tgt_lock); @@ -664,6 +663,7 @@ srr_err: } else set_bit(BNX2FC_FLAG_SRR_SENT, &orig_io_req->req_flags); +srr_err: return rc; } @@ -854,33 +854,57 @@ void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req, kref_put(&els_req->refcount, bnx2fc_cmd_release); } +#define BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC 1 +#define BNX2FC_FCOE_MAC_METHOD_FCF_MAP 2 +#define BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC 3 static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) { struct fcoe_ctlr *fip = arg; struct fc_exch *exch = fc_seq_exch(seq); struct fc_lport *lport = exch->lp; - u8 *mac; - u8 op; + + struct fc_frame_header *fh; + u8 *granted_mac; + u8 fcoe_mac[6]; + u8 fc_map[3]; + int method; if (IS_ERR(fp)) goto done; - mac = fr_cb(fp)->granted_mac; - if (is_zero_ether_addr(mac)) { - op = fc_frame_payload_op(fp); - if (lport->vport) { - if (op == ELS_LS_RJT) { - printk(KERN_ERR PFX "bnx2fc_flogi_resp is LS_RJT\n"); - fc_vport_terminate(lport->vport); - fc_frame_free(fp); - return; - } - } - fcoe_ctlr_recv_flogi(fip, lport, fp); + fh = fc_frame_header_get(fp); + granted_mac = fr_cb(fp)->granted_mac; + + /* + * We set the source MAC for FCoE traffic based on the Granted MAC + * address from the switch. + * + * If granted_mac is non-zero, we use that. + * If the granted_mac is zeroed out, create the FCoE MAC based on + * the sel_fcf->fc_map and the d_id fo the FLOGI frame. + * If sel_fcf->fc_map is 0, then we use the default FCF-MAC plus the + * d_id of the FLOGI frame. + */ + if (!is_zero_ether_addr(granted_mac)) { + ether_addr_copy(fcoe_mac, granted_mac); + method = BNX2FC_FCOE_MAC_METHOD_GRANGED_MAC; + } else if (fip->sel_fcf && fip->sel_fcf->fc_map != 0) { + hton24(fc_map, fip->sel_fcf->fc_map); + fcoe_mac[0] = fc_map[0]; + fcoe_mac[1] = fc_map[1]; + fcoe_mac[2] = fc_map[2]; + fcoe_mac[3] = fh->fh_d_id[0]; + fcoe_mac[4] = fh->fh_d_id[1]; + fcoe_mac[5] = fh->fh_d_id[2]; + method = BNX2FC_FCOE_MAC_METHOD_FCF_MAP; + } else { + fc_fcoe_set_mac(fcoe_mac, fh->fh_d_id); + method = BNX2FC_FCOE_MAC_METHOD_FCOE_SET_MAC; } - if (!is_zero_ether_addr(mac)) - fip->update_mac(lport, mac); + + BNX2FC_HBA_DBG(lport, "fcoe_mac=%pM method=%d\n", fcoe_mac, method); + fip->update_mac(lport, fcoe_mac); done: fc_lport_flogi_resp(seq, fp, lport); } diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index a75e74ad1698..b4bfab5edf8f 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -346,7 +346,7 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp) return -ENOMEM; } frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; - cp = kmap_atomic(skb_frag_page(frag)) + frag->page_offset; + cp = kmap_atomic(skb_frag_page(frag)) + skb_frag_off(frag); } else { cp = skb_put(skb, tlen); } @@ -428,7 +428,6 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, struct fc_lport *lport; struct bnx2fc_interface *interface; struct fcoe_ctlr *ctlr; - struct fc_frame_header *fh; struct fcoe_rcv_info *fr; struct fcoe_percpu_s *bg; struct sk_buff *tmp_skb; @@ -463,7 +462,6 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, goto err; skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); - fh = (struct fc_frame_header *) skb_transport_header(skb); fr = fcoe_dev_from_skb(skb); fr->fr_dev = lport; @@ -2971,7 +2969,8 @@ static struct scsi_host_template bnx2fc_shost_template = { .this_id = -1, .cmd_per_lun = 3, .sg_tablesize = BNX2FC_MAX_BDS_PER_CMD, - .max_sectors = 1024, + .dma_boundary = 0x7fff, + .max_sectors = 0x3fbf, .track_queue_depth = 1, .slave_configure = bnx2fc_slave_configure, .shost_attrs = bnx2fc_host_attrs, diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 747f019fb393..f069e09beb10 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -633,7 +633,6 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) u16 xid; u32 frame_len, len; struct bnx2fc_cmd *io_req = NULL; - struct fcoe_task_ctx_entry *task, *task_page; struct bnx2fc_interface *interface = tgt->port->priv; struct bnx2fc_hba *hba = interface->hba; int task_idx, index; @@ -711,9 +710,6 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) task_idx = xid / BNX2FC_TASKS_PER_PAGE; index = xid % BNX2FC_TASKS_PER_PAGE; - task_page = (struct fcoe_task_ctx_entry *) - hba->task_ctx[task_idx]; - task = &(task_page[index]); io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; if (!io_req) @@ -839,9 +835,6 @@ ret_err_rqe: task_idx = xid / BNX2FC_TASKS_PER_PAGE; index = xid % BNX2FC_TASKS_PER_PAGE; - task_page = (struct fcoe_task_ctx_entry *) - interface->hba->task_ctx[task_idx]; - task = &(task_page[index]); io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; if (!io_req) goto ret_warn_rqe; @@ -1122,7 +1115,6 @@ static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba, struct fcoe_kcqe *ofld_kcqe) { struct bnx2fc_rport *tgt; - struct fcoe_port *port; struct bnx2fc_interface *interface; u32 conn_id; u32 context_id; @@ -1136,7 +1128,6 @@ static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba, } BNX2FC_TGT_DBG(tgt, "Entered ofld compl - context_id = 0x%x\n", ofld_kcqe->fcoe_conn_context_id); - port = tgt->port; interface = tgt->port->priv; if (hba != interface->hba) { printk(KERN_ERR PFX "ERROR:ofld_cmpl: HBA mis-match\n"); @@ -1463,10 +1454,7 @@ void bnx2fc_init_seq_cleanup_task(struct bnx2fc_cmd *seq_clnp_req, { struct scsi_cmnd *sc_cmd = orig_io_req->sc_cmd; struct bnx2fc_rport *tgt = seq_clnp_req->tgt; - struct bnx2fc_interface *interface = tgt->port->priv; struct fcoe_bd_ctx *bd = orig_io_req->bd_tbl->bd_tbl; - struct fcoe_task_ctx_entry *orig_task; - struct fcoe_task_ctx_entry *task_page; struct fcoe_ext_mul_sges_ctx *sgl; u8 task_type = FCOE_TASK_TYPE_SEQUENCE_CLEANUP; u8 orig_task_type; @@ -1528,10 +1516,6 @@ void bnx2fc_init_seq_cleanup_task(struct bnx2fc_cmd *seq_clnp_req, orig_task_idx = orig_xid / BNX2FC_TASKS_PER_PAGE; index = orig_xid % BNX2FC_TASKS_PER_PAGE; - task_page = (struct fcoe_task_ctx_entry *) - interface->hba->task_ctx[orig_task_idx]; - orig_task = &(task_page[index]); - /* Multiple SGEs were used for this IO */ sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl; sgl->mul_sgl.cur_sge_addr.lo = (u32)phys_addr; diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 8def63c0755f..401743e2b429 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -70,7 +70,7 @@ static void bnx2fc_cmd_timeout(struct work_struct *work) &io_req->req_flags)) { /* Handle eh_abort timeout */ BNX2FC_IO_DBG(io_req, "eh_abort timed out\n"); - complete(&io_req->tm_done); + complete(&io_req->abts_done); } else if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { /* Handle internally generated ABTS timeout */ @@ -775,31 +775,32 @@ retry_tmf: io_req->on_tmf_queue = 1; list_add_tail(&io_req->link, &tgt->active_tm_queue); - init_completion(&io_req->tm_done); - io_req->wait_for_comp = 1; + init_completion(&io_req->abts_done); + io_req->wait_for_abts_comp = 1; /* Ring doorbell */ bnx2fc_ring_doorbell(tgt); spin_unlock_bh(&tgt->tgt_lock); - rc = wait_for_completion_timeout(&io_req->tm_done, + rc = wait_for_completion_timeout(&io_req->abts_done, interface->tm_timeout * HZ); spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; + io_req->wait_for_abts_comp = 0; if (!(test_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags))) { set_bit(BNX2FC_FLAG_TM_TIMEOUT, &io_req->req_flags); if (io_req->on_tmf_queue) { list_del_init(&io_req->link); io_req->on_tmf_queue = 0; } - io_req->wait_for_comp = 1; + io_req->wait_for_cleanup_comp = 1; + init_completion(&io_req->cleanup_done); bnx2fc_initiate_cleanup(io_req); spin_unlock_bh(&tgt->tgt_lock); - rc = wait_for_completion_timeout(&io_req->tm_done, + rc = wait_for_completion_timeout(&io_req->cleanup_done, BNX2FC_FW_TIMEOUT); spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; + io_req->wait_for_cleanup_comp = 0; if (!rc) kref_put(&io_req->refcount, bnx2fc_cmd_release); } @@ -929,7 +930,6 @@ abts_err: int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset, enum fc_rctl r_ctl) { - struct fc_lport *lport; struct bnx2fc_rport *tgt = orig_io_req->tgt; struct bnx2fc_interface *interface; struct fcoe_port *port; @@ -947,7 +947,6 @@ int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset, port = orig_io_req->port; interface = port->priv; - lport = port->lport; cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); if (!cb_arg) { @@ -998,7 +997,6 @@ cleanup_err: int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req) { - struct fc_lport *lport; struct bnx2fc_rport *tgt = io_req->tgt; struct bnx2fc_interface *interface; struct fcoe_port *port; @@ -1014,7 +1012,6 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req) port = io_req->port; interface = port->priv; - lport = port->lport; cleanup_io_req = bnx2fc_elstm_alloc(tgt, BNX2FC_CLEANUP); if (!cleanup_io_req) { @@ -1047,6 +1044,9 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req) /* Obtain free SQ entry */ bnx2fc_add_2_sq(tgt, xid); + /* Set flag that cleanup request is pending with the firmware */ + set_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags); + /* Ring doorbell */ bnx2fc_ring_doorbell(tgt); @@ -1085,7 +1085,8 @@ static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req) struct bnx2fc_rport *tgt = io_req->tgt; unsigned int time_left; - io_req->wait_for_comp = 1; + init_completion(&io_req->cleanup_done); + io_req->wait_for_cleanup_comp = 1; bnx2fc_initiate_cleanup(io_req); spin_unlock_bh(&tgt->tgt_lock); @@ -1094,21 +1095,21 @@ static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req) * Can't wait forever on cleanup response lest we let the SCSI error * handler wait forever */ - time_left = wait_for_completion_timeout(&io_req->tm_done, + time_left = wait_for_completion_timeout(&io_req->cleanup_done, BNX2FC_FW_TIMEOUT); - io_req->wait_for_comp = 0; - if (!time_left) + if (!time_left) { BNX2FC_IO_DBG(io_req, "%s(): Wait for cleanup timed out.\n", __func__); - /* - * Release reference held by SCSI command the cleanup completion - * hits the BNX2FC_CLEANUP case in bnx2fc_process_cq_compl() and - * thus the SCSI command is not returnedi by bnx2fc_scsi_done(). - */ - kref_put(&io_req->refcount, bnx2fc_cmd_release); + /* + * Put the extra reference to the SCSI command since it would + * not have been returned in this case. + */ + kref_put(&io_req->refcount, bnx2fc_cmd_release); + } spin_lock_bh(&tgt->tgt_lock); + io_req->wait_for_cleanup_comp = 0; return SUCCESS; } @@ -1197,7 +1198,8 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) /* Move IO req to retire queue */ list_add_tail(&io_req->link, &tgt->io_retire_queue); - init_completion(&io_req->tm_done); + init_completion(&io_req->abts_done); + init_completion(&io_req->cleanup_done); if (test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " @@ -1225,26 +1227,28 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) kref_put(&io_req->refcount, bnx2fc_cmd_release); /* drop timer hold */ set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags); - io_req->wait_for_comp = 1; + io_req->wait_for_abts_comp = 1; rc = bnx2fc_initiate_abts(io_req); if (rc == FAILED) { + io_req->wait_for_cleanup_comp = 1; bnx2fc_initiate_cleanup(io_req); spin_unlock_bh(&tgt->tgt_lock); - wait_for_completion(&io_req->tm_done); + wait_for_completion(&io_req->cleanup_done); spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; + io_req->wait_for_cleanup_comp = 0; goto done; } spin_unlock_bh(&tgt->tgt_lock); /* Wait 2 * RA_TOV + 1 to be sure timeout function hasn't fired */ - time_left = wait_for_completion_timeout(&io_req->tm_done, - (2 * rp->r_a_tov + 1) * HZ); + time_left = wait_for_completion_timeout(&io_req->abts_done, + (2 * rp->r_a_tov + 1) * HZ); if (time_left) - BNX2FC_IO_DBG(io_req, "Timed out in eh_abort waiting for tm_done"); + BNX2FC_IO_DBG(io_req, + "Timed out in eh_abort waiting for abts_done"); spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; + io_req->wait_for_abts_comp = 0; if (test_bit(BNX2FC_FLAG_IO_COMPL, &io_req->req_flags)) { BNX2FC_IO_DBG(io_req, "IO completed in a different context\n"); rc = SUCCESS; @@ -1319,10 +1323,29 @@ void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req, BNX2FC_IO_DBG(io_req, "Entered process_cleanup_compl " "refcnt = %d, cmd_type = %d\n", kref_read(&io_req->refcount), io_req->cmd_type); + /* + * Test whether there is a cleanup request pending. If not just + * exit. + */ + if (!test_and_clear_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, + &io_req->req_flags)) + return; + /* + * If we receive a cleanup completion for this request then the + * firmware will not give us an abort completion for this request + * so clear any ABTS pending flags. + */ + if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags) && + !test_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags)) { + set_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags); + if (io_req->wait_for_abts_comp) + complete(&io_req->abts_done); + } + bnx2fc_scsi_done(io_req, DID_ERROR); kref_put(&io_req->refcount, bnx2fc_cmd_release); - if (io_req->wait_for_comp) - complete(&io_req->tm_done); + if (io_req->wait_for_cleanup_comp) + complete(&io_req->cleanup_done); } void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, @@ -1346,6 +1369,16 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, return; } + /* + * If we receive an ABTS completion here then we will not receive + * a cleanup completion so clear any cleanup pending flags. + */ + if (test_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags)) { + clear_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags); + if (io_req->wait_for_cleanup_comp) + complete(&io_req->cleanup_done); + } + /* Do not issue RRQ as this IO is already cleanedup */ if (test_and_set_bit(BNX2FC_FLAG_IO_CLEANUP, &io_req->req_flags)) @@ -1390,10 +1423,10 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, bnx2fc_cmd_timer_set(io_req, r_a_tov); io_compl: - if (io_req->wait_for_comp) { + if (io_req->wait_for_abts_comp) { if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags)) - complete(&io_req->tm_done); + complete(&io_req->abts_done); } else { /* * We end up here when ABTS is issued as @@ -1577,9 +1610,9 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req, sc_cmd->scsi_done(sc_cmd); kref_put(&io_req->refcount, bnx2fc_cmd_release); - if (io_req->wait_for_comp) { + if (io_req->wait_for_abts_comp) { BNX2FC_IO_DBG(io_req, "tm_compl - wake up the waiter\n"); - complete(&io_req->tm_done); + complete(&io_req->abts_done); } } @@ -1623,6 +1656,7 @@ static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req) u64 addr; int i; + WARN_ON(scsi_sg_count(sc) > BNX2FC_MAX_BDS_PER_CMD); /* * Use dma_map_sg directly to ensure we're using the correct * dev struct off of pcidev. @@ -1670,6 +1704,16 @@ static int bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req) } io_req->bd_tbl->bd_valid = bd_count; + /* + * Return the command to ML if BD count exceeds the max number + * that can be handled by FW. + */ + if (bd_count > BNX2FC_FW_MAX_BDS_PER_CMD) { + pr_err("bd_count = %d exceeded FW supported max BD(255), task_id = 0x%x\n", + bd_count, io_req->xid); + return -ENOMEM; + } + return 0; } @@ -1879,8 +1923,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, struct fcoe_fcp_rsp_payload *fcp_rsp; struct bnx2fc_rport *tgt = io_req->tgt; struct scsi_cmnd *sc_cmd; - struct Scsi_Host *host; - + u16 scope = 0, qualifier = 0; /* scsi_cmd_cmpl is called with tgt lock held */ @@ -1909,7 +1952,6 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, /* parse fcp_rsp and obtain sense data from RQ if available */ bnx2fc_parse_fcp_rsp(io_req, fcp_rsp, num_rq); - host = sc_cmd->device->host; if (!sc_cmd->SCp.ptr) { printk(KERN_ERR PFX "SCp.ptr is NULL\n"); return; @@ -1926,10 +1968,10 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, * between command abort and (late) completion. */ BNX2FC_IO_DBG(io_req, "xid not on active_cmd_queue\n"); - if (io_req->wait_for_comp) + if (io_req->wait_for_abts_comp) if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags)) - complete(&io_req->tm_done); + complete(&io_req->abts_done); } bnx2fc_unmap_sg_list(io_req); @@ -1949,12 +1991,30 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, if (io_req->cdb_status == SAM_STAT_TASK_SET_FULL || io_req->cdb_status == SAM_STAT_BUSY) { - /* Set the jiffies + retry_delay_timer * 100ms - for the rport/tgt */ - tgt->retry_delay_timestamp = jiffies + - fcp_rsp->retry_delay_timer * HZ / 10; + /* Newer array firmware with BUSY or + * TASK_SET_FULL may return a status that needs + * the scope bits masked. + * Or a huge delay timestamp up to 27 minutes + * can result. + */ + if (fcp_rsp->retry_delay_timer) { + /* Upper 2 bits */ + scope = fcp_rsp->retry_delay_timer + & 0xC000; + /* Lower 14 bits */ + qualifier = fcp_rsp->retry_delay_timer + & 0x3FFF; + } + if (scope > 0 && qualifier > 0 && + qualifier <= 0x3FEF) { + /* Set the jiffies + + * retry_delay_timer * 100ms + * for the rport/tgt + */ + tgt->retry_delay_timestamp = jiffies + + (qualifier * HZ / 10); + } } - } if (io_req->fcp_resid) scsi_set_resid(sc_cmd, io_req->fcp_resid); diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c index d735e87e416a..50384b4a817c 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c @@ -187,7 +187,7 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt) /* Handle eh_abort timeout */ BNX2FC_IO_DBG(io_req, "eh_abort for IO " "cleaned up\n"); - complete(&io_req->tm_done); + complete(&io_req->abts_done); } kref_put(&io_req->refcount, bnx2fc_cmd_release); /* drop timer hold */ @@ -210,8 +210,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt) list_del_init(&io_req->link); io_req->on_tmf_queue = 0; BNX2FC_IO_DBG(io_req, "tm_queue cleanup\n"); - if (io_req->wait_for_comp) - complete(&io_req->tm_done); + if (io_req->wait_for_abts_comp) + complete(&io_req->abts_done); } list_for_each_entry_safe(io_req, tmp, &tgt->els_queue, link) { @@ -251,8 +251,8 @@ void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt) /* Handle eh_abort timeout */ BNX2FC_IO_DBG(io_req, "eh_abort for IO " "in retire_q\n"); - if (io_req->wait_for_comp) - complete(&io_req->tm_done); + if (io_req->wait_for_abts_comp) + complete(&io_req->abts_done); } kref_put(&io_req->refcount, bnx2fc_cmd_release); } diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 5f8153c37f77..76751d6c7f0d 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -579,7 +579,6 @@ ch_release(struct inode *inode, struct file *file) scsi_changer *ch = file->private_data; scsi_device_put(ch->device); - ch->device = NULL; file->private_data = NULL; kref_put(&ch->ref, ch_destroy); return 0; diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c index 03bd896cdbb9..0ca695110f54 100644 --- a/drivers/scsi/csiostor/csio_wr.c +++ b/drivers/scsi/csiostor/csio_wr.c @@ -1316,7 +1316,6 @@ csio_wr_fixup_host_params(struct csio_hw *hw) u32 fl_align = clsz < 32 ? 32 : clsz; u32 pack_align; u32 ingpad, ingpack; - int pcie_cap; csio_wr_reg32(hw, HOSTPAGESIZEPF0_V(s_hps) | HOSTPAGESIZEPF1_V(s_hps) | HOSTPAGESIZEPF2_V(s_hps) | HOSTPAGESIZEPF3_V(s_hps) | @@ -1347,8 +1346,7 @@ csio_wr_fixup_host_params(struct csio_hw *hw) * multiple of the Maximum Payload Size. */ pack_align = fl_align; - pcie_cap = pci_find_capability(hw->pdev, PCI_CAP_ID_EXP); - if (pcie_cap) { + if (pci_is_pcie(hw->pdev)) { u32 mps, mps_log; u16 devctl; @@ -1356,9 +1354,7 @@ csio_wr_fixup_host_params(struct csio_hw *hw) * [bits 7:5] encodes sizes as powers of 2 starting at * 128 bytes. */ - pci_read_config_word(hw->pdev, - pcie_cap + PCI_EXP_DEVCTL, - &devctl); + pcie_capability_read_word(hw->pdev, PCI_EXP_DEVCTL, &devctl); mps_log = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5) + 7; mps = 1 << mps_log; if (mps > pack_align) diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index b8dd9e648dd0..524cdbcd29aa 100644 --- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -1243,8 +1243,12 @@ static int cxgb3i_ddp_init(struct cxgbi_device *cdev) tformat.pgsz_order[i] = uinfo.pgsz_factor[i]; cxgbi_tagmask_check(tagmask, &tformat); - cxgbi_ddp_ppm_setup(&tdev->ulp_iscsi, cdev, &tformat, ppmax, - uinfo.llimit, uinfo.llimit, 0); + err = cxgbi_ddp_ppm_setup(&tdev->ulp_iscsi, cdev, &tformat, + (uinfo.ulimit - uinfo.llimit + 1), + uinfo.llimit, uinfo.llimit, 0, 0, 0); + if (err) + return err; + if (!(cdev->flags & CXGBI_FLAG_DDP_OFF)) { uinfo.tagmask = tagmask; uinfo.ulimit = uinfo.llimit + (ppmax << PPOD_SIZE_SHIFT); @@ -1318,7 +1322,7 @@ static void cxgb3i_dev_open(struct t3cdev *t3dev) err = cxgb3i_ddp_init(cdev); if (err) { - pr_info("0x%p ddp init failed\n", cdev); + pr_info("0x%p ddp init failed %d\n", cdev, err); goto err_out; } diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 124f3345420f..da50e87921bc 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -1665,8 +1665,12 @@ static u8 get_iscsi_dcb_priority(struct net_device *ndev) return 0; if (caps & DCB_CAP_DCBX_VER_IEEE) { - iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY; + iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_STREAM; rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app); + if (!rv) { + iscsi_dcb_app.selector = IEEE_8021QAZ_APP_SEL_ANY; + rv = dcb_ieee_getapp_mask(ndev, &iscsi_dcb_app); + } } else if (caps & DCB_CAP_DCBX_VER_CEE) { iscsi_dcb_app.selector = DCB_APP_IDTYPE_PORTNUM; rv = dcb_getapp(ndev, &iscsi_dcb_app); @@ -2070,7 +2074,7 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev) struct net_device *ndev = cdev->ports[0]; struct cxgbi_tag_format tformat; unsigned int ppmax; - int i; + int i, err; if (!lldi->vr->iscsi.size) { pr_warn("%s, iscsi NOT enabled, check config!\n", ndev->name); @@ -2086,8 +2090,17 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev) & 0xF; cxgbi_tagmask_check(lldi->iscsi_tagmask, &tformat); - cxgbi_ddp_ppm_setup(lldi->iscsi_ppm, cdev, &tformat, ppmax, - lldi->iscsi_llimit, lldi->vr->iscsi.start, 2); + pr_info("iscsi_edram.start 0x%x iscsi_edram.size 0x%x", + lldi->vr->ppod_edram.start, lldi->vr->ppod_edram.size); + + err = cxgbi_ddp_ppm_setup(lldi->iscsi_ppm, cdev, &tformat, + lldi->vr->iscsi.size, lldi->iscsi_llimit, + lldi->vr->iscsi.start, 2, + lldi->vr->ppod_edram.start, + lldi->vr->ppod_edram.size); + + if (err < 0) + return err; cdev->csk_ddp_setup_digest = ddp_setup_conn_digest; cdev->csk_ddp_setup_pgidx = ddp_setup_conn_pgidx; @@ -2141,7 +2154,7 @@ static void *t4_uld_add(const struct cxgb4_lld_info *lldi) rc = cxgb4i_ddp_init(cdev); if (rc) { - pr_info("t4 0x%p ddp init failed.\n", cdev); + pr_info("t4 0x%p ddp init failed %d.\n", cdev, rc); goto err_out; } rc = cxgb4i_ofld_init(cdev); @@ -2251,7 +2264,8 @@ cxgb4_dcb_change_notify(struct notifier_block *self, unsigned long val, u8 priority; if (iscsi_app->dcbx & DCB_CAP_DCBX_VER_IEEE) { - if (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY) + if ((iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_STREAM) && + (iscsi_app->app.selector != IEEE_8021QAZ_APP_SEL_ANY)) return NOTIFY_DONE; priority = iscsi_app->app.priority; diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index 7d43e014bd21..3e17af8aedeb 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -1285,14 +1285,15 @@ EXPORT_SYMBOL_GPL(cxgbi_ddp_set_one_ppod); static unsigned char padding[4]; -void cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev, - struct cxgbi_tag_format *tformat, unsigned int ppmax, - unsigned int llimit, unsigned int start, - unsigned int rsvd_factor) +int cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev, + struct cxgbi_tag_format *tformat, + unsigned int iscsi_size, unsigned int llimit, + unsigned int start, unsigned int rsvd_factor, + unsigned int edram_start, unsigned int edram_size) { int err = cxgbi_ppm_init(ppm_pp, cdev->ports[0], cdev->pdev, - cdev->lldev, tformat, ppmax, llimit, start, - rsvd_factor); + cdev->lldev, tformat, iscsi_size, llimit, start, + rsvd_factor, edram_start, edram_size); if (err >= 0) { struct cxgbi_ppm *ppm = (struct cxgbi_ppm *)(*ppm_pp); @@ -1304,6 +1305,8 @@ void cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev, } else { cdev->flags |= CXGBI_FLAG_DDP_OFF; } + + return err; } EXPORT_SYMBOL_GPL(cxgbi_ddp_ppm_setup); diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h index 1917ff57651d..84b96af52655 100644 --- a/drivers/scsi/cxgbi/libcxgbi.h +++ b/drivers/scsi/cxgbi/libcxgbi.h @@ -617,8 +617,9 @@ void cxgbi_ddp_page_size_factor(int *); void cxgbi_ddp_set_one_ppod(struct cxgbi_pagepod *, struct cxgbi_task_tag_info *, struct scatterlist **sg_pp, unsigned int *sg_off); -void cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *, - struct cxgbi_tag_format *, unsigned int ppmax, - unsigned int llimit, unsigned int start, - unsigned int rsvd_factor); +int cxgbi_ddp_ppm_setup(void **ppm_pp, struct cxgbi_device *cdev, + struct cxgbi_tag_format *tformat, + unsigned int iscsi_size, unsigned int llimit, + unsigned int start, unsigned int rsvd_factor, + unsigned int edram_start, unsigned int edram_size); #endif /*__LIBCXGBI_H__*/ diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index b1f4724efde2..93ef97af22df 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -753,10 +753,13 @@ static void term_intr(struct cxlflash_cfg *cfg, enum undo_level level, /* SISL_MSI_ASYNC_ERROR is setup only for the primary HWQ */ if (index == PRIMARY_HWQ) cfg->ops->unmap_afu_irq(hwq->ctx_cookie, 3, hwq); + /* fall through */ case UNMAP_TWO: cfg->ops->unmap_afu_irq(hwq->ctx_cookie, 2, hwq); + /* fall through */ case UNMAP_ONE: cfg->ops->unmap_afu_irq(hwq->ctx_cookie, 1, hwq); + /* fall through */ case FREE_IRQ: cfg->ops->free_afu_irqs(hwq->ctx_cookie); /* fall through */ @@ -973,14 +976,18 @@ static void cxlflash_remove(struct pci_dev *pdev) switch (cfg->init_state) { case INIT_STATE_CDEV: cxlflash_release_chrdev(cfg); + /* fall through */ case INIT_STATE_SCSI: cxlflash_term_local_luns(cfg); scsi_remove_host(cfg->host); + /* fall through */ case INIT_STATE_AFU: term_afu(cfg); + /* fall through */ case INIT_STATE_PCI: cfg->ops->destroy_afu(cfg->afu_cookie); pci_disable_device(pdev); + /* fall through */ case INIT_STATE_NONE: free_mem(cfg); scsi_host_put(cfg->host); @@ -2353,11 +2360,11 @@ retry: cxlflash_schedule_async_reset(cfg); break; } - /* fall through to retry */ + /* fall through - to retry */ case -EAGAIN: if (++nretry < 2) goto retry; - /* fall through to exit */ + /* fall through - to exit */ default: break; } @@ -3017,6 +3024,7 @@ retry: wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); if (cfg->state == STATE_NORMAL) goto retry; + /* else, fall through */ default: /* Ideally should not happen */ dev_err(dev, "%s: Device is not ready, state=%d\n", diff --git a/drivers/scsi/cxlflash/ocxl_hw.c b/drivers/scsi/cxlflash/ocxl_hw.c index 96740c6fcd92..7018cd802569 100644 --- a/drivers/scsi/cxlflash/ocxl_hw.c +++ b/drivers/scsi/cxlflash/ocxl_hw.c @@ -12,6 +12,7 @@ #include <linux/idr.h> #include <linux/module.h> #include <linux/mount.h> +#include <linux/pseudo_fs.h> #include <linux/poll.h> #include <linux/sched/signal.h> @@ -31,31 +32,15 @@ static int ocxlflash_fs_cnt; static struct vfsmount *ocxlflash_vfs_mount; -static const struct dentry_operations ocxlflash_fs_dops = { - .d_dname = simple_dname, -}; - -/* - * ocxlflash_fs_mount() - mount the pseudo-filesystem - * @fs_type: File system type. - * @flags: Flags for the filesystem. - * @dev_name: Device name associated with the filesystem. - * @data: Data pointer. - * - * Return: pointer to the directory entry structure - */ -static struct dentry *ocxlflash_fs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int ocxlflash_fs_init_fs_context(struct fs_context *fc) { - return mount_pseudo(fs_type, "ocxlflash:", NULL, &ocxlflash_fs_dops, - OCXLFLASH_FS_MAGIC); + return init_pseudo(fc, OCXLFLASH_FS_MAGIC) ? 0 : -ENOMEM; } static struct file_system_type ocxlflash_fs_type = { .name = "ocxlflash", .owner = THIS_MODULE, - .mount = ocxlflash_fs_mount, + .init_fs_context = ocxlflash_fs_init_fs_context, .kill_sb = kill_anon_super, }; diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index f0066f8a1786..f32da0ca529e 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -40,6 +40,7 @@ #define ALUA_FAILOVER_TIMEOUT 60 #define ALUA_FAILOVER_RETRIES 5 #define ALUA_RTPG_DELAY_MSECS 5 +#define ALUA_RTPG_RETRY_DELAY 2 /* device handler flags */ #define ALUA_OPTIMIZE_STPG 0x01 @@ -511,6 +512,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) unsigned int tpg_desc_tbl_off; unsigned char orig_transition_tmo; unsigned long flags; + bool transitioning_sense = false; if (!pg->expiry) { unsigned long transition_tmo = ALUA_FAILOVER_TIMEOUT * HZ; @@ -571,13 +573,19 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) goto retry; } /* - * Retry on ALUA state transition or if any - * UNIT ATTENTION occurred. + * If the array returns with 'ALUA state transition' + * sense code here it cannot return RTPG data during + * transition. So set the state to 'transitioning' directly. */ if (sense_hdr.sense_key == NOT_READY && - sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) - err = SCSI_DH_RETRY; - else if (sense_hdr.sense_key == UNIT_ATTENTION) + sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a) { + transitioning_sense = true; + goto skip_rtpg; + } + /* + * Retry on any other UNIT ATTENTION occurred. + */ + if (sense_hdr.sense_key == UNIT_ATTENTION) err = SCSI_DH_RETRY; if (err == SCSI_DH_RETRY && pg->expiry != 0 && time_before(jiffies, pg->expiry)) { @@ -665,7 +673,11 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) off = 8 + (desc[7] * 4); } + skip_rtpg: spin_lock_irqsave(&pg->lock, flags); + if (transitioning_sense) + pg->state = SCSI_ACCESS_STATE_TRANSITIONING; + sdev_printk(KERN_INFO, sdev, "%s: port group %02x state %c %s supports %c%c%c%c%c%c%c\n", ALUA_DH_NAME, pg->group_id, print_alua_state(pg->state), @@ -682,7 +694,7 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg) case SCSI_ACCESS_STATE_TRANSITIONING: if (time_before(jiffies, pg->expiry)) { /* State transition, retry */ - pg->interval = 2; + pg->interval = ALUA_RTPG_RETRY_DELAY; err = SCSI_DH_RETRY; } else { struct alua_dh_data *h; @@ -807,6 +819,8 @@ static void alua_rtpg_work(struct work_struct *work) spin_lock_irqsave(&pg->lock, flags); pg->flags &= ~ALUA_PG_RUNNING; pg->flags |= ALUA_PG_RUN_RTPG; + if (!pg->interval) + pg->interval = ALUA_RTPG_RETRY_DELAY; spin_unlock_irqrestore(&pg->lock, flags); queue_delayed_work(kaluad_wq, &pg->rtpg_work, pg->interval * HZ); @@ -818,6 +832,8 @@ static void alua_rtpg_work(struct work_struct *work) spin_lock_irqsave(&pg->lock, flags); if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) { pg->flags &= ~ALUA_PG_RUNNING; + if (!pg->interval && !(pg->flags & ALUA_PG_RUN_RTPG)) + pg->interval = ALUA_RTPG_RETRY_DELAY; pg->flags |= ALUA_PG_RUN_RTPG; spin_unlock_irqrestore(&pg->lock, flags); queue_delayed_work(kaluad_wq, &pg->rtpg_work, diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 65f1fe343c64..5efc959493ec 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -546,6 +546,8 @@ static void send_mode_select(struct work_struct *work) spin_unlock(&ctlr->ms_lock); retry: + memset(cdb, 0, sizeof(cdb)); + data_size = rdac_failover_get(ctlr, &list, cdb); RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c index 950cd92df2ff..eb7d139ffc00 100644 --- a/drivers/scsi/esas2r/esas2r_init.c +++ b/drivers/scsi/esas2r/esas2r_init.c @@ -762,14 +762,10 @@ u32 esas2r_get_uncached_size(struct esas2r_adapter *a) static void esas2r_init_pci_cfg_space(struct esas2r_adapter *a) { - int pcie_cap_reg; - - pcie_cap_reg = pci_find_capability(a->pcid, PCI_CAP_ID_EXP); - if (pcie_cap_reg) { + if (pci_is_pcie(a->pcid)) { u16 devcontrol; - pci_read_config_word(a->pcid, pcie_cap_reg + PCI_EXP_DEVCTL, - &devcontrol); + pcie_capability_read_word(a->pcid, PCI_EXP_DEVCTL, &devcontrol); if ((devcontrol & PCI_EXP_DEVCTL_READRQ) > PCI_EXP_DEVCTL_READRQ_512B) { @@ -778,9 +774,8 @@ static void esas2r_init_pci_cfg_space(struct esas2r_adapter *a) devcontrol &= ~PCI_EXP_DEVCTL_READRQ; devcontrol |= PCI_EXP_DEVCTL_READRQ_512B; - pci_write_config_word(a->pcid, - pcie_cap_reg + PCI_EXP_DEVCTL, - devcontrol); + pcie_capability_write_word(a->pcid, PCI_EXP_DEVCTL, + devcontrol); } } } diff --git a/drivers/scsi/esas2r/esas2r_ioctl.c b/drivers/scsi/esas2r/esas2r_ioctl.c index 3d130523c288..442c5e70a7b4 100644 --- a/drivers/scsi/esas2r/esas2r_ioctl.c +++ b/drivers/scsi/esas2r/esas2r_ioctl.c @@ -757,7 +757,6 @@ static int hba_ioctl_callback(struct esas2r_adapter *a, struct atto_hba_get_adapter_info *gai = &hi->data.get_adap_info; - int pcie_cap_reg; if (hi->flags & HBAF_TUNNEL) { hi->status = ATTO_STS_UNSUPPORTED; @@ -784,17 +783,14 @@ static int hba_ioctl_callback(struct esas2r_adapter *a, gai->pci.dev_num = PCI_SLOT(a->pcid->devfn); gai->pci.func_num = PCI_FUNC(a->pcid->devfn); - pcie_cap_reg = pci_find_capability(a->pcid, PCI_CAP_ID_EXP); - if (pcie_cap_reg) { + if (pci_is_pcie(a->pcid)) { u16 stat; u32 caps; - pci_read_config_word(a->pcid, - pcie_cap_reg + PCI_EXP_LNKSTA, - &stat); - pci_read_config_dword(a->pcid, - pcie_cap_reg + PCI_EXP_LNKCAP, - &caps); + pcie_capability_read_word(a->pcid, PCI_EXP_LNKSTA, + &stat); + pcie_capability_read_dword(a->pcid, PCI_EXP_LNKCAP, + &caps); gai->pci.link_speed_curr = (u8)(stat & PCI_EXP_LNKSTA_CLS); diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 76e7ca864d6a..bb88995a12c7 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -371,6 +371,7 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd) struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); struct scatterlist *sg = scsi_sglist(cmd); int total = 0, i; + struct scatterlist *s; if (cmd->sc_data_direction == DMA_NONE) return; @@ -381,16 +382,18 @@ static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd) * a dma address, so perform an identity mapping. */ spriv->num_sg = scsi_sg_count(cmd); - for (i = 0; i < spriv->num_sg; i++) { - sg[i].dma_address = (uintptr_t)sg_virt(&sg[i]); - total += sg_dma_len(&sg[i]); + + scsi_for_each_sg(cmd, s, spriv->num_sg, i) { + s->dma_address = (uintptr_t)sg_virt(s); + total += sg_dma_len(s); } } else { spriv->num_sg = scsi_dma_map(cmd); - for (i = 0; i < spriv->num_sg; i++) - total += sg_dma_len(&sg[i]); + scsi_for_each_sg(cmd, s, spriv->num_sg, i) + total += sg_dma_len(s); } spriv->cur_residue = sg_dma_len(sg); + spriv->prv_sg = NULL; spriv->cur_sg = sg; spriv->tot_residue = total; } @@ -444,7 +447,8 @@ static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent, p->tot_residue = 0; } if (!p->cur_residue && p->tot_residue) { - p->cur_sg++; + p->prv_sg = p->cur_sg; + p->cur_sg = sg_next(p->cur_sg); p->cur_residue = sg_dma_len(p->cur_sg); } } @@ -465,6 +469,7 @@ static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent) return; } ent->saved_cur_residue = spriv->cur_residue; + ent->saved_prv_sg = spriv->prv_sg; ent->saved_cur_sg = spriv->cur_sg; ent->saved_tot_residue = spriv->tot_residue; } @@ -479,6 +484,7 @@ static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent) return; } spriv->cur_residue = ent->saved_cur_residue; + spriv->prv_sg = ent->saved_prv_sg; spriv->cur_sg = ent->saved_cur_sg; spriv->tot_residue = ent->saved_tot_residue; } @@ -1647,7 +1653,7 @@ static int esp_msgin_process(struct esp *esp) spriv = ESP_CMD_PRIV(ent->cmd); if (spriv->cur_residue == sg_dma_len(spriv->cur_sg)) { - spriv->cur_sg--; + spriv->cur_sg = spriv->prv_sg; spriv->cur_residue = 1; } else spriv->cur_residue++; diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h index aa87a6b72dcc..91b32f2a1a1b 100644 --- a/drivers/scsi/esp_scsi.h +++ b/drivers/scsi/esp_scsi.h @@ -251,6 +251,7 @@ struct esp_cmd_priv { int num_sg; int cur_residue; + struct scatterlist *prv_sg; struct scatterlist *cur_sg; int tot_residue; }; @@ -273,6 +274,7 @@ struct esp_cmd_entry { struct scsi_cmnd *cmd; unsigned int saved_cur_residue; + struct scatterlist *saved_prv_sg; struct scatterlist *saved_cur_sg; unsigned int saved_tot_residue; diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 00dd47bcbb1e..25dae9f0b205 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1250,15 +1250,21 @@ static int __init fcoe_if_init(void) /* attach to scsi transport */ fcoe_nport_scsi_transport = fc_attach_transport(&fcoe_nport_fc_functions); + if (!fcoe_nport_scsi_transport) + goto err; + fcoe_vport_scsi_transport = fc_attach_transport(&fcoe_vport_fc_functions); - - if (!fcoe_nport_scsi_transport) { - printk(KERN_ERR "fcoe: Failed to attach to the FC transport\n"); - return -ENODEV; - } + if (!fcoe_vport_scsi_transport) + goto err_vport; return 0; + +err_vport: + fc_release_transport(fcoe_nport_scsi_transport); +err: + printk(KERN_ERR "fcoe: Failed to attach to the FC transport\n"); + return -ENODEV; } /** @@ -1522,8 +1528,7 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) return -ENOMEM; } frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; - cp = kmap_atomic(skb_frag_page(frag)) - + frag->page_offset; + cp = kmap_atomic(skb_frag_page(frag)) + skb_frag_off(frag); } else { cp = skb_put(skb, tlen); } @@ -1618,7 +1623,6 @@ static inline int fcoe_filter_frames(struct fc_lport *lport, else fr_flags(fp) |= FCPHF_CRC_UNCHECKED; - fh = (struct fc_frame_header *) skb_transport_header(skb); fh = fc_frame_header_get(fp); if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && fh->fh_type == FC_TYPE_FCP) return 0; diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index 590ec8009f52..1791a393795d 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -1019,7 +1019,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) { struct fcoe_fcf *fcf; struct fcoe_fcf new; - unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV); + unsigned long sol_tov = msecs_to_jiffies(FCOE_CTLR_SOL_TOV); int first = 0; int mtu_valid; int found = 0; @@ -2005,7 +2005,7 @@ EXPORT_SYMBOL_GPL(fcoe_wwn_from_mac); */ static inline struct fcoe_rport *fcoe_ctlr_rport(struct fc_rport_priv *rdata) { - return (struct fcoe_rport *)(rdata + 1); + return container_of(rdata, struct fcoe_rport, rdata); } /** @@ -2269,7 +2269,7 @@ static void fcoe_ctlr_vn_start(struct fcoe_ctlr *fip) */ static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip, struct sk_buff *skb, - struct fc_rport_priv *rdata) + struct fcoe_rport *frport) { struct fip_header *fiph; struct fip_desc *desc = NULL; @@ -2277,16 +2277,12 @@ static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip, struct fip_wwn_desc *wwn = NULL; struct fip_vn_desc *vn = NULL; struct fip_size_desc *size = NULL; - struct fcoe_rport *frport; size_t rlen; size_t dlen; u32 desc_mask = 0; u32 dtype; u8 sub; - memset(rdata, 0, sizeof(*rdata) + sizeof(*frport)); - frport = fcoe_ctlr_rport(rdata); - fiph = (struct fip_header *)skb->data; frport->flags = ntohs(fiph->fip_flags); @@ -2349,15 +2345,17 @@ static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip, if (dlen != sizeof(struct fip_wwn_desc)) goto len_err; wwn = (struct fip_wwn_desc *)desc; - rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn); + frport->rdata.ids.node_name = + get_unaligned_be64(&wwn->fd_wwn); break; case FIP_DT_VN_ID: if (dlen != sizeof(struct fip_vn_desc)) goto len_err; vn = (struct fip_vn_desc *)desc; memcpy(frport->vn_mac, vn->fd_mac, ETH_ALEN); - rdata->ids.port_id = ntoh24(vn->fd_fc_id); - rdata->ids.port_name = get_unaligned_be64(&vn->fd_wwpn); + frport->rdata.ids.port_id = ntoh24(vn->fd_fc_id); + frport->rdata.ids.port_name = + get_unaligned_be64(&vn->fd_wwpn); break; case FIP_DT_FC4F: if (dlen != sizeof(struct fip_fc4_feat)) @@ -2403,16 +2401,14 @@ static void fcoe_ctlr_vn_send_claim(struct fcoe_ctlr *fip) /** * fcoe_ctlr_vn_probe_req() - handle incoming VN2VN probe request. * @fip: The FCoE controller - * @rdata: parsed remote port with frport from the probe request + * @frport: parsed FCoE rport from the probe request * * Called with ctlr_mutex held. */ static void fcoe_ctlr_vn_probe_req(struct fcoe_ctlr *fip, - struct fc_rport_priv *rdata) + struct fcoe_rport *frport) { - struct fcoe_rport *frport = fcoe_ctlr_rport(rdata); - - if (rdata->ids.port_id != fip->port_id) + if (frport->rdata.ids.port_id != fip->port_id) return; switch (fip->state) { @@ -2432,7 +2428,7 @@ static void fcoe_ctlr_vn_probe_req(struct fcoe_ctlr *fip, * Probe's REC bit is not set. * If we don't reply, we will change our address. */ - if (fip->lp->wwpn > rdata->ids.port_name && + if (fip->lp->wwpn > frport->rdata.ids.port_name && !(frport->flags & FIP_FL_REC_OR_P2P)) { LIBFCOE_FIP_DBG(fip, "vn_probe_req: " "port_id collision\n"); @@ -2456,14 +2452,14 @@ static void fcoe_ctlr_vn_probe_req(struct fcoe_ctlr *fip, /** * fcoe_ctlr_vn_probe_reply() - handle incoming VN2VN probe reply. * @fip: The FCoE controller - * @rdata: parsed remote port with frport from the probe request + * @frport: parsed FCoE rport from the probe request * * Called with ctlr_mutex held. */ static void fcoe_ctlr_vn_probe_reply(struct fcoe_ctlr *fip, - struct fc_rport_priv *rdata) + struct fcoe_rport *frport) { - if (rdata->ids.port_id != fip->port_id) + if (frport->rdata.ids.port_id != fip->port_id) return; switch (fip->state) { case FIP_ST_VNMP_START: @@ -2486,11 +2482,11 @@ static void fcoe_ctlr_vn_probe_reply(struct fcoe_ctlr *fip, /** * fcoe_ctlr_vn_add() - Add a VN2VN entry to the list, based on a claim reply. * @fip: The FCoE controller - * @new: newly-parsed remote port with frport as a template for new rdata + * @new: newly-parsed FCoE rport as a template for new rdata * * Called with ctlr_mutex held. */ -static void fcoe_ctlr_vn_add(struct fcoe_ctlr *fip, struct fc_rport_priv *new) +static void fcoe_ctlr_vn_add(struct fcoe_ctlr *fip, struct fcoe_rport *new) { struct fc_lport *lport = fip->lp; struct fc_rport_priv *rdata; @@ -2498,7 +2494,7 @@ static void fcoe_ctlr_vn_add(struct fcoe_ctlr *fip, struct fc_rport_priv *new) struct fcoe_rport *frport; u32 port_id; - port_id = new->ids.port_id; + port_id = new->rdata.ids.port_id; if (port_id == fip->port_id) return; @@ -2515,22 +2511,28 @@ static void fcoe_ctlr_vn_add(struct fcoe_ctlr *fip, struct fc_rport_priv *new) rdata->disc_id = lport->disc.disc_id; ids = &rdata->ids; - if ((ids->port_name != -1 && ids->port_name != new->ids.port_name) || - (ids->node_name != -1 && ids->node_name != new->ids.node_name)) { + if ((ids->port_name != -1 && + ids->port_name != new->rdata.ids.port_name) || + (ids->node_name != -1 && + ids->node_name != new->rdata.ids.node_name)) { mutex_unlock(&rdata->rp_mutex); LIBFCOE_FIP_DBG(fip, "vn_add rport logoff %6.6x\n", port_id); fc_rport_logoff(rdata); mutex_lock(&rdata->rp_mutex); } - ids->port_name = new->ids.port_name; - ids->node_name = new->ids.node_name; + ids->port_name = new->rdata.ids.port_name; + ids->node_name = new->rdata.ids.node_name; mutex_unlock(&rdata->rp_mutex); frport = fcoe_ctlr_rport(rdata); LIBFCOE_FIP_DBG(fip, "vn_add rport %6.6x %s state %d\n", port_id, frport->fcoe_len ? "old" : "new", rdata->rp_state); - *frport = *fcoe_ctlr_rport(new); + frport->fcoe_len = new->fcoe_len; + frport->flags = new->flags; + frport->login_count = new->login_count; + memcpy(frport->enode_mac, new->enode_mac, ETH_ALEN); + memcpy(frport->vn_mac, new->vn_mac, ETH_ALEN); frport->time = 0; } @@ -2562,16 +2564,14 @@ static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *fip, u32 port_id, u8 *mac) /** * fcoe_ctlr_vn_claim_notify() - handle received FIP VN2VN Claim Notification * @fip: The FCoE controller - * @new: newly-parsed remote port with frport as a template for new rdata + * @new: newly-parsed FCoE rport as a template for new rdata * * Called with ctlr_mutex held. */ static void fcoe_ctlr_vn_claim_notify(struct fcoe_ctlr *fip, - struct fc_rport_priv *new) + struct fcoe_rport *new) { - struct fcoe_rport *frport = fcoe_ctlr_rport(new); - - if (frport->flags & FIP_FL_REC_OR_P2P) { + if (new->flags & FIP_FL_REC_OR_P2P) { LIBFCOE_FIP_DBG(fip, "send probe req for P2P/REC\n"); fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); return; @@ -2580,7 +2580,7 @@ static void fcoe_ctlr_vn_claim_notify(struct fcoe_ctlr *fip, case FIP_ST_VNMP_START: case FIP_ST_VNMP_PROBE1: case FIP_ST_VNMP_PROBE2: - if (new->ids.port_id == fip->port_id) { + if (new->rdata.ids.port_id == fip->port_id) { LIBFCOE_FIP_DBG(fip, "vn_claim_notify: " "restart, state %d\n", fip->state); @@ -2589,8 +2589,8 @@ static void fcoe_ctlr_vn_claim_notify(struct fcoe_ctlr *fip, break; case FIP_ST_VNMP_CLAIM: case FIP_ST_VNMP_UP: - if (new->ids.port_id == fip->port_id) { - if (new->ids.port_name > fip->lp->wwpn) { + if (new->rdata.ids.port_id == fip->port_id) { + if (new->rdata.ids.port_name > fip->lp->wwpn) { LIBFCOE_FIP_DBG(fip, "vn_claim_notify: " "restart, port_id collision\n"); fcoe_ctlr_vn_restart(fip); @@ -2602,15 +2602,16 @@ static void fcoe_ctlr_vn_claim_notify(struct fcoe_ctlr *fip, break; } LIBFCOE_FIP_DBG(fip, "vn_claim_notify: send reply to %x\n", - new->ids.port_id); - fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_REP, frport->enode_mac, - min((u32)frport->fcoe_len, + new->rdata.ids.port_id); + fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_REP, new->enode_mac, + min((u32)new->fcoe_len, fcoe_ctlr_fcoe_size(fip))); fcoe_ctlr_vn_add(fip, new); break; default: LIBFCOE_FIP_DBG(fip, "vn_claim_notify: " - "ignoring claim from %x\n", new->ids.port_id); + "ignoring claim from %x\n", + new->rdata.ids.port_id); break; } } @@ -2618,15 +2619,15 @@ static void fcoe_ctlr_vn_claim_notify(struct fcoe_ctlr *fip, /** * fcoe_ctlr_vn_claim_resp() - handle received Claim Response * @fip: The FCoE controller that received the frame - * @new: newly-parsed remote port with frport from the Claim Response + * @new: newly-parsed FCoE rport from the Claim Response * * Called with ctlr_mutex held. */ static void fcoe_ctlr_vn_claim_resp(struct fcoe_ctlr *fip, - struct fc_rport_priv *new) + struct fcoe_rport *new) { LIBFCOE_FIP_DBG(fip, "claim resp from from rport %x - state %s\n", - new->ids.port_id, fcoe_ctlr_state(fip->state)); + new->rdata.ids.port_id, fcoe_ctlr_state(fip->state)); if (fip->state == FIP_ST_VNMP_UP || fip->state == FIP_ST_VNMP_CLAIM) fcoe_ctlr_vn_add(fip, new); } @@ -2634,28 +2635,28 @@ static void fcoe_ctlr_vn_claim_resp(struct fcoe_ctlr *fip, /** * fcoe_ctlr_vn_beacon() - handle received beacon. * @fip: The FCoE controller that received the frame - * @new: newly-parsed remote port with frport from the Beacon + * @new: newly-parsed FCoE rport from the Beacon * * Called with ctlr_mutex held. */ static void fcoe_ctlr_vn_beacon(struct fcoe_ctlr *fip, - struct fc_rport_priv *new) + struct fcoe_rport *new) { struct fc_lport *lport = fip->lp; struct fc_rport_priv *rdata; struct fcoe_rport *frport; - frport = fcoe_ctlr_rport(new); - if (frport->flags & FIP_FL_REC_OR_P2P) { + if (new->flags & FIP_FL_REC_OR_P2P) { LIBFCOE_FIP_DBG(fip, "p2p beacon while in vn2vn mode\n"); fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); return; } - rdata = fc_rport_lookup(lport, new->ids.port_id); + rdata = fc_rport_lookup(lport, new->rdata.ids.port_id); if (rdata) { - if (rdata->ids.node_name == new->ids.node_name && - rdata->ids.port_name == new->ids.port_name) { + if (rdata->ids.node_name == new->rdata.ids.node_name && + rdata->ids.port_name == new->rdata.ids.port_name) { frport = fcoe_ctlr_rport(rdata); + LIBFCOE_FIP_DBG(fip, "beacon from rport %x\n", rdata->ids.port_id); if (!frport->time && fip->state == FIP_ST_VNMP_UP) { @@ -2678,7 +2679,7 @@ static void fcoe_ctlr_vn_beacon(struct fcoe_ctlr *fip, * Don't add the neighbor yet. */ LIBFCOE_FIP_DBG(fip, "beacon from new rport %x. sending claim notify\n", - new->ids.port_id); + new->rdata.ids.port_id); if (time_after(jiffies, fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT))) fcoe_ctlr_vn_send_claim(fip); @@ -2738,10 +2739,7 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb) { struct fip_header *fiph; enum fip_vn2vn_subcode sub; - struct { - struct fc_rport_priv rdata; - struct fcoe_rport frport; - } buf; + struct fcoe_rport frport = { }; int rc, vlan_id = 0; fiph = (struct fip_header *)skb->data; @@ -2757,7 +2755,7 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb) goto drop; } - rc = fcoe_ctlr_vn_parse(fip, skb, &buf.rdata); + rc = fcoe_ctlr_vn_parse(fip, skb, &frport); if (rc) { LIBFCOE_FIP_DBG(fip, "vn_recv vn_parse error %d\n", rc); goto drop; @@ -2766,19 +2764,19 @@ static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb) mutex_lock(&fip->ctlr_mutex); switch (sub) { case FIP_SC_VN_PROBE_REQ: - fcoe_ctlr_vn_probe_req(fip, &buf.rdata); + fcoe_ctlr_vn_probe_req(fip, &frport); break; case FIP_SC_VN_PROBE_REP: - fcoe_ctlr_vn_probe_reply(fip, &buf.rdata); + fcoe_ctlr_vn_probe_reply(fip, &frport); break; case FIP_SC_VN_CLAIM_NOTIFY: - fcoe_ctlr_vn_claim_notify(fip, &buf.rdata); + fcoe_ctlr_vn_claim_notify(fip, &frport); break; case FIP_SC_VN_CLAIM_REP: - fcoe_ctlr_vn_claim_resp(fip, &buf.rdata); + fcoe_ctlr_vn_claim_resp(fip, &frport); break; case FIP_SC_VN_BEACON: - fcoe_ctlr_vn_beacon(fip, &buf.rdata); + fcoe_ctlr_vn_beacon(fip, &frport); break; default: LIBFCOE_FIP_DBG(fip, "vn_recv unknown subcode %d\n", sub); @@ -2802,22 +2800,18 @@ drop: */ static int fcoe_ctlr_vlan_parse(struct fcoe_ctlr *fip, struct sk_buff *skb, - struct fc_rport_priv *rdata) + struct fcoe_rport *frport) { struct fip_header *fiph; struct fip_desc *desc = NULL; struct fip_mac_desc *macd = NULL; struct fip_wwn_desc *wwn = NULL; - struct fcoe_rport *frport; size_t rlen; size_t dlen; u32 desc_mask = 0; u32 dtype; u8 sub; - memset(rdata, 0, sizeof(*rdata) + sizeof(*frport)); - frport = fcoe_ctlr_rport(rdata); - fiph = (struct fip_header *)skb->data; frport->flags = ntohs(fiph->fip_flags); @@ -2871,7 +2865,8 @@ static int fcoe_ctlr_vlan_parse(struct fcoe_ctlr *fip, if (dlen != sizeof(struct fip_wwn_desc)) goto len_err; wwn = (struct fip_wwn_desc *)desc; - rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn); + frport->rdata.ids.node_name = + get_unaligned_be64(&wwn->fd_wwn); break; default: LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x " @@ -2957,13 +2952,13 @@ static void fcoe_ctlr_vlan_send(struct fcoe_ctlr *fip, /** * fcoe_ctlr_vlan_disk_reply() - send FIP VLAN Discovery Notification. * @fip: The FCoE controller + * @frport: The newly-parsed FCoE rport from the Discovery Request * * Called with ctlr_mutex held. */ static void fcoe_ctlr_vlan_disc_reply(struct fcoe_ctlr *fip, - struct fc_rport_priv *rdata) + struct fcoe_rport *frport) { - struct fcoe_rport *frport = fcoe_ctlr_rport(rdata); enum fip_vlan_subcode sub = FIP_SC_VL_NOTE; if (fip->mode == FIP_MODE_VN2VN) @@ -2982,22 +2977,19 @@ static int fcoe_ctlr_vlan_recv(struct fcoe_ctlr *fip, struct sk_buff *skb) { struct fip_header *fiph; enum fip_vlan_subcode sub; - struct { - struct fc_rport_priv rdata; - struct fcoe_rport frport; - } buf; + struct fcoe_rport frport = { }; int rc; fiph = (struct fip_header *)skb->data; sub = fiph->fip_subcode; - rc = fcoe_ctlr_vlan_parse(fip, skb, &buf.rdata); + rc = fcoe_ctlr_vlan_parse(fip, skb, &frport); if (rc) { LIBFCOE_FIP_DBG(fip, "vlan_recv vlan_parse error %d\n", rc); goto drop; } mutex_lock(&fip->ctlr_mutex); if (sub == FIP_SC_VL_REQ) - fcoe_ctlr_vlan_disc_reply(fip, &buf.rdata); + fcoe_ctlr_vlan_disc_reply(fip, &frport); mutex_unlock(&fip->ctlr_mutex); drop: diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index ba4603d76284..a20ddc301c89 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -308,7 +308,7 @@ EXPORT_SYMBOL_GPL(fcoe_get_wwn); u32 fcoe_fc_crc(struct fc_frame *fp) { struct sk_buff *skb = fp_skb(fp); - struct skb_frag_struct *frag; + skb_frag_t *frag; unsigned char *data; unsigned long off, len, clen; u32 crc; @@ -318,7 +318,7 @@ u32 fcoe_fc_crc(struct fc_frame *fp) for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { frag = &skb_shinfo(skb)->frags[i]; - off = frag->page_offset; + off = skb_frag_off(frag); len = skb_frag_size(frag); while (len > 0) { clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c new file mode 100644 index 000000000000..772bdc93930a --- /dev/null +++ b/drivers/scsi/fdomain.c @@ -0,0 +1,597 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Future Domain TMC-16x0 and TMC-3260 SCSI host adapters + * Copyright 2019 Ondrej Zary + * + * Original driver by + * Rickard E. Faith, faith@cs.unc.edu + * + * Future Domain BIOS versions supported for autodetect: + * 2.0, 3.0, 3.2, 3.4 (1.0), 3.5 (2.0), 3.6, 3.61 + * Chips supported: + * TMC-1800, TMC-18C50, TMC-18C30, TMC-36C70 + * Boards supported: + * Future Domain TMC-1650, TMC-1660, TMC-1670, TMC-1680, TMC-1610M/MER/MEX + * Future Domain TMC-3260 (PCI) + * Quantum ISA-200S, ISA-250MG + * Adaptec AHA-2920A (PCI) [BUT *NOT* AHA-2920C -- use aic7xxx instead] + * IBM ? + * + * NOTE: + * + * The Adaptec AHA-2920C has an Adaptec AIC-7850 chip on it. + * Use the aic7xxx driver for this board. + * + * The Adaptec AHA-2920A has a Future Domain chip on it, so this is the right + * driver for that card. Unfortunately, the boxes will probably just say + * "2920", so you'll have to look on the card for a Future Domain logo, or a + * letter after the 2920. + * + * If you have a TMC-8xx or TMC-9xx board, then this is not the driver for + * your board. + * + * DESCRIPTION: + * + * This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680 + * TMC-1650/1670, and TMC-3260 SCSI host adapters. The 1650 and 1670 have a + * 25-pin external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin + * high-density external connector. The 1670 and 1680 have floppy disk + * controllers built in. The TMC-3260 is a PCI bus card. + * + * Future Domain's older boards are based on the TMC-1800 chip, and this + * driver was originally written for a TMC-1680 board with the TMC-1800 chip. + * More recently, boards are being produced with the TMC-18C50 and TMC-18C30 + * chips. + * + * Please note that the drive ordering that Future Domain implemented in BIOS + * versions 3.4 and 3.5 is the opposite of the order (currently) used by the + * rest of the SCSI industry. + * + * + * REFERENCES USED: + * + * "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation, + * 1990. + * + * "Technical Reference Manual: 18C50 SCSI Host Adapter Chip", Future Domain + * Corporation, January 1992. + * + * "LXT SCSI Products: Specifications and OEM Technical Manual (Revision + * B/September 1991)", Maxtor Corporation, 1991. + * + * "7213S product Manual (Revision P3)", Maxtor Corporation, 1992. + * + * "Draft Proposed American National Standard: Small Computer System + * Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109, + * revision 10h, October 17, 1991) + * + * Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric + * Youngdale (ericy@cais.com), 1992. + * + * Private communication, Tuong Le (Future Domain Engineering department), + * 1994. (Disk geometry computations for Future Domain BIOS version 3.4, and + * TMC-18C30 detection.) + * + * Hogan, Thom. The Programmer's PC Sourcebook. Microsoft Press, 1988. Page + * 60 (2.39: Disk Partition Table Layout). + * + * "18C30 Technical Reference Manual", Future Domain Corporation, 1993, page + * 6-1. + */ + +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/workqueue.h> +#include <scsi/scsicam.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include "fdomain.h" + +/* + * FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the + * 18C30 chip have a 2k cache). When this many 512 byte blocks are filled by + * the SCSI device, an interrupt will be raised. Therefore, this could be as + * low as 0, or as high as 16. Note, however, that values which are too high + * or too low seem to prevent any interrupts from occurring, and thereby lock + * up the machine. + */ +#define FIFO_COUNT 2 /* Number of 512 byte blocks before INTR */ +#define PARITY_MASK ACTL_PAREN /* Parity enabled, 0 = disabled */ + +enum chip_type { + unknown = 0x00, + tmc1800 = 0x01, + tmc18c50 = 0x02, + tmc18c30 = 0x03, +}; + +struct fdomain { + int base; + struct scsi_cmnd *cur_cmd; + enum chip_type chip; + struct work_struct work; +}; + +static inline void fdomain_make_bus_idle(struct fdomain *fd) +{ + outb(0, fd->base + REG_BCTL); + outb(0, fd->base + REG_MCTL); + if (fd->chip == tmc18c50 || fd->chip == tmc18c30) + /* Clear forced intr. */ + outb(ACTL_RESET | ACTL_CLRFIRQ | PARITY_MASK, + fd->base + REG_ACTL); + else + outb(ACTL_RESET | PARITY_MASK, fd->base + REG_ACTL); +} + +static enum chip_type fdomain_identify(int port) +{ + u16 id = inb(port + REG_ID_LSB) | inb(port + REG_ID_MSB) << 8; + + switch (id) { + case 0x6127: + return tmc1800; + case 0x60e9: /* 18c50 or 18c30 */ + break; + default: + return unknown; + } + + /* Try to toggle 32-bit mode. This only works on an 18c30 chip. */ + outb(CFG2_32BIT, port + REG_CFG2); + if ((inb(port + REG_CFG2) & CFG2_32BIT)) { + outb(0, port + REG_CFG2); + if ((inb(port + REG_CFG2) & CFG2_32BIT) == 0) + return tmc18c30; + } + /* If that failed, we are an 18c50. */ + return tmc18c50; +} + +static int fdomain_test_loopback(int base) +{ + int i; + + for (i = 0; i < 255; i++) { + outb(i, base + REG_LOOPBACK); + if (inb(base + REG_LOOPBACK) != i) + return 1; + } + + return 0; +} + +static void fdomain_reset(int base) +{ + outb(BCTL_RST, base + REG_BCTL); + mdelay(20); + outb(0, base + REG_BCTL); + mdelay(1150); + outb(0, base + REG_MCTL); + outb(PARITY_MASK, base + REG_ACTL); +} + +static int fdomain_select(struct Scsi_Host *sh, int target) +{ + int status; + unsigned long timeout; + struct fdomain *fd = shost_priv(sh); + + outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL); + outb(BIT(sh->this_id) | BIT(target), fd->base + REG_SCSI_DATA_NOACK); + + /* Stop arbitration and enable parity */ + outb(PARITY_MASK, fd->base + REG_ACTL); + + timeout = 350; /* 350 msec */ + + do { + status = inb(fd->base + REG_BSTAT); + if (status & BSTAT_BSY) { + /* Enable SCSI Bus */ + /* (on error, should make bus idle with 0) */ + outb(BCTL_BUSEN, fd->base + REG_BCTL); + return 0; + } + mdelay(1); + } while (--timeout); + fdomain_make_bus_idle(fd); + return 1; +} + +static void fdomain_finish_cmd(struct fdomain *fd, int result) +{ + outb(0, fd->base + REG_ICTL); + fdomain_make_bus_idle(fd); + fd->cur_cmd->result = result; + fd->cur_cmd->scsi_done(fd->cur_cmd); + fd->cur_cmd = NULL; +} + +static void fdomain_read_data(struct scsi_cmnd *cmd) +{ + struct fdomain *fd = shost_priv(cmd->device->host); + unsigned char *virt, *ptr; + size_t offset, len; + + while ((len = inw(fd->base + REG_FIFO_COUNT)) > 0) { + offset = scsi_bufflen(cmd) - scsi_get_resid(cmd); + virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd), + &offset, &len); + ptr = virt + offset; + if (len & 1) + *ptr++ = inb(fd->base + REG_FIFO); + if (len > 1) + insw(fd->base + REG_FIFO, ptr, len >> 1); + scsi_set_resid(cmd, scsi_get_resid(cmd) - len); + scsi_kunmap_atomic_sg(virt); + } +} + +static void fdomain_write_data(struct scsi_cmnd *cmd) +{ + struct fdomain *fd = shost_priv(cmd->device->host); + /* 8k FIFO for pre-tmc18c30 chips, 2k FIFO for tmc18c30 */ + int FIFO_Size = fd->chip == tmc18c30 ? 0x800 : 0x2000; + unsigned char *virt, *ptr; + size_t offset, len; + + while ((len = FIFO_Size - inw(fd->base + REG_FIFO_COUNT)) > 512) { + offset = scsi_bufflen(cmd) - scsi_get_resid(cmd); + if (len + offset > scsi_bufflen(cmd)) { + len = scsi_bufflen(cmd) - offset; + if (len == 0) + break; + } + virt = scsi_kmap_atomic_sg(scsi_sglist(cmd), scsi_sg_count(cmd), + &offset, &len); + ptr = virt + offset; + if (len & 1) + outb(*ptr++, fd->base + REG_FIFO); + if (len > 1) + outsw(fd->base + REG_FIFO, ptr, len >> 1); + scsi_set_resid(cmd, scsi_get_resid(cmd) - len); + scsi_kunmap_atomic_sg(virt); + } +} + +static void fdomain_work(struct work_struct *work) +{ + struct fdomain *fd = container_of(work, struct fdomain, work); + struct Scsi_Host *sh = container_of((void *)fd, struct Scsi_Host, + hostdata); + struct scsi_cmnd *cmd = fd->cur_cmd; + unsigned long flags; + int status; + int done = 0; + + spin_lock_irqsave(sh->host_lock, flags); + + if (cmd->SCp.phase & in_arbitration) { + status = inb(fd->base + REG_ASTAT); + if (!(status & ASTAT_ARB)) { + fdomain_finish_cmd(fd, DID_BUS_BUSY << 16); + goto out; + } + cmd->SCp.phase = in_selection; + + outb(ICTL_SEL | FIFO_COUNT, fd->base + REG_ICTL); + outb(BCTL_BUSEN | BCTL_SEL, fd->base + REG_BCTL); + outb(BIT(cmd->device->host->this_id) | BIT(scmd_id(cmd)), + fd->base + REG_SCSI_DATA_NOACK); + /* Stop arbitration and enable parity */ + outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL); + goto out; + } else if (cmd->SCp.phase & in_selection) { + status = inb(fd->base + REG_BSTAT); + if (!(status & BSTAT_BSY)) { + /* Try again, for slow devices */ + if (fdomain_select(cmd->device->host, scmd_id(cmd))) { + fdomain_finish_cmd(fd, DID_NO_CONNECT << 16); + goto out; + } + /* Stop arbitration and enable parity */ + outb(ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL); + } + cmd->SCp.phase = in_other; + outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT, fd->base + REG_ICTL); + outb(BCTL_BUSEN, fd->base + REG_BCTL); + goto out; + } + + /* cur_cmd->SCp.phase == in_other: this is the body of the routine */ + status = inb(fd->base + REG_BSTAT); + + if (status & BSTAT_REQ) { + switch (status & (BSTAT_MSG | BSTAT_CMD | BSTAT_IO)) { + case BSTAT_CMD: /* COMMAND OUT */ + outb(cmd->cmnd[cmd->SCp.sent_command++], + fd->base + REG_SCSI_DATA); + break; + case 0: /* DATA OUT -- tmc18c50/tmc18c30 only */ + if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) { + cmd->SCp.have_data_in = -1; + outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN | + PARITY_MASK, fd->base + REG_ACTL); + } + break; + case BSTAT_IO: /* DATA IN -- tmc18c50/tmc18c30 only */ + if (fd->chip != tmc1800 && !cmd->SCp.have_data_in) { + cmd->SCp.have_data_in = 1; + outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK, + fd->base + REG_ACTL); + } + break; + case BSTAT_CMD | BSTAT_IO: /* STATUS IN */ + cmd->SCp.Status = inb(fd->base + REG_SCSI_DATA); + break; + case BSTAT_MSG | BSTAT_CMD: /* MESSAGE OUT */ + outb(MESSAGE_REJECT, fd->base + REG_SCSI_DATA); + break; + case BSTAT_MSG | BSTAT_CMD | BSTAT_IO: /* MESSAGE IN */ + cmd->SCp.Message = inb(fd->base + REG_SCSI_DATA); + if (!cmd->SCp.Message) + ++done; + break; + } + } + + if (fd->chip == tmc1800 && !cmd->SCp.have_data_in && + cmd->SCp.sent_command >= cmd->cmd_len) { + if (cmd->sc_data_direction == DMA_TO_DEVICE) { + cmd->SCp.have_data_in = -1; + outb(ACTL_IRQEN | ACTL_FIFOWR | ACTL_FIFOEN | + PARITY_MASK, fd->base + REG_ACTL); + } else { + cmd->SCp.have_data_in = 1; + outb(ACTL_IRQEN | ACTL_FIFOEN | PARITY_MASK, + fd->base + REG_ACTL); + } + } + + if (cmd->SCp.have_data_in == -1) /* DATA OUT */ + fdomain_write_data(cmd); + + if (cmd->SCp.have_data_in == 1) /* DATA IN */ + fdomain_read_data(cmd); + + if (done) { + fdomain_finish_cmd(fd, (cmd->SCp.Status & 0xff) | + ((cmd->SCp.Message & 0xff) << 8) | + (DID_OK << 16)); + } else { + if (cmd->SCp.phase & disconnect) { + outb(ICTL_FIFO | ICTL_SEL | ICTL_REQ | FIFO_COUNT, + fd->base + REG_ICTL); + outb(0, fd->base + REG_BCTL); + } else + outb(ICTL_FIFO | ICTL_REQ | FIFO_COUNT, + fd->base + REG_ICTL); + } +out: + spin_unlock_irqrestore(sh->host_lock, flags); +} + +static irqreturn_t fdomain_irq(int irq, void *dev_id) +{ + struct fdomain *fd = dev_id; + + /* Is it our IRQ? */ + if ((inb(fd->base + REG_ASTAT) & ASTAT_IRQ) == 0) + return IRQ_NONE; + + outb(0, fd->base + REG_ICTL); + + /* We usually have one spurious interrupt after each command. */ + if (!fd->cur_cmd) /* Spurious interrupt */ + return IRQ_NONE; + + schedule_work(&fd->work); + + return IRQ_HANDLED; +} + +static int fdomain_queue(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +{ + struct fdomain *fd = shost_priv(cmd->device->host); + unsigned long flags; + + cmd->SCp.Status = 0; + cmd->SCp.Message = 0; + cmd->SCp.have_data_in = 0; + cmd->SCp.sent_command = 0; + cmd->SCp.phase = in_arbitration; + scsi_set_resid(cmd, scsi_bufflen(cmd)); + + spin_lock_irqsave(sh->host_lock, flags); + + fd->cur_cmd = cmd; + + fdomain_make_bus_idle(fd); + + /* Start arbitration */ + outb(0, fd->base + REG_ICTL); + outb(0, fd->base + REG_BCTL); /* Disable data drivers */ + /* Set our id bit */ + outb(BIT(cmd->device->host->this_id), fd->base + REG_SCSI_DATA_NOACK); + outb(ICTL_ARB, fd->base + REG_ICTL); + /* Start arbitration */ + outb(ACTL_ARB | ACTL_IRQEN | PARITY_MASK, fd->base + REG_ACTL); + + spin_unlock_irqrestore(sh->host_lock, flags); + + return 0; +} + +static int fdomain_abort(struct scsi_cmnd *cmd) +{ + struct Scsi_Host *sh = cmd->device->host; + struct fdomain *fd = shost_priv(sh); + unsigned long flags; + + if (!fd->cur_cmd) + return FAILED; + + spin_lock_irqsave(sh->host_lock, flags); + + fdomain_make_bus_idle(fd); + fd->cur_cmd->SCp.phase |= aborted; + fd->cur_cmd->result = DID_ABORT << 16; + + /* Aborts are not done well. . . */ + fdomain_finish_cmd(fd, DID_ABORT << 16); + spin_unlock_irqrestore(sh->host_lock, flags); + return SUCCESS; +} + +static int fdomain_host_reset(struct scsi_cmnd *cmd) +{ + struct Scsi_Host *sh = cmd->device->host; + struct fdomain *fd = shost_priv(sh); + unsigned long flags; + + spin_lock_irqsave(sh->host_lock, flags); + fdomain_reset(fd->base); + spin_unlock_irqrestore(sh->host_lock, flags); + return SUCCESS; +} + +static int fdomain_biosparam(struct scsi_device *sdev, + struct block_device *bdev, sector_t capacity, + int geom[]) +{ + unsigned char *p = scsi_bios_ptable(bdev); + + if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */ + && p[4]) { /* Partition type */ + geom[0] = p[5] + 1; /* heads */ + geom[1] = p[6] & 0x3f; /* sectors */ + } else { + if (capacity >= 0x7e0000) { + geom[0] = 255; /* heads */ + geom[1] = 63; /* sectors */ + } else if (capacity >= 0x200000) { + geom[0] = 128; /* heads */ + geom[1] = 63; /* sectors */ + } else { + geom[0] = 64; /* heads */ + geom[1] = 32; /* sectors */ + } + } + geom[2] = sector_div(capacity, geom[0] * geom[1]); + kfree(p); + + return 0; +} + +static struct scsi_host_template fdomain_template = { + .module = THIS_MODULE, + .name = "Future Domain TMC-16x0", + .proc_name = "fdomain", + .queuecommand = fdomain_queue, + .eh_abort_handler = fdomain_abort, + .eh_host_reset_handler = fdomain_host_reset, + .bios_param = fdomain_biosparam, + .can_queue = 1, + .this_id = 7, + .sg_tablesize = 64, + .dma_boundary = PAGE_SIZE - 1, +}; + +struct Scsi_Host *fdomain_create(int base, int irq, int this_id, + struct device *dev) +{ + struct Scsi_Host *sh; + struct fdomain *fd; + enum chip_type chip; + static const char * const chip_names[] = { + "Unknown", "TMC-1800", "TMC-18C50", "TMC-18C30" + }; + unsigned long irq_flags = 0; + + chip = fdomain_identify(base); + if (!chip) + return NULL; + + fdomain_reset(base); + + if (fdomain_test_loopback(base)) + return NULL; + + if (!irq) { + dev_err(dev, "card has no IRQ assigned"); + return NULL; + } + + sh = scsi_host_alloc(&fdomain_template, sizeof(struct fdomain)); + if (!sh) + return NULL; + + if (this_id) + sh->this_id = this_id & 0x07; + + sh->irq = irq; + sh->io_port = base; + sh->n_io_port = FDOMAIN_REGION_SIZE; + + fd = shost_priv(sh); + fd->base = base; + fd->chip = chip; + INIT_WORK(&fd->work, fdomain_work); + + if (dev_is_pci(dev) || !strcmp(dev->bus->name, "pcmcia")) + irq_flags = IRQF_SHARED; + + if (request_irq(irq, fdomain_irq, irq_flags, "fdomain", fd)) + goto fail_put; + + shost_printk(KERN_INFO, sh, "%s chip at 0x%x irq %d SCSI ID %d\n", + dev_is_pci(dev) ? "TMC-36C70 (PCI bus)" : chip_names[chip], + base, irq, sh->this_id); + + if (scsi_add_host(sh, dev)) + goto fail_free_irq; + + scsi_scan_host(sh); + + return sh; + +fail_free_irq: + free_irq(irq, fd); +fail_put: + scsi_host_put(sh); + return NULL; +} +EXPORT_SYMBOL_GPL(fdomain_create); + +int fdomain_destroy(struct Scsi_Host *sh) +{ + struct fdomain *fd = shost_priv(sh); + + cancel_work_sync(&fd->work); + scsi_remove_host(sh); + if (sh->irq) + free_irq(sh->irq, fd); + scsi_host_put(sh); + return 0; +} +EXPORT_SYMBOL_GPL(fdomain_destroy); + +#ifdef CONFIG_PM_SLEEP +static int fdomain_resume(struct device *dev) +{ + struct fdomain *fd = shost_priv(dev_get_drvdata(dev)); + + fdomain_reset(fd->base); + return 0; +} + +static SIMPLE_DEV_PM_OPS(fdomain_pm_ops, NULL, fdomain_resume); +#endif /* CONFIG_PM_SLEEP */ + +MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith"); +MODULE_DESCRIPTION("Future Domain TMC-16x0/TMC-3260 SCSI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/fdomain.h b/drivers/scsi/fdomain.h new file mode 100644 index 000000000000..6f63fc6b0d12 --- /dev/null +++ b/drivers/scsi/fdomain.h @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#define FDOMAIN_REGION_SIZE 0x10 +#define FDOMAIN_BIOS_SIZE 0x2000 + +enum { + in_arbitration = 0x02, + in_selection = 0x04, + in_other = 0x08, + disconnect = 0x10, + aborted = 0x20, + sent_ident = 0x40, +}; + +/* (@) = not present on TMC1800, (#) = not present on TMC1800 and TMC18C50 */ +#define REG_SCSI_DATA 0 /* R/W: SCSI Data (with ACK) */ +#define REG_BSTAT 1 /* R: SCSI Bus Status */ +#define BSTAT_BSY BIT(0) /* Busy */ +#define BSTAT_MSG BIT(1) /* Message */ +#define BSTAT_IO BIT(2) /* Input/Output */ +#define BSTAT_CMD BIT(3) /* Command/Data */ +#define BSTAT_REQ BIT(4) /* Request and Not Ack */ +#define BSTAT_SEL BIT(5) /* Select */ +#define BSTAT_ACK BIT(6) /* Acknowledge and Request */ +#define BSTAT_ATN BIT(7) /* Attention */ +#define REG_BCTL 1 /* W: SCSI Bus Control */ +#define BCTL_RST BIT(0) /* Bus Reset */ +#define BCTL_SEL BIT(1) /* Select */ +#define BCTL_BSY BIT(2) /* Busy */ +#define BCTL_ATN BIT(3) /* Attention */ +#define BCTL_IO BIT(4) /* Input/Output */ +#define BCTL_CMD BIT(5) /* Command/Data */ +#define BCTL_MSG BIT(6) /* Message */ +#define BCTL_BUSEN BIT(7) /* Enable bus drivers */ +#define REG_ASTAT 2 /* R: Adapter Status 1 */ +#define ASTAT_IRQ BIT(0) /* Interrupt active */ +#define ASTAT_ARB BIT(1) /* Arbitration complete */ +#define ASTAT_PARERR BIT(2) /* Parity error */ +#define ASTAT_RST BIT(3) /* SCSI reset occurred */ +#define ASTAT_FIFODIR BIT(4) /* FIFO direction */ +#define ASTAT_FIFOEN BIT(5) /* FIFO enabled */ +#define ASTAT_PAREN BIT(6) /* Parity enabled */ +#define ASTAT_BUSEN BIT(7) /* Bus drivers enabled */ +#define REG_ICTL 2 /* W: Interrupt Control */ +#define ICTL_FIFO_MASK 0x0f /* FIFO threshold, 1/16 FIFO size */ +#define ICTL_FIFO BIT(4) /* Int. on FIFO count */ +#define ICTL_ARB BIT(5) /* Int. on Arbitration complete */ +#define ICTL_SEL BIT(6) /* Int. on SCSI Select */ +#define ICTL_REQ BIT(7) /* Int. on SCSI Request */ +#define REG_FSTAT 3 /* R: Adapter Status 2 (FIFO) - (@) */ +#define FSTAT_ONOTEMPTY BIT(0) /* Output FIFO not empty */ +#define FSTAT_INOTEMPTY BIT(1) /* Input FIFO not empty */ +#define FSTAT_NOTEMPTY BIT(2) /* Main FIFO not empty */ +#define FSTAT_NOTFULL BIT(3) /* Main FIFO not full */ +#define REG_MCTL 3 /* W: SCSI Data Mode Control */ +#define MCTL_ACK_MASK 0x0f /* Acknowledge period */ +#define MCTL_ACTDEASS BIT(4) /* Active deassert of REQ and ACK */ +#define MCTL_TARGET BIT(5) /* Enable target mode */ +#define MCTL_FASTSYNC BIT(6) /* Enable Fast Synchronous */ +#define MCTL_SYNC BIT(7) /* Enable Synchronous */ +#define REG_INTCOND 4 /* R: Interrupt Condition - (@) */ +#define IRQ_FIFO BIT(1) /* FIFO interrupt */ +#define IRQ_REQ BIT(2) /* SCSI Request interrupt */ +#define IRQ_SEL BIT(3) /* SCSI Select interrupt */ +#define IRQ_ARB BIT(4) /* SCSI Arbitration interrupt */ +#define IRQ_RST BIT(5) /* SCSI Reset interrupt */ +#define IRQ_FORCED BIT(6) /* Forced interrupt */ +#define IRQ_TIMEOUT BIT(7) /* Bus timeout */ +#define REG_ACTL 4 /* W: Adapter Control 1 */ +#define ACTL_RESET BIT(0) /* Reset FIFO, parity, reset int. */ +#define ACTL_FIRQ BIT(1) /* Set Forced interrupt */ +#define ACTL_ARB BIT(2) /* Initiate Bus Arbitration */ +#define ACTL_PAREN BIT(3) /* Enable SCSI Parity */ +#define ACTL_IRQEN BIT(4) /* Enable interrupts */ +#define ACTL_CLRFIRQ BIT(5) /* Clear Forced interrupt */ +#define ACTL_FIFOWR BIT(6) /* FIFO Direction (1=write) */ +#define ACTL_FIFOEN BIT(7) /* Enable FIFO */ +#define REG_ID_LSB 5 /* R: ID Code (LSB) */ +#define REG_ACTL2 5 /* Adapter Control 2 - (@) */ +#define ACTL2_RAMOVRLY BIT(0) /* Enable RAM overlay */ +#define ACTL2_SLEEP BIT(7) /* Sleep mode */ +#define REG_ID_MSB 6 /* R: ID Code (MSB) */ +#define REG_LOOPBACK 7 /* R/W: Loopback */ +#define REG_SCSI_DATA_NOACK 8 /* R/W: SCSI Data (no ACK) */ +#define REG_ASTAT3 9 /* R: Adapter Status 3 */ +#define ASTAT3_ACTDEASS BIT(0) /* Active deassert enabled */ +#define ASTAT3_RAMOVRLY BIT(1) /* RAM overlay enabled */ +#define ASTAT3_TARGERR BIT(2) /* Target error */ +#define ASTAT3_IRQEN BIT(3) /* Interrupts enabled */ +#define ASTAT3_IRQMASK 0xf0 /* Enabled interrupts mask */ +#define REG_CFG1 10 /* R: Configuration Register 1 */ +#define CFG1_BUS BIT(0) /* 0 = ISA */ +#define CFG1_IRQ_MASK 0x0e /* IRQ jumpers */ +#define CFG1_IO_MASK 0x30 /* I/O base jumpers */ +#define CFG1_BIOS_MASK 0xc0 /* BIOS base jumpers */ +#define REG_CFG2 11 /* R/W: Configuration Register 2 (@) */ +#define CFG2_ROMDIS BIT(0) /* ROM disabled */ +#define CFG2_RAMDIS BIT(1) /* RAM disabled */ +#define CFG2_IRQEDGE BIT(2) /* Edge-triggered interrupts */ +#define CFG2_NOWS BIT(3) /* No wait states */ +#define CFG2_32BIT BIT(7) /* 32-bit mode */ +#define REG_FIFO 12 /* R/W: FIFO */ +#define REG_FIFO_COUNT 14 /* R: FIFO Data Count */ + +#ifdef CONFIG_PM_SLEEP +static const struct dev_pm_ops fdomain_pm_ops; +#define FDOMAIN_PM_OPS (&fdomain_pm_ops) +#else +#define FDOMAIN_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +struct Scsi_Host *fdomain_create(int base, int irq, int this_id, + struct device *dev); +int fdomain_destroy(struct Scsi_Host *sh); diff --git a/drivers/scsi/fdomain_isa.c b/drivers/scsi/fdomain_isa.c new file mode 100644 index 000000000000..f2da4fa382e8 --- /dev/null +++ b/drivers/scsi/fdomain_isa.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/module.h> +#include <linux/io.h> +#include <linux/isa.h> +#include <scsi/scsi_host.h> +#include "fdomain.h" + +#define MAXBOARDS_PARAM 4 +static int io[MAXBOARDS_PARAM] = { 0, 0, 0, 0 }; +module_param_hw_array(io, int, ioport, NULL, 0); +MODULE_PARM_DESC(io, "base I/O address of controller (0x140, 0x150, 0x160, 0x170)"); + +static int irq[MAXBOARDS_PARAM] = { 0, 0, 0, 0 }; +module_param_hw_array(irq, int, irq, NULL, 0); +MODULE_PARM_DESC(irq, "IRQ of controller (0=auto [default])"); + +static int scsi_id[MAXBOARDS_PARAM] = { 0, 0, 0, 0 }; +module_param_hw_array(scsi_id, int, other, NULL, 0); +MODULE_PARM_DESC(scsi_id, "SCSI ID of controller (default = 7)"); + +static unsigned long addresses[] = { + 0xc8000, + 0xca000, + 0xce000, + 0xde000, +}; +#define ADDRESS_COUNT ARRAY_SIZE(addresses) + +static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 }; +#define PORT_COUNT ARRAY_SIZE(ports) + +static unsigned short irqs[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; + +/* This driver works *ONLY* for Future Domain cards using the TMC-1800, + * TMC-18C50, or TMC-18C30 chip. This includes models TMC-1650, 1660, 1670, + * and 1680. These are all 16-bit cards. + * BIOS versions prior to 3.2 assigned SCSI ID 6 to SCSI adapter. + * + * The following BIOS signature signatures are for boards which do *NOT* + * work with this driver (these TMC-8xx and TMC-9xx boards may work with the + * Seagate driver): + * + * FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88 + * FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89 + * FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89 + * FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90 + * FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90 + * FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90 + * FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92 + * + * (The cards which do *NOT* work are all 8-bit cards -- although some of + * them have a 16-bit form-factor, the upper 8-bits are used only for IRQs + * and are *NOT* used for data. You can tell the difference by following + * the tracings on the circuit board -- if only the IRQ lines are involved, + * you have a "8-bit" card, and should *NOT* use this driver.) + */ + +static struct signature { + const char *signature; + int offset; + int length; + int this_id; + int base_offset; +} signatures[] = { +/* 1 2 3 4 5 6 */ +/* 123456789012345678901234567890123456789012345678901234567890 */ +{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 6, 0x1fcc }, +{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89", 5, 50, 6, 0x1fcc }, +{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50, 6, 0x1fa2 }, +{ "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0", 73, 43, 6, 0x1fa2 }, +{ "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.", 72, 39, 6, 0x1fa3 }, +{ "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 6, 0 }, +{ "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 7, 0 }, +{ "IBM F1 P2 BIOS v1.0011/09/92", 5, 28, 7, 0x1ff3 }, +{ "IBM F1 P2 BIOS v1.0104/29/93", 5, 28, 7, 0 }, +{ "Future Domain Corp. V1.0008/18/93", 5, 33, 7, 0 }, +{ "Future Domain Corp. V2.0108/18/93", 5, 33, 7, 0 }, +{ "FUTURE DOMAIN CORP. V3.5008/18/93", 5, 34, 7, 0 }, +{ "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5", 5, 44, 7, 0 }, +{ "FUTURE DOMAIN CORP. V3.6008/18/93", 5, 34, 7, 0 }, +{ "FUTURE DOMAIN CORP. V3.6108/18/93", 5, 34, 7, 0 }, +}; +#define SIGNATURE_COUNT ARRAY_SIZE(signatures) + +static int fdomain_isa_match(struct device *dev, unsigned int ndev) +{ + struct Scsi_Host *sh; + int i, base = 0, irq = 0; + unsigned long bios_base = 0; + struct signature *sig = NULL; + void __iomem *p; + static struct signature *saved_sig; + int this_id = 7; + + if (ndev < ADDRESS_COUNT) { /* scan supported ISA BIOS addresses */ + p = ioremap(addresses[ndev], FDOMAIN_BIOS_SIZE); + if (!p) + return 0; + for (i = 0; i < SIGNATURE_COUNT; i++) + if (check_signature(p + signatures[i].offset, + signatures[i].signature, + signatures[i].length)) + break; + if (i == SIGNATURE_COUNT) /* no signature found */ + goto fail_unmap; + sig = &signatures[i]; + bios_base = addresses[ndev]; + /* read I/O base from BIOS area */ + if (sig->base_offset) + base = readb(p + sig->base_offset) + + (readb(p + sig->base_offset + 1) << 8); + iounmap(p); + if (base) + dev_info(dev, "BIOS at 0x%lx specifies I/O base 0x%x\n", + bios_base, base); + else + dev_info(dev, "BIOS at 0x%lx\n", bios_base); + if (!base) { /* no I/O base in BIOS area */ + /* save BIOS signature for later use in port probing */ + saved_sig = sig; + return 0; + } + } else /* scan supported I/O ports */ + base = ports[ndev - ADDRESS_COUNT]; + + /* use saved BIOS signature if present */ + if (!sig && saved_sig) + sig = saved_sig; + + if (!request_region(base, FDOMAIN_REGION_SIZE, "fdomain_isa")) + return 0; + + irq = irqs[(inb(base + REG_CFG1) & CFG1_IRQ_MASK) >> 1]; + + if (sig) + this_id = sig->this_id; + + sh = fdomain_create(base, irq, this_id, dev); + if (!sh) { + release_region(base, FDOMAIN_REGION_SIZE); + return 0; + } + + dev_set_drvdata(dev, sh); + return 1; +fail_unmap: + iounmap(p); + return 0; +} + +static int fdomain_isa_param_match(struct device *dev, unsigned int ndev) +{ + struct Scsi_Host *sh; + int irq_ = irq[ndev]; + + if (!io[ndev]) + return 0; + + if (!request_region(io[ndev], FDOMAIN_REGION_SIZE, "fdomain_isa")) { + dev_err(dev, "base 0x%x already in use", io[ndev]); + return 0; + } + + if (irq_ <= 0) + irq_ = irqs[(inb(io[ndev] + REG_CFG1) & CFG1_IRQ_MASK) >> 1]; + + sh = fdomain_create(io[ndev], irq_, scsi_id[ndev], dev); + if (!sh) { + dev_err(dev, "controller not found at base 0x%x", io[ndev]); + release_region(io[ndev], FDOMAIN_REGION_SIZE); + return 0; + } + + dev_set_drvdata(dev, sh); + return 1; +} + +static int fdomain_isa_remove(struct device *dev, unsigned int ndev) +{ + struct Scsi_Host *sh = dev_get_drvdata(dev); + int base = sh->io_port; + + fdomain_destroy(sh); + release_region(base, FDOMAIN_REGION_SIZE); + dev_set_drvdata(dev, NULL); + return 0; +} + +static struct isa_driver fdomain_isa_driver = { + .match = fdomain_isa_match, + .remove = fdomain_isa_remove, + .driver = { + .name = "fdomain_isa", + .pm = FDOMAIN_PM_OPS, + }, +}; + +static int __init fdomain_isa_init(void) +{ + int isa_probe_count = ADDRESS_COUNT + PORT_COUNT; + + if (io[0]) { /* use module parameters if present */ + fdomain_isa_driver.match = fdomain_isa_param_match; + isa_probe_count = MAXBOARDS_PARAM; + } + + return isa_register_driver(&fdomain_isa_driver, isa_probe_count); +} + +static void __exit fdomain_isa_exit(void) +{ + isa_unregister_driver(&fdomain_isa_driver); +} + +module_init(fdomain_isa_init); +module_exit(fdomain_isa_exit); + +MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith"); +MODULE_DESCRIPTION("Future Domain TMC-16x0 ISA SCSI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/fdomain_pci.c b/drivers/scsi/fdomain_pci.c new file mode 100644 index 000000000000..3e05ce7b89e5 --- /dev/null +++ b/drivers/scsi/fdomain_pci.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/module.h> +#include <linux/pci.h> +#include "fdomain.h" + +static int fdomain_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *d) +{ + int err; + struct Scsi_Host *sh; + + err = pci_enable_device(pdev); + if (err) + goto fail; + + err = pci_request_regions(pdev, "fdomain_pci"); + if (err) + goto disable_device; + + err = -ENODEV; + if (pci_resource_len(pdev, 0) == 0) + goto release_region; + + sh = fdomain_create(pci_resource_start(pdev, 0), pdev->irq, 7, + &pdev->dev); + if (!sh) + goto release_region; + + pci_set_drvdata(pdev, sh); + return 0; + +release_region: + pci_release_regions(pdev); +disable_device: + pci_disable_device(pdev); +fail: + return err; +} + +static void fdomain_pci_remove(struct pci_dev *pdev) +{ + struct Scsi_Host *sh = pci_get_drvdata(pdev); + + fdomain_destroy(sh); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static struct pci_device_id fdomain_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70) }, + {} +}; +MODULE_DEVICE_TABLE(pci, fdomain_pci_table); + +static struct pci_driver fdomain_pci_driver = { + .name = "fdomain_pci", + .id_table = fdomain_pci_table, + .probe = fdomain_pci_probe, + .remove = fdomain_pci_remove, + .driver.pm = FDOMAIN_PM_OPS, +}; + +module_pci_driver(fdomain_pci_driver); + +MODULE_AUTHOR("Ondrej Zary, Rickard E. Faith"); +MODULE_DESCRIPTION("Future Domain TMC-3260 PCI SCSI driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/fnic/fnic_debugfs.c b/drivers/scsi/fnic/fnic_debugfs.c index 21991c99db7c..13f7d88d6e57 100644 --- a/drivers/scsi/fnic/fnic_debugfs.c +++ b/drivers/scsi/fnic/fnic_debugfs.c @@ -52,7 +52,6 @@ static struct fc_trace_flag_type *fc_trc_flag; */ int fnic_debugfs_init(void) { - int rc = -1; fnic_trace_debugfs_root = debugfs_create_dir("fnic", NULL); fnic_stats_debugfs_root = debugfs_create_dir("statistics", @@ -70,8 +69,7 @@ int fnic_debugfs_init(void) fc_trc_flag->fc_clear = 4; } - rc = 0; - return rc; + return 0; } /* diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 911a5adc289c..673887e383cc 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -52,6 +52,7 @@ void fnic_handle_link(struct work_struct *work) unsigned long flags; int old_link_status; u32 old_link_down_cnt; + u64 old_port_speed, new_port_speed; spin_lock_irqsave(&fnic->fnic_lock, flags); @@ -62,14 +63,19 @@ void fnic_handle_link(struct work_struct *work) old_link_down_cnt = fnic->link_down_cnt; old_link_status = fnic->link_status; + old_port_speed = atomic64_read( + &fnic->fnic_stats.misc_stats.current_port_speed); + fnic->link_status = vnic_dev_link_status(fnic->vdev); fnic->link_down_cnt = vnic_dev_link_down_cnt(fnic->vdev); + new_port_speed = vnic_dev_port_speed(fnic->vdev); atomic64_set(&fnic->fnic_stats.misc_stats.current_port_speed, - vnic_dev_port_speed(fnic->vdev)); - shost_printk(KERN_INFO, fnic->lport->host, "Current vnic speed set to : %llu\n", - (u64)atomic64_read( - &fnic->fnic_stats.misc_stats.current_port_speed)); + new_port_speed); + if (old_port_speed != new_port_speed) + shost_printk(KERN_INFO, fnic->lport->host, + "Current vnic speed set to : %llu\n", + new_port_speed); switch (vnic_dev_port_speed(fnic->vdev)) { case DCEM_PORTSPEED_10G: diff --git a/drivers/scsi/fnic/fnic_isr.c b/drivers/scsi/fnic/fnic_isr.c index da4602b63495..2fb2731f50fb 100644 --- a/drivers/scsi/fnic/fnic_isr.c +++ b/drivers/scsi/fnic/fnic_isr.c @@ -254,7 +254,7 @@ int fnic_set_intr_mode(struct fnic *fnic) int vecs = n + m + o + 1; if (pci_alloc_irq_vectors(fnic->pdev, vecs, vecs, - PCI_IRQ_MSIX) < 0) { + PCI_IRQ_MSIX) == vecs) { fnic->rq_count = n; fnic->raw_wq_count = m; fnic->wq_copy_count = o; @@ -280,7 +280,7 @@ int fnic_set_intr_mode(struct fnic *fnic) fnic->wq_copy_count >= 1 && fnic->cq_count >= 3 && fnic->intr_count >= 1 && - pci_alloc_irq_vectors(fnic->pdev, 1, 1, PCI_IRQ_MSI) < 0) { + pci_alloc_irq_vectors(fnic->pdev, 1, 1, PCI_IRQ_MSI) == 1) { fnic->rq_count = 1; fnic->raw_wq_count = 1; fnic->wq_copy_count = 1; diff --git a/drivers/scsi/fnic/fnic_trace.c b/drivers/scsi/fnic/fnic_trace.c index 9621831e17ba..a0d01aea28f7 100644 --- a/drivers/scsi/fnic/fnic_trace.c +++ b/drivers/scsi/fnic/fnic_trace.c @@ -453,7 +453,7 @@ int fnic_get_stats_data(struct stats_debug_info *debug, (u64)atomic64_read(&stats->misc_stats.frame_errors)); len += snprintf(debug->debug_buffer + len, buf_size - len, - "Firmware reported port seed: %llu\n", + "Firmware reported port speed: %llu\n", (u64)atomic64_read( &stats->misc_stats.current_port_speed)); diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 8d9a8fb2dd32..720c4d6be939 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -31,7 +31,13 @@ #define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES #define HISI_SAS_RESET_BIT 0 #define HISI_SAS_REJECT_CMD_BIT 1 -#define HISI_SAS_RESERVED_IPTT_CNT 96 +#define HISI_SAS_MAX_COMMANDS (HISI_SAS_QUEUE_SLOTS) +#define HISI_SAS_RESERVED_IPTT 96 +#define HISI_SAS_UNRESERVED_IPTT \ + (HISI_SAS_MAX_COMMANDS - HISI_SAS_RESERVED_IPTT) + +#define HISI_SAS_IOST_ITCT_CACHE_NUM 64 +#define HISI_SAS_IOST_ITCT_CACHE_DW_SZ 10 #define HISI_SAS_STATUS_BUF_SZ (sizeof(struct hisi_sas_status_buffer)) #define HISI_SAS_COMMAND_TABLE_SZ (sizeof(union hisi_sas_command_table)) @@ -61,10 +67,6 @@ #define HISI_SAS_MAX_SMP_RESP_SZ 1028 #define HISI_SAS_MAX_STP_RESP_SZ 28 -#define DEV_IS_EXPANDER(type) \ - ((type == SAS_EDGE_EXPANDER_DEVICE) || \ - (type == SAS_FANOUT_EXPANDER_DEVICE)) - #define HISI_SAS_SATA_PROTOCOL_NONDATA 0x1 #define HISI_SAS_SATA_PROTOCOL_PIO 0x2 #define HISI_SAS_SATA_PROTOCOL_DMA 0x4 @@ -132,7 +134,6 @@ struct hisi_sas_rst { #define HISI_SAS_DECLARE_RST_WORK_ON_STACK(r) \ DECLARE_COMPLETION_ONSTACK(c); \ - DECLARE_WORK(w, hisi_sas_sync_rst_work_handler); \ struct hisi_sas_rst r = HISI_SAS_RST_WORK_INIT(r, c) enum hisi_sas_bit_err_type { @@ -253,6 +254,22 @@ struct hisi_sas_debugfs_reg { }; }; +struct hisi_sas_iost_itct_cache { + u32 data[HISI_SAS_IOST_ITCT_CACHE_DW_SZ]; +}; + +enum hisi_sas_debugfs_reg_array_member { + DEBUGFS_GLOBAL = 0, + DEBUGFS_AXI, + DEBUGFS_RAS, + DEBUGFS_REGS_NUM +}; + +enum hisi_sas_debugfs_cache_type { + HISI_SAS_ITCT_CACHE, + HISI_SAS_IOST_CACHE, +}; + struct hisi_sas_hw { int (*hw_init)(struct hisi_hba *hisi_hba); void (*setup_itct)(struct hisi_hba *hisi_hba, @@ -261,7 +278,6 @@ struct hisi_sas_hw { struct domain_device *device); struct hisi_sas_device *(*alloc_dev)(struct domain_device *device); void (*sl_notify_ssp)(struct hisi_hba *hisi_hba, int phy_no); - int (*get_free_slot)(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq); void (*start_delivery)(struct hisi_sas_dq *dq); void (*prep_ssp)(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot); @@ -272,8 +288,6 @@ struct hisi_sas_hw { void (*prep_abort)(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot, int device_id, int abort_flag, int tag_to_abort); - int (*slot_complete)(struct hisi_hba *hisi_hba, - struct hisi_sas_slot *slot); void (*phys_init)(struct hisi_hba *hisi_hba); void (*phy_start)(struct hisi_hba *hisi_hba, int phy_no); void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no); @@ -292,15 +306,18 @@ struct hisi_sas_hw { u32 (*get_phys_state)(struct hisi_hba *hisi_hba); int (*write_gpio)(struct hisi_hba *hisi_hba, u8 reg_type, u8 reg_index, u8 reg_count, u8 *write_data); - int (*wait_cmds_complete_timeout)(struct hisi_hba *hisi_hba, - int delay_ms, int timeout_ms); + void (*wait_cmds_complete_timeout)(struct hisi_hba *hisi_hba, + int delay_ms, int timeout_ms); void (*snapshot_prepare)(struct hisi_hba *hisi_hba); void (*snapshot_restore)(struct hisi_hba *hisi_hba); - int max_command_entries; + int (*set_bist)(struct hisi_hba *hisi_hba, bool enable); + void (*read_iost_itct_cache)(struct hisi_hba *hisi_hba, + enum hisi_sas_debugfs_cache_type type, + u32 *cache); int complete_hdr_size; struct scsi_host_template *sht; - const struct hisi_sas_debugfs_reg *debugfs_reg_global; + const struct hisi_sas_debugfs_reg *debugfs_reg_array[DEBUGFS_REGS_NUM]; const struct hisi_sas_debugfs_reg *debugfs_reg_port; }; @@ -375,16 +392,28 @@ struct hisi_hba { int cq_nvecs; unsigned int *reply_map; + /* bist */ + enum sas_linkrate debugfs_bist_linkrate; + int debugfs_bist_code_mode; + int debugfs_bist_phy_no; + int debugfs_bist_mode; + u32 debugfs_bist_cnt; + int debugfs_bist_enable; + /* debugfs memories */ - u32 *debugfs_global_reg; + /* Put Global AXI and RAS Register into register array */ + u32 *debugfs_regs[DEBUGFS_REGS_NUM]; u32 *debugfs_port_reg[HISI_SAS_MAX_PHYS]; void *debugfs_complete_hdr[HISI_SAS_MAX_QUEUES]; struct hisi_sas_cmd_hdr *debugfs_cmd_hdr[HISI_SAS_MAX_QUEUES]; struct hisi_sas_iost *debugfs_iost; struct hisi_sas_itct *debugfs_itct; + u64 *debugfs_iost_cache; + u64 *debugfs_itct_cache; struct dentry *debugfs_dir; struct dentry *debugfs_dump_dentry; + struct dentry *debugfs_bist_dentry; bool debugfs_snapshot; }; @@ -479,12 +508,12 @@ struct hisi_sas_command_table_stp { u8 atapi_cdb[ATAPI_CDB_LEN]; }; -#define HISI_SAS_SGE_PAGE_CNT SG_CHUNK_SIZE +#define HISI_SAS_SGE_PAGE_CNT (124) struct hisi_sas_sge_page { struct hisi_sas_sge sge[HISI_SAS_SGE_PAGE_CNT]; } __aligned(16); -#define HISI_SAS_SGE_DIF_PAGE_CNT SG_CHUNK_SIZE +#define HISI_SAS_SGE_DIF_PAGE_CNT HISI_SAS_SGE_PAGE_CNT struct hisi_sas_sge_dif_page { struct hisi_sas_sge sge[HISI_SAS_SGE_DIF_PAGE_CNT]; } __aligned(16); @@ -537,7 +566,6 @@ extern u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, extern struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port); extern void hisi_sas_sata_done(struct sas_task *task, struct hisi_sas_slot *slot); -extern int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag); extern int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba); extern int hisi_sas_probe(struct platform_device *pdev, const struct hisi_sas_hw *ops); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 5879771d82b2..0847e682797b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -118,21 +118,6 @@ void hisi_sas_sata_done(struct sas_task *task, } EXPORT_SYMBOL_GPL(hisi_sas_sata_done); -int hisi_sas_get_ncq_tag(struct sas_task *task, u32 *tag) -{ - struct ata_queued_cmd *qc = task->uldd_task; - - if (qc) { - if (qc->tf.command == ATA_CMD_FPDMA_WRITE || - qc->tf.command == ATA_CMD_FPDMA_READ) { - *tag = qc->tag; - return 1; - } - } - return 0; -} -EXPORT_SYMBOL_GPL(hisi_sas_get_ncq_tag); - /* * This function assumes linkrate mask fits in 8 bits, which it * does for all HW versions supported. @@ -180,8 +165,8 @@ static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx) { unsigned long flags; - if (hisi_hba->hw->slot_index_alloc || (slot_idx >= - hisi_hba->hw->max_command_entries - HISI_SAS_RESERVED_IPTT_CNT)) { + if (hisi_hba->hw->slot_index_alloc || + slot_idx >= HISI_SAS_UNRESERVED_IPTT) { spin_lock_irqsave(&hisi_hba->lock, flags); hisi_sas_slot_index_clear(hisi_hba, slot_idx); spin_unlock_irqrestore(&hisi_hba->lock, flags); @@ -211,8 +196,7 @@ static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, if (index >= hisi_hba->slot_index_count) { index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, - hisi_hba->hw->max_command_entries - - HISI_SAS_RESERVED_IPTT_CNT); + HISI_SAS_UNRESERVED_IPTT); if (index >= hisi_hba->slot_index_count) { spin_unlock_irqrestore(&hisi_hba->lock, flags); return -SAS_QUEUE_FULL; @@ -301,7 +285,7 @@ static void hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba, static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba, struct sas_task *task, int n_elem, - int n_elem_req, int n_elem_resp) + int n_elem_req) { struct device *dev = hisi_hba->dev; @@ -315,16 +299,13 @@ static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba, if (n_elem_req) dma_unmap_sg(dev, &task->smp_task.smp_req, 1, DMA_TO_DEVICE); - if (n_elem_resp) - dma_unmap_sg(dev, &task->smp_task.smp_resp, - 1, DMA_FROM_DEVICE); } } } static int hisi_sas_dma_map(struct hisi_hba *hisi_hba, struct sas_task *task, int *n_elem, - int *n_elem_req, int *n_elem_resp) + int *n_elem_req) { struct device *dev = hisi_hba->dev; int rc; @@ -332,7 +313,7 @@ static int hisi_sas_dma_map(struct hisi_hba *hisi_hba, if (sas_protocol_ata(task->task_proto)) { *n_elem = task->num_scatter; } else { - unsigned int req_len, resp_len; + unsigned int req_len; if (task->num_scatter) { *n_elem = dma_map_sg(dev, task->scatter, @@ -353,17 +334,6 @@ static int hisi_sas_dma_map(struct hisi_hba *hisi_hba, rc = -EINVAL; goto err_out_dma_unmap; } - *n_elem_resp = dma_map_sg(dev, &task->smp_task.smp_resp, - 1, DMA_FROM_DEVICE); - if (!*n_elem_resp) { - rc = -ENOMEM; - goto err_out_dma_unmap; - } - resp_len = sg_dma_len(&task->smp_task.smp_resp); - if (resp_len & 0x3) { - rc = -EINVAL; - goto err_out_dma_unmap; - } } } @@ -378,7 +348,7 @@ static int hisi_sas_dma_map(struct hisi_hba *hisi_hba, err_out_dma_unmap: /* It would be better to call dma_unmap_sg() here, but it's messy */ hisi_sas_dma_unmap(hisi_hba, task, *n_elem, - *n_elem_req, *n_elem_resp); + *n_elem_req); prep_out: return rc; } @@ -450,7 +420,7 @@ static int hisi_sas_task_prep(struct sas_task *task, struct asd_sas_port *sas_port = device->port; struct device *dev = hisi_hba->dev; int dlvry_queue_slot, dlvry_queue, rc, slot_idx; - int n_elem = 0, n_elem_dif = 0, n_elem_req = 0, n_elem_resp = 0; + int n_elem = 0, n_elem_dif = 0, n_elem_req = 0; struct hisi_sas_dq *dq; unsigned long flags; int wr_q_index; @@ -486,7 +456,7 @@ static int hisi_sas_task_prep(struct sas_task *task, } rc = hisi_sas_dma_map(hisi_hba, task, &n_elem, - &n_elem_req, &n_elem_resp); + &n_elem_req); if (rc < 0) goto prep_out; @@ -520,13 +490,8 @@ static int hisi_sas_task_prep(struct sas_task *task, slot = &hisi_hba->slot_info[slot_idx]; spin_lock_irqsave(&dq->lock, flags); - wr_q_index = hisi_hba->hw->get_free_slot(hisi_hba, dq); - if (wr_q_index < 0) { - spin_unlock_irqrestore(&dq->lock, flags); - rc = -EAGAIN; - goto err_out_tag; - } - + wr_q_index = dq->wr_point; + dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; list_add_tail(&slot->delivery, &dq->list); spin_unlock_irqrestore(&dq->lock, flags); spin_lock_irqsave(&sas_dev->lock, flags); @@ -551,7 +516,8 @@ static int hisi_sas_task_prep(struct sas_task *task, memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr)); memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ); - memset(hisi_sas_status_buf_addr_mem(slot), 0, HISI_SAS_STATUS_BUF_SZ); + memset(hisi_sas_status_buf_addr_mem(slot), 0, + sizeof(struct hisi_sas_err_record)); switch (task->task_proto) { case SAS_PROTOCOL_SMP: @@ -580,14 +546,12 @@ static int hisi_sas_task_prep(struct sas_task *task, return 0; -err_out_tag: - hisi_sas_slot_index_free(hisi_hba, slot_idx); err_out_dif_dma_unmap: if (!sas_protocol_ata(task->task_proto)) hisi_sas_dif_dma_unmap(hisi_hba, task, n_elem_dif); err_out_dma_unmap: hisi_sas_dma_unmap(hisi_hba, task, n_elem, - n_elem_req, n_elem_resp); + n_elem_req); prep_out: dev_err(dev, "task prep: failed[%d]!\n", rc); return rc; @@ -719,13 +683,13 @@ static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device) return sas_dev; } -#define HISI_SAS_SRST_ATA_DISK_CNT 3 +#define HISI_SAS_DISK_RECOVER_CNT 3 static int hisi_sas_init_device(struct domain_device *device) { int rc = TMF_RESP_FUNC_COMPLETE; struct scsi_lun lun; struct hisi_sas_tmf_task tmf_task; - int retry = HISI_SAS_SRST_ATA_DISK_CNT; + int retry = HISI_SAS_DISK_RECOVER_CNT; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct device *dev = hisi_hba->dev; struct sas_phy *local_phy; @@ -735,10 +699,14 @@ static int hisi_sas_init_device(struct domain_device *device) int_to_scsilun(0, &lun); tmf_task.tmf = TMF_CLEAR_TASK_SET; - rc = hisi_sas_debug_issue_ssp_tmf(device, lun.scsi_lun, - &tmf_task); - if (rc == TMF_RESP_FUNC_COMPLETE) - hisi_sas_release_task(hisi_hba, device); + while (retry-- > 0) { + rc = hisi_sas_debug_issue_ssp_tmf(device, lun.scsi_lun, + &tmf_task); + if (rc == TMF_RESP_FUNC_COMPLETE) { + hisi_sas_release_task(hisi_hba, device); + break; + } + } break; case SAS_SATA_DEV: case SAS_SATA_PM: @@ -803,7 +771,7 @@ static int hisi_sas_dev_found(struct domain_device *device) device->lldd_dev = sas_dev; hisi_hba->hw->setup_itct(hisi_hba, sas_dev); - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) { + if (parent_dev && dev_is_expander(parent_dev->dev_type)) { int phy_no; u8 phy_num = parent_dev->ex_dev.num_phys; struct ex_phy *phy; @@ -1081,21 +1049,22 @@ static void hisi_sas_dev_gone(struct domain_device *device) dev_info(dev, "dev[%d:%x] is gone\n", sas_dev->device_id, sas_dev->dev_type); + down(&hisi_hba->sem); if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) { hisi_sas_internal_task_abort(hisi_hba, device, HISI_SAS_INT_ABT_DEV, 0); hisi_sas_dereg_device(hisi_hba, device); - down(&hisi_hba->sem); hisi_hba->hw->clear_itct(hisi_hba, sas_dev); - up(&hisi_hba->sem); device->lldd_dev = NULL; } if (hisi_hba->hw->free_device) hisi_hba->hw->free_device(sas_dev); sas_dev->dev_type = SAS_PHY_UNUSED; + sas_dev->sas_device = NULL; + up(&hisi_hba->sem); } static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) @@ -1423,8 +1392,7 @@ static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba) } } -static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, - u32 state) +static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 state) { struct sas_ha_struct *sas_ha = &hisi_hba->sha; struct asd_sas_port *_sas_port = NULL; @@ -1446,7 +1414,7 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 old_state, _sas_port = sas_port; - if (DEV_IS_EXPANDER(dev->dev_type)) + if (dev_is_expander(dev->dev_type)) sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); } @@ -1533,7 +1501,7 @@ static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba) struct domain_device *port_dev = sas_port->port_dev; struct domain_device *device; - if (!port_dev || !DEV_IS_EXPANDER(port_dev->dev_type)) + if (!port_dev || !dev_is_expander(port_dev->dev_type)) continue; /* Try to find a SATA device */ @@ -1576,16 +1544,16 @@ void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba) msleep(1000); hisi_sas_refresh_port_id(hisi_hba); clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); - up(&hisi_hba->sem); if (hisi_hba->reject_stp_links_msk) hisi_sas_terminate_stp_reject(hisi_hba); hisi_sas_reset_init_all_devices(hisi_hba); + up(&hisi_hba->sem); scsi_unblock_requests(shost); clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); state = hisi_hba->hw->get_phys_state(hisi_hba); - hisi_sas_rescan_topology(hisi_hba, hisi_hba->phy_state, state); + hisi_sas_rescan_topology(hisi_hba, state); } EXPORT_SYMBOL_GPL(hisi_sas_controller_reset_done); @@ -1770,24 +1738,34 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct sas_ha_struct *sas_ha = &hisi_hba->sha; - struct asd_sas_phy *sas_phy = sas_ha->sas_phy[local_phy->number]; - struct hisi_sas_phy *phy = container_of(sas_phy, - struct hisi_sas_phy, sas_phy); DECLARE_COMPLETION_ONSTACK(phyreset); int rc, reset_type; + if (!local_phy->enabled) { + sas_put_local_phy(local_phy); + return -ENODEV; + } + if (scsi_is_sas_phy_local(local_phy)) { + struct asd_sas_phy *sas_phy = + sas_ha->sas_phy[local_phy->number]; + struct hisi_sas_phy *phy = + container_of(sas_phy, struct hisi_sas_phy, sas_phy); phy->in_reset = 1; phy->reset_completion = &phyreset; } reset_type = (sas_dev->dev_status == HISI_SAS_DEV_INIT || - !dev_is_sata(device)) ? 1 : 0; + !dev_is_sata(device)) ? true : false; rc = sas_phy_reset(local_phy, reset_type); sas_put_local_phy(local_phy); if (scsi_is_sas_phy_local(local_phy)) { + struct asd_sas_phy *sas_phy = + sas_ha->sas_phy[local_phy->number]; + struct hisi_sas_phy *phy = + container_of(sas_phy, struct hisi_sas_phy, sas_phy); int ret = wait_for_completion_timeout(&phyreset, 2 * HZ); unsigned long flags; @@ -1802,9 +1780,10 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) } else if (sas_dev->dev_status != HISI_SAS_DEV_INIT) { /* * If in init state, we rely on caller to wait for link to be - * ready; otherwise, delay. + * ready; otherwise, except phy reset is fail, delay. */ - msleep(2000); + if (!rc) + msleep(2000); } return rc; @@ -1845,21 +1824,21 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) struct device *dev = hisi_hba->dev; int rc = TMF_RESP_FUNC_FAILED; + /* Clear internal IO and then lu reset */ + rc = hisi_sas_internal_task_abort(hisi_hba, device, + HISI_SAS_INT_ABT_DEV, 0); + if (rc < 0) { + dev_err(dev, "lu_reset: internal abort failed\n"); + goto out; + } + hisi_sas_dereg_device(hisi_hba, device); + if (dev_is_sata(device)) { struct sas_phy *phy; - /* Clear internal IO and then hardreset */ - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, 0); - if (rc < 0) { - dev_err(dev, "lu_reset: internal abort failed\n"); - goto out; - } - hisi_sas_dereg_device(hisi_hba, device); - phy = sas_get_local_phy(device); - rc = sas_phy_reset(phy, 1); + rc = sas_phy_reset(phy, true); if (rc == 0) hisi_sas_release_task(hisi_hba, device); @@ -1867,14 +1846,6 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) } else { struct hisi_sas_tmf_task tmf_task = { .tmf = TMF_LU_RESET }; - rc = hisi_sas_internal_task_abort(hisi_hba, device, - HISI_SAS_INT_ABT_DEV, 0); - if (rc < 0) { - dev_err(dev, "lu_reset: internal abort failed\n"); - goto out; - } - hisi_sas_dereg_device(hisi_hba, device); - rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task); if (rc == TMF_RESP_FUNC_COMPLETE) hisi_sas_release_task(hisi_hba, device); @@ -1903,7 +1874,7 @@ static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha) struct domain_device *device = sas_dev->sas_device; if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device || - DEV_IS_EXPANDER(device->dev_type)) + dev_is_expander(device->dev_type)) continue; rc = hisi_sas_debug_I_T_nexus_reset(device); @@ -1964,7 +1935,7 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, struct asd_sas_port *sas_port = device->port; struct hisi_sas_cmd_hdr *cmd_hdr_base; int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; - unsigned long flags, flags_dq = 0; + unsigned long flags; int wr_q_index; if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) @@ -1983,15 +1954,11 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, slot_idx = rc; slot = &hisi_hba->slot_info[slot_idx]; - spin_lock_irqsave(&dq->lock, flags_dq); - wr_q_index = hisi_hba->hw->get_free_slot(hisi_hba, dq); - if (wr_q_index < 0) { - spin_unlock_irqrestore(&dq->lock, flags_dq); - rc = -EAGAIN; - goto err_out_tag; - } + spin_lock_irqsave(&dq->lock, flags); + wr_q_index = dq->wr_point; + dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; list_add_tail(&slot->delivery, &dq->list); - spin_unlock_irqrestore(&dq->lock, flags_dq); + spin_unlock_irqrestore(&dq->lock, flags); spin_lock_irqsave(&sas_dev->lock, flags); list_add_tail(&slot->entry, &sas_dev->list); spin_unlock_irqrestore(&sas_dev->lock, flags); @@ -2012,7 +1979,8 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr)); memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ); - memset(hisi_sas_status_buf_addr_mem(slot), 0, HISI_SAS_STATUS_BUF_SZ); + memset(hisi_sas_status_buf_addr_mem(slot), 0, + sizeof(struct hisi_sas_err_record)); hisi_sas_task_prep_abort(hisi_hba, slot, device_id, abort_flag, task_tag); @@ -2028,8 +1996,6 @@ hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, return 0; -err_out_tag: - hisi_sas_slot_index_free(hisi_hba, slot_idx); err_out: dev_err(dev, "internal abort task prep: failed[%d]!\n", rc); @@ -2089,6 +2055,9 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, /* Internal abort timed out */ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { + if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct) + queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); + if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { struct hisi_sas_slot *slot = task->lldd_task; @@ -2123,7 +2092,7 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, } exit: - dev_dbg(dev, "internal task abort: task to dev %016llx task=%p resp: 0x%x sts 0x%x\n", + dev_dbg(dev, "internal task abort: task to dev %016llx task=%pK resp: 0x%x sts 0x%x\n", SAS_ADDR(device->sas_addr), task, task->task_status.resp, /* 0 is complete, -1 is undelivered */ task->task_status.stat); @@ -2291,7 +2260,7 @@ static struct sas_domain_function_template hisi_sas_transport_ops = { void hisi_sas_init_mem(struct hisi_hba *hisi_hba) { - int i, s, j, max_command_entries = hisi_hba->hw->max_command_entries; + int i, s, j, max_command_entries = HISI_SAS_MAX_COMMANDS; struct hisi_sas_breakpoint *sata_breakpoint = hisi_hba->sata_breakpoint; for (i = 0; i < hisi_hba->queue_count; i++) { @@ -2328,7 +2297,7 @@ EXPORT_SYMBOL_GPL(hisi_sas_init_mem); int hisi_sas_alloc(struct hisi_hba *hisi_hba) { struct device *dev = hisi_hba->dev; - int i, j, s, max_command_entries = hisi_hba->hw->max_command_entries; + int i, j, s, max_command_entries = HISI_SAS_MAX_COMMANDS; int max_command_entries_ru, sz_slot_buf_ru; int blk_cnt, slots_per_blk; @@ -2379,7 +2348,7 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba) s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct); hisi_hba->itct = dmam_alloc_coherent(dev, s, &hisi_hba->itct_dma, - GFP_KERNEL | __GFP_ZERO); + GFP_KERNEL); if (!hisi_hba->itct) goto err_out; @@ -2396,7 +2365,7 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba) else sz_slot_buf_ru = sizeof(struct hisi_sas_slot_buf_table); sz_slot_buf_ru = roundup(sz_slot_buf_ru, 64); - s = lcm(max_command_entries_ru, sz_slot_buf_ru); + s = max(lcm(max_command_entries_ru, sz_slot_buf_ru), PAGE_SIZE); blk_cnt = (max_command_entries_ru * sz_slot_buf_ru) / s; slots_per_blk = s / sz_slot_buf_ru; @@ -2406,7 +2375,7 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba) void *buf; buf = dmam_alloc_coherent(dev, s, &buf_dma, - GFP_KERNEL | __GFP_ZERO); + GFP_KERNEL); if (!buf) goto err_out; @@ -2455,11 +2424,9 @@ int hisi_sas_alloc(struct hisi_hba *hisi_hba) GFP_KERNEL); if (!hisi_hba->sata_breakpoint) goto err_out; - hisi_sas_init_mem(hisi_hba); hisi_sas_slot_index_init(hisi_hba); - hisi_hba->last_slot_index = hisi_hba->hw->max_command_entries - - HISI_SAS_RESERVED_IPTT_CNT; + hisi_hba->last_slot_index = HISI_SAS_UNRESERVED_IPTT; hisi_hba->wq = create_singlethread_workqueue(dev_name(dev)); if (!hisi_hba->wq) { @@ -2475,6 +2442,14 @@ EXPORT_SYMBOL_GPL(hisi_sas_alloc); void hisi_sas_free(struct hisi_hba *hisi_hba) { + int i; + + for (i = 0; i < hisi_hba->n_phy; i++) { + struct hisi_sas_phy *phy = &hisi_hba->phy[i]; + + del_timer_sync(&phy->timer); + } + if (hisi_hba->wq) destroy_workqueue(hisi_hba->wq); } @@ -2602,8 +2577,7 @@ static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, goto err_out; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hisi_hba->regs = devm_ioremap_resource(dev, res); + hisi_hba->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hisi_hba->regs)) goto err_out; @@ -2664,13 +2638,11 @@ int hisi_sas_probe(struct platform_device *pdev, shost->max_channel = 1; shost->max_cmd_len = 16; if (hisi_hba->hw->slot_index_alloc) { - shost->can_queue = hisi_hba->hw->max_command_entries; - shost->cmd_per_lun = hisi_hba->hw->max_command_entries; + shost->can_queue = HISI_SAS_MAX_COMMANDS; + shost->cmd_per_lun = HISI_SAS_MAX_COMMANDS; } else { - shost->can_queue = hisi_hba->hw->max_command_entries - - HISI_SAS_RESERVED_IPTT_CNT; - shost->cmd_per_lun = hisi_hba->hw->max_command_entries - - HISI_SAS_RESERVED_IPTT_CNT; + shost->can_queue = HISI_SAS_UNRESERVED_IPTT; + shost->cmd_per_lun = HISI_SAS_UNRESERVED_IPTT; } sha->sas_ha_name = DRV_NAME; @@ -2761,21 +2733,52 @@ static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba) { - u32 *databuf = (u32 *)hisi_hba->debugfs_global_reg; + u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_GLOBAL]; + const struct hisi_sas_hw *hw = hisi_hba->hw; const struct hisi_sas_debugfs_reg *global = - hisi_hba->hw->debugfs_reg_global; + hw->debugfs_reg_array[DEBUGFS_GLOBAL]; int i; for (i = 0; i < global->count; i++, databuf++) *databuf = global->read_global_reg(hisi_hba, 4 * i); } +static void hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba *hisi_hba) +{ + u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_AXI]; + const struct hisi_sas_hw *hw = hisi_hba->hw; + const struct hisi_sas_debugfs_reg *axi = + hw->debugfs_reg_array[DEBUGFS_AXI]; + int i; + + for (i = 0; i < axi->count; i++, databuf++) + *databuf = axi->read_global_reg(hisi_hba, + 4 * i + axi->base_off); +} + +static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba) +{ + u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_RAS]; + const struct hisi_sas_hw *hw = hisi_hba->hw; + const struct hisi_sas_debugfs_reg *ras = + hw->debugfs_reg_array[DEBUGFS_RAS]; + int i; + + for (i = 0; i < ras->count; i++, databuf++) + *databuf = ras->read_global_reg(hisi_hba, + 4 * i + ras->base_off); +} + static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba) { + void *cachebuf = hisi_hba->debugfs_itct_cache; void *databuf = hisi_hba->debugfs_itct; struct hisi_sas_itct *itct; int i; + hisi_hba->hw->read_iost_itct_cache(hisi_hba, HISI_SAS_ITCT_CACHE, + cachebuf); + itct = hisi_hba->itct; for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) { @@ -2786,11 +2789,15 @@ static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba) { - int max_command_entries = hisi_hba->hw->max_command_entries; + int max_command_entries = HISI_SAS_MAX_COMMANDS; + void *cachebuf = hisi_hba->debugfs_iost_cache; void *databuf = hisi_hba->debugfs_iost; struct hisi_sas_iost *iost; int i; + hisi_hba->hw->read_iost_itct_cache(hisi_hba, HISI_SAS_IOST_CACHE, + cachebuf); + iost = hisi_hba->iost; for (i = 0; i < max_command_entries; i++, iost++) { @@ -2837,9 +2844,9 @@ static int hisi_sas_debugfs_global_show(struct seq_file *s, void *p) { struct hisi_hba *hisi_hba = s->private; const struct hisi_sas_hw *hw = hisi_hba->hw; - const struct hisi_sas_debugfs_reg *reg_global = hw->debugfs_reg_global; + const void *reg_global = hw->debugfs_reg_array[DEBUGFS_GLOBAL]; - hisi_sas_debugfs_print_reg(hisi_hba->debugfs_global_reg, + hisi_sas_debugfs_print_reg(hisi_hba->debugfs_regs[DEBUGFS_GLOBAL], reg_global, s); return 0; @@ -2859,6 +2866,58 @@ static const struct file_operations hisi_sas_debugfs_global_fops = { .owner = THIS_MODULE, }; +static int hisi_sas_debugfs_axi_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + const struct hisi_sas_hw *hw = hisi_hba->hw; + const void *reg_axi = hw->debugfs_reg_array[DEBUGFS_AXI]; + + hisi_sas_debugfs_print_reg(hisi_hba->debugfs_regs[DEBUGFS_AXI], + reg_axi, s); + + return 0; +} + +static int hisi_sas_debugfs_axi_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_axi_show, + inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_axi_fops = { + .open = hisi_sas_debugfs_axi_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static int hisi_sas_debugfs_ras_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + const struct hisi_sas_hw *hw = hisi_hba->hw; + const void *reg_ras = hw->debugfs_reg_array[DEBUGFS_RAS]; + + hisi_sas_debugfs_print_reg(hisi_hba->debugfs_regs[DEBUGFS_RAS], + reg_ras, s); + + return 0; +} + +static int hisi_sas_debugfs_ras_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_ras_show, + inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_ras_fops = { + .open = hisi_sas_debugfs_ras_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + static int hisi_sas_debugfs_port_show(struct seq_file *s, void *p) { struct hisi_sas_phy *phy = s->private; @@ -2885,8 +2944,8 @@ static const struct file_operations hisi_sas_debugfs_port_fops = { .owner = THIS_MODULE, }; -static int hisi_sas_show_row_64(struct seq_file *s, int index, - int sz, __le64 *ptr) +static void hisi_sas_show_row_64(struct seq_file *s, int index, + int sz, __le64 *ptr) { int i; @@ -2899,12 +2958,10 @@ static int hisi_sas_show_row_64(struct seq_file *s, int index, } seq_puts(s, "\n"); - - return 0; } -static int hisi_sas_show_row_32(struct seq_file *s, int index, - int sz, __le32 *ptr) +static void hisi_sas_show_row_32(struct seq_file *s, int index, + int sz, __le32 *ptr) { int i; @@ -2916,11 +2973,9 @@ static int hisi_sas_show_row_32(struct seq_file *s, int index, seq_puts(s, "\n\t"); } seq_puts(s, "\n"); - - return 0; } -static int hisi_sas_cq_show_slot(struct seq_file *s, int slot, void *cq_ptr) +static void hisi_sas_cq_show_slot(struct seq_file *s, int slot, void *cq_ptr) { struct hisi_sas_cq *cq = cq_ptr; struct hisi_hba *hisi_hba = cq->hisi_hba; @@ -2928,20 +2983,18 @@ static int hisi_sas_cq_show_slot(struct seq_file *s, int slot, void *cq_ptr) __le32 *complete_hdr = complete_queue + (hisi_hba->hw->complete_hdr_size * slot); - return hisi_sas_show_row_32(s, slot, - hisi_hba->hw->complete_hdr_size, - complete_hdr); + hisi_sas_show_row_32(s, slot, + hisi_hba->hw->complete_hdr_size, + complete_hdr); } static int hisi_sas_debugfs_cq_show(struct seq_file *s, void *p) { struct hisi_sas_cq *cq = s->private; - int slot, ret; + int slot; for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) { - ret = hisi_sas_cq_show_slot(s, slot, cq); - if (ret) - return ret; + hisi_sas_cq_show_slot(s, slot, cq); } return 0; } @@ -2959,7 +3012,7 @@ static const struct file_operations hisi_sas_debugfs_cq_fops = { .owner = THIS_MODULE, }; -static int hisi_sas_dq_show_slot(struct seq_file *s, int slot, void *dq_ptr) +static void hisi_sas_dq_show_slot(struct seq_file *s, int slot, void *dq_ptr) { struct hisi_sas_dq *dq = dq_ptr; struct hisi_hba *hisi_hba = dq->hisi_hba; @@ -2967,18 +3020,15 @@ static int hisi_sas_dq_show_slot(struct seq_file *s, int slot, void *dq_ptr) __le32 *cmd_hdr = cmd_queue + sizeof(struct hisi_sas_cmd_hdr) * slot; - return hisi_sas_show_row_32(s, slot, sizeof(struct hisi_sas_cmd_hdr), - cmd_hdr); + hisi_sas_show_row_32(s, slot, sizeof(struct hisi_sas_cmd_hdr), cmd_hdr); } static int hisi_sas_debugfs_dq_show(struct seq_file *s, void *p) { - int slot, ret; + int slot; for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) { - ret = hisi_sas_dq_show_slot(s, slot, s->private); - if (ret) - return ret; + hisi_sas_dq_show_slot(s, slot, s->private); } return 0; } @@ -3000,14 +3050,12 @@ static int hisi_sas_debugfs_iost_show(struct seq_file *s, void *p) { struct hisi_hba *hisi_hba = s->private; struct hisi_sas_iost *debugfs_iost = hisi_hba->debugfs_iost; - int i, ret, max_command_entries = hisi_hba->hw->max_command_entries; - __le64 *iost = &debugfs_iost->qw0; + int i, max_command_entries = HISI_SAS_MAX_COMMANDS; for (i = 0; i < max_command_entries; i++, debugfs_iost++) { - ret = hisi_sas_show_row_64(s, i, sizeof(*debugfs_iost), - iost); - if (ret) - return ret; + __le64 *iost = &debugfs_iost->qw0; + + hisi_sas_show_row_64(s, i, sizeof(*debugfs_iost), iost); } return 0; @@ -3026,18 +3074,56 @@ static const struct file_operations hisi_sas_debugfs_iost_fops = { .owner = THIS_MODULE, }; +static int hisi_sas_debugfs_iost_cache_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + struct hisi_sas_iost_itct_cache *iost_cache = + (struct hisi_sas_iost_itct_cache *)hisi_hba->debugfs_iost_cache; + u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; + int i, tab_idx; + __le64 *iost; + + for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, iost_cache++) { + /* + * Data struct of IOST cache: + * Data[1]: BIT0~15: Table index + * Bit16: Valid mask + * Data[2]~[9]: IOST table + */ + tab_idx = (iost_cache->data[1] & 0xffff); + iost = (__le64 *)iost_cache; + + hisi_sas_show_row_64(s, tab_idx, cache_size, iost); + } + + return 0; +} + +static int hisi_sas_debugfs_iost_cache_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_iost_cache_show, + inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_iost_cache_fops = { + .open = hisi_sas_debugfs_iost_cache_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + static int hisi_sas_debugfs_itct_show(struct seq_file *s, void *p) { - int i, ret; + int i; struct hisi_hba *hisi_hba = s->private; struct hisi_sas_itct *debugfs_itct = hisi_hba->debugfs_itct; - __le64 *itct = &debugfs_itct->qw0; for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, debugfs_itct++) { - ret = hisi_sas_show_row_64(s, i, sizeof(*debugfs_itct), - itct); - if (ret) - return ret; + __le64 *itct = &debugfs_itct->qw0; + + hisi_sas_show_row_64(s, i, sizeof(*debugfs_itct), itct); } return 0; @@ -3056,6 +3142,46 @@ static const struct file_operations hisi_sas_debugfs_itct_fops = { .owner = THIS_MODULE, }; +static int hisi_sas_debugfs_itct_cache_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + struct hisi_sas_iost_itct_cache *itct_cache = + (struct hisi_sas_iost_itct_cache *)hisi_hba->debugfs_itct_cache; + u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; + int i, tab_idx; + __le64 *itct; + + for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, itct_cache++) { + /* + * Data struct of ITCT cache: + * Data[1]: BIT0~15: Table index + * Bit16: Valid mask + * Data[2]~[9]: ITCT table + */ + tab_idx = itct_cache->data[1] & 0xffff; + itct = (__le64 *)itct_cache; + + hisi_sas_show_row_64(s, tab_idx, cache_size, itct); + } + + return 0; +} + +static int hisi_sas_debugfs_itct_cache_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_itct_cache_show, + inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_itct_cache_fops = { + .open = hisi_sas_debugfs_itct_cache_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) { struct dentry *dump_dentry; @@ -3102,9 +3228,21 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) debugfs_create_file("iost", 0400, dump_dentry, hisi_hba, &hisi_sas_debugfs_iost_fops); + debugfs_create_file("iost_cache", 0400, dump_dentry, hisi_hba, + &hisi_sas_debugfs_iost_cache_fops); + debugfs_create_file("itct", 0400, dump_dentry, hisi_hba, &hisi_sas_debugfs_itct_fops); + debugfs_create_file("itct_cache", 0400, dump_dentry, hisi_hba, + &hisi_sas_debugfs_itct_cache_fops); + + debugfs_create_file("axi", 0400, dump_dentry, hisi_hba, + &hisi_sas_debugfs_axi_fops); + + debugfs_create_file("ras", 0400, dump_dentry, hisi_hba, + &hisi_sas_debugfs_ras_fops); + return; } @@ -3114,6 +3252,8 @@ static void hisi_sas_debugfs_snapshot_regs(struct hisi_hba *hisi_hba) hisi_sas_debugfs_snapshot_global_reg(hisi_hba); hisi_sas_debugfs_snapshot_port_reg(hisi_hba); + hisi_sas_debugfs_snapshot_axi_reg(hisi_hba); + hisi_sas_debugfs_snapshot_ras_reg(hisi_hba); hisi_sas_debugfs_snapshot_cq_reg(hisi_hba); hisi_sas_debugfs_snapshot_dq_reg(hisi_hba); hisi_sas_debugfs_snapshot_itct_reg(hisi_hba); @@ -3154,6 +3294,382 @@ static const struct file_operations hisi_sas_debugfs_trigger_dump_fops = { .owner = THIS_MODULE, }; +enum { + HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL = 0, + HISI_SAS_BIST_LOOPBACK_MODE_SERDES, + HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, +}; + +enum { + HISI_SAS_BIST_CODE_MODE_PRBS7 = 0, + HISI_SAS_BIST_CODE_MODE_PRBS23, + HISI_SAS_BIST_CODE_MODE_PRBS31, + HISI_SAS_BIST_CODE_MODE_JTPAT, + HISI_SAS_BIST_CODE_MODE_CJTPAT, + HISI_SAS_BIST_CODE_MODE_SCRAMBED_0, + HISI_SAS_BIST_CODE_MODE_TRAIN, + HISI_SAS_BIST_CODE_MODE_TRAIN_DONE, + HISI_SAS_BIST_CODE_MODE_HFTP, + HISI_SAS_BIST_CODE_MODE_MFTP, + HISI_SAS_BIST_CODE_MODE_LFTP, + HISI_SAS_BIST_CODE_MODE_FIXED_DATA, +}; + +static const struct { + int value; + char *name; +} hisi_sas_debugfs_loop_linkrate[] = { + { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" }, + { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" }, + { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" }, + { SAS_LINK_RATE_12_0_GBPS, "12.0 Gbit" }, +}; + +static int hisi_sas_debugfs_bist_linkrate_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + int i; + + for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_linkrate); i++) { + int match = (hisi_hba->debugfs_bist_linkrate == + hisi_sas_debugfs_loop_linkrate[i].value); + + seq_printf(s, "%s%s%s ", match ? "[" : "", + hisi_sas_debugfs_loop_linkrate[i].name, + match ? "]" : ""); + } + seq_puts(s, "\n"); + + return 0; +} + +static ssize_t hisi_sas_debugfs_bist_linkrate_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct seq_file *m = filp->private_data; + struct hisi_hba *hisi_hba = m->private; + char kbuf[16] = {}, *pkbuf; + bool found = false; + int i; + + if (hisi_hba->debugfs_bist_enable) + return -EPERM; + + if (count >= sizeof(kbuf)) + return -EOVERFLOW; + + if (copy_from_user(kbuf, buf, count)) + return -EINVAL; + + pkbuf = strstrip(kbuf); + + for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_linkrate); i++) { + if (!strncmp(hisi_sas_debugfs_loop_linkrate[i].name, + pkbuf, 16)) { + hisi_hba->debugfs_bist_linkrate = + hisi_sas_debugfs_loop_linkrate[i].value; + found = true; + break; + } + } + + if (!found) + return -EINVAL; + + return count; +} + +static int hisi_sas_debugfs_bist_linkrate_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_bist_linkrate_show, + inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_bist_linkrate_ops = { + .open = hisi_sas_debugfs_bist_linkrate_open, + .read = seq_read, + .write = hisi_sas_debugfs_bist_linkrate_write, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct { + int value; + char *name; +} hisi_sas_debugfs_loop_code_mode[] = { + { HISI_SAS_BIST_CODE_MODE_PRBS7, "PRBS7" }, + { HISI_SAS_BIST_CODE_MODE_PRBS23, "PRBS23" }, + { HISI_SAS_BIST_CODE_MODE_PRBS31, "PRBS31" }, + { HISI_SAS_BIST_CODE_MODE_JTPAT, "JTPAT" }, + { HISI_SAS_BIST_CODE_MODE_CJTPAT, "CJTPAT" }, + { HISI_SAS_BIST_CODE_MODE_SCRAMBED_0, "SCRAMBED_0" }, + { HISI_SAS_BIST_CODE_MODE_TRAIN, "TRAIN" }, + { HISI_SAS_BIST_CODE_MODE_TRAIN_DONE, "TRAIN_DONE" }, + { HISI_SAS_BIST_CODE_MODE_HFTP, "HFTP" }, + { HISI_SAS_BIST_CODE_MODE_MFTP, "MFTP" }, + { HISI_SAS_BIST_CODE_MODE_LFTP, "LFTP" }, + { HISI_SAS_BIST_CODE_MODE_FIXED_DATA, "FIXED_DATA" }, +}; + +static int hisi_sas_debugfs_bist_code_mode_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + int i; + + for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_code_mode); i++) { + int match = (hisi_hba->debugfs_bist_code_mode == + hisi_sas_debugfs_loop_code_mode[i].value); + + seq_printf(s, "%s%s%s ", match ? "[" : "", + hisi_sas_debugfs_loop_code_mode[i].name, + match ? "]" : ""); + } + seq_puts(s, "\n"); + + return 0; +} + +static ssize_t hisi_sas_debugfs_bist_code_mode_write(struct file *filp, + const char __user *buf, + size_t count, + loff_t *ppos) +{ + struct seq_file *m = filp->private_data; + struct hisi_hba *hisi_hba = m->private; + char kbuf[16] = {}, *pkbuf; + bool found = false; + int i; + + if (hisi_hba->debugfs_bist_enable) + return -EPERM; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(kbuf, buf, count)) + return -EOVERFLOW; + + pkbuf = strstrip(kbuf); + + for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_code_mode); i++) { + if (!strncmp(hisi_sas_debugfs_loop_code_mode[i].name, + pkbuf, 16)) { + hisi_hba->debugfs_bist_code_mode = + hisi_sas_debugfs_loop_code_mode[i].value; + found = true; + break; + } + } + + if (!found) + return -EINVAL; + + return count; +} + +static int hisi_sas_debugfs_bist_code_mode_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_bist_code_mode_show, + inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_bist_code_mode_ops = { + .open = hisi_sas_debugfs_bist_code_mode_open, + .read = seq_read, + .write = hisi_sas_debugfs_bist_code_mode_write, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static ssize_t hisi_sas_debugfs_bist_phy_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct seq_file *m = filp->private_data; + struct hisi_hba *hisi_hba = m->private; + unsigned int phy_no; + int val; + + if (hisi_hba->debugfs_bist_enable) + return -EPERM; + + val = kstrtouint_from_user(buf, count, 0, &phy_no); + if (val) + return val; + + if (phy_no >= hisi_hba->n_phy) + return -EINVAL; + + hisi_hba->debugfs_bist_phy_no = phy_no; + + return count; +} + +static int hisi_sas_debugfs_bist_phy_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + + seq_printf(s, "%d\n", hisi_hba->debugfs_bist_phy_no); + + return 0; +} + +static int hisi_sas_debugfs_bist_phy_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_bist_phy_show, + inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_bist_phy_ops = { + .open = hisi_sas_debugfs_bist_phy_open, + .read = seq_read, + .write = hisi_sas_debugfs_bist_phy_write, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static const struct { + int value; + char *name; +} hisi_sas_debugfs_loop_modes[] = { + { HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL, "digial" }, + { HISI_SAS_BIST_LOOPBACK_MODE_SERDES, "serdes" }, + { HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, "remote" }, +}; + +static int hisi_sas_debugfs_bist_mode_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + int i; + + for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_modes); i++) { + int match = (hisi_hba->debugfs_bist_mode == + hisi_sas_debugfs_loop_modes[i].value); + + seq_printf(s, "%s%s%s ", match ? "[" : "", + hisi_sas_debugfs_loop_modes[i].name, + match ? "]" : ""); + } + seq_puts(s, "\n"); + + return 0; +} + +static ssize_t hisi_sas_debugfs_bist_mode_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct seq_file *m = filp->private_data; + struct hisi_hba *hisi_hba = m->private; + char kbuf[16] = {}, *pkbuf; + bool found = false; + int i; + + if (hisi_hba->debugfs_bist_enable) + return -EPERM; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(kbuf, buf, count)) + return -EOVERFLOW; + + pkbuf = strstrip(kbuf); + + for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_modes); i++) { + if (!strncmp(hisi_sas_debugfs_loop_modes[i].name, pkbuf, 16)) { + hisi_hba->debugfs_bist_mode = + hisi_sas_debugfs_loop_modes[i].value; + found = true; + break; + } + } + + if (!found) + return -EINVAL; + + return count; +} + +static int hisi_sas_debugfs_bist_mode_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_bist_mode_show, + inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_bist_mode_ops = { + .open = hisi_sas_debugfs_bist_mode_open, + .read = seq_read, + .write = hisi_sas_debugfs_bist_mode_write, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + +static ssize_t hisi_sas_debugfs_bist_enable_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct seq_file *m = filp->private_data; + struct hisi_hba *hisi_hba = m->private; + unsigned int enable; + int val; + + val = kstrtouint_from_user(buf, count, 0, &enable); + if (val) + return val; + + if (enable > 1) + return -EINVAL; + + if (enable == hisi_hba->debugfs_bist_enable) + return count; + + if (!hisi_hba->hw->set_bist) + return -EPERM; + + val = hisi_hba->hw->set_bist(hisi_hba, enable); + if (val < 0) + return val; + + hisi_hba->debugfs_bist_enable = enable; + + return count; +} + +static int hisi_sas_debugfs_bist_enable_show(struct seq_file *s, void *p) +{ + struct hisi_hba *hisi_hba = s->private; + + seq_printf(s, "%d\n", hisi_hba->debugfs_bist_enable); + + return 0; +} + +static int hisi_sas_debugfs_bist_enable_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_bist_enable_show, + inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_bist_enable_ops = { + .open = hisi_sas_debugfs_bist_enable_open, + .read = seq_read, + .write = hisi_sas_debugfs_bist_enable_write, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + void hisi_sas_debugfs_work_handler(struct work_struct *work) { struct hisi_hba *hisi_hba = @@ -3167,89 +3683,165 @@ void hisi_sas_debugfs_work_handler(struct work_struct *work) } EXPORT_SYMBOL_GPL(hisi_sas_debugfs_work_handler); -void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba) +static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba) { - int max_command_entries = hisi_hba->hw->max_command_entries; struct device *dev = hisi_hba->dev; - int p, i, c, d; + int i; + + devm_kfree(dev, hisi_hba->debugfs_iost_cache); + devm_kfree(dev, hisi_hba->debugfs_itct_cache); + devm_kfree(dev, hisi_hba->debugfs_iost); + + for (i = 0; i < hisi_hba->queue_count; i++) + devm_kfree(dev, hisi_hba->debugfs_cmd_hdr[i]); + + for (i = 0; i < hisi_hba->queue_count; i++) + devm_kfree(dev, hisi_hba->debugfs_complete_hdr[i]); + + for (i = 0; i < DEBUGFS_REGS_NUM; i++) + devm_kfree(dev, hisi_hba->debugfs_regs[i]); + + for (i = 0; i < hisi_hba->n_phy; i++) + devm_kfree(dev, hisi_hba->debugfs_port_reg[i]); +} + +static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) +{ + const struct hisi_sas_hw *hw = hisi_hba->hw; + struct device *dev = hisi_hba->dev; + int p, c, d; size_t sz; - hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev), - hisi_sas_debugfs_dir); - debugfs_create_file("trigger_dump", 0600, - hisi_hba->debugfs_dir, - hisi_hba, - &hisi_sas_debugfs_trigger_dump_fops); + hisi_hba->debugfs_dump_dentry = + debugfs_create_dir("dump", hisi_hba->debugfs_dir); - /* Alloc buffer for global */ - sz = hisi_hba->hw->debugfs_reg_global->count * 4; - hisi_hba->debugfs_global_reg = - devm_kmalloc(dev, sz, GFP_KERNEL); + sz = hw->debugfs_reg_array[DEBUGFS_GLOBAL]->count * 4; + hisi_hba->debugfs_regs[DEBUGFS_GLOBAL] = + devm_kmalloc(dev, sz, GFP_KERNEL); - if (!hisi_hba->debugfs_global_reg) - goto fail_global; + if (!hisi_hba->debugfs_regs[DEBUGFS_GLOBAL]) + goto fail; - /* Alloc buffer for port */ - sz = hisi_hba->hw->debugfs_reg_port->count * 4; + sz = hw->debugfs_reg_port->count * 4; for (p = 0; p < hisi_hba->n_phy; p++) { hisi_hba->debugfs_port_reg[p] = devm_kmalloc(dev, sz, GFP_KERNEL); if (!hisi_hba->debugfs_port_reg[p]) - goto fail_port; + goto fail; } - /* Alloc buffer for cq */ - sz = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; + sz = hw->debugfs_reg_array[DEBUGFS_AXI]->count * 4; + hisi_hba->debugfs_regs[DEBUGFS_AXI] = + devm_kmalloc(dev, sz, GFP_KERNEL); + + if (!hisi_hba->debugfs_regs[DEBUGFS_AXI]) + goto fail; + + sz = hw->debugfs_reg_array[DEBUGFS_RAS]->count * 4; + hisi_hba->debugfs_regs[DEBUGFS_RAS] = + devm_kmalloc(dev, sz, GFP_KERNEL); + + if (!hisi_hba->debugfs_regs[DEBUGFS_RAS]) + goto fail; + + sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; for (c = 0; c < hisi_hba->queue_count; c++) { hisi_hba->debugfs_complete_hdr[c] = devm_kmalloc(dev, sz, GFP_KERNEL); if (!hisi_hba->debugfs_complete_hdr[c]) - goto fail_cq; + goto fail; } - /* Alloc buffer for dq */ sz = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; for (d = 0; d < hisi_hba->queue_count; d++) { hisi_hba->debugfs_cmd_hdr[d] = devm_kmalloc(dev, sz, GFP_KERNEL); if (!hisi_hba->debugfs_cmd_hdr[d]) - goto fail_iost_dq; + goto fail; } - /* Alloc buffer for iost */ - sz = max_command_entries * sizeof(struct hisi_sas_iost); + sz = HISI_SAS_MAX_COMMANDS * sizeof(struct hisi_sas_iost); hisi_hba->debugfs_iost = devm_kmalloc(dev, sz, GFP_KERNEL); if (!hisi_hba->debugfs_iost) - goto fail_iost_dq; + goto fail; + + sz = HISI_SAS_IOST_ITCT_CACHE_NUM * + sizeof(struct hisi_sas_iost_itct_cache); + + hisi_hba->debugfs_iost_cache = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_iost_cache) + goto fail; + + sz = HISI_SAS_IOST_ITCT_CACHE_NUM * + sizeof(struct hisi_sas_iost_itct_cache); + + hisi_hba->debugfs_itct_cache = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_itct_cache) + goto fail; - /* Alloc buffer for itct */ /* New memory allocation must be locate before itct */ sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct); hisi_hba->debugfs_itct = devm_kmalloc(dev, sz, GFP_KERNEL); if (!hisi_hba->debugfs_itct) - goto fail_itct; + goto fail; - return; -fail_itct: - devm_kfree(dev, hisi_hba->debugfs_iost); -fail_iost_dq: - for (i = 0; i < d; i++) - devm_kfree(dev, hisi_hba->debugfs_cmd_hdr[i]); -fail_cq: - for (i = 0; i < c; i++) - devm_kfree(dev, hisi_hba->debugfs_complete_hdr[i]); -fail_port: - for (i = 0; i < p; i++) - devm_kfree(dev, hisi_hba->debugfs_port_reg[i]); - devm_kfree(dev, hisi_hba->debugfs_global_reg); -fail_global: - debugfs_remove_recursive(hisi_hba->debugfs_dir); - dev_dbg(dev, "failed to init debugfs!\n"); + return 0; +fail: + hisi_sas_debugfs_release(hisi_hba); + return -ENOMEM; +} + +static void hisi_sas_debugfs_bist_init(struct hisi_hba *hisi_hba) +{ + hisi_hba->debugfs_bist_dentry = + debugfs_create_dir("bist", hisi_hba->debugfs_dir); + debugfs_create_file("link_rate", 0600, + hisi_hba->debugfs_bist_dentry, hisi_hba, + &hisi_sas_debugfs_bist_linkrate_ops); + + debugfs_create_file("code_mode", 0600, + hisi_hba->debugfs_bist_dentry, hisi_hba, + &hisi_sas_debugfs_bist_code_mode_ops); + + debugfs_create_file("phy_id", 0600, hisi_hba->debugfs_bist_dentry, + hisi_hba, &hisi_sas_debugfs_bist_phy_ops); + + debugfs_create_u32("cnt", 0600, hisi_hba->debugfs_bist_dentry, + &hisi_hba->debugfs_bist_cnt); + + debugfs_create_file("loopback_mode", 0600, + hisi_hba->debugfs_bist_dentry, + hisi_hba, &hisi_sas_debugfs_bist_mode_ops); + + debugfs_create_file("enable", 0600, hisi_hba->debugfs_bist_dentry, + hisi_hba, &hisi_sas_debugfs_bist_enable_ops); + + hisi_hba->debugfs_bist_linkrate = SAS_LINK_RATE_1_5_GBPS; +} + +void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba) +{ + struct device *dev = hisi_hba->dev; + + hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev), + hisi_sas_debugfs_dir); + debugfs_create_file("trigger_dump", 0600, + hisi_hba->debugfs_dir, + hisi_hba, + &hisi_sas_debugfs_trigger_dump_fops); + + /* create bist structures */ + hisi_sas_debugfs_bist_init(hisi_hba); + + if (hisi_sas_debugfs_alloc(hisi_hba)) { + debugfs_remove_recursive(hisi_hba->debugfs_dir); + dev_dbg(dev, "failed to init debugfs!\n"); + } } EXPORT_SYMBOL_GPL(hisi_sas_debugfs_init); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index 3912216e8a4f..b861a0f14c9d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -401,8 +401,6 @@ enum { TRANS_RX_SMP_RESP_TIMEOUT_ERR, /* 0x31a */ }; -#define HISI_SAS_COMMAND_ENTRIES_V1_HW 8192 - #define HISI_SAS_PHY_MAX_INT_NR (HISI_SAS_PHY_INT_NR * HISI_SAS_MAX_PHYS) #define HISI_SAS_CQ_MAX_INT_NR (HISI_SAS_MAX_QUEUES) #define HISI_SAS_FATAL_INT_NR (2) @@ -418,13 +416,6 @@ static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) return readl(regs); } -static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off) -{ - void __iomem *regs = hisi_hba->regs + off; - - return readl_relaxed(regs); -} - static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val) { @@ -866,30 +857,6 @@ static int get_wideport_bitmap_v1_hw(struct hisi_hba *hisi_hba, int port_id) return bitmap; } -/* - * The callpath to this function and upto writing the write - * queue pointer should be safe from interruption. - */ -static int -get_free_slot_v1_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq) -{ - struct device *dev = hisi_hba->dev; - int queue = dq->id; - u32 r, w; - - w = dq->wr_point; - r = hisi_sas_read32_relaxed(hisi_hba, - DLVRY_Q_0_RD_PTR + (queue * 0x14)); - if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) { - dev_warn(dev, "could not find free slot\n"); - return -EAGAIN; - } - - dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; - - return w; -} - /* DQ lock must be taken here */ static void start_delivery_v1_hw(struct hisi_sas_dq *dq) { @@ -1308,21 +1275,17 @@ static int slot_complete_v1_hw(struct hisi_hba *hisi_hba, } case SAS_PROTOCOL_SMP: { - void *to; struct scatterlist *sg_resp = &task->smp_task.smp_resp; + void *to = page_address(sg_page(sg_resp)); ts->stat = SAM_STAT_GOOD; - to = kmap_atomic(sg_page(sg_resp)); - dma_unmap_sg(dev, &task->smp_task.smp_resp, 1, - DMA_FROM_DEVICE); dma_unmap_sg(dev, &task->smp_task.smp_req, 1, DMA_TO_DEVICE); memcpy(to + sg_resp->offset, hisi_sas_status_buf_addr_mem(slot) + sizeof(struct hisi_sas_err_record), - sg_dma_len(sg_resp)); - kunmap_atomic(to); + sg_resp->length); break; } case SAS_PROTOCOL_SATA: @@ -1534,11 +1497,9 @@ static irqreturn_t cq_interrupt_v1_hw(int irq, void *p) struct hisi_sas_complete_v1_hdr *complete_queue = (struct hisi_sas_complete_v1_hdr *) hisi_hba->complete_hdr[queue]; - u32 irq_value, rd_point = cq->rd_point, wr_point; + u32 rd_point = cq->rd_point, wr_point; spin_lock(&hisi_hba->lock); - irq_value = hisi_sas_read32(hisi_hba, OQ_INT_SRC); - hisi_sas_write32(hisi_hba, OQ_INT_SRC, 1 << queue); wr_point = hisi_sas_read32(hisi_hba, COMPL_Q_0_WR_PTR + (0x14 * queue)); @@ -1820,9 +1781,7 @@ static const struct hisi_sas_hw hisi_sas_v1_hw = { .clear_itct = clear_itct_v1_hw, .prep_smp = prep_smp_v1_hw, .prep_ssp = prep_ssp_v1_hw, - .get_free_slot = get_free_slot_v1_hw, .start_delivery = start_delivery_v1_hw, - .slot_complete = slot_complete_v1_hw, .phys_init = phys_init_v1_hw, .phy_start = start_phy_v1_hw, .phy_disable = disable_phy_v1_hw, @@ -1830,7 +1789,6 @@ static const struct hisi_sas_hw hisi_sas_v1_hw = { .phy_set_linkrate = phy_set_linkrate_v1_hw, .phy_get_max_linkrate = phy_get_max_linkrate_v1_hw, .get_wideport_bitmap = get_wideport_bitmap_v1_hw, - .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V1_HW, .complete_hdr_size = sizeof(struct hisi_sas_complete_v1_hdr), .sht = &sht_v1_hw, }; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index d99086ef6244..8e96a257e439 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -422,70 +422,70 @@ static const struct hisi_sas_hw_error one_bit_ecc_errors[] = { .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_1B_OFF), .msk = HGC_DQE_ECC_1B_ADDR_MSK, .shift = HGC_DQE_ECC_1B_ADDR_OFF, - .msg = "hgc_dqe_acc1b_intr found: Ram address is 0x%08X\n", + .msg = "hgc_dqe_ecc1b_intr", .reg = HGC_DQE_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_1B_OFF), .msk = HGC_IOST_ECC_1B_ADDR_MSK, .shift = HGC_IOST_ECC_1B_ADDR_OFF, - .msg = "hgc_iost_acc1b_intr found: Ram address is 0x%08X\n", + .msg = "hgc_iost_ecc1b_intr", .reg = HGC_IOST_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_1B_OFF), .msk = HGC_ITCT_ECC_1B_ADDR_MSK, .shift = HGC_ITCT_ECC_1B_ADDR_OFF, - .msg = "hgc_itct_acc1b_intr found: am address is 0x%08X\n", + .msg = "hgc_itct_ecc1b_intr", .reg = HGC_ITCT_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_1B_OFF), .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK, .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF, - .msg = "hgc_iostl_acc1b_intr found: memory address is 0x%08X\n", + .msg = "hgc_iostl_ecc1b_intr", .reg = HGC_LM_DFX_STATUS2, }, { .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_1B_OFF), .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK, .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF, - .msg = "hgc_itctl_acc1b_intr found: memory address is 0x%08X\n", + .msg = "hgc_itctl_ecc1b_intr", .reg = HGC_LM_DFX_STATUS2, }, { .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_1B_OFF), .msk = HGC_CQE_ECC_1B_ADDR_MSK, .shift = HGC_CQE_ECC_1B_ADDR_OFF, - .msg = "hgc_cqe_acc1b_intr found: Ram address is 0x%08X\n", + .msg = "hgc_cqe_ecc1b_intr", .reg = HGC_CQE_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_1B_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF, - .msg = "rxm_mem0_acc1b_intr found: memory address is 0x%08X\n", + .msg = "rxm_mem0_ecc1b_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_1B_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF, - .msg = "rxm_mem1_acc1b_intr found: memory address is 0x%08X\n", + .msg = "rxm_mem1_ecc1b_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_1B_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF, - .msg = "rxm_mem2_acc1b_intr found: memory address is 0x%08X\n", + .msg = "rxm_mem2_ecc1b_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_1B_OFF), .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK, .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF, - .msg = "rxm_mem3_acc1b_intr found: memory address is 0x%08X\n", + .msg = "rxm_mem3_ecc1b_intr", .reg = HGC_RXM_DFX_STATUS15, }, }; @@ -495,70 +495,70 @@ static const struct hisi_sas_hw_error multi_bit_ecc_errors[] = { .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF), .msk = HGC_DQE_ECC_MB_ADDR_MSK, .shift = HGC_DQE_ECC_MB_ADDR_OFF, - .msg = "hgc_dqe_accbad_intr (0x%x) found: Ram address is 0x%08X\n", + .msg = "hgc_dqe_eccbad_intr", .reg = HGC_DQE_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF), .msk = HGC_IOST_ECC_MB_ADDR_MSK, .shift = HGC_IOST_ECC_MB_ADDR_OFF, - .msg = "hgc_iost_accbad_intr (0x%x) found: Ram address is 0x%08X\n", + .msg = "hgc_iost_eccbad_intr", .reg = HGC_IOST_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF), .msk = HGC_ITCT_ECC_MB_ADDR_MSK, .shift = HGC_ITCT_ECC_MB_ADDR_OFF, - .msg = "hgc_itct_accbad_intr (0x%x) found: Ram address is 0x%08X\n", + .msg = "hgc_itct_eccbad_intr", .reg = HGC_ITCT_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF), .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK, .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF, - .msg = "hgc_iostl_accbad_intr (0x%x) found: memory address is 0x%08X\n", + .msg = "hgc_iostl_eccbad_intr", .reg = HGC_LM_DFX_STATUS2, }, { .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF), .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK, .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF, - .msg = "hgc_itctl_accbad_intr (0x%x) found: memory address is 0x%08X\n", + .msg = "hgc_itctl_eccbad_intr", .reg = HGC_LM_DFX_STATUS2, }, { .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF), .msk = HGC_CQE_ECC_MB_ADDR_MSK, .shift = HGC_CQE_ECC_MB_ADDR_OFF, - .msg = "hgc_cqe_accbad_intr (0x%x) found: Ram address is 0x%08X\n", + .msg = "hgc_cqe_eccbad_intr", .reg = HGC_CQE_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF, - .msg = "rxm_mem0_accbad_intr (0x%x) found: memory address is 0x%08X\n", + .msg = "rxm_mem0_eccbad_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF, - .msg = "rxm_mem1_accbad_intr (0x%x) found: memory address is 0x%08X\n", + .msg = "rxm_mem1_eccbad_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF, - .msg = "rxm_mem2_accbad_intr (0x%x) found: memory address is 0x%08X\n", + .msg = "rxm_mem2_eccbad_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF), .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK, .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF, - .msg = "rxm_mem3_accbad_intr (0x%x) found: memory address is 0x%08X\n", + .msg = "rxm_mem3_eccbad_intr", .reg = HGC_RXM_DFX_STATUS15, }, }; @@ -944,7 +944,7 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, break; case SAS_SATA_DEV: case SAS_SATA_PENDING: - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + if (parent_dev && dev_is_expander(parent_dev->dev_type)) qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF; else qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF; @@ -1637,31 +1637,6 @@ static int get_wideport_bitmap_v2_hw(struct hisi_hba *hisi_hba, int port_id) return bitmap; } -/* - * The callpath to this function and upto writing the write - * queue pointer should be safe from interruption. - */ -static int -get_free_slot_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq) -{ - struct device *dev = hisi_hba->dev; - int queue = dq->id; - u32 r, w; - - w = dq->wr_point; - r = hisi_sas_read32_relaxed(hisi_hba, - DLVRY_Q_0_RD_PTR + (queue * 0x14)); - if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) { - dev_warn(dev, "full queue=%d r=%d w=%d\n", - queue, r, w); - return -EAGAIN; - } - - dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; - - return w; -} - /* DQ lock must be taken here */ static void start_delivery_v2_hw(struct hisi_sas_dq *dq) { @@ -2418,7 +2393,7 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) slot_err_v2_hw(hisi_hba, task, slot, 2); if (ts->stat != SAS_DATA_UNDERRUN) - dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n", + dev_info(dev, "erroneous completion iptt=%d task=%pK dev id=%d CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n", slot->idx, task, sas_dev->device_id, complete_hdr->dw0, complete_hdr->dw1, complete_hdr->act, complete_hdr->dw3, @@ -2444,20 +2419,16 @@ slot_complete_v2_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) case SAS_PROTOCOL_SMP: { struct scatterlist *sg_resp = &task->smp_task.smp_resp; - void *to; + void *to = page_address(sg_page(sg_resp)); ts->stat = SAM_STAT_GOOD; - to = kmap_atomic(sg_page(sg_resp)); - dma_unmap_sg(dev, &task->smp_task.smp_resp, 1, - DMA_FROM_DEVICE); dma_unmap_sg(dev, &task->smp_task.smp_req, 1, DMA_TO_DEVICE); memcpy(to + sg_resp->offset, hisi_sas_status_buf_addr_mem(slot) + sizeof(struct hisi_sas_err_record), - sg_dma_len(sg_resp)); - kunmap_atomic(to); + sg_resp->length); break; } case SAS_PROTOCOL_SATA: @@ -2484,7 +2455,7 @@ out: spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { spin_unlock_irqrestore(&task->task_state_lock, flags); - dev_info(dev, "slot complete: task(%p) aborted\n", task); + dev_info(dev, "slot complete: task(%pK) aborted\n", task); return SAS_ABORTED_TASK; } task->task_state_flags |= SAS_TASK_STATE_DONE; @@ -2495,7 +2466,7 @@ out: spin_lock_irqsave(&device->done_lock, flags); if (test_bit(SAS_HA_FROZEN, &ha->state)) { spin_unlock_irqrestore(&device->done_lock, flags); - dev_info(dev, "slot complete: task(%p) ignored\n", + dev_info(dev, "slot complete: task(%pK) ignored\n", task); return sts; } @@ -2526,7 +2497,7 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, /* create header */ /* dw0 */ dw0 = port->id << CMD_HDR_PORT_OFF; - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + if (parent_dev && dev_is_expander(parent_dev->dev_type)) dw0 |= 3 << CMD_HDR_CMD_OFF; else dw0 |= 4 << CMD_HDR_CMD_OFF; @@ -2563,7 +2534,10 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba, hdr->dw1 = cpu_to_le32(dw1); /* dw2 */ - if (task->ata_task.use_ncq && hisi_sas_get_ncq_tag(task, &hdr_tag)) { + if (task->ata_task.use_ncq) { + struct ata_queued_cmd *qc = task->uldd_task; + + hdr_tag = qc->tag; task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF; } @@ -2973,7 +2947,8 @@ one_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba, u32 irq_value) val = hisi_sas_read32(hisi_hba, ecc_error->reg); val &= ecc_error->msk; val >>= ecc_error->shift; - dev_warn(dev, ecc_error->msg, val); + dev_warn(dev, "%s found: mem addr is 0x%08X\n", + ecc_error->msg, val); } } } @@ -2992,7 +2967,8 @@ static void multi_bit_ecc_error_process_v2_hw(struct hisi_hba *hisi_hba, val = hisi_sas_read32(hisi_hba, ecc_error->reg); val &= ecc_error->msk; val >>= ecc_error->shift; - dev_err(dev, ecc_error->msg, irq_value, val); + dev_err(dev, "%s (0x%x) found: mem addr is 0x%08X\n", + ecc_error->msg, irq_value, val); queue_work(hisi_hba->wq, &hisi_hba->rst_work); } } @@ -3331,8 +3307,8 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) { struct platform_device *pdev = hisi_hba->platform_dev; struct device *dev = &pdev->dev; - int irq, rc, irq_map[128]; - int i, phy_no, fatal_no, queue_no, k; + int irq, rc = 0, irq_map[128]; + int i, phy_no, fatal_no, queue_no; for (i = 0; i < 128; i++) irq_map[i] = platform_get_irq(pdev, i); @@ -3345,7 +3321,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) dev_err(dev, "irq init: could not request phy interrupt %d, rc=%d\n", irq, rc); rc = -ENOENT; - goto free_phy_int_irqs; + goto err_out; } } @@ -3359,7 +3335,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) dev_err(dev, "irq init: could not request sata interrupt %d, rc=%d\n", irq, rc); rc = -ENOENT; - goto free_sata_int_irqs; + goto err_out; } } @@ -3371,7 +3347,7 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) dev_err(dev, "irq init: could not request fatal interrupt %d, rc=%d\n", irq, rc); rc = -ENOENT; - goto free_fatal_int_irqs; + goto err_out; } } @@ -3386,34 +3362,14 @@ static int interrupt_init_v2_hw(struct hisi_hba *hisi_hba) dev_err(dev, "irq init: could not request cq interrupt %d, rc=%d\n", irq, rc); rc = -ENOENT; - goto free_cq_int_irqs; + goto err_out; } tasklet_init(t, cq_tasklet_v2_hw, (unsigned long)cq); } hisi_hba->cq_nvecs = hisi_hba->queue_count; - return 0; - -free_cq_int_irqs: - for (k = 0; k < queue_no; k++) { - struct hisi_sas_cq *cq = &hisi_hba->cq[k]; - - free_irq(irq_map[k + 96], cq); - tasklet_kill(&cq->tasklet); - } -free_fatal_int_irqs: - for (k = 0; k < fatal_no; k++) - free_irq(irq_map[k + 81], hisi_hba); -free_sata_int_irqs: - for (k = 0; k < phy_no; k++) { - struct hisi_sas_phy *phy = &hisi_hba->phy[k]; - - free_irq(irq_map[k + 72], phy); - } -free_phy_int_irqs: - for (k = 0; k < i; k++) - free_irq(irq_map[k + 1], hisi_hba); +err_out: return rc; } @@ -3542,8 +3498,8 @@ static int write_gpio_v2_hw(struct hisi_hba *hisi_hba, u8 reg_type, return 0; } -static int wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba, - int delay_ms, int timeout_ms) +static void wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba, + int delay_ms, int timeout_ms) { struct device *dev = hisi_hba->dev; int entries, entries_old = 0, time; @@ -3557,12 +3513,13 @@ static int wait_cmds_complete_timeout_v2_hw(struct hisi_hba *hisi_hba, msleep(delay_ms); } - if (time >= timeout_ms) - return -ETIMEDOUT; + if (time >= timeout_ms) { + dev_dbg(dev, "Wait commands complete timeout!\n"); + return; + } dev_dbg(dev, "wait commands complete %dms\n", time); - return 0; } static struct device_attribute *host_attrs_v2_hw[] = { @@ -3604,9 +3561,7 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = { .prep_ssp = prep_ssp_v2_hw, .prep_stp = prep_ata_v2_hw, .prep_abort = prep_abort_v2_hw, - .get_free_slot = get_free_slot_v2_hw, .start_delivery = start_delivery_v2_hw, - .slot_complete = slot_complete_v2_hw, .phys_init = phys_init_v2_hw, .phy_start = start_phy_v2_hw, .phy_disable = disable_phy_v2_hw, @@ -3614,7 +3569,6 @@ static const struct hisi_sas_hw hisi_sas_v2_hw = { .get_events = phy_get_events_v2_hw, .phy_set_linkrate = phy_set_linkrate_v2_hw, .phy_get_max_linkrate = phy_get_max_linkrate_v2_hw, - .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V2_HW, .complete_hdr_size = sizeof(struct hisi_sas_complete_v2_hdr), .soft_reset = soft_reset_v2_hw, .get_phys_state = get_phys_state_v2_hw, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 0efd55baacd3..cb8d087762db 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -23,6 +23,7 @@ #define ITCT_CLR_EN_MSK (0x1 << ITCT_CLR_EN_OFF) #define ITCT_DEV_OFF 0 #define ITCT_DEV_MSK (0x7ff << ITCT_DEV_OFF) +#define SAS_AXI_USER3 0x50 #define IO_SATA_BROKEN_MSG_ADDR_LO 0x58 #define IO_SATA_BROKEN_MSG_ADDR_HI 0x5c #define SATA_INITI_D2H_STORE_ADDR_LO 0x60 @@ -70,6 +71,7 @@ #define HGC_DQE_ECC_MB_ADDR_OFF 16 #define HGC_DQE_ECC_MB_ADDR_MSK (0xfff << HGC_DQE_ECC_MB_ADDR_OFF) #define CHNL_INT_STATUS 0x148 +#define TAB_DFX 0x14c #define HGC_ITCT_ECC_ADDR 0x150 #define HGC_ITCT_ECC_1B_ADDR_OFF 0 #define HGC_ITCT_ECC_1B_ADDR_MSK (0x3ff << \ @@ -82,6 +84,7 @@ #define AXI_ERR_INFO_MSK (0xff << AXI_ERR_INFO_OFF) #define FIFO_ERR_INFO_OFF 8 #define FIFO_ERR_INFO_MSK (0xff << FIFO_ERR_INFO_OFF) +#define TAB_RD_TYPE 0x15c #define INT_COAL_EN 0x19c #define OQ_INT_COAL_TIME 0x1a0 #define OQ_INT_COAL_CNT 0x1a4 @@ -188,12 +191,30 @@ #define PHY_CFG_PHY_RST_OFF 3 #define PHY_CFG_PHY_RST_MSK (0x1 << PHY_CFG_PHY_RST_OFF) #define PROG_PHY_LINK_RATE (PORT_BASE + 0x8) +#define CFG_PROG_PHY_LINK_RATE_OFF 8 +#define CFG_PROG_PHY_LINK_RATE_MSK (0xf << CFG_PROG_PHY_LINK_RATE_OFF) #define PHY_CTRL (PORT_BASE + 0x14) #define PHY_CTRL_RESET_OFF 0 #define PHY_CTRL_RESET_MSK (0x1 << PHY_CTRL_RESET_OFF) #define CMD_HDR_PIR_OFF 8 #define CMD_HDR_PIR_MSK (0x1 << CMD_HDR_PIR_OFF) #define SERDES_CFG (PORT_BASE + 0x1c) +#define CFG_ALOS_CHK_DISABLE_OFF 9 +#define CFG_ALOS_CHK_DISABLE_MSK (0x1 << CFG_ALOS_CHK_DISABLE_OFF) +#define SAS_PHY_BIST_CTRL (PORT_BASE + 0x2c) +#define CFG_BIST_MODE_SEL_OFF 0 +#define CFG_BIST_MODE_SEL_MSK (0xf << CFG_BIST_MODE_SEL_OFF) +#define CFG_LOOP_TEST_MODE_OFF 14 +#define CFG_LOOP_TEST_MODE_MSK (0x3 << CFG_LOOP_TEST_MODE_OFF) +#define CFG_RX_BIST_EN_OFF 16 +#define CFG_RX_BIST_EN_MSK (0x1 << CFG_RX_BIST_EN_OFF) +#define CFG_TX_BIST_EN_OFF 17 +#define CFG_TX_BIST_EN_MSK (0x1 << CFG_TX_BIST_EN_OFF) +#define CFG_BIST_TEST_OFF 18 +#define CFG_BIST_TEST_MSK (0x1 << CFG_BIST_TEST_OFF) +#define SAS_PHY_BIST_CODE (PORT_BASE + 0x30) +#define SAS_PHY_BIST_CODE1 (PORT_BASE + 0x34) +#define SAS_BIST_ERR_CNT (PORT_BASE + 0x38) #define SL_CFG (PORT_BASE + 0x84) #define AIP_LIMIT (PORT_BASE + 0x90) #define SL_CONTROL (PORT_BASE + 0x94) @@ -498,13 +519,6 @@ static u32 hisi_sas_read32(struct hisi_hba *hisi_hba, u32 off) return readl(regs); } -static u32 hisi_sas_read32_relaxed(struct hisi_hba *hisi_hba, u32 off) -{ - void __iomem *regs = hisi_hba->regs + off; - - return readl_relaxed(regs); -} - static void hisi_sas_write32(struct hisi_hba *hisi_hba, u32 off, u32 val) { void __iomem *regs = hisi_hba->regs + off; @@ -549,6 +563,7 @@ static void init_reg_v3_hw(struct hisi_hba *hisi_hba) /* Global registers init */ hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, (u32)((1ULL << hisi_hba->queue_count) - 1)); + hisi_sas_write32(hisi_hba, SAS_AXI_USER3, 0); hisi_sas_write32(hisi_hba, CFG_MAX_TAG, 0xfff0400); hisi_sas_write32(hisi_hba, HGC_SAS_TXFAIL_RETRY_CTRL, 0x108); hisi_sas_write32(hisi_hba, CFG_AGING_TIME, 0x1); @@ -752,7 +767,7 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba, break; case SAS_SATA_DEV: case SAS_SATA_PENDING: - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + if (parent_dev && dev_is_expander(parent_dev->dev_type)) qw0 = HISI_SAS_DEV_TYPE_STP << ITCT_HDR_DEV_TYPE_OFF; else qw0 = HISI_SAS_DEV_TYPE_SATA << ITCT_HDR_DEV_TYPE_OFF; @@ -906,8 +921,14 @@ static void enable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) { u32 cfg = hisi_sas_phy_read32(hisi_hba, phy_no, PHY_CFG); + u32 irq_msk = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2_MSK); + static const u32 msk = BIT(CHL_INT2_RX_DISP_ERR_OFF) | + BIT(CHL_INT2_RX_CODE_ERR_OFF) | + BIT(CHL_INT2_RX_INVLD_DW_OFF); u32 state; + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2_MSK, msk | irq_msk); + cfg &= ~PHY_CFG_ENA_MSK; hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); @@ -918,6 +939,15 @@ static void disable_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) cfg |= PHY_CFG_PHY_RST_MSK; hisi_sas_phy_write32(hisi_hba, phy_no, PHY_CFG, cfg); } + + udelay(1); + + hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_INVLD_DW); + hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_DISP_ERR); + hisi_sas_phy_read32(hisi_hba, phy_no, ERR_CNT_CODE_ERR); + + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2, msk); + hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2_MSK, irq_msk); } static void start_phy_v3_hw(struct hisi_hba *hisi_hba, int phy_no) @@ -989,31 +1019,6 @@ static int get_wideport_bitmap_v3_hw(struct hisi_hba *hisi_hba, int port_id) return bitmap; } -/** - * The callpath to this function and upto writing the write - * queue pointer should be safe from interruption. - */ -static int -get_free_slot_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_dq *dq) -{ - struct device *dev = hisi_hba->dev; - int queue = dq->id; - u32 r, w; - - w = dq->wr_point; - r = hisi_sas_read32_relaxed(hisi_hba, - DLVRY_Q_0_RD_PTR + (queue * 0x14)); - if (r == (w+1) % HISI_SAS_QUEUE_SLOTS) { - dev_warn(dev, "full queue=%d r=%d w=%d\n", - queue, r, w); - return -EAGAIN; - } - - dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; - - return w; -} - static void start_delivery_v3_hw(struct hisi_sas_dq *dq) { struct hisi_hba *hisi_hba = dq->hisi_hba; @@ -1336,10 +1341,10 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, u32 dw1 = 0, dw2 = 0; hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF); - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + if (parent_dev && dev_is_expander(parent_dev->dev_type)) hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF); else - hdr->dw0 |= cpu_to_le32(4 << CMD_HDR_CMD_OFF); + hdr->dw0 |= cpu_to_le32(4U << CMD_HDR_CMD_OFF); switch (task->data_dir) { case DMA_TO_DEVICE: @@ -1369,7 +1374,10 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba, hdr->dw1 = cpu_to_le32(dw1); /* dw2 */ - if (task->ata_task.use_ncq && hisi_sas_get_ncq_tag(task, &hdr_tag)) { + if (task->ata_task.use_ncq) { + struct ata_queued_cmd *qc = task->uldd_task; + + hdr_tag = qc->tag; task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); dw2 |= hdr_tag << CMD_HDR_NCQ_TAG_OFF; } @@ -1407,7 +1415,7 @@ static void prep_abort_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_port *port = slot->port; /* dw0 */ - hdr->dw0 = cpu_to_le32((5 << CMD_HDR_CMD_OFF) | /*abort*/ + hdr->dw0 = cpu_to_le32((5U << CMD_HDR_CMD_OFF) | /*abort*/ (port->id << CMD_HDR_PORT_OFF) | (dev_is_sata(dev) << CMD_HDR_ABORT_DEVICE_TYPE_OFF) | @@ -1826,77 +1834,77 @@ static const struct hisi_sas_hw_error multi_bit_ecc_errors[] = { .irq_msk = BIT(SAS_ECC_INTR_DQE_ECC_MB_OFF), .msk = HGC_DQE_ECC_MB_ADDR_MSK, .shift = HGC_DQE_ECC_MB_ADDR_OFF, - .msg = "hgc_dqe_eccbad_intr found: ram addr is 0x%08X\n", + .msg = "hgc_dqe_eccbad_intr", .reg = HGC_DQE_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_IOST_ECC_MB_OFF), .msk = HGC_IOST_ECC_MB_ADDR_MSK, .shift = HGC_IOST_ECC_MB_ADDR_OFF, - .msg = "hgc_iost_eccbad_intr found: ram addr is 0x%08X\n", + .msg = "hgc_iost_eccbad_intr", .reg = HGC_IOST_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_ITCT_ECC_MB_OFF), .msk = HGC_ITCT_ECC_MB_ADDR_MSK, .shift = HGC_ITCT_ECC_MB_ADDR_OFF, - .msg = "hgc_itct_eccbad_intr found: ram addr is 0x%08X\n", + .msg = "hgc_itct_eccbad_intr", .reg = HGC_ITCT_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_IOSTLIST_ECC_MB_OFF), .msk = HGC_LM_DFX_STATUS2_IOSTLIST_MSK, .shift = HGC_LM_DFX_STATUS2_IOSTLIST_OFF, - .msg = "hgc_iostl_eccbad_intr found: mem addr is 0x%08X\n", + .msg = "hgc_iostl_eccbad_intr", .reg = HGC_LM_DFX_STATUS2, }, { .irq_msk = BIT(SAS_ECC_INTR_ITCTLIST_ECC_MB_OFF), .msk = HGC_LM_DFX_STATUS2_ITCTLIST_MSK, .shift = HGC_LM_DFX_STATUS2_ITCTLIST_OFF, - .msg = "hgc_itctl_eccbad_intr found: mem addr is 0x%08X\n", + .msg = "hgc_itctl_eccbad_intr", .reg = HGC_LM_DFX_STATUS2, }, { .irq_msk = BIT(SAS_ECC_INTR_CQE_ECC_MB_OFF), .msk = HGC_CQE_ECC_MB_ADDR_MSK, .shift = HGC_CQE_ECC_MB_ADDR_OFF, - .msg = "hgc_cqe_eccbad_intr found: ram address is 0x%08X\n", + .msg = "hgc_cqe_eccbad_intr", .reg = HGC_CQE_ECC_ADDR, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM0_ECC_MB_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM0_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM0_OFF, - .msg = "rxm_mem0_eccbad_intr found: mem addr is 0x%08X\n", + .msg = "rxm_mem0_eccbad_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM1_ECC_MB_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM1_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM1_OFF, - .msg = "rxm_mem1_eccbad_intr found: mem addr is 0x%08X\n", + .msg = "rxm_mem1_eccbad_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM2_ECC_MB_OFF), .msk = HGC_RXM_DFX_STATUS14_MEM2_MSK, .shift = HGC_RXM_DFX_STATUS14_MEM2_OFF, - .msg = "rxm_mem2_eccbad_intr found: mem addr is 0x%08X\n", + .msg = "rxm_mem2_eccbad_intr", .reg = HGC_RXM_DFX_STATUS14, }, { .irq_msk = BIT(SAS_ECC_INTR_NCQ_MEM3_ECC_MB_OFF), .msk = HGC_RXM_DFX_STATUS15_MEM3_MSK, .shift = HGC_RXM_DFX_STATUS15_MEM3_OFF, - .msg = "rxm_mem3_eccbad_intr found: mem addr is 0x%08X\n", + .msg = "rxm_mem3_eccbad_intr", .reg = HGC_RXM_DFX_STATUS15, }, { .irq_msk = BIT(SAS_ECC_INTR_OOO_RAM_ECC_MB_OFF), .msk = AM_ROB_ECC_ERR_ADDR_MSK, .shift = AM_ROB_ECC_ERR_ADDR_OFF, - .msg = "ooo_ram_eccbad_intr found: ROB_ECC_ERR_ADDR=0x%08X\n", + .msg = "ooo_ram_eccbad_intr", .reg = AM_ROB_ECC_ERR_ADDR, }, }; @@ -1915,7 +1923,8 @@ static void multi_bit_ecc_error_process_v3_hw(struct hisi_hba *hisi_hba, val = hisi_sas_read32(hisi_hba, ecc_error->reg); val &= ecc_error->msk; val >>= ecc_error->shift; - dev_err(dev, ecc_error->msg, irq_value, val); + dev_err(dev, "%s (0x%x) found: mem addr is 0x%08X\n", + ecc_error->msg, irq_value, val); queue_work(hisi_hba->wq, &hisi_hba->rst_work); } } @@ -1926,7 +1935,7 @@ static void fatal_ecc_int_v3_hw(struct hisi_hba *hisi_hba) u32 irq_value, irq_msk; irq_msk = hisi_sas_read32(hisi_hba, SAS_ECC_INTR_MSK); - hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, irq_msk | 0xffffffff); + hisi_sas_write32(hisi_hba, SAS_ECC_INTR_MSK, 0xffffffff); irq_value = hisi_sas_read32(hisi_hba, SAS_ECC_INTR); if (irq_value) @@ -2202,7 +2211,7 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) slot_err_v3_hw(hisi_hba, task, slot); if (ts->stat != SAS_DATA_UNDERRUN) - dev_info(dev, "erroneous completion iptt=%d task=%p dev id=%d CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n", + dev_info(dev, "erroneous completion iptt=%d task=%pK dev id=%d CQ hdr: 0x%x 0x%x 0x%x 0x%x Error info: 0x%x 0x%x 0x%x 0x%x\n", slot->idx, task, sas_dev->device_id, dw0, dw1, complete_hdr->act, dw3, error_info[0], error_info[1], @@ -2223,20 +2232,16 @@ slot_complete_v3_hw(struct hisi_hba *hisi_hba, struct hisi_sas_slot *slot) } case SAS_PROTOCOL_SMP: { struct scatterlist *sg_resp = &task->smp_task.smp_resp; - void *to; + void *to = page_address(sg_page(sg_resp)); ts->stat = SAM_STAT_GOOD; - to = kmap_atomic(sg_page(sg_resp)); - dma_unmap_sg(dev, &task->smp_task.smp_resp, 1, - DMA_FROM_DEVICE); dma_unmap_sg(dev, &task->smp_task.smp_req, 1, DMA_TO_DEVICE); memcpy(to + sg_resp->offset, hisi_sas_status_buf_addr_mem(slot) + sizeof(struct hisi_sas_err_record), - sg_dma_len(sg_resp)); - kunmap_atomic(to); + sg_resp->length); break; } case SAS_PROTOCOL_SATA: @@ -2261,7 +2266,7 @@ out: spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { spin_unlock_irqrestore(&task->task_state_lock, flags); - dev_info(dev, "slot complete: task(%p) aborted\n", task); + dev_info(dev, "slot complete: task(%pK) aborted\n", task); return SAS_ABORTED_TASK; } task->task_state_flags |= SAS_TASK_STATE_DONE; @@ -2272,7 +2277,7 @@ out: spin_lock_irqsave(&device->done_lock, flags); if (test_bit(SAS_HA_FROZEN, &ha->state)) { spin_unlock_irqrestore(&device->done_lock, flags); - dev_info(dev, "slot complete: task(%p) ignored\n ", + dev_info(dev, "slot complete: task(%pK) ignored\n ", task); return sts; } @@ -2367,8 +2372,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) { struct device *dev = hisi_hba->dev; struct pci_dev *pdev = hisi_hba->pci_dev; - int vectors, rc; - int i, k; + int vectors, rc, i; int max_msi = HISI_SAS_MSI_COUNT_V3_HW, min_msi; if (auto_affine_msi_experimental) { @@ -2416,7 +2420,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) if (rc) { dev_err(dev, "could not request chnl interrupt, rc=%d\n", rc); rc = -ENOENT; - goto free_phy_irq; + goto free_irq_vectors; } rc = devm_request_irq(dev, pci_irq_vector(pdev, 11), @@ -2425,7 +2429,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) if (rc) { dev_err(dev, "could not request fatal interrupt, rc=%d\n", rc); rc = -ENOENT; - goto free_chnl_interrupt; + goto free_irq_vectors; } /* Init tasklets for cq only */ @@ -2442,7 +2446,7 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) dev_err(dev, "could not request cq%d interrupt, rc=%d\n", i, rc); rc = -ENOENT; - goto free_cq_irqs; + goto free_irq_vectors; } tasklet_init(t, cq_tasklet_v3_hw, (unsigned long)cq); @@ -2450,18 +2454,6 @@ static int interrupt_init_v3_hw(struct hisi_hba *hisi_hba) return 0; -free_cq_irqs: - for (k = 0; k < i; k++) { - struct hisi_sas_cq *cq = &hisi_hba->cq[k]; - int nr = hisi_sas_intr_conv ? 16 : 16 + k; - - free_irq(pci_irq_vector(pdev, nr), cq); - } - free_irq(pci_irq_vector(pdev, 11), hisi_hba); -free_chnl_interrupt: - free_irq(pci_irq_vector(pdev, 2), hisi_hba); -free_phy_irq: - free_irq(pci_irq_vector(pdev, 1), hisi_hba); free_irq_vectors: pci_free_irq_vectors(pdev); return rc; @@ -2602,8 +2594,8 @@ static int write_gpio_v3_hw(struct hisi_hba *hisi_hba, u8 reg_type, return 0; } -static int wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba, - int delay_ms, int timeout_ms) +static void wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba, + int delay_ms, int timeout_ms) { struct device *dev = hisi_hba->dev; int entries, entries_old = 0, time; @@ -2617,12 +2609,12 @@ static int wait_cmds_complete_timeout_v3_hw(struct hisi_hba *hisi_hba, msleep(delay_ms); } - if (time >= timeout_ms) - return -ETIMEDOUT; + if (time >= timeout_ms) { + dev_dbg(dev, "Wait commands complete timeout!\n"); + return; + } dev_dbg(dev, "wait commands complete %dms\n", time); - - return 0; } static ssize_t intr_conv_v3_hw_show(struct device *dev, @@ -2869,16 +2861,45 @@ static const struct hisi_sas_debugfs_reg debugfs_global_reg = { .read_global_reg = hisi_sas_read32, }; +static const struct hisi_sas_debugfs_reg_lu debugfs_axi_reg_lu[] = { + HISI_SAS_DEBUGFS_REG(AM_CFG_MAX_TRANS), + HISI_SAS_DEBUGFS_REG(AM_CFG_SINGLE_PORT_MAX_TRANS), + HISI_SAS_DEBUGFS_REG(AXI_CFG), + HISI_SAS_DEBUGFS_REG(AM_ROB_ECC_ERR_ADDR), + {} +}; + +static const struct hisi_sas_debugfs_reg debugfs_axi_reg = { + .lu = debugfs_axi_reg_lu, + .count = 0x61, + .base_off = AXI_MASTER_CFG_BASE, + .read_global_reg = hisi_sas_read32, +}; + +static const struct hisi_sas_debugfs_reg_lu debugfs_ras_reg_lu[] = { + HISI_SAS_DEBUGFS_REG(SAS_RAS_INTR1), + HISI_SAS_DEBUGFS_REG(SAS_RAS_INTR0_MASK), + HISI_SAS_DEBUGFS_REG(SAS_RAS_INTR1_MASK), + HISI_SAS_DEBUGFS_REG(CFG_SAS_RAS_INTR_MASK), + HISI_SAS_DEBUGFS_REG(SAS_RAS_INTR2), + HISI_SAS_DEBUGFS_REG(SAS_RAS_INTR2_MASK), + {} +}; + +static const struct hisi_sas_debugfs_reg debugfs_ras_reg = { + .lu = debugfs_ras_reg_lu, + .count = 0x10, + .base_off = RAS_BASE, + .read_global_reg = hisi_sas_read32, +}; + static void debugfs_snapshot_prepare_v3_hw(struct hisi_hba *hisi_hba) { - struct device *dev = hisi_hba->dev; - set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); hisi_sas_write32(hisi_hba, DLVRY_QUEUE_ENABLE, 0); - if (wait_cmds_complete_timeout_v3_hw(hisi_hba, 100, 5000) == -ETIMEDOUT) - dev_dbg(dev, "Wait commands complete timeout!\n"); + wait_cmds_complete_timeout_v3_hw(hisi_hba, 100, 5000); hisi_sas_kill_tasklets(hisi_hba); } @@ -2891,6 +2912,142 @@ static void debugfs_snapshot_restore_v3_hw(struct hisi_hba *hisi_hba) clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); } +static void read_iost_itct_cache_v3_hw(struct hisi_hba *hisi_hba, + enum hisi_sas_debugfs_cache_type type, + u32 *cache) +{ + u32 cache_dw_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * + HISI_SAS_IOST_ITCT_CACHE_NUM; + u32 *buf = cache; + u32 i, val; + + hisi_sas_write32(hisi_hba, TAB_RD_TYPE, type); + + for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_DW_SZ; i++) { + val = hisi_sas_read32(hisi_hba, TAB_DFX); + if (val == 0xffffffff) + break; + } + + if (val != 0xffffffff) { + pr_err("Issue occur when reading IOST/ITCT cache!\n"); + return; + } + + memset(buf, 0, cache_dw_size * 4); + buf[0] = val; + + for (i = 1; i < cache_dw_size; i++) + buf[i] = hisi_sas_read32(hisi_hba, TAB_DFX); +} + +static void hisi_sas_bist_test_prep_v3_hw(struct hisi_hba *hisi_hba) +{ + u32 reg_val; + int phy_id = hisi_hba->debugfs_bist_phy_no; + + /* disable PHY */ + hisi_sas_phy_enable(hisi_hba, phy_id, 0); + + /* disable ALOS */ + reg_val = hisi_sas_phy_read32(hisi_hba, phy_id, SERDES_CFG); + reg_val |= CFG_ALOS_CHK_DISABLE_MSK; + hisi_sas_phy_write32(hisi_hba, phy_id, SERDES_CFG, reg_val); +} + +static void hisi_sas_bist_test_restore_v3_hw(struct hisi_hba *hisi_hba) +{ + u32 reg_val; + int phy_id = hisi_hba->debugfs_bist_phy_no; + + /* disable loopback */ + reg_val = hisi_sas_phy_read32(hisi_hba, phy_id, SAS_PHY_BIST_CTRL); + reg_val &= ~(CFG_RX_BIST_EN_MSK | CFG_TX_BIST_EN_MSK | + CFG_BIST_TEST_MSK); + hisi_sas_phy_write32(hisi_hba, phy_id, SAS_PHY_BIST_CTRL, reg_val); + + /* enable ALOS */ + reg_val = hisi_sas_phy_read32(hisi_hba, phy_id, SERDES_CFG); + reg_val &= ~CFG_ALOS_CHK_DISABLE_MSK; + hisi_sas_phy_write32(hisi_hba, phy_id, SERDES_CFG, reg_val); + + /* restore the linkrate */ + reg_val = hisi_sas_phy_read32(hisi_hba, phy_id, PROG_PHY_LINK_RATE); + /* init OOB link rate as 1.5 Gbits */ + reg_val &= ~CFG_PROG_PHY_LINK_RATE_MSK; + reg_val |= (0x8 << CFG_PROG_PHY_LINK_RATE_OFF); + hisi_sas_phy_write32(hisi_hba, phy_id, PROG_PHY_LINK_RATE, reg_val); + + /* enable PHY */ + hisi_sas_phy_enable(hisi_hba, phy_id, 1); +} + +#define SAS_PHY_BIST_CODE_INIT 0x1 +#define SAS_PHY_BIST_CODE1_INIT 0X80 +static int debugfs_set_bist_v3_hw(struct hisi_hba *hisi_hba, bool enable) +{ + u32 reg_val, mode_tmp; + u32 linkrate = hisi_hba->debugfs_bist_linkrate; + u32 phy_id = hisi_hba->debugfs_bist_phy_no; + u32 code_mode = hisi_hba->debugfs_bist_code_mode; + u32 path_mode = hisi_hba->debugfs_bist_mode; + struct device *dev = hisi_hba->dev; + + dev_info(dev, "BIST info:linkrate=%d phy_id=%d code_mode=%d path_mode=%d\n", + linkrate, phy_id, code_mode, path_mode); + mode_tmp = path_mode ? 2 : 1; + if (enable) { + /* some preparations before bist test */ + hisi_sas_bist_test_prep_v3_hw(hisi_hba); + + /* set linkrate of bit test*/ + reg_val = hisi_sas_phy_read32(hisi_hba, phy_id, + PROG_PHY_LINK_RATE); + reg_val &= ~CFG_PROG_PHY_LINK_RATE_MSK; + reg_val |= (linkrate << CFG_PROG_PHY_LINK_RATE_OFF); + hisi_sas_phy_write32(hisi_hba, phy_id, + PROG_PHY_LINK_RATE, reg_val); + + /* set code mode of bit test */ + reg_val = hisi_sas_phy_read32(hisi_hba, phy_id, + SAS_PHY_BIST_CTRL); + reg_val &= ~(CFG_BIST_MODE_SEL_MSK | + CFG_LOOP_TEST_MODE_MSK | + CFG_RX_BIST_EN_MSK | + CFG_TX_BIST_EN_MSK | + CFG_BIST_TEST_MSK); + reg_val |= ((code_mode << CFG_BIST_MODE_SEL_OFF) | + (mode_tmp << CFG_LOOP_TEST_MODE_OFF) | + CFG_BIST_TEST_MSK); + hisi_sas_phy_write32(hisi_hba, phy_id, + SAS_PHY_BIST_CTRL, reg_val); + + mdelay(100); + reg_val |= (CFG_RX_BIST_EN_MSK | CFG_TX_BIST_EN_MSK); + hisi_sas_phy_write32(hisi_hba, phy_id, + SAS_PHY_BIST_CTRL, reg_val); + + /* set the bist init value */ + hisi_sas_phy_write32(hisi_hba, phy_id, + SAS_PHY_BIST_CODE, + SAS_PHY_BIST_CODE_INIT); + hisi_sas_phy_write32(hisi_hba, phy_id, + SAS_PHY_BIST_CODE1, + SAS_PHY_BIST_CODE1_INIT); + + /* clear error bit */ + mdelay(100); + hisi_sas_phy_read32(hisi_hba, phy_id, SAS_BIST_ERR_CNT); + } else { + /* disable bist test and recover it */ + hisi_hba->debugfs_bist_cnt += hisi_sas_phy_read32(hisi_hba, + phy_id, SAS_BIST_ERR_CNT); + hisi_sas_bist_test_restore_v3_hw(hisi_hba); + } + + return 0; +} + static struct scsi_host_template sht_v3_hw = { .name = DRV_NAME, .module = THIS_MODULE, @@ -2917,7 +3074,6 @@ static struct scsi_host_template sht_v3_hw = { static const struct hisi_sas_hw hisi_sas_v3_hw = { .hw_init = hisi_sas_v3_init, .setup_itct = setup_itct_v3_hw, - .max_command_entries = HISI_SAS_COMMAND_ENTRIES_V3_HW, .get_wideport_bitmap = get_wideport_bitmap_v3_hw, .complete_hdr_size = sizeof(struct hisi_sas_complete_v3_hdr), .clear_itct = clear_itct_v3_hw, @@ -2926,9 +3082,7 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = { .prep_smp = prep_smp_v3_hw, .prep_stp = prep_ata_v3_hw, .prep_abort = prep_abort_v3_hw, - .get_free_slot = get_free_slot_v3_hw, .start_delivery = start_delivery_v3_hw, - .slot_complete = slot_complete_v3_hw, .phys_init = phys_init_v3_hw, .phy_start = start_phy_v3_hw, .phy_disable = disable_phy_v3_hw, @@ -2941,10 +3095,14 @@ static const struct hisi_sas_hw hisi_sas_v3_hw = { .get_events = phy_get_events_v3_hw, .write_gpio = write_gpio_v3_hw, .wait_cmds_complete_timeout = wait_cmds_complete_timeout_v3_hw, - .debugfs_reg_global = &debugfs_global_reg, + .debugfs_reg_array[DEBUGFS_GLOBAL] = &debugfs_global_reg, + .debugfs_reg_array[DEBUGFS_AXI] = &debugfs_axi_reg, + .debugfs_reg_array[DEBUGFS_RAS] = &debugfs_ras_reg, .debugfs_reg_port = &debugfs_port_reg, .snapshot_prepare = debugfs_snapshot_prepare_v3_hw, .snapshot_restore = debugfs_snapshot_restore_v3_hw, + .read_iost_itct_cache = read_iost_itct_cache_v3_hw, + .set_bist = debugfs_set_bist_v3_hw, }; static struct Scsi_Host * @@ -2975,8 +3133,6 @@ hisi_sas_shost_alloc_pci(struct pci_dev *pdev) else hisi_hba->prot_mask = prot_mask; - timer_setup(&hisi_hba->timer, NULL, 0); - if (hisi_sas_get_fw_info(hisi_hba) < 0) goto err_out; @@ -3058,17 +3214,14 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) shost->max_lun = ~0; shost->max_channel = 1; shost->max_cmd_len = 16; - shost->can_queue = hisi_hba->hw->max_command_entries - - HISI_SAS_RESERVED_IPTT_CNT; - shost->cmd_per_lun = hisi_hba->hw->max_command_entries - - HISI_SAS_RESERVED_IPTT_CNT; + shost->can_queue = HISI_SAS_UNRESERVED_IPTT; + shost->cmd_per_lun = HISI_SAS_UNRESERVED_IPTT; sha->sas_ha_name = DRV_NAME; sha->dev = dev; sha->lldd_module = THIS_MODULE; sha->sas_addr = &hisi_hba->sas_addr[0]; sha->num_phys = hisi_hba->n_phy; - sha->core.shost = hisi_hba->shost; for (i = 0; i < hisi_hba->n_phy; i++) { sha->sas_phy[i] = &hisi_hba->phy[i].sas_phy; @@ -3255,15 +3408,21 @@ static int hisi_sas_v3_resume(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D0, 0); pci_restore_state(pdev); rc = pci_enable_device(pdev); - if (rc) + if (rc) { dev_err(dev, "enable device failed during resume (%d)\n", rc); + return rc; + } pci_set_master(pdev); scsi_unblock_requests(shost); clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); sas_prep_resume_ha(sha); - init_reg_v3_hw(hisi_hba); + rc = hw_init_v3_hw(hisi_hba); + if (rc) { + scsi_remove_host(shost); + pci_disable_device(pdev); + } hisi_hba->hw->phys_init(hisi_hba); sas_resume_ha(sha); clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index ff0d8c6a8d0c..55522b7162d3 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -462,6 +462,9 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) else shost->dma_boundary = 0xffffffff; + if (sht->virt_boundary_mask) + shost->virt_boundary_mask = sht->virt_boundary_mask; + device_initialize(&shost->shost_gendev); dev_set_name(&shost->shost_gendev, "host%d", shost->host_no); shost->shost_gendev.bus = &scsi_bus_type; diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 8068520cf89e..216e557f703e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -21,7 +21,6 @@ #include <linux/interrupt.h> #include <linux/types.h> #include <linux/pci.h> -#include <linux/pci-aspm.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/delay.h> @@ -60,7 +59,7 @@ * HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' * with an optional trailing '-' followed by a byte value (0-255). */ -#define HPSA_DRIVER_VERSION "3.4.20-160" +#define HPSA_DRIVER_VERSION "3.4.20-170" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" @@ -73,6 +72,8 @@ /*define how many times we will try a command because of bus resets */ #define MAX_CMD_RETRIES 3 +/* How long to wait before giving up on a command */ +#define HPSA_EH_PTRAID_TIMEOUT (240 * HZ) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Hewlett-Packard Company"); @@ -344,11 +345,6 @@ static inline bool hpsa_is_cmd_idle(struct CommandList *c) return c->scsi_cmd == SCSI_CMD_IDLE; } -static inline bool hpsa_is_pending_event(struct CommandList *c) -{ - return c->reset_pending; -} - /* extract sense key, asc, and ascq from sense data. -1 means invalid. */ static void decode_sense_data(const u8 *sense_data, int sense_data_len, u8 *sense_key, u8 *asc, u8 *ascq) @@ -1144,6 +1140,8 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h, { dial_down_lockup_detection_during_fw_flash(h, c); atomic_inc(&h->commands_outstanding); + if (c->device) + atomic_inc(&c->device->commands_outstanding); reply_queue = h->reply_map[raw_smp_processor_id()]; switch (c->cmd_type) { @@ -1167,9 +1165,6 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h, static void enqueue_cmd_and_start_io(struct ctlr_info *h, struct CommandList *c) { - if (unlikely(hpsa_is_pending_event(c))) - return finish_cmd(c); - __enqueue_cmd_and_start_io(h, c, DEFAULT_REPLY_QUEUE); } @@ -1842,25 +1837,33 @@ static int hpsa_find_outstanding_commands_for_dev(struct ctlr_info *h, return count; } +#define NUM_WAIT 20 static void hpsa_wait_for_outstanding_commands_for_dev(struct ctlr_info *h, struct hpsa_scsi_dev_t *device) { int cmds = 0; int waits = 0; + int num_wait = NUM_WAIT; + + if (device->external) + num_wait = HPSA_EH_PTRAID_TIMEOUT; while (1) { cmds = hpsa_find_outstanding_commands_for_dev(h, device); if (cmds == 0) break; - if (++waits > 20) + if (++waits > num_wait) break; msleep(1000); } - if (waits > 20) + if (waits > num_wait) { dev_warn(&h->pdev->dev, - "%s: removing device with %d outstanding commands!\n", - __func__, cmds); + "%s: removing device [%d:%d:%d:%d] with %d outstanding commands!\n", + __func__, + h->scsi_host->host_no, + device->bus, device->target, device->lun, cmds); + } } static void hpsa_remove_device(struct ctlr_info *h, @@ -2131,11 +2134,16 @@ static int hpsa_slave_configure(struct scsi_device *sdev) sdev->no_uld_attach = !sd || !sd->expose_device; if (sd) { - if (sd->external) + sd->was_removed = 0; + if (sd->external) { queue_depth = EXTERNAL_QD; - else + sdev->eh_timeout = HPSA_EH_PTRAID_TIMEOUT; + blk_queue_rq_timeout(sdev->request_queue, + HPSA_EH_PTRAID_TIMEOUT); + } else { queue_depth = sd->queue_depth != 0 ? sd->queue_depth : sdev->host->can_queue; + } } else queue_depth = sdev->host->can_queue; @@ -2146,7 +2154,12 @@ static int hpsa_slave_configure(struct scsi_device *sdev) static void hpsa_slave_destroy(struct scsi_device *sdev) { - /* nothing to do. */ + struct hpsa_scsi_dev_t *hdev = NULL; + + hdev = sdev->hostdata; + + if (hdev) + hdev->was_removed = 1; } static void hpsa_free_ioaccel2_sg_chain_blocks(struct ctlr_info *h) @@ -2320,6 +2333,8 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, case IOACCEL2_SERV_RESPONSE_COMPLETE: switch (c2->error_data.status) { case IOACCEL2_STATUS_SR_TASK_COMP_GOOD: + if (cmd) + cmd->result = 0; break; case IOACCEL2_STATUS_SR_TASK_COMP_CHK_COND: cmd->result |= SAM_STAT_CHECK_CONDITION; @@ -2414,13 +2429,16 @@ static int handle_ioaccel_mode2_error(struct ctlr_info *h, break; } + if (dev->in_reset) + retry = 0; + return retry; /* retry on raid path? */ } static void hpsa_cmd_resolve_events(struct ctlr_info *h, struct CommandList *c) { - bool do_wake = false; + struct hpsa_scsi_dev_t *dev = c->device; /* * Reset c->scsi_cmd here so that the reset handler will know @@ -2429,25 +2447,12 @@ static void hpsa_cmd_resolve_events(struct ctlr_info *h, */ c->scsi_cmd = SCSI_CMD_IDLE; mb(); /* Declare command idle before checking for pending events. */ - if (c->reset_pending) { - unsigned long flags; - struct hpsa_scsi_dev_t *dev; - - /* - * There appears to be a reset pending; lock the lock and - * reconfirm. If so, then decrement the count of outstanding - * commands and wake the reset command if this is the last one. - */ - spin_lock_irqsave(&h->lock, flags); - dev = c->reset_pending; /* Re-fetch under the lock. */ - if (dev && atomic_dec_and_test(&dev->reset_cmds_out)) - do_wake = true; - c->reset_pending = NULL; - spin_unlock_irqrestore(&h->lock, flags); + if (dev) { + atomic_dec(&dev->commands_outstanding); + if (dev->in_reset && + atomic_read(&dev->commands_outstanding) <= 0) + wake_up_all(&h->event_sync_wait_queue); } - - if (do_wake) - wake_up_all(&h->event_sync_wait_queue); } static void hpsa_cmd_resolve_and_free(struct ctlr_info *h, @@ -2479,8 +2484,10 @@ static void process_ioaccel2_completion(struct ctlr_info *h, /* check for good status */ if (likely(c2->error_data.serv_response == 0 && - c2->error_data.status == 0)) + c2->error_data.status == 0)) { + cmd->result = 0; return hpsa_cmd_free_and_done(h, c, cmd); + } /* * Any RAID offload error results in retry which will use @@ -2496,6 +2503,11 @@ static void process_ioaccel2_completion(struct ctlr_info *h, dev->offload_to_be_enabled = 0; } + if (dev->in_reset) { + cmd->result = DID_RESET << 16; + return hpsa_cmd_free_and_done(h, c, cmd); + } + return hpsa_retry_cmd(h, c); } @@ -2574,6 +2586,12 @@ static void complete_scsi_command(struct CommandList *cp) cmd->result = (DID_OK << 16); /* host byte */ cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ + /* SCSI command has already been cleaned up in SML */ + if (dev->was_removed) { + hpsa_cmd_resolve_and_free(h, cp); + return; + } + if (cp->cmd_type == CMD_IOACCEL2 || cp->cmd_type == CMD_IOACCEL1) { if (dev->physical_device && dev->expose_device && dev->removed) { @@ -2595,10 +2613,6 @@ static void complete_scsi_command(struct CommandList *cp) return hpsa_cmd_free_and_done(h, cp, cmd); } - if ((unlikely(hpsa_is_pending_event(cp)))) - if (cp->reset_pending) - return hpsa_cmd_free_and_done(h, cp, cmd); - if (cp->cmd_type == CMD_IOACCEL2) return process_ioaccel2_completion(h, cp, cmd, dev); @@ -3048,7 +3062,7 @@ out: return rc; } -static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, +static int hpsa_send_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, u8 reset_type, int reply_queue) { int rc = IO_OK; @@ -3056,11 +3070,10 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, struct ErrorInfo *ei; c = cmd_alloc(h); - + c->device = dev; /* fill_cmd can't fail here, no data buffer to map. */ - (void) fill_cmd(c, reset_type, h, NULL, 0, 0, - scsi3addr, TYPE_MSG); + (void) fill_cmd(c, reset_type, h, NULL, 0, 0, dev->scsi3addr, TYPE_MSG); rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); if (rc) { dev_warn(&h->pdev->dev, "Failed to send reset command\n"); @@ -3138,9 +3151,8 @@ static bool hpsa_cmd_dev_match(struct ctlr_info *h, struct CommandList *c, } static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, - unsigned char *scsi3addr, u8 reset_type, int reply_queue) + u8 reset_type, int reply_queue) { - int i; int rc = 0; /* We can really only handle one reset at a time */ @@ -3149,38 +3161,14 @@ static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, return -EINTR; } - BUG_ON(atomic_read(&dev->reset_cmds_out) != 0); - - for (i = 0; i < h->nr_cmds; i++) { - struct CommandList *c = h->cmd_pool + i; - int refcount = atomic_inc_return(&c->refcount); - - if (refcount > 1 && hpsa_cmd_dev_match(h, c, dev, scsi3addr)) { - unsigned long flags; - - /* - * Mark the target command as having a reset pending, - * then lock a lock so that the command cannot complete - * while we're considering it. If the command is not - * idle then count it; otherwise revoke the event. - */ - c->reset_pending = dev; - spin_lock_irqsave(&h->lock, flags); /* Implied MB */ - if (!hpsa_is_cmd_idle(c)) - atomic_inc(&dev->reset_cmds_out); - else - c->reset_pending = NULL; - spin_unlock_irqrestore(&h->lock, flags); - } - - cmd_free(h, c); - } - - rc = hpsa_send_reset(h, scsi3addr, reset_type, reply_queue); - if (!rc) + rc = hpsa_send_reset(h, dev, reset_type, reply_queue); + if (!rc) { + /* incremented by sending the reset request */ + atomic_dec(&dev->commands_outstanding); wait_event(h->event_sync_wait_queue, - atomic_read(&dev->reset_cmds_out) == 0 || + atomic_read(&dev->commands_outstanding) <= 0 || lockup_detected(h)); + } if (unlikely(lockup_detected(h))) { dev_warn(&h->pdev->dev, @@ -3188,10 +3176,8 @@ static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, rc = -ENODEV; } - if (unlikely(rc)) - atomic_set(&dev->reset_cmds_out, 0); - else - rc = wait_for_device_to_become_ready(h, scsi3addr, 0); + if (!rc) + rc = wait_for_device_to_become_ready(h, dev->scsi3addr, 0); mutex_unlock(&h->reset_mutex); return rc; @@ -4820,6 +4806,9 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h, c->phys_disk = dev; + if (dev->in_reset) + return -1; + return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle, cmd->cmnd, cmd->cmd_len, dev->scsi3addr, dev); } @@ -5010,6 +4999,11 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, } else cp->sg_count = (u8) use_sg; + if (phys_disk->in_reset) { + cmd->result = DID_RESET << 16; + return -1; + } + enqueue_cmd_and_start_io(h, c); return 0; } @@ -5027,6 +5021,9 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, if (!c->scsi_cmd->device->hostdata) return -1; + if (phys_disk->in_reset) + return -1; + /* Try to honor the device's queue depth */ if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) > phys_disk->queue_depth) { @@ -5110,6 +5107,9 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, if (!dev) return -1; + if (dev->in_reset) + return -1; + /* check for valid opcode, get LBA and block count */ switch (cmd->cmnd[0]) { case WRITE_6: @@ -5414,13 +5414,13 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, */ static int hpsa_ciss_submit(struct ctlr_info *h, struct CommandList *c, struct scsi_cmnd *cmd, - unsigned char scsi3addr[]) + struct hpsa_scsi_dev_t *dev) { cmd->host_scribble = (unsigned char *) c; c->cmd_type = CMD_SCSI; c->scsi_cmd = cmd; c->Header.ReplyQueue = 0; /* unused in simple mode */ - memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); + memcpy(&c->Header.LUN.LunAddrBytes[0], &dev->scsi3addr[0], 8); c->Header.tag = cpu_to_le64((c->cmdindex << DIRECT_LOOKUP_SHIFT)); /* Fill in the request block... */ @@ -5471,6 +5471,14 @@ static int hpsa_ciss_submit(struct ctlr_info *h, hpsa_cmd_resolve_and_free(h, c); return SCSI_MLQUEUE_HOST_BUSY; } + + if (dev->in_reset) { + hpsa_cmd_resolve_and_free(h, c); + return SCSI_MLQUEUE_HOST_BUSY; + } + + c->device = dev; + enqueue_cmd_and_start_io(h, c); /* the cmd'll come back via intr handler in complete_scsi_command() */ return 0; @@ -5522,8 +5530,7 @@ static inline void hpsa_cmd_partial_init(struct ctlr_info *h, int index, } static int hpsa_ioaccel_submit(struct ctlr_info *h, - struct CommandList *c, struct scsi_cmnd *cmd, - unsigned char *scsi3addr) + struct CommandList *c, struct scsi_cmnd *cmd) { struct hpsa_scsi_dev_t *dev = cmd->device->hostdata; int rc = IO_ACCEL_INELIGIBLE; @@ -5531,12 +5538,19 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, if (!dev) return SCSI_MLQUEUE_HOST_BUSY; + if (dev->in_reset) + return SCSI_MLQUEUE_HOST_BUSY; + + if (hpsa_simple_mode) + return IO_ACCEL_INELIGIBLE; + cmd->host_scribble = (unsigned char *) c; if (dev->offload_enabled) { hpsa_cmd_init(h, c->cmdindex, c); c->cmd_type = CMD_SCSI; c->scsi_cmd = cmd; + c->device = dev; rc = hpsa_scsi_ioaccel_raid_map(h, c); if (rc < 0) /* scsi_dma_map failed. */ rc = SCSI_MLQUEUE_HOST_BUSY; @@ -5544,6 +5558,7 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h, hpsa_cmd_init(h, c->cmdindex, c); c->cmd_type = CMD_SCSI; c->scsi_cmd = cmd; + c->device = dev; rc = hpsa_scsi_ioaccel_direct_map(h, c); if (rc < 0) /* scsi_dma_map failed. */ rc = SCSI_MLQUEUE_HOST_BUSY; @@ -5563,8 +5578,12 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) cmd->result = DID_NO_CONNECT << 16; return hpsa_cmd_free_and_done(c->h, c, cmd); } - if (c->reset_pending) + + if (dev->in_reset) { + cmd->result = DID_RESET << 16; return hpsa_cmd_free_and_done(c->h, c, cmd); + } + if (c->cmd_type == CMD_IOACCEL2) { struct ctlr_info *h = c->h; struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex]; @@ -5572,7 +5591,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) if (c2->error_data.serv_response == IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL) { - rc = hpsa_ioaccel_submit(h, c, cmd, dev->scsi3addr); + rc = hpsa_ioaccel_submit(h, c, cmd); if (rc == 0) return; if (rc == SCSI_MLQUEUE_HOST_BUSY) { @@ -5588,7 +5607,7 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) } } hpsa_cmd_partial_init(c->h, c->cmdindex, c); - if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) { + if (hpsa_ciss_submit(c->h, c, cmd, dev)) { /* * If we get here, it means dma mapping failed. Try * again via scsi mid layer, which will then get @@ -5607,7 +5626,6 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) { struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; - unsigned char scsi3addr[8]; struct CommandList *c; int rc = 0; @@ -5629,14 +5647,24 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return 0; } - memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); - if (unlikely(lockup_detected(h))) { cmd->result = DID_NO_CONNECT << 16; cmd->scsi_done(cmd); return 0; } + + if (dev->in_reset) + return SCSI_MLQUEUE_DEVICE_BUSY; + c = cmd_tagged_alloc(h, cmd); + if (c == NULL) + return SCSI_MLQUEUE_DEVICE_BUSY; + + /* + * This is necessary because the SML doesn't zero out this field during + * error recovery. + */ + cmd->result = 0; /* * Call alternate submit routine for I/O accelerated commands. @@ -5645,7 +5673,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) if (likely(cmd->retries == 0 && !blk_rq_is_passthrough(cmd->request) && h->acciopath_status)) { - rc = hpsa_ioaccel_submit(h, c, cmd, scsi3addr); + rc = hpsa_ioaccel_submit(h, c, cmd); if (rc == 0) return 0; if (rc == SCSI_MLQUEUE_HOST_BUSY) { @@ -5653,7 +5681,7 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) return SCSI_MLQUEUE_HOST_BUSY; } } - return hpsa_ciss_submit(h, c, cmd, scsi3addr); + return hpsa_ciss_submit(h, c, cmd, dev); } static void hpsa_scan_complete(struct ctlr_info *h) @@ -5935,8 +5963,9 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h, static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) { int rc = SUCCESS; + int i; struct ctlr_info *h; - struct hpsa_scsi_dev_t *dev; + struct hpsa_scsi_dev_t *dev = NULL; u8 reset_type; char msg[48]; unsigned long flags; @@ -6002,9 +6031,19 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical "); hpsa_show_dev_msg(KERN_WARNING, h, dev, msg); + /* + * wait to see if any commands will complete before sending reset + */ + dev->in_reset = true; /* block any new cmds from OS for this device */ + for (i = 0; i < 10; i++) { + if (atomic_read(&dev->commands_outstanding) > 0) + msleep(1000); + else + break; + } + /* send a reset to the SCSI LUN which the command was sent to */ - rc = hpsa_do_reset(h, dev, dev->scsi3addr, reset_type, - DEFAULT_REPLY_QUEUE); + rc = hpsa_do_reset(h, dev, reset_type, DEFAULT_REPLY_QUEUE); if (rc == 0) rc = SUCCESS; else @@ -6018,6 +6057,8 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) return_reset_status: spin_lock_irqsave(&h->reset_lock, flags); h->reset_in_progress = 0; + if (dev) + dev->in_reset = false; spin_unlock_irqrestore(&h->reset_lock, flags); return rc; } @@ -6043,7 +6084,6 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, BUG(); } - atomic_inc(&c->refcount); if (unlikely(!hpsa_is_cmd_idle(c))) { /* * We expect that the SCSI layer will hand us a unique tag @@ -6051,14 +6091,18 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h, * two requests...because if the selected command isn't idle * then someone is going to be very disappointed. */ - dev_err(&h->pdev->dev, - "tag collision (tag=%d) in cmd_tagged_alloc().\n", - idx); - if (c->scsi_cmd != NULL) - scsi_print_command(c->scsi_cmd); - scsi_print_command(scmd); + if (idx != h->last_collision_tag) { /* Print once per tag */ + dev_warn(&h->pdev->dev, + "%s: tag collision (tag=%d)\n", __func__, idx); + if (scmd) + scsi_print_command(scmd); + h->last_collision_tag = idx; + } + return NULL; } + atomic_inc(&c->refcount); + hpsa_cmd_partial_init(h, idx, c); return c; } @@ -6126,6 +6170,7 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h) break; /* it's ours now. */ } hpsa_cmd_partial_init(h, i, c); + c->device = NULL; return c; } @@ -6579,8 +6624,7 @@ static int hpsa_ioctl(struct scsi_device *dev, unsigned int cmd, } } -static void hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr, - u8 reset_type) +static void hpsa_send_host_reset(struct ctlr_info *h, u8 reset_type) { struct CommandList *c; @@ -7765,7 +7809,7 @@ static void hpsa_free_pci_init(struct ctlr_info *h) hpsa_disable_interrupt_mode(h); /* pci_init 2 */ /* * call pci_disable_device before pci_release_regions per - * Documentation/PCI/pci.txt + * Documentation/driver-api/pci/pci.rst */ pci_disable_device(h->pdev); /* pci_init 1 */ pci_release_regions(h->pdev); /* pci_init 2 */ @@ -7848,7 +7892,7 @@ clean2: /* intmode+region, pci */ clean1: /* * call pci_disable_device before pci_release_regions per - * Documentation/PCI/pci.txt + * Documentation/driver-api/pci/pci.rst */ pci_disable_device(h->pdev); pci_release_regions(h->pdev); @@ -7983,10 +8027,15 @@ clean_up: static void hpsa_free_irqs(struct ctlr_info *h) { int i; + int irq_vector = 0; + + if (hpsa_simple_mode) + irq_vector = h->intr_mode; if (!h->msix_vectors || h->intr_mode != PERF_MODE_INT) { /* Single reply queue, only one irq to free */ - free_irq(pci_irq_vector(h->pdev, 0), &h->q[h->intr_mode]); + free_irq(pci_irq_vector(h->pdev, irq_vector), + &h->q[h->intr_mode]); h->q[h->intr_mode] = 0; return; } @@ -8005,6 +8054,10 @@ static int hpsa_request_irqs(struct ctlr_info *h, irqreturn_t (*intxhandler)(int, void *)) { int rc, i; + int irq_vector = 0; + + if (hpsa_simple_mode) + irq_vector = h->intr_mode; /* * initialize h->q[x] = x so that interrupt handlers know which @@ -8040,14 +8093,14 @@ static int hpsa_request_irqs(struct ctlr_info *h, if (h->msix_vectors > 0 || h->pdev->msi_enabled) { sprintf(h->intrname[0], "%s-msi%s", h->devname, h->msix_vectors ? "x" : ""); - rc = request_irq(pci_irq_vector(h->pdev, 0), + rc = request_irq(pci_irq_vector(h->pdev, irq_vector), msixhandler, 0, h->intrname[0], &h->q[h->intr_mode]); } else { sprintf(h->intrname[h->intr_mode], "%s-intx", h->devname); - rc = request_irq(pci_irq_vector(h->pdev, 0), + rc = request_irq(pci_irq_vector(h->pdev, irq_vector), intxhandler, IRQF_SHARED, h->intrname[0], &h->q[h->intr_mode]); @@ -8055,7 +8108,7 @@ static int hpsa_request_irqs(struct ctlr_info *h, } if (rc) { dev_err(&h->pdev->dev, "failed to get irq %d for %s\n", - pci_irq_vector(h->pdev, 0), h->devname); + pci_irq_vector(h->pdev, irq_vector), h->devname); hpsa_free_irqs(h); return -ENODEV; } @@ -8065,7 +8118,7 @@ static int hpsa_request_irqs(struct ctlr_info *h, static int hpsa_kdump_soft_reset(struct ctlr_info *h) { int rc; - hpsa_send_host_reset(h, RAID_CTLR_LUNID, HPSA_RESET_TYPE_CONTROLLER); + hpsa_send_host_reset(h, HPSA_RESET_TYPE_CONTROLLER); dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n"); rc = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY); @@ -8121,6 +8174,11 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) destroy_workqueue(h->rescan_ctlr_wq); h->rescan_ctlr_wq = NULL; } + if (h->monitor_ctlr_wq) { + destroy_workqueue(h->monitor_ctlr_wq); + h->monitor_ctlr_wq = NULL; + } + kfree(h); /* init_one 1 */ } @@ -8456,8 +8514,8 @@ static void hpsa_event_monitor_worker(struct work_struct *work) spin_lock_irqsave(&h->lock, flags); if (!h->remove_in_progress) - schedule_delayed_work(&h->event_monitor_work, - HPSA_EVENT_MONITOR_INTERVAL); + queue_delayed_work(h->monitor_ctlr_wq, &h->event_monitor_work, + HPSA_EVENT_MONITOR_INTERVAL); spin_unlock_irqrestore(&h->lock, flags); } @@ -8502,7 +8560,7 @@ static void hpsa_monitor_ctlr_worker(struct work_struct *work) spin_lock_irqsave(&h->lock, flags); if (!h->remove_in_progress) - schedule_delayed_work(&h->monitor_ctlr_work, + queue_delayed_work(h->monitor_ctlr_wq, &h->monitor_ctlr_work, h->heartbeat_sample_interval); spin_unlock_irqrestore(&h->lock, flags); } @@ -8670,6 +8728,12 @@ reinit_after_soft_reset: goto clean7; /* aer/h */ } + h->monitor_ctlr_wq = hpsa_create_controller_wq(h, "monitor"); + if (!h->monitor_ctlr_wq) { + rc = -ENOMEM; + goto clean7; + } + /* * At this point, the controller is ready to take commands. * Now, if reset_devices and the hard reset didn't work, try @@ -8799,6 +8863,10 @@ clean1: /* wq/aer/h */ destroy_workqueue(h->rescan_ctlr_wq); h->rescan_ctlr_wq = NULL; } + if (h->monitor_ctlr_wq) { + destroy_workqueue(h->monitor_ctlr_wq); + h->monitor_ctlr_wq = NULL; + } kfree(h); return rc; } @@ -8946,6 +9014,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) cancel_delayed_work_sync(&h->event_monitor_work); destroy_workqueue(h->rescan_ctlr_wq); destroy_workqueue(h->resubmit_wq); + destroy_workqueue(h->monitor_ctlr_wq); hpsa_delete_sas_host(h); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 59e023696fff..f8c88fc7b80a 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -65,6 +65,7 @@ struct hpsa_scsi_dev_t { u8 physical_device : 1; u8 expose_device; u8 removed : 1; /* device is marked for death */ + u8 was_removed : 1; /* device actually removed */ #define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0" unsigned char device_id[16]; /* from inquiry pg. 0x83 */ u64 sas_address; @@ -75,11 +76,12 @@ struct hpsa_scsi_dev_t { unsigned char raid_level; /* from inquiry page 0xC1 */ unsigned char volume_offline; /* discovered via TUR or VPD */ u16 queue_depth; /* max queue_depth for this device */ - atomic_t reset_cmds_out; /* Count of commands to-be affected */ + atomic_t commands_outstanding; /* track commands sent to device */ atomic_t ioaccel_cmds_out; /* Only used for physical devices * counts commands sent to physical * device via "ioaccel" path. */ + bool in_reset; u32 ioaccel_handle; u8 active_path_index; u8 path_map; @@ -174,6 +176,7 @@ struct ctlr_info { struct CfgTable __iomem *cfgtable; int interrupts_enabled; int max_commands; + int last_collision_tag; /* tags are global */ atomic_t commands_outstanding; # define PERF_MODE_INT 0 # define DOORBELL_INT 1 @@ -300,6 +303,7 @@ struct ctlr_info { int needs_abort_tags_swizzled; struct workqueue_struct *resubmit_wq; struct workqueue_struct *rescan_ctlr_wq; + struct workqueue_struct *monitor_ctlr_wq; atomic_t abort_cmds_available; wait_queue_head_t event_sync_wait_queue; struct mutex reset_mutex; diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index f6afca4b2319..7825cbfea4dc 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -448,7 +448,7 @@ struct CommandList { struct hpsa_scsi_dev_t *phys_disk; int abort_pending; - struct hpsa_scsi_dev_t *reset_pending; + struct hpsa_scsi_dev_t *device; atomic_t refcount; /* Must be last to avoid memset in hpsa_cmd_init() */ } __aligned(COMMANDLIST_ALIGNMENT); diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index acd16e0d52cf..df897df5cafe 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -1830,6 +1830,7 @@ static int ibmvfc_bsg_request(struct bsg_job *job) port_id = (bsg_request->rqst_data.h_els.port_id[0] << 16) | (bsg_request->rqst_data.h_els.port_id[1] << 8) | bsg_request->rqst_data.h_els.port_id[2]; + /* fall through */ case FC_BSG_RPT_ELS: fc_flags = IBMVFC_FC_ELS; break; @@ -1838,6 +1839,7 @@ static int ibmvfc_bsg_request(struct bsg_job *job) port_id = (bsg_request->rqst_data.h_ct.port_id[0] << 16) | (bsg_request->rqst_data.h_ct.port_id[1] << 8) | bsg_request->rqst_data.h_ct.port_id[2]; + /* fall through */ case FC_BSG_RPT_CT: fc_flags = IBMVFC_FC_CT_IU; break; @@ -4020,6 +4022,7 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt) return; case IBMVFC_MAD_CRQ_ERROR: ibmvfc_retry_host_init(vhost); + /* fall through */ case IBMVFC_MAD_DRIVER_FAILED: ibmvfc_free_event(evt); return; @@ -4864,8 +4867,8 @@ static int ibmvfc_remove(struct vio_dev *vdev) spin_lock_irqsave(vhost->host->host_lock, flags); ibmvfc_purge_requests(vhost, DID_ERROR); - ibmvfc_free_event_pool(vhost); spin_unlock_irqrestore(vhost->host->host_lock, flags); + ibmvfc_free_event_pool(vhost); ibmvfc_free_mem(vhost); spin_lock(&ibmvfc_driver_lock); diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 4aea97ee4b24..7f66a7783209 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -814,7 +814,7 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata) atomic_set(&hostdata->request_limit, 0); purge_requests(hostdata, DID_ERROR); - hostdata->reset_crq = 1; + hostdata->action = IBMVSCSI_HOST_ACTION_RESET; wake_up(&hostdata->work_wait_q); } @@ -1165,7 +1165,8 @@ static void login_rsp(struct srp_event_struct *evt_struct) be32_to_cpu(evt_struct->xfer_iu->srp.login_rsp.req_lim_delta)); /* If we had any pending I/Os, kick them */ - scsi_unblock_requests(hostdata->host); + hostdata->action = IBMVSCSI_HOST_ACTION_UNBLOCK; + wake_up(&hostdata->work_wait_q); } /** @@ -1783,7 +1784,7 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq, /* We need to re-setup the interpartition connection */ dev_info(hostdata->dev, "Re-enabling adapter!\n"); hostdata->client_migrated = 1; - hostdata->reenable_crq = 1; + hostdata->action = IBMVSCSI_HOST_ACTION_REENABLE; purge_requests(hostdata, DID_REQUEUE); wake_up(&hostdata->work_wait_q); } else { @@ -2036,6 +2037,16 @@ static struct device_attribute ibmvscsi_host_config = { .show = show_host_config, }; +static int ibmvscsi_host_reset(struct Scsi_Host *shost, int reset_type) +{ + struct ibmvscsi_host_data *hostdata = shost_priv(shost); + + dev_info(hostdata->dev, "Initiating adapter reset!\n"); + ibmvscsi_reset_host(hostdata); + + return 0; +} + static struct device_attribute *ibmvscsi_attrs[] = { &ibmvscsi_host_vhost_loc, &ibmvscsi_host_vhost_name, @@ -2062,6 +2073,7 @@ static struct scsi_host_template driver_template = { .eh_host_reset_handler = ibmvscsi_eh_host_reset_handler, .slave_configure = ibmvscsi_slave_configure, .change_queue_depth = ibmvscsi_change_queue_depth, + .host_reset = ibmvscsi_host_reset, .cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT, .can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT, .this_id = -1, @@ -2091,48 +2103,75 @@ static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev) static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata) { + unsigned long flags; int rc; char *action = "reset"; - if (hostdata->reset_crq) { - smp_rmb(); - hostdata->reset_crq = 0; - + spin_lock_irqsave(hostdata->host->host_lock, flags); + switch (hostdata->action) { + case IBMVSCSI_HOST_ACTION_UNBLOCK: + rc = 0; + break; + case IBMVSCSI_HOST_ACTION_RESET: + spin_unlock_irqrestore(hostdata->host->host_lock, flags); rc = ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata); + spin_lock_irqsave(hostdata->host->host_lock, flags); if (!rc) rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0); vio_enable_interrupts(to_vio_dev(hostdata->dev)); - } else if (hostdata->reenable_crq) { - smp_rmb(); + break; + case IBMVSCSI_HOST_ACTION_REENABLE: action = "enable"; + spin_unlock_irqrestore(hostdata->host->host_lock, flags); rc = ibmvscsi_reenable_crq_queue(&hostdata->queue, hostdata); - hostdata->reenable_crq = 0; + spin_lock_irqsave(hostdata->host->host_lock, flags); if (!rc) rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0); - } else + break; + case IBMVSCSI_HOST_ACTION_NONE: + default: + spin_unlock_irqrestore(hostdata->host->host_lock, flags); return; + } + + hostdata->action = IBMVSCSI_HOST_ACTION_NONE; if (rc) { atomic_set(&hostdata->request_limit, -1); dev_err(hostdata->dev, "error after %s\n", action); } + spin_unlock_irqrestore(hostdata->host->host_lock, flags); scsi_unblock_requests(hostdata->host); } -static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) +static int __ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) { if (kthread_should_stop()) return 1; - else if (hostdata->reset_crq) { - smp_rmb(); - return 1; - } else if (hostdata->reenable_crq) { - smp_rmb(); - return 1; + switch (hostdata->action) { + case IBMVSCSI_HOST_ACTION_NONE: + return 0; + case IBMVSCSI_HOST_ACTION_RESET: + case IBMVSCSI_HOST_ACTION_REENABLE: + case IBMVSCSI_HOST_ACTION_UNBLOCK: + default: + break; } - return 0; + return 1; +} + +static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) +{ + unsigned long flags; + int rc; + + spin_lock_irqsave(hostdata->host->host_lock, flags); + rc = __ibmvscsi_work_to_do(hostdata); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + + return rc; } static int ibmvscsi_work(void *data) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 6ebd1410488d..e60916ef7a49 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -74,13 +74,19 @@ struct event_pool { dma_addr_t iu_token; }; +enum ibmvscsi_host_action { + IBMVSCSI_HOST_ACTION_NONE = 0, + IBMVSCSI_HOST_ACTION_RESET, + IBMVSCSI_HOST_ACTION_REENABLE, + IBMVSCSI_HOST_ACTION_UNBLOCK, +}; + /* all driver data associated with a host adapter */ struct ibmvscsi_host_data { struct list_head host_list; atomic_t request_limit; int client_migrated; - int reset_crq; - int reenable_crq; + enum ibmvscsi_host_action action; struct device *dev; struct event_pool pool; struct crq_queue queue; diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 7f9535392a93..a929fe76102b 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -1581,6 +1581,7 @@ static long ibmvscsis_adapter_info(struct scsi_info *vscsi, case H_PERMISSION: if (connection_broken(vscsi)) flag_bits = (RESPONSE_Q_DOWN | CLIENT_FAILED); + /* Fall through */ default: dev_err(&vscsi->dev, "adapter_info: h_copy_rdma to client failed, rc %ld\n", rc); @@ -2492,8 +2493,10 @@ static long ibmvscsis_ping_response(struct scsi_info *vscsi) break; case H_CLOSED: vscsi->flags |= CLIENT_FAILED; + /* Fall through */ case H_DROPPED: vscsi->flags |= RESPONSE_Q_DOWN; + /* Fall through */ case H_REMOTE_PARM: dev_err(&vscsi->dev, "ping_response: h_send_crq failed, rc %ld\n", rc); diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 9751309f8b8c..2519fb7aee51 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -687,7 +687,7 @@ static int imm_completion(struct scsi_cmnd *cmd) if (cmd->SCp.buffer && !cmd->SCp.this_residual) { /* if scatter/gather, advance to the next segment */ if (cmd->SCp.buffers_residual--) { - cmd->SCp.buffer++; + cmd->SCp.buffer = sg_next(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index d06bc1a817a1..079c04bc448a 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -3901,22 +3901,23 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist, u8 *buffer, u32 len) { int bsize_elem, i, result = 0; - struct scatterlist *scatterlist; + struct scatterlist *sg; void *kaddr; /* Determine the actual number of bytes per element */ bsize_elem = PAGE_SIZE * (1 << sglist->order); - scatterlist = sglist->scatterlist; + sg = sglist->scatterlist; - for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); + for (i = 0; i < (len / bsize_elem); i++, sg = sg_next(sg), + buffer += bsize_elem) { + struct page *page = sg_page(sg); kaddr = kmap(page); memcpy(kaddr, buffer, bsize_elem); kunmap(page); - scatterlist[i].length = bsize_elem; + sg->length = bsize_elem; if (result != 0) { ipr_trace; @@ -3925,13 +3926,13 @@ static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist, } if (len % bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); + struct page *page = sg_page(sg); kaddr = kmap(page); memcpy(kaddr, buffer, len % bsize_elem); kunmap(page); - scatterlist[i].length = len % bsize_elem; + sg->length = len % bsize_elem; } sglist->buffer_len = len; @@ -3952,6 +3953,7 @@ static void ipr_build_ucode_ioadl64(struct ipr_cmnd *ipr_cmd, struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64; struct scatterlist *scatterlist = sglist->scatterlist; + struct scatterlist *sg; int i; ipr_cmd->dma_use_sg = sglist->num_dma_sg; @@ -3960,10 +3962,10 @@ static void ipr_build_ucode_ioadl64(struct ipr_cmnd *ipr_cmd, ioarcb->ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl64_desc) * ipr_cmd->dma_use_sg); - for (i = 0; i < ipr_cmd->dma_use_sg; i++) { + for_each_sg(scatterlist, sg, ipr_cmd->dma_use_sg, i) { ioadl64[i].flags = cpu_to_be32(IPR_IOADL_FLAGS_WRITE); - ioadl64[i].data_len = cpu_to_be32(sg_dma_len(&scatterlist[i])); - ioadl64[i].address = cpu_to_be64(sg_dma_address(&scatterlist[i])); + ioadl64[i].data_len = cpu_to_be32(sg_dma_len(sg)); + ioadl64[i].address = cpu_to_be64(sg_dma_address(sg)); } ioadl64[i-1].flags |= cpu_to_be32(IPR_IOADL_FLAGS_LAST); @@ -3983,6 +3985,7 @@ static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd, struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl; struct scatterlist *scatterlist = sglist->scatterlist; + struct scatterlist *sg; int i; ipr_cmd->dma_use_sg = sglist->num_dma_sg; @@ -3992,11 +3995,11 @@ static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd, ioarcb->ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); - for (i = 0; i < ipr_cmd->dma_use_sg; i++) { + for_each_sg(scatterlist, sg, ipr_cmd->dma_use_sg, i) { ioadl[i].flags_and_data_len = - cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(&scatterlist[i])); + cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(sg)); ioadl[i].address = - cpu_to_be32(sg_dma_address(&scatterlist[i])); + cpu_to_be32(sg_dma_address(sg)); } ioadl[i-1].flags_and_data_len |= diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index 9d29edb9f590..49aa4e657c44 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c @@ -1087,7 +1087,7 @@ static void sci_remote_device_ready_state_enter(struct sci_base_state_machine *s if (dev->dev_type == SAS_SATA_DEV || (dev->tproto & SAS_PROTOCOL_SATA)) { sci_change_state(&idev->sm, SCI_STP_DEV_IDLE); - } else if (dev_is_expander(dev)) { + } else if (dev_is_expander(dev->dev_type)) { sci_change_state(&idev->sm, SCI_SMP_DEV_IDLE); } else isci_remote_device_ready(ihost, idev); @@ -1478,7 +1478,7 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport, struct domain_device *dev = idev->domain_dev; enum sci_status status; - if (dev->parent && dev_is_expander(dev->parent)) + if (dev->parent && dev_is_expander(dev->parent->dev_type)) status = sci_remote_device_ea_construct(iport, idev); else status = sci_remote_device_da_construct(iport, idev); diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h index 47a013fffae7..3ad681c4c20a 100644 --- a/drivers/scsi/isci/remote_device.h +++ b/drivers/scsi/isci/remote_device.h @@ -295,11 +295,6 @@ static inline struct isci_remote_device *rnc_to_dev(struct sci_remote_node_conte return idev; } -static inline bool dev_is_expander(struct domain_device *dev) -{ - return dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE; -} - static inline void sci_remote_device_decrement_request_count(struct isci_remote_device *idev) { /* XXX delete this voodoo when converting to the top-level device diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 1b18cf55167e..343d24c7e788 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -224,7 +224,7 @@ static void scu_ssp_request_construct_task_context( idev = ireq->target_device; iport = idev->owning_port; - /* Fill in the TC with the its required data */ + /* Fill in the TC with its required data */ task_context->abort = 0; task_context->priority = 0; task_context->initiator_request = 1; @@ -506,7 +506,7 @@ static void scu_sata_request_construct_task_context( idev = ireq->target_device; iport = idev->owning_port; - /* Fill in the TC with the its required data */ + /* Fill in the TC with its required data */ task_context->abort = 0; task_context->priority = SCU_TASK_PRIORITY_NORMAL; task_context->initiator_request = 1; @@ -3101,7 +3101,7 @@ sci_io_request_construct(struct isci_host *ihost, /* pass */; else if (dev_is_sata(dev)) memset(&ireq->stp.cmd, 0, sizeof(ireq->stp.cmd)); - else if (dev_is_expander(dev)) + else if (dev_is_expander(dev->dev_type)) /* pass */; else return SCI_FAILURE_UNSUPPORTED_PROTOCOL; @@ -3235,7 +3235,7 @@ sci_io_request_construct_smp(struct device *dev, iport = idev->owning_port; /* - * Fill in the TC with the its required data + * Fill in the TC with its required data * 00h */ task_context->priority = 0; diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index fb6eba331ac6..26fa1a4d1e6b 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -511,7 +511,7 @@ int isci_task_abort_task(struct sas_task *task) "%s: dev = %p (%s%s), task = %p, old_request == %p\n", __func__, idev, (dev_is_sata(task->dev) ? "STP/SATA" - : ((dev_is_expander(task->dev)) + : ((dev_is_expander(task->dev->dev_type)) ? "SMP" : "SSP")), ((idev) ? ((test_bit(IDEV_GONE, &idev->flags)) diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 8e1053bdd843..52e866659853 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -2591,7 +2591,7 @@ void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp) /* lport lock ? */ if (!lport || lport->state == LPORT_ST_DISABLED) { - FC_LPORT_DBG(lport, "Receiving frames for an lport that " + FC_LIBFC_DBG("Receiving frames for an lport that " "has not been initialized correctly\n"); fc_frame_free(fp); return; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index e0f3852fdad1..da6e97d8dc3b 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -128,6 +128,7 @@ EXPORT_SYMBOL(fc_rport_lookup); struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, u32 port_id) { struct fc_rport_priv *rdata; + size_t rport_priv_size = sizeof(*rdata); lockdep_assert_held(&lport->disc.disc_mutex); @@ -135,7 +136,9 @@ struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, u32 port_id) if (rdata) return rdata; - rdata = kzalloc(sizeof(*rdata) + lport->rport_priv_size, GFP_KERNEL); + if (lport->rport_priv_size > 0) + rport_priv_size = lport->rport_priv_size; + rdata = kzalloc(rport_priv_size, GFP_KERNEL); if (!rdata) return NULL; diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 719e57685dd5..6ef93c7af954 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -8,8 +8,6 @@ * Copyright (C) 2006 Red Hat, Inc. All rights reserved. * maintained by open-iscsi@googlegroups.com * - * See the file COPYING included with this distribution for more details. - * * Credits: * Christoph Hellwig * FUJITA Tomonori diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 726ada9b8c79..f47b4b281b14 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -1,25 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Serial Attached SCSI (SAS) Discover process * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/scatterlist.h> @@ -309,7 +293,7 @@ void sas_free_device(struct kref *kref) dev->phy = NULL; /* remove the phys and ports, everything else should be gone */ - if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) + if (dev_is_expander(dev->dev_type)) kfree(dev->ex_dev.ex_phy); if (dev_is_sata(dev) && dev->sata_dev.ap) { @@ -475,6 +459,7 @@ static void sas_discover_domain(struct work_struct *work) pr_notice("ATA device seen but CONFIG_SCSI_SAS_ATA=N so cannot attach\n"); /* Fall through */ #endif + /* Fall through - only for the #else condition above. */ default: error = -ENXIO; pr_err("unhandled device %d\n", dev->dev_type); @@ -519,8 +504,7 @@ static void sas_revalidate_domain(struct work_struct *work) pr_debug("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id, task_pid_nr(current)); - if (ddev && (ddev->dev_type == SAS_FANOUT_EXPANDER_DEVICE || - ddev->dev_type == SAS_EDGE_EXPANDER_DEVICE)) + if (ddev && dev_is_expander(ddev->dev_type)) res = sas_ex_revalidate_domain(ddev); pr_debug("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n", diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index b1e0f7d2b396..a1852f6c042b 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -1,25 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Serial Attached SCSI (SAS) Event processing * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/export.h> diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 9f7e2457360e..9fdb9c9fbda4 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Serial Attached SCSI (SAS) Expander discovery and configuration * @@ -5,21 +6,6 @@ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> * * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include <linux/scatterlist.h> @@ -1106,7 +1092,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) SAS_ADDR(dev->sas_addr), phy_id); sas_ex_disable_phy(dev, phy_id); - break; + return res; } else memcpy(dev->port->disc.fanout_sas_addr, ex_phy->attached_sas_addr, SAS_ADDR_SIZE); @@ -1118,27 +1104,9 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) break; } - if (child) { - int i; - - for (i = 0; i < ex->num_phys; i++) { - if (ex->ex_phy[i].phy_state == PHY_VACANT || - ex->ex_phy[i].phy_state == PHY_NOT_PRESENT) - continue; - /* - * Due to races, the phy might not get added to the - * wide port, so we add the phy to the wide port here. - */ - if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) == - SAS_ADDR(child->sas_addr)) { - ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED; - if (sas_ex_join_wide_port(dev, i)) - pr_debug("Attaching ex phy%02d to wide port %016llx\n", - i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr)); - } - } - } - + if (!child) + pr_notice("ex %016llx phy%02d failed to discover\n", + SAS_ADDR(dev->sas_addr), phy_id); return res; } @@ -1154,8 +1122,7 @@ static int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr) phy->phy_state == PHY_NOT_PRESENT) continue; - if ((phy->attached_dev_type == SAS_EDGE_EXPANDER_DEVICE || - phy->attached_dev_type == SAS_FANOUT_EXPANDER_DEVICE) && + if (dev_is_expander(phy->attached_dev_type) && phy->routing_attr == SUBTRACTIVE_ROUTING) { memcpy(sub_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); @@ -1173,8 +1140,7 @@ static int sas_check_level_subtractive_boundary(struct domain_device *dev) u8 sub_addr[SAS_ADDR_SIZE] = {0, }; list_for_each_entry(child, &ex->children, siblings) { - if (child->dev_type != SAS_EDGE_EXPANDER_DEVICE && - child->dev_type != SAS_FANOUT_EXPANDER_DEVICE) + if (!dev_is_expander(child->dev_type)) continue; if (sub_addr[0] == 0) { sas_find_sub_addr(child, sub_addr); @@ -1259,8 +1225,7 @@ static int sas_check_ex_subtractive_boundary(struct domain_device *dev) phy->phy_state == PHY_NOT_PRESENT) continue; - if ((phy->attached_dev_type == SAS_FANOUT_EXPANDER_DEVICE || - phy->attached_dev_type == SAS_EDGE_EXPANDER_DEVICE) && + if (dev_is_expander(phy->attached_dev_type) && phy->routing_attr == SUBTRACTIVE_ROUTING) { if (!sub_sas_addr) @@ -1356,8 +1321,7 @@ static int sas_check_parent_topology(struct domain_device *child) if (!child->parent) return 0; - if (child->parent->dev_type != SAS_EDGE_EXPANDER_DEVICE && - child->parent->dev_type != SAS_FANOUT_EXPANDER_DEVICE) + if (!dev_is_expander(child->parent->dev_type)) return 0; parent_ex = &child->parent->ex_dev; @@ -1653,8 +1617,7 @@ static int sas_ex_level_discovery(struct asd_sas_port *port, const int level) struct domain_device *dev; list_for_each_entry(dev, &port->dev_list, dev_list_node) { - if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || - dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) { + if (dev_is_expander(dev->dev_type)) { struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy); @@ -1886,7 +1849,7 @@ static int sas_find_bcast_dev(struct domain_device *dev, SAS_ADDR(dev->sas_addr)); } list_for_each_entry(ch, &ex->children, siblings) { - if (ch->dev_type == SAS_EDGE_EXPANDER_DEVICE || ch->dev_type == SAS_FANOUT_EXPANDER_DEVICE) { + if (dev_is_expander(ch->dev_type)) { res = sas_find_bcast_dev(ch, src_dev); if (*src_dev) return res; @@ -1903,8 +1866,7 @@ static void sas_unregister_ex_tree(struct asd_sas_port *port, struct domain_devi list_for_each_entry_safe(child, n, &ex->children, siblings) { set_bit(SAS_DEV_GONE, &child->state); - if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE || - child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) + if (dev_is_expander(child->dev_type)) sas_unregister_ex_tree(port, child); else sas_unregister_dev(port, child); @@ -1924,8 +1886,7 @@ static void sas_unregister_devs_sas_addr(struct domain_device *parent, if (SAS_ADDR(child->sas_addr) == SAS_ADDR(phy->attached_sas_addr)) { set_bit(SAS_DEV_GONE, &child->state); - if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE || - child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) + if (dev_is_expander(child->dev_type)) sas_unregister_ex_tree(parent->port, child); else sas_unregister_dev(parent->port, child); @@ -1954,8 +1915,7 @@ static int sas_discover_bfs_by_root_level(struct domain_device *root, int res = 0; list_for_each_entry(child, &ex_root->children, siblings) { - if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE || - child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) { + if (dev_is_expander(child->dev_type)) { struct sas_expander_device *ex = rphy_to_expander_device(child->rphy); @@ -2008,8 +1968,7 @@ static int sas_discover_new(struct domain_device *dev, int phy_id) list_for_each_entry(child, &dev->ex_dev.children, siblings) { if (SAS_ADDR(child->sas_addr) == SAS_ADDR(ex_phy->attached_sas_addr)) { - if (child->dev_type == SAS_EDGE_EXPANDER_DEVICE || - child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) + if (dev_is_expander(child->dev_type)) res = sas_discover_bfs_by_root(child); break; } diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index d50810da53a9..21c43b18d5d5 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: GPL-2.0-only /* * Serial Attached SCSI (SAS) Transport Layer initialization * diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index 1f1e07e98477..01f1738ce6df 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Serial Attached SCSI (SAS) class internal header file * diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c index b71f5ac6c7dc..4ca4b1f30bd0 100644 --- a/drivers/scsi/libsas/sas_phy.c +++ b/drivers/scsi/libsas/sas_phy.c @@ -1,25 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Serial Attached SCSI (SAS) Phy class * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include "sas_internal.h" diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index 38a10478605c..7c86fd248129 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c @@ -1,25 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Serial Attached SCSI (SAS) Port class * * Copyright (C) 2005 Adaptec, Inc. All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include "sas_internal.h" @@ -70,7 +54,7 @@ static void sas_resume_port(struct asd_sas_phy *phy) continue; } - if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) { + if (dev_is_expander(dev->dev_type)) { dev->ex_dev.ex_change_count = -1; for (i = 0; i < dev->ex_dev.num_phys; i++) { struct ex_phy *phy = &dev->ex_dev.ex_phy[i]; @@ -195,7 +179,7 @@ static void sas_form_port(struct asd_sas_phy *phy) sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN); /* Only insert a revalidate event after initial discovery */ - if (port_dev && sas_dev_type_is_expander(port_dev->dev_type)) { + if (port_dev && dev_is_expander(port_dev->dev_type)) { struct expander_device *ex_dev = &port_dev->ex_dev; ex_dev->ex_change_count = -1; @@ -264,7 +248,7 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone) spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); /* Only insert revalidate event if the port still has members */ - if (port->port && dev && sas_dev_type_is_expander(dev->dev_type)) { + if (port->port && dev && dev_is_expander(dev->dev_type)) { struct expander_device *ex_dev = &dev->ex_dev; ex_dev->ex_change_count = -1; diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index ede0674d8399..bec83eb8ab87 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: GPL-2.0-only /* * Serial Attached SCSI (SAS) class SCSI Host glue. * @@ -414,7 +414,6 @@ static void sas_wait_eh(struct domain_device *dev) goto retry; } } -EXPORT_SYMBOL(sas_wait_eh); static int sas_queue_reset(struct domain_device *dev, int reset_type, u64 lun, int wait) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 2c3bb8a966e5..691acbdcc46d 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -51,6 +51,8 @@ struct lpfc_sli2_slim; cmnd for menlo needs nearly twice as for firmware downloads using bsg */ +#define LPFC_DEFAULT_XPSGL_SIZE 256 +#define LPFC_MAX_SG_TABLESIZE 0xffff #define LPFC_MIN_SG_SLI4_BUF_SZ 0x800 /* based on LPFC_DEFAULT_SG_SEG_CNT */ #define LPFC_MAX_BG_SLI4_SEG_CNT_DIF 128 /* sg element count for BlockGuard */ #define LPFC_MAX_SG_SEG_CNT_DIF 512 /* sg element count per scsi cmnd */ @@ -732,14 +734,13 @@ struct lpfc_hba { #define HBA_AER_ENABLED 0x1000 /* AER enabled with HBA */ #define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */ #define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */ -#define HBA_FCP_IOQ_FLUSH 0x8000 /* FCP I/O queues being flushed */ +#define HBA_IOQ_FLUSH 0x8000 /* FCP/NVME I/O queues being flushed */ #define HBA_FW_DUMP_OP 0x10000 /* Skips fn reset before FW dump */ #define HBA_RECOVERABLE_UE 0x20000 /* Firmware supports recoverable UE */ #define HBA_FORCED_LINK_SPEED 0x40000 /* * Firmware supports Forced Link Speed * capability */ -#define HBA_NVME_IOQ_FLUSH 0x80000 /* NVME IO queues flushed. */ #define HBA_FLOGI_ISSUED 0x100000 /* FLOGI was issued */ uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ @@ -795,10 +796,12 @@ struct lpfc_hba { uint8_t mds_diags_support; uint8_t bbcredit_support; uint8_t enab_exp_wqcq_pages; + u8 nsler; /* Firmware supports FC-NVMe-2 SLER */ /* HBA Config Parameters */ uint32_t cfg_ack0; uint32_t cfg_xri_rebalancing; + uint32_t cfg_xpsgl; uint32_t cfg_enable_npiv; uint32_t cfg_enable_rrq; uint32_t cfg_topology; @@ -824,6 +827,7 @@ struct lpfc_hba { uint32_t cfg_cq_poll_threshold; uint32_t cfg_cq_max_proc_limit; uint32_t cfg_fcp_cpu_map; + uint32_t cfg_fcp_mq_threshold; uint32_t cfg_hdw_queue; uint32_t cfg_irq_chann; uint32_t cfg_suppress_rsp; @@ -904,6 +908,7 @@ struct lpfc_hba { wait_queue_head_t work_waitq; struct task_struct *worker_thread; unsigned long data_flags; + uint32_t border_sge_num; uint32_t hbq_in_use; /* HBQs in use flag */ uint32_t hbq_count; /* Count of configured HBQs */ @@ -986,6 +991,7 @@ struct lpfc_hba { struct dma_pool *lpfc_nvmet_drb_pool; /* data receive buffer pool */ struct dma_pool *lpfc_hbq_pool; /* SLI3 hbq buffer pool */ struct dma_pool *txrdy_payload_pool; + struct dma_pool *lpfc_cmd_rsp_buf_pool; struct lpfc_dma_pool lpfc_mbuf_safety_pool; mempool_t *mbox_mem_pool; @@ -1033,8 +1039,6 @@ struct lpfc_hba { struct dentry *debug_hbqinfo; struct dentry *debug_dumpHostSlim; struct dentry *debug_dumpHBASlim; - struct dentry *debug_dumpData; /* BlockGuard BPL */ - struct dentry *debug_dumpDif; /* BlockGuard BPL */ struct dentry *debug_InjErrLBA; /* LBA to inject errors at */ struct dentry *debug_InjErrNPortID; /* NPortID to inject errors at */ struct dentry *debug_InjErrWWPN; /* WWPN to inject errors at */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 2bd1e014103b..25aa7a53d255 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -841,7 +841,8 @@ lpfc_hdw_show(struct device *dev, struct device_attribute *attr, char *buf) lpfc_vpd_t *vp = &phba->vpd; lpfc_jedec_to_ascii(vp->rev.biuRev, hdw); - return scnprintf(buf, PAGE_SIZE, "%s\n", hdw); + return scnprintf(buf, PAGE_SIZE, "%s %08x %08x\n", hdw, + vp->rev.smRev, vp->rev.smFwRev); } /** @@ -3682,8 +3683,8 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport) if (rport) remoteport = rport->remoteport; spin_unlock(&vport->phba->hbalock); - if (remoteport) - nvme_fc_set_remoteport_devloss(rport->remoteport, + if (rport && remoteport) + nvme_fc_set_remoteport_devloss(remoteport, vport->cfg_devloss_tmo); #endif } @@ -4097,9 +4098,9 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr, } if ((phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC || phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC) && - val != FLAGS_TOPOLOGY_MODE_PT_PT) { + val == 4) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "3114 Only non-FC-AL mode is supported\n"); + "3114 Loop mode not supported\n"); return -EINVAL; } phba->cfg_topology = val; @@ -5180,7 +5181,8 @@ lpfc_cq_max_proc_limit_store(struct device *dev, struct device_attribute *attr, /* set the values on the cq's */ for (i = 0; i < phba->cfg_irq_chann; i++) { - eq = phba->sli4_hba.hdwq[i].hba_eq; + /* Get the EQ corresponding to the IRQ vector */ + eq = phba->sli4_hba.hba_eq_hdl[i].eq; if (!eq) continue; @@ -5301,35 +5303,44 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, len += scnprintf( buf + len, PAGE_SIZE - len, "CPU %02d hdwq None " - "physid %d coreid %d ht %d\n", + "physid %d coreid %d ht %d ua %d\n", phba->sli4_hba.curr_disp_cpu, - cpup->phys_id, - cpup->core_id, cpup->hyper); + cpup->phys_id, cpup->core_id, + (cpup->flag & LPFC_CPU_MAP_HYPER), + (cpup->flag & LPFC_CPU_MAP_UNASSIGN)); else len += scnprintf( buf + len, PAGE_SIZE - len, "CPU %02d EQ %04d hdwq %04d " - "physid %d coreid %d ht %d\n", + "physid %d coreid %d ht %d ua %d\n", phba->sli4_hba.curr_disp_cpu, cpup->eq, cpup->hdwq, cpup->phys_id, - cpup->core_id, cpup->hyper); + cpup->core_id, + (cpup->flag & LPFC_CPU_MAP_HYPER), + (cpup->flag & LPFC_CPU_MAP_UNASSIGN)); } else { if (cpup->hdwq == LPFC_VECTOR_MAP_EMPTY) len += scnprintf( buf + len, PAGE_SIZE - len, "CPU %02d hdwq None " - "physid %d coreid %d ht %d IRQ %d\n", + "physid %d coreid %d ht %d ua %d IRQ %d\n", phba->sli4_hba.curr_disp_cpu, cpup->phys_id, - cpup->core_id, cpup->hyper, cpup->irq); + cpup->core_id, + (cpup->flag & LPFC_CPU_MAP_HYPER), + (cpup->flag & LPFC_CPU_MAP_UNASSIGN), + cpup->irq); else len += scnprintf( buf + len, PAGE_SIZE - len, "CPU %02d EQ %04d hdwq %04d " - "physid %d coreid %d ht %d IRQ %d\n", + "physid %d coreid %d ht %d ua %d IRQ %d\n", phba->sli4_hba.curr_disp_cpu, cpup->eq, cpup->hdwq, cpup->phys_id, - cpup->core_id, cpup->hyper, cpup->irq); + cpup->core_id, + (cpup->flag & LPFC_CPU_MAP_HYPER), + (cpup->flag & LPFC_CPU_MAP_UNASSIGN), + cpup->irq); } phba->sli4_hba.curr_disp_cpu++; @@ -5457,15 +5468,12 @@ LPFC_ATTR_RW(nvmet_fb_size, 0, 0, 65536, * lpfc_nvme_enable_fb: Enable NVME first burst on I and T functions. * For the Initiator (I), enabling this parameter means that an NVMET * PRLI response with FBA enabled and an FB_SIZE set to a nonzero value will be - * processed by the initiator for subsequent NVME FCP IO. For the target - * function (T), enabling this parameter qualifies the lpfc_nvmet_fb_size - * driver parameter as the target function's first burst size returned to the - * initiator in the target's NVME PRLI response. Parameter supported on physical - * port only - no NPIV support. + * processed by the initiator for subsequent NVME FCP IO. + * Currently, this feature is not supported on the NVME target * Value range is [0,1]. Default value is 0 (disabled). */ LPFC_ATTR_RW(nvme_enable_fb, 0, 0, 1, - "Enable First Burst feature on I and T functions."); + "Enable First Burst feature for NVME Initiator."); /* # lpfc_max_scsicmpl_time: Use scsi command completion time to control I/O queue @@ -5699,6 +5707,19 @@ LPFC_ATTR_RW(nvme_embed_cmd, 1, 0, 2, "Embed NVME Command in WQE"); /* + * lpfc_fcp_mq_threshold: Set the maximum number of Hardware Queues + * the driver will advertise it supports to the SCSI layer. + * + * 0 = Set nr_hw_queues by the number of CPUs or HW queues. + * 1,128 = Manually specify the maximum nr_hw_queue value to be set, + * + * Value range is [0,256]. Default value is 8. + */ +LPFC_ATTR_R(fcp_mq_threshold, LPFC_FCP_MQ_THRESHOLD_DEF, + LPFC_FCP_MQ_THRESHOLD_MIN, LPFC_FCP_MQ_THRESHOLD_MAX, + "Set the number of SCSI Queues advertised"); + +/* * lpfc_hdw_queue: Set the number of Hardware Queues the driver * will advertise it supports to the NVME and SCSI layers. This also * will map to the number of CQ/WQ pairs the driver will create. @@ -5904,7 +5925,7 @@ lpfc_sg_seg_cnt_init(struct lpfc_hba *phba, int val) * 1 = MDS Diagnostics enabled * Value range is [0,1]. Default value is 0. */ -LPFC_ATTR_R(enable_mds_diags, 0, 0, 1, "Enable MDS Diagnostics"); +LPFC_ATTR_RW(enable_mds_diags, 0, 0, 1, "Enable MDS Diagnostics"); /* * lpfc_ras_fwlog_buffsize: Firmware logging host buffer size @@ -6020,6 +6041,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_cq_poll_threshold, &dev_attr_lpfc_cq_max_proc_limit, &dev_attr_lpfc_fcp_cpu_map, + &dev_attr_lpfc_fcp_mq_threshold, &dev_attr_lpfc_hdw_queue, &dev_attr_lpfc_irq_chann, &dev_attr_lpfc_suppress_rsp, @@ -6835,10 +6857,31 @@ lpfc_get_starget_port_name(struct scsi_target *starget) static void lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) { + struct lpfc_rport_data *rdata = rport->dd_data; + struct lpfc_nodelist *ndlp = rdata->pnode; +#if (IS_ENABLED(CONFIG_NVME_FC)) + struct lpfc_nvme_rport *nrport = NULL; +#endif + if (timeout) rport->dev_loss_tmo = timeout; else rport->dev_loss_tmo = 1; + + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + dev_info(&rport->dev, "Cannot find remote node to " + "set rport dev loss tmo, port_id x%x\n", + rport->port_id); + return; + } + +#if (IS_ENABLED(CONFIG_NVME_FC)) + nrport = lpfc_ndlp_get_nrport(ndlp); + + if (nrport && nrport->remoteport) + nvme_fc_set_remoteport_devloss(nrport->remoteport, + rport->dev_loss_tmo); +#endif } /** @@ -7035,6 +7078,21 @@ struct fc_function_template lpfc_vport_transport_functions = { }; /** + * lpfc_get_hba_function_mode - Used to determine the HBA function in FCoE + * Mode + * @phba: lpfc_hba pointer. + **/ +static void +lpfc_get_hba_function_mode(struct lpfc_hba *phba) +{ + /* If it's a SkyHawk FCoE adapter */ + if (phba->pcidev->device == PCI_DEVICE_ID_SKYHAWK) + phba->hba_flag |= HBA_FCOE_MODE; + else + phba->hba_flag &= ~HBA_FCOE_MODE; +} + +/** * lpfc_get_cfgparam - Used during probe_one to init the adapter structure * @phba: lpfc_hba pointer. **/ @@ -7090,8 +7148,18 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) else phba->cfg_poll = lpfc_poll; - if (phba->cfg_enable_bg) + /* Get the function mode */ + lpfc_get_hba_function_mode(phba); + + /* BlockGuard allowed for FC only. */ + if (phba->cfg_enable_bg && phba->hba_flag & HBA_FCOE_MODE) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0581 BlockGuard feature not supported\n"); + /* If set, clear the BlockGuard support param */ + phba->cfg_enable_bg = 0; + } else if (phba->cfg_enable_bg) { phba->sli3_options |= LPFC_SLI3_BG_ENABLED; + } lpfc_suppress_rsp_init(phba, lpfc_suppress_rsp); @@ -7102,6 +7170,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) /* Initialize first burst. Target vs Initiator are different. */ lpfc_nvme_enable_fb_init(phba, lpfc_nvme_enable_fb); lpfc_nvmet_fb_size_init(phba, lpfc_nvmet_fb_size); + lpfc_fcp_mq_threshold_init(phba, lpfc_fcp_mq_threshold); lpfc_hdw_queue_init(phba, lpfc_hdw_queue); lpfc_irq_chann_init(phba, lpfc_irq_chann); lpfc_enable_bbcr_init(phba, lpfc_enable_bbcr); @@ -7150,16 +7219,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_ras_fwlog_level_init(phba, lpfc_ras_fwlog_level); lpfc_ras_fwlog_func_init(phba, lpfc_ras_fwlog_func); - - /* If the NVME FC4 type is enabled, scale the sg_seg_cnt to - * accommodate 512K and 1M IOs in a single nvme buf and supply - * enough NVME LS iocb buffers for larger connectivity counts. - */ - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - phba->cfg_sg_seg_cnt = LPFC_MAX_NVME_SEG_CNT; - phba->cfg_iocb_cnt = 5; - } - return; } diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index b0202bc0aa62..39a736b887b1 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1040,7 +1040,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (!dmabuf) { lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, "2616 No dmabuf " - "found for iocbq 0x%p\n", + "found for iocbq x%px\n", iocbq); kfree(evt_dat->data); kfree(evt_dat); @@ -1276,9 +1276,7 @@ lpfc_bsg_hba_set_event(struct bsg_job *job) return 0; /* call job done later */ job_error: - if (dd_data != NULL) - kfree(dd_data); - + kfree(dd_data); job->dd_data = NULL; return rc; } @@ -1571,7 +1569,6 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag, "2722 Xmit CT response on exchange x%x Data: x%x x%x x%x\n", icmd->ulpContext, icmd->ulpIoTag, tag, phba->link_state); - ctiocb->iocb_cmpl = NULL; ctiocb->iocb_flag |= LPFC_IO_LIBDFC; ctiocb->vport = phba->pport; ctiocb->context1 = dd_data; @@ -5451,7 +5448,9 @@ ras_job_error: bsg_reply->result = rc; /* complete the job back to userspace */ - bsg_job_done(job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + if (!rc) + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); return rc; } @@ -5530,8 +5529,9 @@ ras_job_error: bsg_reply->result = rc; /* complete the job back to userspace */ - bsg_job_done(job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); + if (!rc) + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); return rc; } @@ -5591,7 +5591,9 @@ ras_job_error: bsg_reply->result = rc; /* complete the job back to userspace */ - bsg_job_done(job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + if (!rc) + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); return rc; } @@ -5673,7 +5675,9 @@ lpfc_bsg_get_ras_fwlog(struct bsg_job *job) ras_job_error: bsg_reply->result = rc; - bsg_job_done(job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + if (!rc) + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); return rc; } @@ -5741,11 +5745,12 @@ lpfc_get_trunk_info(struct bsg_job *job) event_reply->port_speed = phba->sli4_hba.link_state.speed / 1000; event_reply->logical_speed = - phba->sli4_hba.link_state.logical_speed / 100; + phba->sli4_hba.link_state.logical_speed / 1000; job_error: bsg_reply->result = rc; - bsg_job_done(job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); + if (!rc) + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); return rc; } diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 866374801140..b2ad8c750486 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -326,7 +326,7 @@ void lpfc_sli_bemem_bcopy(void *, void *, uint32_t); void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *); void lpfc_sli_abort_fcp_rings(struct lpfc_hba *phba); void lpfc_sli_hba_iocb_abort(struct lpfc_hba *); -void lpfc_sli_flush_fcp_rings(struct lpfc_hba *); +void lpfc_sli_flush_io_rings(struct lpfc_hba *phba); int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_dmabuf *); struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, @@ -433,16 +433,6 @@ int lpfc_sli4_get_allocated_extnts(struct lpfc_hba *, uint16_t, int lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *, uint16_t, uint16_t *, uint16_t *); -/* externs BlockGuard */ -extern char *_dump_buf_data; -extern unsigned long _dump_buf_data_order; -extern char *_dump_buf_dif; -extern unsigned long _dump_buf_dif_order; -extern spinlock_t _dump_buf_lock; -extern int _dump_buf_done; -extern spinlock_t pgcnt_lock; -extern unsigned int pgcnt; - /* Interface exported by fabric iocb scheduler */ void lpfc_fabric_abort_nport(struct lpfc_nodelist *); void lpfc_fabric_abort_hba(struct lpfc_hba *); @@ -572,7 +562,8 @@ void lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba); void lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb); void lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint32_t idx, - struct rqb_dmabuf *nvmebuf, uint64_t isr_ts); + struct rqb_dmabuf *nvmebuf, uint64_t isr_ts, + uint8_t cqflag); void lpfc_nvme_mod_param_dep(struct lpfc_hba *phba); void lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, @@ -594,6 +585,7 @@ void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *ncmd, struct lpfc_sli4_hdw_queue *qp); void lpfc_nvme_cmd_template(void); void lpfc_nvmet_cmd_template(void); +void lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn); extern int lpfc_enable_nvmet_cnt; extern unsigned long long lpfc_enable_nvmet[]; extern int lpfc_no_hba_reset_cnt; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 4812bbbf43cc..25e86706e207 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -462,6 +462,7 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) struct lpfc_nodelist *ndlp; if ((vport->port_type != LPFC_NPIV_PORT) || + (fc4_type == FC_TYPE_FCP) || !(vport->ct_flags & FC_CT_RFF_ID) || !vport->cfg_restrict_login) { ndlp = lpfc_setup_disc_node(vport, Did); @@ -480,10 +481,20 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0238 Process x%06x NameServer Rsp " - "Data: x%x x%x x%x x%x\n", Did, + "Data: x%x x%x x%x x%x x%x\n", Did, ndlp->nlp_flag, ndlp->nlp_fc4_type, - vport->fc_flag, + ndlp->nlp_state, vport->fc_flag, vport->fc_rscn_id_cnt); + + /* if ndlp needs to be discovered and prior + * state of ndlp hit devloss, change state to + * allow rediscovery. + */ + if (ndlp->nlp_flag & NLP_NPR_2B_DISC && + ndlp->nlp_state == NLP_STE_UNUSED_NODE) { + lpfc_nlp_set_state(vport, ndlp, + NLP_STE_NPR_NODE); + } } else { lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, "Skip1 GID_FTrsp: did:x%x flg:x%x cnt:%d", @@ -491,9 +502,9 @@ lpfc_prep_node_fc4type(struct lpfc_vport *vport, uint32_t Did, uint8_t fc4_type) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0239 Skip x%06x NameServer Rsp " - "Data: x%x x%x\n", Did, - vport->fc_flag, - vport->fc_rscn_id_cnt); + "Data: x%x x%x %p\n", + Did, vport->fc_flag, + vport->fc_rscn_id_cnt, ndlp); } } else { if (!(vport->fc_flag & FC_RSCN_MODE) || @@ -751,9 +762,11 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (CTrsp->CommandResponse.bits.CmdRsp == cpu_to_be16(SLI_CT_RESPONSE_FS_ACC)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0208 NameServer Rsp Data: x%x x%x\n", + "0208 NameServer Rsp Data: x%x x%x " + "sz x%x\n", vport->fc_flag, - CTreq->un.gid.Fc4Type); + CTreq->un.gid.Fc4Type, + irsp->un.genreq64.bdl.bdeSize); lpfc_ns_rsp(vport, outp, @@ -814,6 +827,11 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } vport->gidft_inp--; } + + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "4216 GID_FT cmpl inp %d disc %d\n", + vport->gidft_inp, vport->num_disc_nodes); + /* Link up / RSCN discovery */ if ((vport->num_disc_nodes == 0) && (vport->gidft_inp == 0)) { @@ -1209,14 +1227,34 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (fc4_data_1 & LPFC_FC4_TYPE_BITMASK) ndlp->nlp_fc4_type |= NLP_FC4_NVME; lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "3064 Setting ndlp %p, DID x%06x with " - "FC4 x%08x, Data: x%08x x%08x\n", + "3064 Setting ndlp x%px, DID x%06x " + "with FC4 x%08x, Data: x%08x x%08x " + "%d\n", ndlp, did, ndlp->nlp_fc4_type, - FC_TYPE_FCP, FC_TYPE_NVME); - ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; - - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE); - lpfc_issue_els_prli(vport, ndlp, 0); + FC_TYPE_FCP, FC_TYPE_NVME, + ndlp->nlp_state); + + if (ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE && + ndlp->nlp_fc4_type) { + ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; + + lpfc_nlp_set_state(vport, ndlp, + NLP_STE_PRLI_ISSUE); + lpfc_issue_els_prli(vport, ndlp, 0); + } else if (!ndlp->nlp_fc4_type) { + /* If fc4 type is still unknown, then LOGO */ + lpfc_printf_vlog(vport, KERN_INFO, + LOG_DISCOVERY, + "6443 Sending LOGO ndlp x%px," + "DID x%06x with fc4_type: " + "x%08x, state: %d\n", + ndlp, did, ndlp->nlp_fc4_type, + ndlp->nlp_state); + lpfc_issue_els_logo(vport, ndlp, 0); + ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; + lpfc_nlp_set_state(vport, ndlp, + NLP_STE_NPR_NODE); + } } } else lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, @@ -2358,6 +2396,7 @@ static int lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport, struct lpfc_fdmi_attr_def *ad) { + struct lpfc_hba *phba = vport->phba; struct lpfc_fdmi_attr_entry *ae; uint32_t size; @@ -2366,9 +2405,13 @@ lpfc_fdmi_port_attr_fc4type(struct lpfc_vport *vport, ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */ ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */ - if (vport->nvmei_support || vport->phba->nvmet_support) - ae->un.AttrTypes[6] = 0x01; /* Type 0x28 - NVME */ ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */ + + /* Check to see if Firmware supports NVME and on physical port */ + if ((phba->sli_rev == LPFC_SLI_REV4) && (vport == phba->pport) && + phba->sli4_hba.pc_sli4_params.nvme) + ae->un.AttrTypes[6] = 0x01; /* Type 0x28 - NVME */ + size = FOURBYTES + 32; ad->AttrLen = cpu_to_be16(size); ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_FC4_TYPES); @@ -2510,7 +2553,7 @@ lpfc_fdmi_port_attr_max_frame(struct lpfc_vport *vport, ae = (struct lpfc_fdmi_attr_entry *)&ad->AttrValue; hsp = (struct serv_parm *)&vport->fc_sparam; - ae->un.AttrInt = (((uint32_t) hsp->cmn.bbRcvSizeMsb) << 8) | + ae->un.AttrInt = (((uint32_t) hsp->cmn.bbRcvSizeMsb & 0x0F) << 8) | (uint32_t) hsp->cmn.bbRcvSizeLsb; ae->un.AttrInt = cpu_to_be32(ae->un.AttrInt); size = FOURBYTES + sizeof(uint32_t); @@ -2680,9 +2723,12 @@ lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport, ae->un.AttrTypes[3] = 0x02; /* Type 0x1 - ELS */ ae->un.AttrTypes[2] = 0x01; /* Type 0x8 - FCP */ + ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */ + + /* Check to see if NVME is configured or not */ if (vport->phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) ae->un.AttrTypes[6] = 0x1; /* Type 0x28 - NVME */ - ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */ + size = FOURBYTES + 32; ad->AttrLen = cpu_to_be16(size); ad->AttrType = cpu_to_be16(RPRT_ACTIVE_FC4_TYPES); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 1ee857d9d165..8d34be60d379 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -361,7 +361,7 @@ lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff); if (phys == le32_to_cpu(hbqe->bde.addrLow)) { len += scnprintf(buf+len, size-len, - "Buf%d: %p %06x\n", i, + "Buf%d: x%px %06x\n", i, hbq_buf->dbuf.virt, hbq_buf->tag); found = 1; break; @@ -416,8 +416,7 @@ lpfc_debugfs_commonxripools_data(struct lpfc_hba *phba, char *buf, int size) qp = &phba->sli4_hba.hdwq[lpfc_debugfs_last_xripool]; len += scnprintf(buf + len, size - len, "HdwQ %d Info ", i); - spin_lock_irqsave(&qp->abts_scsi_buf_list_lock, iflag); - spin_lock(&qp->abts_nvme_buf_list_lock); + spin_lock_irqsave(&qp->abts_io_buf_list_lock, iflag); spin_lock(&qp->io_buf_list_get_lock); spin_lock(&qp->io_buf_list_put_lock); out = qp->total_io_bufs - (qp->get_io_bufs + qp->put_io_bufs + @@ -430,8 +429,7 @@ lpfc_debugfs_commonxripools_data(struct lpfc_hba *phba, char *buf, int size) qp->abts_nvme_io_bufs, out); spin_unlock(&qp->io_buf_list_put_lock); spin_unlock(&qp->io_buf_list_get_lock); - spin_unlock(&qp->abts_nvme_buf_list_lock); - spin_unlock_irqrestore(&qp->abts_scsi_buf_list_lock, iflag); + spin_unlock_irqrestore(&qp->abts_io_buf_list_lock, iflag); lpfc_debugfs_last_xripool++; if (lpfc_debugfs_last_xripool >= phba->cfg_hdw_queue) @@ -533,9 +531,7 @@ lpfc_debugfs_multixripools_data(struct lpfc_hba *phba, char *buf, int size) continue; pbl_pool = &multixri_pool->pbl_pool; pvt_pool = &multixri_pool->pvt_pool; - txcmplq_cnt = qp->fcp_wq->pring->txcmplq_cnt; - if (qp->nvme_wq) - txcmplq_cnt += qp->nvme_wq->pring->txcmplq_cnt; + txcmplq_cnt = qp->io_wq->pring->txcmplq_cnt; scnprintf(tmp, sizeof(tmp), "%03d: %4d %4d %4d %4d | %10d %10d ", @@ -2166,89 +2162,6 @@ out: return rc; } -static int -lpfc_debugfs_dumpData_open(struct inode *inode, struct file *file) -{ - struct lpfc_debug *debug; - int rc = -ENOMEM; - - if (!_dump_buf_data) - return -EBUSY; - - debug = kmalloc(sizeof(*debug), GFP_KERNEL); - if (!debug) - goto out; - - /* Round to page boundary */ - pr_err("9059 BLKGRD: %s: _dump_buf_data=0x%p\n", - __func__, _dump_buf_data); - debug->buffer = _dump_buf_data; - if (!debug->buffer) { - kfree(debug); - goto out; - } - - debug->len = (1 << _dump_buf_data_order) << PAGE_SHIFT; - file->private_data = debug; - - rc = 0; -out: - return rc; -} - -static int -lpfc_debugfs_dumpDif_open(struct inode *inode, struct file *file) -{ - struct lpfc_debug *debug; - int rc = -ENOMEM; - - if (!_dump_buf_dif) - return -EBUSY; - - debug = kmalloc(sizeof(*debug), GFP_KERNEL); - if (!debug) - goto out; - - /* Round to page boundary */ - pr_err("9060 BLKGRD: %s: _dump_buf_dif=0x%p file=%pD\n", - __func__, _dump_buf_dif, file); - debug->buffer = _dump_buf_dif; - if (!debug->buffer) { - kfree(debug); - goto out; - } - - debug->len = (1 << _dump_buf_dif_order) << PAGE_SHIFT; - file->private_data = debug; - - rc = 0; -out: - return rc; -} - -static ssize_t -lpfc_debugfs_dumpDataDif_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) -{ - /* - * The Data/DIF buffers only save one failing IO - * The write op is used as a reset mechanism after an IO has - * already been saved to the next one can be saved - */ - spin_lock(&_dump_buf_lock); - - memset((void *)_dump_buf_data, 0, - ((1 << PAGE_SHIFT) << _dump_buf_data_order)); - memset((void *)_dump_buf_dif, 0, - ((1 << PAGE_SHIFT) << _dump_buf_dif_order)); - - _dump_buf_done = 0; - - spin_unlock(&_dump_buf_lock); - - return nbytes; -} - static ssize_t lpfc_debugfs_dif_err_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) @@ -2461,17 +2374,6 @@ lpfc_debugfs_release(struct inode *inode, struct file *file) return 0; } -static int -lpfc_debugfs_dumpDataDif_release(struct inode *inode, struct file *file) -{ - struct lpfc_debug *debug = file->private_data; - - debug->buffer = NULL; - kfree(debug); - - return 0; -} - /** * lpfc_debugfs_multixripools_write - Clear multi-XRI pools statistics * @file: The file pointer to read from. @@ -3786,23 +3688,13 @@ lpfc_idiag_wqs_for_cq(struct lpfc_hba *phba, char *wqtype, char *pbuffer, int qidx; for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { - qp = phba->sli4_hba.hdwq[qidx].fcp_wq; + qp = phba->sli4_hba.hdwq[qidx].io_wq; if (qp->assoc_qid != cq_id) continue; *len = __lpfc_idiag_print_wq(qp, wqtype, pbuffer, *len); if (*len >= max_cnt) return 1; } - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { - qp = phba->sli4_hba.hdwq[qidx].nvme_wq; - if (qp->assoc_qid != cq_id) - continue; - *len = __lpfc_idiag_print_wq(qp, wqtype, pbuffer, *len); - if (*len >= max_cnt) - return 1; - } - } return 0; } @@ -3868,9 +3760,9 @@ lpfc_idiag_cqs_for_eq(struct lpfc_hba *phba, char *pbuffer, struct lpfc_queue *qp; int rc; - qp = phba->sli4_hba.hdwq[eqidx].fcp_cq; + qp = phba->sli4_hba.hdwq[eqidx].io_cq; - *len = __lpfc_idiag_print_cq(qp, "FCP", pbuffer, *len); + *len = __lpfc_idiag_print_cq(qp, "IO", pbuffer, *len); /* Reset max counter */ qp->CQ_max_cqe = 0; @@ -3878,28 +3770,11 @@ lpfc_idiag_cqs_for_eq(struct lpfc_hba *phba, char *pbuffer, if (*len >= max_cnt) return 1; - rc = lpfc_idiag_wqs_for_cq(phba, "FCP", pbuffer, len, + rc = lpfc_idiag_wqs_for_cq(phba, "IO", pbuffer, len, max_cnt, qp->queue_id); if (rc) return 1; - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - qp = phba->sli4_hba.hdwq[eqidx].nvme_cq; - - *len = __lpfc_idiag_print_cq(qp, "NVME", pbuffer, *len); - - /* Reset max counter */ - qp->CQ_max_cqe = 0; - - if (*len >= max_cnt) - return 1; - - rc = lpfc_idiag_wqs_for_cq(phba, "NVME", pbuffer, len, - max_cnt, qp->queue_id); - if (rc) - return 1; - } - if ((eqidx < phba->cfg_nvmet_mrq) && phba->nvmet_support) { /* NVMET CQset */ qp = phba->sli4_hba.nvmet_cqset[eqidx]; @@ -4348,7 +4223,7 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, if (phba->sli4_hba.hdwq) { for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { - qp = phba->sli4_hba.hdwq[qidx].fcp_cq; + qp = phba->sli4_hba.hdwq[qidx].io_cq; if (qp && qp->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( @@ -4360,22 +4235,6 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, } } } - /* NVME complete queue */ - if (phba->sli4_hba.hdwq) { - qidx = 0; - do { - qp = phba->sli4_hba.hdwq[qidx].nvme_cq; - if (qp && qp->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - qp, index, count); - if (rc) - goto error_out; - idiag.ptr_private = qp; - goto pass_check; - } - } while (++qidx < phba->cfg_hdw_queue); - } goto error_out; break; case LPFC_IDIAG_MQ: @@ -4419,20 +4278,7 @@ lpfc_idiag_queacc_write(struct file *file, const char __user *buf, if (phba->sli4_hba.hdwq) { /* FCP/SCSI work queue */ for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { - qp = phba->sli4_hba.hdwq[qidx].fcp_wq; - if (qp && qp->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - qp, index, count); - if (rc) - goto error_out; - idiag.ptr_private = qp; - goto pass_check; - } - } - /* NVME work queue */ - for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { - qp = phba->sli4_hba.hdwq[qidx].nvme_wq; + qp = phba->sli4_hba.hdwq[qidx].io_wq; if (qp && qp->queue_id == queid) { /* Sanity check */ rc = lpfc_idiag_que_param_check( @@ -5508,26 +5354,6 @@ static const struct file_operations lpfc_debugfs_op_cpucheck = { .release = lpfc_debugfs_release, }; -#undef lpfc_debugfs_op_dumpData -static const struct file_operations lpfc_debugfs_op_dumpData = { - .owner = THIS_MODULE, - .open = lpfc_debugfs_dumpData_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_debugfs_read, - .write = lpfc_debugfs_dumpDataDif_write, - .release = lpfc_debugfs_dumpDataDif_release, -}; - -#undef lpfc_debugfs_op_dumpDif -static const struct file_operations lpfc_debugfs_op_dumpDif = { - .owner = THIS_MODULE, - .open = lpfc_debugfs_dumpDif_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_debugfs_read, - .write = lpfc_debugfs_dumpDataDif_write, - .release = lpfc_debugfs_dumpDataDif_release, -}; - #undef lpfc_debugfs_op_dif_err static const struct file_operations lpfc_debugfs_op_dif_err = { .owner = THIS_MODULE, @@ -5924,20 +5750,6 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) } else phba->debug_dumpHostSlim = NULL; - /* Setup dumpData */ - snprintf(name, sizeof(name), "dumpData"); - phba->debug_dumpData = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dumpData); - - /* Setup dumpDif */ - snprintf(name, sizeof(name), "dumpDif"); - phba->debug_dumpDif = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dumpDif); - /* Setup DIF Error Injections */ snprintf(name, sizeof(name), "InjErrLBA"); phba->debug_InjErrLBA = @@ -6315,12 +6127,6 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */ phba->debug_dumpHostSlim = NULL; - debugfs_remove(phba->debug_dumpData); /* dumpData */ - phba->debug_dumpData = NULL; - - debugfs_remove(phba->debug_dumpDif); /* dumpDif */ - phba->debug_dumpDif = NULL; - debugfs_remove(phba->debug_InjErrLBA); /* InjErrLBA */ phba->debug_InjErrLBA = NULL; @@ -6442,12 +6248,7 @@ lpfc_debug_dump_all_queues(struct lpfc_hba *phba) lpfc_debug_dump_wq(phba, DUMP_NVMELS, 0); for (idx = 0; idx < phba->cfg_hdw_queue; idx++) - lpfc_debug_dump_wq(phba, DUMP_FCP, idx); - - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - for (idx = 0; idx < phba->cfg_hdw_queue; idx++) - lpfc_debug_dump_wq(phba, DUMP_NVME, idx); - } + lpfc_debug_dump_wq(phba, DUMP_IO, idx); lpfc_debug_dump_hdr_rq(phba); lpfc_debug_dump_dat_rq(phba); @@ -6459,12 +6260,7 @@ lpfc_debug_dump_all_queues(struct lpfc_hba *phba) lpfc_debug_dump_cq(phba, DUMP_NVMELS, 0); for (idx = 0; idx < phba->cfg_hdw_queue; idx++) - lpfc_debug_dump_cq(phba, DUMP_FCP, idx); - - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - for (idx = 0; idx < phba->cfg_hdw_queue; idx++) - lpfc_debug_dump_cq(phba, DUMP_NVME, idx); - } + lpfc_debug_dump_cq(phba, DUMP_IO, idx); /* * Dump Event Queues (EQs) diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index 2322ddb085c0..20f2537af511 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -291,8 +291,7 @@ struct lpfc_idiag { #define LPFC_DUMP_MULTIXRIPOOL_SIZE 8192 enum { - DUMP_FCP, - DUMP_NVME, + DUMP_IO, DUMP_MBX, DUMP_ELS, DUMP_NVMELS, @@ -330,7 +329,7 @@ enum { * This function dumps an entry indexed by @idx from a queue specified by the * queue descriptor @q. **/ -static inline void +static void lpfc_debug_dump_qe(struct lpfc_queue *q, uint32_t idx) { char line_buf[LPFC_LBUF_SZ]; @@ -415,12 +414,9 @@ lpfc_debug_dump_wq(struct lpfc_hba *phba, int qtype, int wqidx) struct lpfc_queue *wq; char *qtypestr; - if (qtype == DUMP_FCP) { - wq = phba->sli4_hba.hdwq[wqidx].fcp_wq; - qtypestr = "FCP"; - } else if (qtype == DUMP_NVME) { - wq = phba->sli4_hba.hdwq[wqidx].nvme_wq; - qtypestr = "NVME"; + if (qtype == DUMP_IO) { + wq = phba->sli4_hba.hdwq[wqidx].io_wq; + qtypestr = "IO"; } else if (qtype == DUMP_MBX) { wq = phba->sli4_hba.mbx_wq; qtypestr = "MBX"; @@ -433,7 +429,7 @@ lpfc_debug_dump_wq(struct lpfc_hba *phba, int qtype, int wqidx) } else return; - if (qtype == DUMP_FCP || qtype == DUMP_NVME) + if (qtype == DUMP_IO) pr_err("%s WQ: WQ[Idx:%d|Qid:%d]\n", qtypestr, wqidx, wq->queue_id); else @@ -459,17 +455,13 @@ lpfc_debug_dump_cq(struct lpfc_hba *phba, int qtype, int wqidx) char *qtypestr; int eqidx; - /* fcp/nvme wq and cq are 1:1, thus same indexes */ + /* io wq and cq are 1:1, thus same indexes */ eq = NULL; - if (qtype == DUMP_FCP) { - wq = phba->sli4_hba.hdwq[wqidx].fcp_wq; - cq = phba->sli4_hba.hdwq[wqidx].fcp_cq; - qtypestr = "FCP"; - } else if (qtype == DUMP_NVME) { - wq = phba->sli4_hba.hdwq[wqidx].nvme_wq; - cq = phba->sli4_hba.hdwq[wqidx].nvme_cq; - qtypestr = "NVME"; + if (qtype == DUMP_IO) { + wq = phba->sli4_hba.hdwq[wqidx].io_wq; + cq = phba->sli4_hba.hdwq[wqidx].io_cq; + qtypestr = "IO"; } else if (qtype == DUMP_MBX) { wq = phba->sli4_hba.mbx_wq; cq = phba->sli4_hba.mbx_cq; @@ -496,7 +488,7 @@ lpfc_debug_dump_cq(struct lpfc_hba *phba, int qtype, int wqidx) eq = phba->sli4_hba.hdwq[0].hba_eq; } - if (qtype == DUMP_FCP || qtype == DUMP_NVME) + if (qtype == DUMP_IO) pr_err("%s CQ: WQ[Idx:%d|Qid%d]->CQ[Idx%d|Qid%d]" "->EQ[Idx:%d|Qid:%d]:\n", qtypestr, wqidx, wq->queue_id, wqidx, cq->queue_id, @@ -572,20 +564,11 @@ lpfc_debug_dump_wq_by_id(struct lpfc_hba *phba, int qid) int wq_idx; for (wq_idx = 0; wq_idx < phba->cfg_hdw_queue; wq_idx++) - if (phba->sli4_hba.hdwq[wq_idx].fcp_wq->queue_id == qid) - break; - if (wq_idx < phba->cfg_hdw_queue) { - pr_err("FCP WQ[Idx:%d|Qid:%d]\n", wq_idx, qid); - lpfc_debug_dump_q(phba->sli4_hba.hdwq[wq_idx].fcp_wq); - return; - } - - for (wq_idx = 0; wq_idx < phba->cfg_hdw_queue; wq_idx++) - if (phba->sli4_hba.hdwq[wq_idx].nvme_wq->queue_id == qid) + if (phba->sli4_hba.hdwq[wq_idx].io_wq->queue_id == qid) break; if (wq_idx < phba->cfg_hdw_queue) { - pr_err("NVME WQ[Idx:%d|Qid:%d]\n", wq_idx, qid); - lpfc_debug_dump_q(phba->sli4_hba.hdwq[wq_idx].nvme_wq); + pr_err("IO WQ[Idx:%d|Qid:%d]\n", wq_idx, qid); + lpfc_debug_dump_q(phba->sli4_hba.hdwq[wq_idx].io_wq); return; } @@ -654,22 +637,12 @@ lpfc_debug_dump_cq_by_id(struct lpfc_hba *phba, int qid) int cq_idx; for (cq_idx = 0; cq_idx < phba->cfg_hdw_queue; cq_idx++) - if (phba->sli4_hba.hdwq[cq_idx].fcp_cq->queue_id == qid) - break; - - if (cq_idx < phba->cfg_hdw_queue) { - pr_err("FCP CQ[Idx:%d|Qid:%d]\n", cq_idx, qid); - lpfc_debug_dump_q(phba->sli4_hba.hdwq[cq_idx].fcp_cq); - return; - } - - for (cq_idx = 0; cq_idx < phba->cfg_hdw_queue; cq_idx++) - if (phba->sli4_hba.hdwq[cq_idx].nvme_cq->queue_id == qid) + if (phba->sli4_hba.hdwq[cq_idx].io_cq->queue_id == qid) break; if (cq_idx < phba->cfg_hdw_queue) { - pr_err("NVME CQ[Idx:%d|Qid:%d]\n", cq_idx, qid); - lpfc_debug_dump_q(phba->sli4_hba.hdwq[cq_idx].nvme_cq); + pr_err("IO CQ[Idx:%d|Qid:%d]\n", cq_idx, qid); + lpfc_debug_dump_q(phba->sli4_hba.hdwq[cq_idx].io_cq); return; } diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 1c89c9f314fa..482e4a888dae 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -112,6 +112,8 @@ struct lpfc_nodelist { uint8_t nlp_retry; /* used for ELS retries */ uint8_t nlp_fcp_info; /* class info, bits 0-3 */ #define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */ + u8 nlp_nvme_info; /* NVME NSLER Support */ +#define NLP_NVME_NSLER 0x1 /* NVME NSLER device */ uint16_t nlp_usg_map; /* ndlp management usage bitmap */ #define NLP_USG_NODE_ACT_BIT 0x1 /* Indicate ndlp is actively used */ @@ -157,6 +159,7 @@ struct lpfc_node_rrq { /* Defines for nlp_flag (uint32) */ #define NLP_IGNR_REG_CMPL 0x00000001 /* Rcvd rscn before we cmpl reg login */ #define NLP_REG_LOGIN_SEND 0x00000002 /* sent reglogin to adapter */ +#define NLP_RELEASE_RPI 0x00000004 /* Release RPI to free pool */ #define NLP_SUPPRESS_RSP 0x00000010 /* Remote NPort supports suppress rsp */ #define NLP_PLOGI_SND 0x00000020 /* sent PLOGI request for this entry */ #define NLP_PRLI_SND 0x00000040 /* sent PRLI request for this entry */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 968ed0fd37f7..d5303994bfd6 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1052,17 +1052,18 @@ stop_rr_fcf_flogi: if (lpfc_els_retry(phba, cmdiocb, rspiocb)) goto out; + lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, + "0150 FLOGI failure Status:x%x/x%x " + "xri x%x TMO:x%x\n", + irsp->ulpStatus, irsp->un.ulpWord[4], + cmdiocb->sli4_xritag, irsp->ulpTimeout); + /* If this is not a loop open failure, bail out */ if (!(irsp->ulpStatus == IOSTAT_LOCAL_REJECT && ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK) == IOERR_LOOP_OPEN_FAILURE))) goto flogifail; - lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS, - "0150 FLOGI failure Status:x%x/x%x xri x%x TMO:x%x\n", - irsp->ulpStatus, irsp->un.ulpWord[4], - cmdiocb->sli4_xritag, irsp->ulpTimeout); - /* FLOGI failed, so there is no fabric */ spin_lock_irq(shost->host_lock); vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); @@ -1207,6 +1208,39 @@ out: } /** + * lpfc_cmpl_els_link_down - Completion callback function for ELS command + * aborted during a link down + * @phba: pointer to lpfc hba data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @rspiocb: pointer to lpfc response iocb data structure. + * + */ +static void +lpfc_cmpl_els_link_down(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + IOCB_t *irsp; + uint32_t *pcmd; + uint32_t cmd; + + pcmd = (uint32_t *)(((struct lpfc_dmabuf *)cmdiocb->context2)->virt); + cmd = *pcmd; + irsp = &rspiocb->iocb; + + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "6445 ELS completes after LINK_DOWN: " + " Status %x/%x cmd x%x flg x%x\n", + irsp->ulpStatus, irsp->un.ulpWord[4], cmd, + cmdiocb->iocb_flag); + + if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) { + cmdiocb->iocb_flag &= ~LPFC_IO_FABRIC; + atomic_dec(&phba->fabric_iocb_count); + } + lpfc_els_free_iocb(phba, cmdiocb); +} + +/** * lpfc_issue_els_flogi - Issue an flogi iocb command for a vport * @vport: pointer to a host virtual N_Port data structure. * @ndlp: pointer to a node-list data structure. @@ -2107,7 +2141,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) !(vport->fc_flag & FC_OFFLINE_MODE)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "4110 Issue PLOGI x%x deferred " - "on NPort x%x rpi x%x Data: %p\n", + "on NPort x%x rpi x%x Data: x%px\n", ndlp->nlp_defer_did, ndlp->nlp_DID, ndlp->nlp_rpi, ndlp); @@ -2401,6 +2435,10 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, npr_nvme = (struct lpfc_nvme_prli *)pcmd; bf_set(prli_type_code, npr_nvme, PRLI_NVME_TYPE); bf_set(prli_estabImagePair, npr_nvme, 0); /* Should be 0 */ + if (phba->nsler) { + bf_set(prli_nsler, npr_nvme, 1); + bf_set(prli_conf, npr_nvme, 1); + } /* Only initiators request first burst. */ if ((phba->cfg_nvme_enable_fb) && @@ -4203,7 +4241,7 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) mempool_free(pmb, phba->mbox_mem_pool); if (ndlp) { lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "0006 rpi%x DID:%x flg:%x %d map:%x %p\n", + "0006 rpi%x DID:%x flg:%x %d map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); @@ -4308,6 +4346,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if ((rspiocb->iocb.ulpStatus == 0) && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { if (!lpfc_unreg_rpi(vport, ndlp) && + (!(vport->fc_flag & FC_PT2PT)) && (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE)) { lpfc_printf_vlog(vport, KERN_INFO, @@ -5633,16 +5672,16 @@ lpfc_rdp_res_attach_port_names(struct fc_rdp_port_name_desc *desc, desc->tag = cpu_to_be32(RDP_PORT_NAMES_DESC_TAG); if (vport->fc_flag & FC_FABRIC) { memcpy(desc->port_names.wwnn, &vport->fabric_nodename, - sizeof(desc->port_names.wwnn)); + sizeof(desc->port_names.wwnn)); memcpy(desc->port_names.wwpn, &vport->fabric_portname, - sizeof(desc->port_names.wwpn)); + sizeof(desc->port_names.wwpn)); } else { /* Point to Point */ memcpy(desc->port_names.wwnn, &ndlp->nlp_nodename, - sizeof(desc->port_names.wwnn)); + sizeof(desc->port_names.wwnn)); - memcpy(desc->port_names.wwnn, &ndlp->nlp_portname, - sizeof(desc->port_names.wwpn)); + memcpy(desc->port_names.wwpn, &ndlp->nlp_portname, + sizeof(desc->port_names.wwpn)); } desc->length = cpu_to_be32(sizeof(desc->port_names)); @@ -6326,7 +6365,11 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport) continue; } - if (ndlp->nlp_fc4_type & NLP_FC4_NVME) + /* Check to see if we need to NVME rescan this target + * remoteport. + */ + if (ndlp->nlp_fc4_type & NLP_FC4_NVME && + ndlp->nlp_type & (NLP_NVME_TARGET | NLP_NVME_DISCOVERY)) lpfc_nvme_rescan_port(vport, ndlp); lpfc_disc_state_machine(vport, ndlp, NULL, @@ -6440,7 +6483,11 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, *lp, vport->fc_flag, payload_len); lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - if (ndlp->nlp_fc4_type & NLP_FC4_NVME) + /* Check to see if we need to NVME rescan this target + * remoteport. + */ + if (ndlp->nlp_fc4_type & NLP_FC4_NVME && + ndlp->nlp_type & (NLP_NVME_TARGET | NLP_NVME_DISCOVERY)) lpfc_nvme_rescan_port(vport, ndlp); return 0; } @@ -7959,18 +8006,40 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) if (phba->sli_rev == LPFC_SLI_REV4) spin_lock(&pring->ring_lock); + /* First we need to issue aborts to outstanding cmds on txcmpl */ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { if (piocb->iocb_flag & LPFC_IO_LIBDFC) continue; if (piocb->vport != vport) continue; - list_add_tail(&piocb->dlist, &abort_list); + + /* On the ELS ring we can have ELS_REQUESTs or + * GEN_REQUESTs waiting for a response. + */ + cmd = &piocb->iocb; + if (cmd->ulpCommand == CMD_ELS_REQUEST64_CR) { + list_add_tail(&piocb->dlist, &abort_list); + + /* If the link is down when flushing ELS commands + * the firmware will not complete them till after + * the link comes back up. This may confuse + * discovery for the new link up, so we need to + * change the compl routine to just clean up the iocb + * and avoid any retry logic. + */ + if (phba->link_state == LPFC_LINK_DOWN) + piocb->iocb_cmpl = lpfc_cmpl_els_link_down; + } + if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) + list_add_tail(&piocb->dlist, &abort_list); } + if (phba->sli_rev == LPFC_SLI_REV4) spin_unlock(&pring->ring_lock); spin_unlock_irq(&phba->hbalock); - /* Abort each iocb on the aborted list and remove the dlist links. */ + + /* Abort each txcmpl iocb on aborted list and remove the dlist links. */ list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) { spin_lock_irq(&phba->hbalock); list_del_init(&piocb->dlist); @@ -7986,6 +8055,9 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) if (phba->sli_rev == LPFC_SLI_REV4) spin_lock(&pring->ring_lock); + /* No need to abort the txq list, + * just queue them up for lpfc_sli_cancel_iocbs + */ list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) { cmd = &piocb->iocb; @@ -8006,11 +8078,22 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) list_del_init(&piocb->list); list_add_tail(&piocb->list, &abort_list); } + + /* The same holds true for any FLOGI/FDISC on the fabric_iocb_list */ + if (vport == phba->pport) { + list_for_each_entry_safe(piocb, tmp_iocb, + &phba->fabric_iocb_list, list) { + cmd = &piocb->iocb; + list_del_init(&piocb->list); + list_add_tail(&piocb->list, &abort_list); + } + } + if (phba->sli_rev == LPFC_SLI_REV4) spin_unlock(&pring->ring_lock); spin_unlock_irq(&phba->hbalock); - /* Cancell all the IOCBs from the completions list */ + /* Cancel all the IOCBs from the completions list */ lpfc_sli_cancel_iocbs(phba, &abort_list, IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 28ecaa7fc715..749286acdc17 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -118,6 +118,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) struct lpfc_work_evt *evtp; int put_node; int put_rport; + unsigned long iflags; rdata = rport->dd_data; ndlp = rdata->pnode; @@ -132,7 +133,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "3181 dev_loss_callbk x%06x, rport %p flg x%x\n", + "3181 dev_loss_callbk x%06x, rport x%px flg x%x\n", ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag); /* Don't defer this if we are in the process of deleting the vport @@ -170,22 +171,22 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) } shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(shost->host_lock, iflags); ndlp->nlp_flag |= NLP_IN_DEV_LOSS; - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(shost->host_lock, iflags); /* We need to hold the node by incrementing the reference * count until this queued work is done */ evtp->evt_arg1 = lpfc_nlp_get(ndlp); - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); if (evtp->evt_arg1) { evtp->evt = LPFC_EVT_DEV_LOSS; list_add_tail(&evtp->evt_listp, &phba->work_list); lpfc_worker_wake_up(phba); } - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); return; } @@ -212,14 +213,15 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) int put_node; int warn_on = 0; int fcf_inuse = 0; + unsigned long iflags; rport = ndlp->rport; vport = ndlp->vport; shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(shost->host_lock, iflags); ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS; - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(shost->host_lock, iflags); if (!rport) return fcf_inuse; @@ -235,7 +237,7 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "3182 dev_loss_tmo_handler x%06x, rport %p flg x%x\n", + "3182 dev_loss_tmo_handler x%06x, rport x%px flg x%x\n", ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag); /* @@ -903,6 +905,8 @@ lpfc_linkdown(struct lpfc_hba *phba) phba->trunk_link.link1.state = 0; phba->trunk_link.link2.state = 0; phba->trunk_link.link3.state = 0; + phba->sli4_hba.link_state.logical_speed = + LPFC_LINK_SPEED_UNKNOWN; } spin_lock_irq(shost->host_lock); phba->pport->fc_flag &= ~FC_LBIT; @@ -3115,8 +3119,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) int rc; struct fcf_record *fcf_record; uint32_t fc_flags = 0; + unsigned long iflags; - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la); if (!(phba->hba_flag & HBA_FCOE_MODE)) { @@ -3213,12 +3218,12 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) vport->fc_myDID = phba->fc_pref_DID; fc_flags |= FC_LBIT; } - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); if (fc_flags) { - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(shost->host_lock, iflags); vport->fc_flag |= fc_flags; - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(shost->host_lock, iflags); } lpfc_linkup(phba); @@ -3292,22 +3297,22 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) * The driver is expected to do FIP/FCF. Call the port * and get the FCF Table. */ - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); if (phba->hba_flag & FCF_TS_INPROG) { - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); return; } /* This is the initial FCF discovery scan */ phba->fcf.fcf_flag |= FCF_INIT_DISC; - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, "2778 Start FCF table scan at linkup\n"); rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST); if (rc) { - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); phba->fcf.fcf_flag &= ~FCF_INIT_DISC; - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); goto out; } /* Reset FCF roundrobin bmask for new discovery */ @@ -3318,7 +3323,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) out: lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "0263 Discovery Mailbox error: state: 0x%x : %p %p\n", + "0263 Discovery Mailbox error: state: 0x%x : x%px x%px\n", vport->port_state, sparam_mbox, cfglink_mbox); lpfc_issue_clear_la(phba, vport); return; @@ -3366,6 +3371,7 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) MAILBOX_t *mb = &pmb->u.mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf); uint8_t attn_type; + unsigned long iflags; /* Unblock ELS traffic */ pring = lpfc_phba_elsring(phba); @@ -3387,12 +3393,12 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) memcpy(&phba->alpa_map[0], mp->virt, 128); - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(shost->host_lock, iflags); if (bf_get(lpfc_mbx_read_top_pb, la)) vport->fc_flag |= FC_BYPASSED_MODE; else vport->fc_flag &= ~FC_BYPASSED_MODE; - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(shost->host_lock, iflags); if (phba->fc_eventTag <= la->eventTag) { phba->fc_stat.LinkMultiEvent++; @@ -3403,12 +3409,12 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) phba->fc_eventTag = la->eventTag; if (phba->sli_rev < LPFC_SLI_REV4) { - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); if (bf_get(lpfc_mbx_read_top_mm, la)) phba->sli.sli_flag |= LPFC_MENLO_MAINT; else phba->sli.sli_flag &= ~LPFC_MENLO_MAINT; - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); } phba->link_events++; @@ -3529,7 +3535,7 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) pmb->ctx_ndlp = NULL; lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, - "0002 rpi:%x DID:%x flg:%x %d map:%x %p\n", + "0002 rpi:%x DID:%x flg:%x %d map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); @@ -4041,7 +4047,7 @@ out: ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, - "0003 rpi:%x DID:%x flg:%x %d map%x %p\n", + "0003 rpi:%x DID:%x flg:%x %d map%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); @@ -4160,7 +4166,7 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) fc_remote_port_rolechg(rport, rport_ids.roles); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "3183 rport register x%06x, rport %p role x%x\n", + "3183 rport register x%06x, rport x%px role x%x\n", ndlp->nlp_DID, rport, rport_ids.roles); if ((rport->scsi_target_id != -1) && @@ -4184,7 +4190,7 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "3184 rport unregister x%06x, rport %p\n", + "3184 rport unregister x%06x, rport x%px\n", ndlp->nlp_DID, rport); fc_remote_port_delete(rport); @@ -4196,8 +4202,9 @@ static void lpfc_nlp_counters(struct lpfc_vport *vport, int state, int count) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + unsigned long iflags; - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(shost->host_lock, iflags); switch (state) { case NLP_STE_UNUSED_NODE: vport->fc_unused_cnt += count; @@ -4227,7 +4234,7 @@ lpfc_nlp_counters(struct lpfc_vport *vport, int state, int count) vport->fc_npr_cnt += count; break; } - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(shost->host_lock, iflags); } static void @@ -4480,9 +4487,21 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return NULL; if (phba->sli_rev == LPFC_SLI_REV4) { - rpi = lpfc_sli4_alloc_rpi(vport->phba); - if (rpi == LPFC_RPI_ALLOC_ERROR) + if (ndlp->nlp_rpi == LPFC_RPI_ALLOC_ERROR) + rpi = lpfc_sli4_alloc_rpi(vport->phba); + else + rpi = ndlp->nlp_rpi; + + if (rpi == LPFC_RPI_ALLOC_ERROR) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, + "0359 %s: ndlp:x%px " + "usgmap:x%x refcnt:%d FAILED RPI " + " ALLOC\n", + __func__, + (void *)ndlp, ndlp->nlp_usg_map, + kref_read(&ndlp->kref)); return NULL; + } } spin_lock_irqsave(&phba->ndlp_lock, flags); @@ -4490,9 +4509,9 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (NLP_CHK_FREE_REQ(ndlp)) { spin_unlock_irqrestore(&phba->ndlp_lock, flags); lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0277 lpfc_enable_node: ndlp:x%p " + "0277 %s: ndlp:x%px " "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, + __func__, (void *)ndlp, ndlp->nlp_usg_map, kref_read(&ndlp->kref)); goto free_rpi; } @@ -4500,9 +4519,9 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (NLP_CHK_NODE_ACT(ndlp)) { spin_unlock_irqrestore(&phba->ndlp_lock, flags); lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0278 lpfc_enable_node: ndlp:x%p " + "0278 %s: ndlp:x%px " "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, + __func__, (void *)ndlp, ndlp->nlp_usg_map, kref_read(&ndlp->kref)); goto free_rpi; } @@ -4532,7 +4551,7 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_rpi = rpi; lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, "0008 rpi:%x DID:%x flg:%x refcnt:%d " - "map:%x %p\n", ndlp->nlp_rpi, ndlp->nlp_DID, + "map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); @@ -4541,6 +4560,14 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (state != NLP_STE_UNUSED_NODE) lpfc_nlp_set_state(vport, ndlp, state); + else + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, + "0013 rpi:%x DID:%x flg:%x refcnt:%d " + "map:%x x%px STATE=UNUSED\n", + ndlp->nlp_rpi, ndlp->nlp_DID, + ndlp->nlp_flag, + kref_read(&ndlp->kref), + ndlp->nlp_usg_map, ndlp); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, "node enable: did:x%x", @@ -4797,7 +4824,7 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "1434 UNREG cmpl deferred logo x%x " - "on NPort x%x Data: x%x %p\n", + "on NPort x%x Data: x%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_defer_did, ndlp); @@ -4805,6 +4832,10 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING; lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); } else { + if (ndlp->nlp_flag & NLP_RELEASE_RPI) { + lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); + ndlp->nlp_flag &= ~NLP_RELEASE_RPI; + } ndlp->nlp_flag &= ~NLP_UNREG_INP; } } @@ -4843,7 +4874,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "1436 unreg_rpi SKIP UNREG x%x on " "NPort x%x deferred x%x flg x%x " - "Data: %p\n", + "Data: x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_defer_did, ndlp->nlp_flag, ndlp); @@ -4893,7 +4924,8 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "1433 unreg_rpi UNREG x%x on " - "NPort x%x deferred flg x%x Data:%p\n", + "NPort x%x deferred flg x%x " + "Data:x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, ndlp); @@ -5034,16 +5066,16 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ndlp->nlp_state, ndlp->nlp_rpi); if (NLP_CHK_FREE_REQ(ndlp)) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0280 lpfc_cleanup_node: ndlp:x%p " + "0280 %s: ndlp:x%px " "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, + __func__, (void *)ndlp, ndlp->nlp_usg_map, kref_read(&ndlp->kref)); lpfc_dequeue_node(vport, ndlp); } else { lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0281 lpfc_cleanup_node: ndlp:x%p " + "0281 %s: ndlp:x%px " "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, + __func__, (void *)ndlp, ndlp->nlp_usg_map, kref_read(&ndlp->kref)); lpfc_disable_node(vport, ndlp); } @@ -5104,6 +5136,8 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) list_del_init(&ndlp->els_retry_evt.evt_listp); list_del_init(&ndlp->dev_loss_evt.evt_listp); lpfc_cleanup_vports_rrqs(vport, ndlp); + if (phba->sli_rev == LPFC_SLI_REV4) + ndlp->nlp_flag |= NLP_RELEASE_RPI; lpfc_unreg_rpi(vport, ndlp); return 0; @@ -5132,7 +5166,7 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * allocated by the firmware. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0005 rpi:%x DID:%x flg:%x %d map:%x %p\n", + "0005 rpi:%x DID:%x flg:%x %d map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); @@ -5168,8 +5202,8 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * for registered rport so need to cleanup rport */ lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0940 removed node x%p DID x%x " - " rport not null %p\n", + "0940 removed node x%px DID x%x " + " rport not null x%px\n", ndlp, ndlp->nlp_DID, ndlp->rport); rport = ndlp->rport; rdata = rport->dd_data; @@ -5243,15 +5277,15 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { if (lpfc_matchdid(vport, ndlp, did)) { - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); + data1 = (((uint32_t)ndlp->nlp_state << 24) | + ((uint32_t)ndlp->nlp_xri << 16) | + ((uint32_t)ndlp->nlp_type << 8) | + ((uint32_t)ndlp->nlp_usg_map & 0xff)); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, "0929 FIND node DID " - "Data: x%p x%x x%x x%x %p\n", + "Data: x%px x%x x%x x%x x%x x%px\n", ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1, + ndlp->nlp_flag, data1, ndlp->nlp_rpi, ndlp->active_rrqs_xri_bitmap); return ndlp; } @@ -5296,7 +5330,7 @@ lpfc_findnode_mapped(struct lpfc_vport *vport) spin_unlock_irqrestore(shost->host_lock, iflags); lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, "2025 FIND node DID " - "Data: x%p x%x x%x x%x %p\n", + "Data: x%px x%x x%x x%x x%px\n", ndlp, ndlp->nlp_DID, ndlp->nlp_flag, data1, ndlp->active_rrqs_xri_bitmap); @@ -5336,8 +5370,11 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) if (vport->phba->nvmet_support) return NULL; ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE); - if (!ndlp) + if (!ndlp) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_SLI, + "0014 Could not enable ndlp\n"); return NULL; + } spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); @@ -5960,7 +5997,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, - "0004 rpi:%x DID:%x flg:%x %d map:%x %p\n", + "0004 rpi:%x DID:%x flg:%x %d map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); @@ -6014,8 +6051,8 @@ __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { if (filter(ndlp, param)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "3185 FIND node filter %p DID " - "ndlp %p did x%x flg x%x st x%x " + "3185 FIND node filter %ps DID " + "ndlp x%px did x%x flg x%x st x%x " "xri x%x type x%x rpi x%x\n", filter, ndlp, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, @@ -6025,7 +6062,7 @@ __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) } } lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "3186 FIND node filter %p NOT FOUND.\n", filter); + "3186 FIND node filter %ps NOT FOUND.\n", filter); return NULL; } @@ -6065,10 +6102,11 @@ lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp; + unsigned long flags; - spin_lock_irq(shost->host_lock); + spin_lock_irqsave(shost->host_lock, flags); ndlp = __lpfc_findnode_rpi(vport, rpi); - spin_unlock_irq(shost->host_lock); + spin_unlock_irqrestore(shost->host_lock, flags); return ndlp; } @@ -6149,7 +6187,7 @@ lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did) ndlp->nlp_rpi = rpi; lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, "0007 rpi:%x DID:%x flg:%x refcnt:%d " - "map:%x %p\n", ndlp->nlp_rpi, ndlp->nlp_DID, + "map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); @@ -6187,8 +6225,9 @@ lpfc_nlp_release(struct kref *kref) ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "0279 lpfc_nlp_release: ndlp:x%p did %x " + "0279 %s: ndlp:x%px did %x " "usgmap:x%x refcnt:%d rpi:%x\n", + __func__, (void *)ndlp, ndlp->nlp_DID, ndlp->nlp_usg_map, kref_read(&ndlp->kref), ndlp->nlp_rpi); @@ -6200,8 +6239,6 @@ lpfc_nlp_release(struct kref *kref) spin_lock_irqsave(&phba->ndlp_lock, flags); NLP_CLR_NODE_ACT(ndlp); spin_unlock_irqrestore(&phba->ndlp_lock, flags); - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); /* free ndlp memory for final ndlp release */ if (NLP_CHK_FREE_REQ(ndlp)) { @@ -6237,9 +6274,9 @@ lpfc_nlp_get(struct lpfc_nodelist *ndlp) if (!NLP_CHK_NODE_ACT(ndlp) || NLP_CHK_FREE_ACK(ndlp)) { spin_unlock_irqrestore(&phba->ndlp_lock, flags); lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0276 lpfc_nlp_get: ndlp:x%p " + "0276 %s: ndlp:x%px " "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, + __func__, (void *)ndlp, ndlp->nlp_usg_map, kref_read(&ndlp->kref)); return NULL; } else @@ -6265,9 +6302,9 @@ lpfc_nlp_put(struct lpfc_nodelist *ndlp) return 1; lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, - "node put: did:x%x flg:x%x refcnt:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, - kref_read(&ndlp->kref)); + "node put: did:x%x flg:x%x refcnt:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, + kref_read(&ndlp->kref)); phba = ndlp->phba; spin_lock_irqsave(&phba->ndlp_lock, flags); /* Check the ndlp memory free acknowledge flag to avoid the @@ -6277,9 +6314,9 @@ lpfc_nlp_put(struct lpfc_nodelist *ndlp) if (NLP_CHK_FREE_ACK(ndlp)) { spin_unlock_irqrestore(&phba->ndlp_lock, flags); lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0274 lpfc_nlp_put: ndlp:x%p " + "0274 %s: ndlp:x%px " "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, + __func__, (void *)ndlp, ndlp->nlp_usg_map, kref_read(&ndlp->kref)); return 1; } @@ -6290,9 +6327,9 @@ lpfc_nlp_put(struct lpfc_nodelist *ndlp) if (NLP_CHK_IACT_REQ(ndlp)) { spin_unlock_irqrestore(&phba->ndlp_lock, flags); lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0275 lpfc_nlp_put: ndlp:x%p " + "0275 %s: ndlp:x%px " "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, + __func__, (void *)ndlp, ndlp->nlp_usg_map, kref_read(&ndlp->kref)); return 1; } diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 5b439a6dcde1..436cdc8c5ef4 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -843,7 +843,7 @@ typedef struct _ADISC { /* Structure is in Big Endian format */ struct lpfc_name portName; struct lpfc_name nodeName; uint32_t DID; -} ADISC; +} __packed ADISC; typedef struct _FARP { /* Structure is in Big Endian format */ uint32_t Mflags:8; @@ -873,7 +873,7 @@ typedef struct _FAN { /* Structure is in Big Endian format */ uint32_t Fdid; struct lpfc_name FportName; struct lpfc_name FnodeName; -} FAN; +} __packed FAN; typedef struct _SCR { /* Structure is in Big Endian format */ uint8_t resvd1; @@ -917,7 +917,7 @@ typedef struct _RNID { /* Structure is in Big Endian format */ union { RNID_TOP_DISC topologyDisc; /* topology disc (0xdf) */ } un; -} RNID; +} __packed RNID; typedef struct _RPS { /* Structure is in Big Endian format */ union { diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 77f9a55a3f54..bd533475c86a 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -2050,6 +2050,23 @@ struct sli4_sge { /* SLI-4 */ uint32_t sge_len; }; +struct sli4_hybrid_sgl { + struct list_head list_node; + struct sli4_sge *dma_sgl; + dma_addr_t dma_phys_sgl; +}; + +struct fcp_cmd_rsp_buf { + struct list_head list_node; + + /* for storing cmd/rsp dma alloc'ed virt_addr */ + struct fcp_cmnd *fcp_cmnd; + struct fcp_rsp *fcp_rsp; + + /* for storing this cmd/rsp's dma mapped phys addr from per CPU pool */ + dma_addr_t fcp_cmd_rsp_dma_handle; +}; + struct sli4_sge_diseed { /* SLI-4 */ uint32_t ref_tag; uint32_t ref_tag_tran; @@ -3449,6 +3466,9 @@ struct lpfc_sli4_parameters { #define cfg_xib_SHIFT 4 #define cfg_xib_MASK 0x00000001 #define cfg_xib_WORD word19 +#define cfg_xpsgl_SHIFT 6 +#define cfg_xpsgl_MASK 0x00000001 +#define cfg_xpsgl_WORD word19 #define cfg_eqdr_SHIFT 8 #define cfg_eqdr_MASK 0x00000001 #define cfg_eqdr_WORD word19 @@ -3460,6 +3480,10 @@ struct lpfc_sli4_parameters { #define cfg_bv1s_MASK 0x00000001 #define cfg_bv1s_WORD word19 +#define cfg_nsler_SHIFT 12 +#define cfg_nsler_MASK 0x00000001 +#define cfg_nsler_WORD word19 + uint32_t word20; #define cfg_max_tow_xri_SHIFT 0 #define cfg_max_tow_xri_MASK 0x0000ffff @@ -4314,6 +4338,12 @@ struct wqe_common { #define wqe_rcvoxid_SHIFT 16 #define wqe_rcvoxid_MASK 0x0000FFFF #define wqe_rcvoxid_WORD word9 +#define wqe_sof_SHIFT 24 +#define wqe_sof_MASK 0x000000FF +#define wqe_sof_WORD word9 +#define wqe_eof_SHIFT 16 +#define wqe_eof_MASK 0x000000FF +#define wqe_eof_WORD word9 uint32_t word10; #define wqe_ebde_cnt_SHIFT 0 #define wqe_ebde_cnt_MASK 0x0000000f @@ -4595,6 +4625,7 @@ struct lpfc_nvme_prli { #define prli_type_code_WORD word1 uint32_t word_rsvd2; uint32_t word_rsvd3; + uint32_t word4; #define prli_fba_SHIFT 0 #define prli_fba_MASK 0x00000001 @@ -4611,6 +4642,9 @@ struct lpfc_nvme_prli { #define prli_conf_SHIFT 7 #define prli_conf_MASK 0x00000001 #define prli_conf_WORD word4 +#define prli_nsler_SHIFT 8 +#define prli_nsler_MASK 0x00000001 +#define prli_nsler_WORD word4 uint32_t word5; #define prli_fb_sz_SHIFT 0 #define prli_fb_sz_MASK 0x0000ffff diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index eaaef682de25..e8813d26e594 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -39,6 +39,7 @@ #include <linux/msi.h> #include <linux/irq.h> #include <linux/bitops.h> +#include <linux/crash_dump.h> #include <scsi/scsi.h> #include <scsi/scsi_device.h> @@ -65,14 +66,8 @@ #include "lpfc_version.h" #include "lpfc_ids.h" -char *_dump_buf_data; -unsigned long _dump_buf_data_order; -char *_dump_buf_dif; -unsigned long _dump_buf_dif_order; -spinlock_t _dump_buf_lock; - /* Used when mapping IRQ vectors in a driver centric manner */ -uint32_t lpfc_present_cpu; +static uint32_t lpfc_present_cpu; static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *); static int lpfc_post_rcv_buf(struct lpfc_hba *); @@ -93,8 +88,8 @@ static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *); static void lpfc_sli4_disable_intr(struct lpfc_hba *); static uint32_t lpfc_sli4_enable_intr(struct lpfc_hba *, uint32_t); static void lpfc_sli4_oas_verify(struct lpfc_hba *phba); -static uint16_t lpfc_find_eq_handle(struct lpfc_hba *, uint16_t); static uint16_t lpfc_find_cpu_handle(struct lpfc_hba *, uint16_t, int); +static void lpfc_setup_bg(struct lpfc_hba *, struct Scsi_Host *); static struct scsi_transport_template *lpfc_transport_template = NULL; static struct scsi_transport_template *lpfc_vport_transport_template = NULL; @@ -1081,8 +1076,8 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba) for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { qp = &phba->sli4_hba.hdwq[idx]; - spin_lock(&qp->abts_scsi_buf_list_lock); - list_splice_init(&qp->lpfc_abts_scsi_buf_list, + spin_lock(&qp->abts_io_buf_list_lock); + list_splice_init(&qp->lpfc_abts_io_buf_list, &aborts); list_for_each_entry_safe(psb, psb_next, &aborts, list) { @@ -1093,29 +1088,11 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba) spin_lock(&qp->io_buf_list_put_lock); list_splice_init(&aborts, &qp->lpfc_io_buf_list_put); qp->put_io_bufs += qp->abts_scsi_io_bufs; + qp->put_io_bufs += qp->abts_nvme_io_bufs; qp->abts_scsi_io_bufs = 0; + qp->abts_nvme_io_bufs = 0; spin_unlock(&qp->io_buf_list_put_lock); - spin_unlock(&qp->abts_scsi_buf_list_lock); - - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - spin_lock(&qp->abts_nvme_buf_list_lock); - list_splice_init(&qp->lpfc_abts_nvme_buf_list, - &nvme_aborts); - list_for_each_entry_safe(psb, psb_next, &nvme_aborts, - list) { - psb->pCmd = NULL; - psb->status = IOSTAT_SUCCESS; - cnt++; - } - spin_lock(&qp->io_buf_list_put_lock); - qp->put_io_bufs += qp->abts_nvme_io_bufs; - qp->abts_nvme_io_bufs = 0; - list_splice_init(&nvme_aborts, - &qp->lpfc_io_buf_list_put); - spin_unlock(&qp->io_buf_list_put_lock); - spin_unlock(&qp->abts_nvme_buf_list_lock); - - } + spin_unlock(&qp->abts_io_buf_list_lock); } spin_unlock_irq(&phba->hbalock); @@ -1261,6 +1238,7 @@ lpfc_hb_eq_delay_work(struct work_struct *work) unsigned char *eqcnt = NULL; uint32_t usdelay; int i; + bool update = false; if (!phba->cfg_auto_imax || phba->pport->load_flag & FC_UNLOADING) return; @@ -1274,18 +1252,29 @@ lpfc_hb_eq_delay_work(struct work_struct *work) if (!eqcnt) goto requeue; - for (i = 0; i < phba->cfg_irq_chann; i++) { - eq = phba->sli4_hba.hdwq[i].hba_eq; - if (eq && eqcnt[eq->last_cpu] < 2) - eqcnt[eq->last_cpu]++; - continue; - } + if (phba->cfg_irq_chann > 1) { + /* Loop thru all IRQ vectors */ + for (i = 0; i < phba->cfg_irq_chann; i++) { + /* Get the EQ corresponding to the IRQ vector */ + eq = phba->sli4_hba.hba_eq_hdl[i].eq; + if (!eq) + continue; + if (eq->q_mode) { + update = true; + break; + } + if (eqcnt[eq->last_cpu] < 2) + eqcnt[eq->last_cpu]++; + } + } else + update = true; for_each_present_cpu(i) { - if (phba->cfg_irq_chann > 1 && eqcnt[i] < 2) - continue; - eqi = per_cpu_ptr(phba->sli4_hba.eq_info, i); + if (!update && eqcnt[i] < 2) { + eqi->icnt = 0; + continue; + } usdelay = (eqi->icnt / LPFC_IMAX_THRESHOLD) * LPFC_EQ_DELAY_STEP; @@ -1533,6 +1522,7 @@ lpfc_sli4_offline_eratt(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT); + lpfc_sli_flush_io_rings(phba); lpfc_offline(phba); lpfc_hba_down_post(phba); lpfc_unblock_mgmt_io(phba); @@ -1794,6 +1784,7 @@ lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, "2887 Reset Needed: Attempting Port " "Recovery...\n"); lpfc_offline_prep(phba, mbx_action); + lpfc_sli_flush_io_rings(phba); lpfc_offline(phba); /* release interrupt for possible resource change */ lpfc_sli4_disable_intr(phba); @@ -1913,7 +1904,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "7624 Firmware not ready: Failing UE recovery," " waited %dSec", i); - lpfc_sli4_offline_eratt(phba); + phba->link_state = LPFC_HBA_ERROR; break; case LPFC_SLI_INTF_IF_TYPE_2: @@ -1987,9 +1978,8 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba) } /* fall through for not able to recover */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3152 Unrecoverable error, bring the port " - "offline\n"); - lpfc_sli4_offline_eratt(phba); + "3152 Unrecoverable error\n"); + phba->link_state = LPFC_HBA_ERROR; break; case LPFC_SLI_INTF_IF_TYPE_1: default: @@ -2861,7 +2851,7 @@ lpfc_cleanup(struct lpfc_vport *vport) &vport->fc_nodes, nlp_listp) { lpfc_printf_vlog(ndlp->vport, KERN_ERR, LOG_NODE, - "0282 did:x%x ndlp:x%p " + "0282 did:x%x ndlp:x%px " "usgmap:x%x refcnt:%d\n", ndlp->nlp_DID, (void *)ndlp, ndlp->nlp_usg_map, @@ -2963,7 +2953,7 @@ lpfc_stop_hba_timers(struct lpfc_hba *phba) del_timer_sync(&phba->fcp_poll_timer); break; case LPFC_PCI_DEV_OC: - /* Stop any OneConnect device sepcific driver timers */ + /* Stop any OneConnect device specific driver timers */ lpfc_sli4_stop_fcf_redisc_wait_timer(phba); break; default: @@ -3065,7 +3055,7 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba) ndlp->nlp_rpi = rpi; lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, "0009 rpi:%x DID:%x " - "flg:%x map:%x %p\n", ndlp->nlp_rpi, + "flg:%x map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_usg_map, ndlp); } @@ -3250,12 +3240,8 @@ static void lpfc_destroy_multixri_pools(struct lpfc_hba *phba) if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) lpfc_destroy_expedite_pool(phba); - if (!(phba->pport->load_flag & FC_UNLOADING)) { - lpfc_sli_flush_fcp_rings(phba); - - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) - lpfc_sli_flush_nvme_rings(phba); - } + if (!(phba->pport->load_flag & FC_UNLOADING)) + lpfc_sli_flush_io_rings(phba); hwq_count = phba->cfg_hdw_queue; @@ -3489,7 +3475,7 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, "0011 lpfc_offline: " - "ndlp:x%p did %x " + "ndlp:x%px did %x " "usgmap:x%x rpi:%x\n", ndlp, ndlp->nlp_DID, ndlp->nlp_usg_map, @@ -3634,6 +3620,9 @@ lpfc_io_free(struct lpfc_hba *phba) qp->put_io_bufs--; dma_pool_free(phba->lpfc_sg_dma_buf_pool, lpfc_ncmd->data, lpfc_ncmd->dma_handle); + if (phba->cfg_xpsgl && !phba->nvmet_support) + lpfc_put_sgl_per_hdwq(phba, lpfc_ncmd); + lpfc_put_cmd_rsp_buf_per_hdwq(phba, lpfc_ncmd); kfree(lpfc_ncmd); qp->total_io_bufs--; } @@ -3647,6 +3636,9 @@ lpfc_io_free(struct lpfc_hba *phba) qp->get_io_bufs--; dma_pool_free(phba->lpfc_sg_dma_buf_pool, lpfc_ncmd->data, lpfc_ncmd->dma_handle); + if (phba->cfg_xpsgl && !phba->nvmet_support) + lpfc_put_sgl_per_hdwq(phba, lpfc_ncmd); + lpfc_put_cmd_rsp_buf_per_hdwq(phba, lpfc_ncmd); kfree(lpfc_ncmd); qp->total_io_bufs--; } @@ -4095,18 +4087,9 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc) LIST_HEAD(post_nblist); LIST_HEAD(nvme_nblist); - /* Sanity check to ensure our sizing is right for both SCSI and NVME */ - if (sizeof(struct lpfc_io_buf) > LPFC_COMMON_IO_BUF_SZ) { - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "6426 Common buffer size %zd exceeds %d\n", - sizeof(struct lpfc_io_buf), - LPFC_COMMON_IO_BUF_SZ); - return 0; - } - phba->sli4_hba.io_xri_cnt = 0; for (bcnt = 0; bcnt < num_to_alloc; bcnt++) { - lpfc_ncmd = kzalloc(LPFC_COMMON_IO_BUF_SZ, GFP_KERNEL); + lpfc_ncmd = kzalloc(sizeof(*lpfc_ncmd), GFP_KERNEL); if (!lpfc_ncmd) break; /* @@ -4114,31 +4097,38 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc) * pci bus space for an I/O. The DMA buffer includes the * number of SGE's necessary to support the sg_tablesize. */ - lpfc_ncmd->data = dma_pool_alloc(phba->lpfc_sg_dma_buf_pool, - GFP_KERNEL, - &lpfc_ncmd->dma_handle); + lpfc_ncmd->data = dma_pool_zalloc(phba->lpfc_sg_dma_buf_pool, + GFP_KERNEL, + &lpfc_ncmd->dma_handle); if (!lpfc_ncmd->data) { kfree(lpfc_ncmd); break; } - memset(lpfc_ncmd->data, 0, phba->cfg_sg_dma_buf_size); - /* - * 4K Page alignment is CRITICAL to BlockGuard, double check - * to be sure. - */ - if ((phba->sli3_options & LPFC_SLI3_BG_ENABLED) && - (((unsigned long)(lpfc_ncmd->data) & - (unsigned long)(SLI4_PAGE_SIZE - 1)) != 0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "3369 Memory alignment err: addr=%lx\n", - (unsigned long)lpfc_ncmd->data); - dma_pool_free(phba->lpfc_sg_dma_buf_pool, - lpfc_ncmd->data, lpfc_ncmd->dma_handle); - kfree(lpfc_ncmd); - break; + if (phba->cfg_xpsgl && !phba->nvmet_support) { + INIT_LIST_HEAD(&lpfc_ncmd->dma_sgl_xtra_list); + } else { + /* + * 4K Page alignment is CRITICAL to BlockGuard, double + * check to be sure. + */ + if ((phba->sli3_options & LPFC_SLI3_BG_ENABLED) && + (((unsigned long)(lpfc_ncmd->data) & + (unsigned long)(SLI4_PAGE_SIZE - 1)) != 0)) { + lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + "3369 Memory alignment err: " + "addr=%lx\n", + (unsigned long)lpfc_ncmd->data); + dma_pool_free(phba->lpfc_sg_dma_buf_pool, + lpfc_ncmd->data, + lpfc_ncmd->dma_handle); + kfree(lpfc_ncmd); + break; + } } + INIT_LIST_HEAD(&lpfc_ncmd->dma_cmd_rsp_list); + lxri = lpfc_sli4_next_xritag(phba); if (lxri == NO_XRI) { dma_pool_free(phba->lpfc_sg_dma_buf_pool, @@ -4308,14 +4298,20 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) shost->max_cmd_len = 16; if (phba->sli_rev == LPFC_SLI_REV4) { - if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ) - shost->nr_hw_queues = phba->cfg_hdw_queue; - else - shost->nr_hw_queues = phba->sli4_hba.num_present_cpu; + if (!phba->cfg_fcp_mq_threshold || + phba->cfg_fcp_mq_threshold > phba->cfg_hdw_queue) + phba->cfg_fcp_mq_threshold = phba->cfg_hdw_queue; + + shost->nr_hw_queues = min_t(int, 2 * num_possible_nodes(), + phba->cfg_fcp_mq_threshold); shost->dma_boundary = phba->sli4_hba.pc_sli4_params.sge_supp_len-1; - shost->sg_tablesize = phba->cfg_scsi_seg_cnt; + + if (phba->cfg_xpsgl && !phba->nvmet_support) + shost->sg_tablesize = LPFC_MAX_SG_TABLESIZE; + else + shost->sg_tablesize = phba->cfg_scsi_seg_cnt; } else /* SLI-3 has a limited number of hardware queues (3), * thus there is only one for FCP processing. @@ -4347,6 +4343,9 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) timer_setup(&vport->delayed_disc_tmo, lpfc_delayed_disc_tmo, 0); + if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) + lpfc_setup_bg(phba, shost); + error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev); if (error) goto out_put_shost; @@ -5055,7 +5054,7 @@ lpfc_update_trunk_link_status(struct lpfc_hba *phba, bf_get(lpfc_acqe_fc_la_speed, acqe_fc)); phba->sli4_hba.link_state.logical_speed = - bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc); + bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc) * 10; /* We got FC link speed, convert to fc_linkspeed (READ_TOPOLOGY) */ phba->fc_linkspeed = lpfc_async_link_speed_to_read_top( @@ -5158,8 +5157,14 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) bf_get(lpfc_acqe_fc_la_port_number, acqe_fc); phba->sli4_hba.link_state.fault = bf_get(lpfc_acqe_link_fault, acqe_fc); - phba->sli4_hba.link_state.logical_speed = + + if (bf_get(lpfc_acqe_fc_la_att_type, acqe_fc) == + LPFC_FC_LA_TYPE_LINK_DOWN) + phba->sli4_hba.link_state.logical_speed = 0; + else if (!phba->sli4_hba.conf_trunk) + phba->sli4_hba.link_state.logical_speed = bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc) * 10; + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "2896 Async FC event - Speed:%dGBaud Topology:x%x " "LA Type:x%x Port Type:%d Port Number:%d Logical speed:" @@ -6324,6 +6329,24 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) if (lpfc_mem_alloc(phba, BPL_ALIGN_SZ)) return -ENOMEM; + phba->lpfc_sg_dma_buf_pool = + dma_pool_create("lpfc_sg_dma_buf_pool", + &phba->pcidev->dev, phba->cfg_sg_dma_buf_size, + BPL_ALIGN_SZ, 0); + + if (!phba->lpfc_sg_dma_buf_pool) + goto fail_free_mem; + + phba->lpfc_cmd_rsp_buf_pool = + dma_pool_create("lpfc_cmd_rsp_buf_pool", + &phba->pcidev->dev, + sizeof(struct fcp_cmnd) + + sizeof(struct fcp_rsp), + BPL_ALIGN_SZ, 0); + + if (!phba->lpfc_cmd_rsp_buf_pool) + goto fail_free_dma_buf_pool; + /* * Enable sr-iov virtual functions if supported and configured * through the module parameter. @@ -6342,6 +6365,13 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) } return 0; + +fail_free_dma_buf_pool: + dma_pool_destroy(phba->lpfc_sg_dma_buf_pool); + phba->lpfc_sg_dma_buf_pool = NULL; +fail_free_mem: + lpfc_mem_free(phba); + return -ENOMEM; } /** @@ -6402,6 +6432,11 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) if (rc) return -ENODEV; + /* Allocate all driver workqueues here */ + + /* The lpfc_wq workqueue for deferred irq use */ + phba->wq = alloc_workqueue("lpfc_wq", WQ_MEM_RECLAIM, 0); + /* * Initialize timers used by driver */ @@ -6436,102 +6471,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) * The WQ create will allocate the ring. */ - /* - * 1 for cmd, 1 for rsp, NVME adds an extra one - * for boundary conditions in its max_sgl_segment template. - */ - extra = 2; - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) - extra++; - - /* - * It doesn't matter what family our adapter is in, we are - * limited to 2 Pages, 512 SGEs, for our SGL. - * There are going to be 2 reserved SGEs: 1 FCP cmnd + 1 FCP rsp - */ - max_buf_size = (2 * SLI4_PAGE_SIZE); - - /* - * Since lpfc_sg_seg_cnt is module param, the sg_dma_buf_size - * used to create the sg_dma_buf_pool must be calculated. - */ - if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) { - /* - * The scsi_buf for a T10-DIF I/O holds the FCP cmnd, - * the FCP rsp, and a SGE. Sice we have no control - * over how many protection segments the SCSI Layer - * will hand us (ie: there could be one for every block - * in the IO), just allocate enough SGEs to accomidate - * our max amount and we need to limit lpfc_sg_seg_cnt - * to minimize the risk of running out. - */ - phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) + - sizeof(struct fcp_rsp) + max_buf_size; - - /* Total SGEs for scsi_sg_list and scsi_sg_prot_list */ - phba->cfg_total_seg_cnt = LPFC_MAX_SGL_SEG_CNT; - - /* - * If supporting DIF, reduce the seg count for scsi to - * allow room for the DIF sges. - */ - if (phba->cfg_enable_bg && - phba->cfg_sg_seg_cnt > LPFC_MAX_BG_SLI4_SEG_CNT_DIF) - phba->cfg_scsi_seg_cnt = LPFC_MAX_BG_SLI4_SEG_CNT_DIF; - else - phba->cfg_scsi_seg_cnt = phba->cfg_sg_seg_cnt; - - } else { - /* - * The scsi_buf for a regular I/O holds the FCP cmnd, - * the FCP rsp, a SGE for each, and a SGE for up to - * cfg_sg_seg_cnt data segments. - */ - phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) + - sizeof(struct fcp_rsp) + - ((phba->cfg_sg_seg_cnt + extra) * - sizeof(struct sli4_sge)); - - /* Total SGEs for scsi_sg_list */ - phba->cfg_total_seg_cnt = phba->cfg_sg_seg_cnt + extra; - phba->cfg_scsi_seg_cnt = phba->cfg_sg_seg_cnt; - - /* - * NOTE: if (phba->cfg_sg_seg_cnt + extra) <= 256 we only - * need to post 1 page for the SGL. - */ - } - - /* Limit to LPFC_MAX_NVME_SEG_CNT for NVME. */ - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - if (phba->cfg_sg_seg_cnt > LPFC_MAX_NVME_SEG_CNT) { - lpfc_printf_log(phba, KERN_INFO, LOG_NVME | LOG_INIT, - "6300 Reducing NVME sg segment " - "cnt to %d\n", - LPFC_MAX_NVME_SEG_CNT); - phba->cfg_nvme_seg_cnt = LPFC_MAX_NVME_SEG_CNT; - } else - phba->cfg_nvme_seg_cnt = phba->cfg_sg_seg_cnt; - } - - /* Initialize the host templates with the updated values. */ - lpfc_vport_template.sg_tablesize = phba->cfg_scsi_seg_cnt; - lpfc_template.sg_tablesize = phba->cfg_scsi_seg_cnt; - lpfc_template_no_hr.sg_tablesize = phba->cfg_scsi_seg_cnt; - - if (phba->cfg_sg_dma_buf_size <= LPFC_MIN_SG_SLI4_BUF_SZ) - phba->cfg_sg_dma_buf_size = LPFC_MIN_SG_SLI4_BUF_SZ; - else - phba->cfg_sg_dma_buf_size = - SLI4_PAGE_ALIGN(phba->cfg_sg_dma_buf_size); - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP, - "9087 sg_seg_cnt:%d dmabuf_size:%d " - "total:%d scsi:%d nvme:%d\n", - phba->cfg_sg_seg_cnt, phba->cfg_sg_dma_buf_size, - phba->cfg_total_seg_cnt, phba->cfg_scsi_seg_cnt, - phba->cfg_nvme_seg_cnt); - /* Initialize buffer queue management fields */ INIT_LIST_HEAD(&phba->hbqs[LPFC_ELS_HBQ].hbq_buffer_list); phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_sli4_rb_alloc; @@ -6540,17 +6479,17 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* * Initialize the SLI Layer to run with lpfc SLI4 HBAs. */ - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) { - /* Initialize the Abort scsi buffer list used by driver */ - spin_lock_init(&phba->sli4_hba.abts_scsi_buf_list_lock); - INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_scsi_buf_list); - } + /* Initialize the Abort buffer list used by driver */ + spin_lock_init(&phba->sli4_hba.abts_io_buf_list_lock); + INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_io_buf_list); if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { /* Initialize the Abort nvme buffer list used by driver */ spin_lock_init(&phba->sli4_hba.abts_nvmet_buf_list_lock); INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_nvmet_ctx_list); INIT_LIST_HEAD(&phba->sli4_hba.lpfc_nvmet_io_wait_list); + spin_lock_init(&phba->sli4_hba.t_active_list_lock); + INIT_LIST_HEAD(&phba->sli4_hba.t_active_ctx_list); } /* This abort list used by worker thread */ @@ -6750,6 +6689,131 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) } } + /* + * 1 for cmd, 1 for rsp, NVME adds an extra one + * for boundary conditions in its max_sgl_segment template. + */ + extra = 2; + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) + extra++; + + /* + * It doesn't matter what family our adapter is in, we are + * limited to 2 Pages, 512 SGEs, for our SGL. + * There are going to be 2 reserved SGEs: 1 FCP cmnd + 1 FCP rsp + */ + max_buf_size = (2 * SLI4_PAGE_SIZE); + + /* + * Since lpfc_sg_seg_cnt is module param, the sg_dma_buf_size + * used to create the sg_dma_buf_pool must be calculated. + */ + if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) { + /* Both cfg_enable_bg and cfg_external_dif code paths */ + + /* + * The scsi_buf for a T10-DIF I/O holds the FCP cmnd, + * the FCP rsp, and a SGE. Sice we have no control + * over how many protection segments the SCSI Layer + * will hand us (ie: there could be one for every block + * in the IO), just allocate enough SGEs to accomidate + * our max amount and we need to limit lpfc_sg_seg_cnt + * to minimize the risk of running out. + */ + phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) + + sizeof(struct fcp_rsp) + max_buf_size; + + /* Total SGEs for scsi_sg_list and scsi_sg_prot_list */ + phba->cfg_total_seg_cnt = LPFC_MAX_SGL_SEG_CNT; + + /* + * If supporting DIF, reduce the seg count for scsi to + * allow room for the DIF sges. + */ + if (phba->cfg_enable_bg && + phba->cfg_sg_seg_cnt > LPFC_MAX_BG_SLI4_SEG_CNT_DIF) + phba->cfg_scsi_seg_cnt = LPFC_MAX_BG_SLI4_SEG_CNT_DIF; + else + phba->cfg_scsi_seg_cnt = phba->cfg_sg_seg_cnt; + + } else { + /* + * The scsi_buf for a regular I/O holds the FCP cmnd, + * the FCP rsp, a SGE for each, and a SGE for up to + * cfg_sg_seg_cnt data segments. + */ + phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) + + sizeof(struct fcp_rsp) + + ((phba->cfg_sg_seg_cnt + extra) * + sizeof(struct sli4_sge)); + + /* Total SGEs for scsi_sg_list */ + phba->cfg_total_seg_cnt = phba->cfg_sg_seg_cnt + extra; + phba->cfg_scsi_seg_cnt = phba->cfg_sg_seg_cnt; + + /* + * NOTE: if (phba->cfg_sg_seg_cnt + extra) <= 256 we only + * need to post 1 page for the SGL. + */ + } + + if (phba->cfg_xpsgl && !phba->nvmet_support) + phba->cfg_sg_dma_buf_size = LPFC_DEFAULT_XPSGL_SIZE; + else if (phba->cfg_sg_dma_buf_size <= LPFC_MIN_SG_SLI4_BUF_SZ) + phba->cfg_sg_dma_buf_size = LPFC_MIN_SG_SLI4_BUF_SZ; + else + phba->cfg_sg_dma_buf_size = + SLI4_PAGE_ALIGN(phba->cfg_sg_dma_buf_size); + + phba->border_sge_num = phba->cfg_sg_dma_buf_size / + sizeof(struct sli4_sge); + + /* Limit to LPFC_MAX_NVME_SEG_CNT for NVME. */ + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { + if (phba->cfg_sg_seg_cnt > LPFC_MAX_NVME_SEG_CNT) { + lpfc_printf_log(phba, KERN_INFO, LOG_NVME | LOG_INIT, + "6300 Reducing NVME sg segment " + "cnt to %d\n", + LPFC_MAX_NVME_SEG_CNT); + phba->cfg_nvme_seg_cnt = LPFC_MAX_NVME_SEG_CNT; + } else + phba->cfg_nvme_seg_cnt = phba->cfg_sg_seg_cnt; + } + + /* Initialize the host templates with the updated values. */ + lpfc_vport_template.sg_tablesize = phba->cfg_scsi_seg_cnt; + lpfc_template.sg_tablesize = phba->cfg_scsi_seg_cnt; + lpfc_template_no_hr.sg_tablesize = phba->cfg_scsi_seg_cnt; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_FCP, + "9087 sg_seg_cnt:%d dmabuf_size:%d " + "total:%d scsi:%d nvme:%d\n", + phba->cfg_sg_seg_cnt, phba->cfg_sg_dma_buf_size, + phba->cfg_total_seg_cnt, phba->cfg_scsi_seg_cnt, + phba->cfg_nvme_seg_cnt); + + if (phba->cfg_sg_dma_buf_size < SLI4_PAGE_SIZE) + i = phba->cfg_sg_dma_buf_size; + else + i = SLI4_PAGE_SIZE; + + phba->lpfc_sg_dma_buf_pool = + dma_pool_create("lpfc_sg_dma_buf_pool", + &phba->pcidev->dev, + phba->cfg_sg_dma_buf_size, + i, 0); + if (!phba->lpfc_sg_dma_buf_pool) + goto out_free_bsmbx; + + phba->lpfc_cmd_rsp_buf_pool = + dma_pool_create("lpfc_cmd_rsp_buf_pool", + &phba->pcidev->dev, + sizeof(struct fcp_cmnd) + + sizeof(struct fcp_rsp), + i, 0); + if (!phba->lpfc_cmd_rsp_buf_pool) + goto out_free_sg_dma_buf; + mempool_free(mboxq, phba->mbox_mem_pool); /* Verify OAS is supported */ @@ -6761,12 +6825,12 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* Verify all the SLI4 queues */ rc = lpfc_sli4_queue_verify(phba); if (rc) - goto out_free_bsmbx; + goto out_free_cmd_rsp_buf; /* Create driver internal CQE event pool */ rc = lpfc_sli4_cq_event_pool_create(phba); if (rc) - goto out_free_bsmbx; + goto out_free_cmd_rsp_buf; /* Initialize sgl lists per host */ lpfc_init_sgl_list(phba); @@ -6857,6 +6921,12 @@ out_free_active_sgl: lpfc_free_active_sgl(phba); out_destroy_cq_event_pool: lpfc_sli4_cq_event_pool_destroy(phba); +out_free_cmd_rsp_buf: + dma_pool_destroy(phba->lpfc_cmd_rsp_buf_pool); + phba->lpfc_cmd_rsp_buf_pool = NULL; +out_free_sg_dma_buf: + dma_pool_destroy(phba->lpfc_sg_dma_buf_pool); + phba->lpfc_sg_dma_buf_pool = NULL; out_free_bsmbx: lpfc_destroy_bootstrap_mbox(phba); out_free_mem: @@ -6983,12 +7053,6 @@ lpfc_setup_driver_resource_phase2(struct lpfc_hba *phba) return error; } - /* The lpfc_wq workqueue for deferred irq use, is only used for SLI4 */ - if (phba->sli_rev == LPFC_SLI_REV4) - phba->wq = alloc_workqueue("lpfc_wq", WQ_MEM_RECLAIM, 0); - else - phba->wq = NULL; - return 0; } @@ -7549,7 +7613,6 @@ lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost) uint32_t old_mask; uint32_t old_guard; - int pagecnt = 10; if (phba->cfg_prot_mask && phba->cfg_prot_guard) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "1478 Registering BlockGuard with the " @@ -7586,56 +7649,6 @@ lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost) "layer, Bad protection parameters: %d %d\n", old_mask, old_guard); } - - if (!_dump_buf_data) { - while (pagecnt) { - spin_lock_init(&_dump_buf_lock); - _dump_buf_data = - (char *) __get_free_pages(GFP_KERNEL, pagecnt); - if (_dump_buf_data) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9043 BLKGRD: allocated %d pages for " - "_dump_buf_data at 0x%p\n", - (1 << pagecnt), _dump_buf_data); - _dump_buf_data_order = pagecnt; - memset(_dump_buf_data, 0, - ((1 << PAGE_SHIFT) << pagecnt)); - break; - } else - --pagecnt; - } - if (!_dump_buf_data_order) - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9044 BLKGRD: ERROR unable to allocate " - "memory for hexdump\n"); - } else - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9045 BLKGRD: already allocated _dump_buf_data=0x%p" - "\n", _dump_buf_data); - if (!_dump_buf_dif) { - while (pagecnt) { - _dump_buf_dif = - (char *) __get_free_pages(GFP_KERNEL, pagecnt); - if (_dump_buf_dif) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9046 BLKGRD: allocated %d pages for " - "_dump_buf_dif at 0x%p\n", - (1 << pagecnt), _dump_buf_dif); - _dump_buf_dif_order = pagecnt; - memset(_dump_buf_dif, 0, - ((1 << PAGE_SHIFT) << pagecnt)); - break; - } else - --pagecnt; - } - if (!_dump_buf_dif_order) - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9047 BLKGRD: ERROR unable to allocate " - "memory for hexdump\n"); - } else - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9048 BLKGRD: already allocated _dump_buf_dif=0x%p\n", - _dump_buf_dif); } /** @@ -7660,8 +7673,6 @@ lpfc_post_init_setup(struct lpfc_hba *phba) */ shost = pci_get_drvdata(phba->pcidev); shost->can_queue = phba->cfg_hba_queue_depth - 10; - if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) - lpfc_setup_bg(phba, shost); lpfc_host_attrib_init(shost); @@ -8297,6 +8308,10 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) bf_get(lpfc_mbx_rd_conf_extnts_inuse, rd_config); phba->sli4_hba.max_cfg_param.max_xri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config); + /* Reduce resource usage in kdump environment */ + if (is_kdump_kernel() && + phba->sli4_hba.max_cfg_param.max_xri > 512) + phba->sli4_hba.max_cfg_param.max_xri = 512; phba->sli4_hba.max_cfg_param.xri_base = bf_get(lpfc_mbx_rd_conf_xri_base, rd_config); phba->sli4_hba.max_cfg_param.max_vpi = @@ -8370,11 +8385,6 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) */ qmin -= 4; - /* If NVME is configured, double the number of CQ/WQs needed */ - if ((phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) && - !phba->nvmet_support) - qmin /= 2; - /* Check to see if there is enough for NVME */ if ((phba->cfg_irq_chann > qmin) || (phba->cfg_hdw_queue > qmin)) { @@ -8631,51 +8641,14 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba) } static int -lpfc_alloc_nvme_wq_cq(struct lpfc_hba *phba, int wqidx) +lpfc_alloc_io_wq_cq(struct lpfc_hba *phba, int idx) { struct lpfc_queue *qdesc; + u32 wqesize; int cpu; - cpu = lpfc_find_cpu_handle(phba, wqidx, LPFC_FIND_BY_HDWQ); - qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, - phba->sli4_hba.cq_esize, - LPFC_CQE_EXP_COUNT, cpu); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0508 Failed allocate fast-path NVME CQ (%d)\n", - wqidx); - return 1; - } - qdesc->qe_valid = 1; - qdesc->hdwq = wqidx; - qdesc->chann = cpu; - phba->sli4_hba.hdwq[wqidx].nvme_cq = qdesc; - - qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, - LPFC_WQE128_SIZE, LPFC_WQE_EXP_COUNT, - cpu); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0509 Failed allocate fast-path NVME WQ (%d)\n", - wqidx); - return 1; - } - qdesc->hdwq = wqidx; - qdesc->chann = wqidx; - phba->sli4_hba.hdwq[wqidx].nvme_wq = qdesc; - list_add_tail(&qdesc->wq_list, &phba->sli4_hba.lpfc_wq_list); - return 0; -} - -static int -lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx) -{ - struct lpfc_queue *qdesc; - uint32_t wqesize; - int cpu; - - cpu = lpfc_find_cpu_handle(phba, wqidx, LPFC_FIND_BY_HDWQ); - /* Create Fast Path FCP CQs */ + cpu = lpfc_find_cpu_handle(phba, idx, LPFC_FIND_BY_HDWQ); + /* Create Fast Path IO CQs */ if (phba->enab_exp_wqcq_pages) /* Increase the CQ size when WQEs contain an embedded cdb */ qdesc = lpfc_sli4_queue_alloc(phba, LPFC_EXPANDED_PAGE_SIZE, @@ -8688,15 +8661,15 @@ lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx) phba->sli4_hba.cq_ecount, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0499 Failed allocate fast-path FCP CQ (%d)\n", wqidx); + "0499 Failed allocate fast-path IO CQ (%d)\n", idx); return 1; } qdesc->qe_valid = 1; - qdesc->hdwq = wqidx; + qdesc->hdwq = idx; qdesc->chann = cpu; - phba->sli4_hba.hdwq[wqidx].fcp_cq = qdesc; + phba->sli4_hba.hdwq[idx].io_cq = qdesc; - /* Create Fast Path FCP WQs */ + /* Create Fast Path IO WQs */ if (phba->enab_exp_wqcq_pages) { /* Increase the WQ size when WQEs contain an embedded cdb */ wqesize = (phba->fcp_embed_io) ? @@ -8711,13 +8684,13 @@ lpfc_alloc_fcp_wq_cq(struct lpfc_hba *phba, int wqidx) if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0503 Failed allocate fast-path FCP WQ (%d)\n", - wqidx); + "0503 Failed allocate fast-path IO WQ (%d)\n", + idx); return 1; } - qdesc->hdwq = wqidx; - qdesc->chann = wqidx; - phba->sli4_hba.hdwq[wqidx].fcp_wq = qdesc; + qdesc->hdwq = idx; + qdesc->chann = cpu; + phba->sli4_hba.hdwq[idx].io_wq = qdesc; list_add_tail(&qdesc->wq_list, &phba->sli4_hba.lpfc_wq_list); return 0; } @@ -8740,8 +8713,10 @@ int lpfc_sli4_queue_create(struct lpfc_hba *phba) { struct lpfc_queue *qdesc; - int idx, eqidx, cpu; + int idx, cpu, eqcpu; struct lpfc_sli4_hdw_queue *qp; + struct lpfc_vector_map_info *cpup; + struct lpfc_vector_map_info *eqcpup; struct lpfc_eq_intr_info *eqi; /* @@ -8779,12 +8754,13 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) qp->get_io_bufs = 0; qp->put_io_bufs = 0; qp->total_io_bufs = 0; - spin_lock_init(&qp->abts_scsi_buf_list_lock); - INIT_LIST_HEAD(&qp->lpfc_abts_scsi_buf_list); + spin_lock_init(&qp->abts_io_buf_list_lock); + INIT_LIST_HEAD(&qp->lpfc_abts_io_buf_list); qp->abts_scsi_io_bufs = 0; - spin_lock_init(&qp->abts_nvme_buf_list_lock); - INIT_LIST_HEAD(&qp->lpfc_abts_nvme_buf_list); qp->abts_nvme_io_bufs = 0; + INIT_LIST_HEAD(&qp->sgl_list); + INIT_LIST_HEAD(&qp->cmd_rsp_buf_list); + spin_lock_init(&qp->hdwq_lock); } } @@ -8826,76 +8802,86 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) INIT_LIST_HEAD(&phba->sli4_hba.lpfc_wq_list); /* Create HBA Event Queues (EQs) */ - for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { - /* determine EQ affinity */ - eqidx = lpfc_find_eq_handle(phba, idx); - cpu = lpfc_find_cpu_handle(phba, eqidx, LPFC_FIND_BY_EQ); - /* - * If there are more Hardware Queues than available - * EQs, multiple Hardware Queues may share a common EQ. + for_each_present_cpu(cpu) { + /* We only want to create 1 EQ per vector, even though + * multiple CPUs might be using that vector. so only + * selects the CPUs that are LPFC_CPU_FIRST_IRQ. */ - if (idx >= phba->cfg_irq_chann) { - /* Share an existing EQ */ - phba->sli4_hba.hdwq[idx].hba_eq = - phba->sli4_hba.hdwq[eqidx].hba_eq; + cpup = &phba->sli4_hba.cpu_map[cpu]; + if (!(cpup->flag & LPFC_CPU_FIRST_IRQ)) continue; - } - /* Create an EQ */ + + /* Get a ptr to the Hardware Queue associated with this CPU */ + qp = &phba->sli4_hba.hdwq[cpup->hdwq]; + + /* Allocate an EQ */ qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.eq_esize, phba->sli4_hba.eq_ecount, cpu); if (!qdesc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0497 Failed allocate EQ (%d)\n", idx); + "0497 Failed allocate EQ (%d)\n", + cpup->hdwq); goto out_error; } qdesc->qe_valid = 1; - qdesc->hdwq = idx; - - /* Save the CPU this EQ is affinitised to */ - qdesc->chann = cpu; - phba->sli4_hba.hdwq[idx].hba_eq = qdesc; + qdesc->hdwq = cpup->hdwq; + qdesc->chann = cpu; /* First CPU this EQ is affinitized to */ qdesc->last_cpu = qdesc->chann; + + /* Save the allocated EQ in the Hardware Queue */ + qp->hba_eq = qdesc; + eqi = per_cpu_ptr(phba->sli4_hba.eq_info, qdesc->last_cpu); list_add(&qdesc->cpu_list, &eqi->list); } + /* Now we need to populate the other Hardware Queues, that share + * an IRQ vector, with the associated EQ ptr. + */ + for_each_present_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* Check for EQ already allocated in previous loop */ + if (cpup->flag & LPFC_CPU_FIRST_IRQ) + continue; + + /* Check for multiple CPUs per hdwq */ + qp = &phba->sli4_hba.hdwq[cpup->hdwq]; + if (qp->hba_eq) + continue; + + /* We need to share an EQ for this hdwq */ + eqcpu = lpfc_find_cpu_handle(phba, cpup->eq, LPFC_FIND_BY_EQ); + eqcpup = &phba->sli4_hba.cpu_map[eqcpu]; + qp->hba_eq = phba->sli4_hba.hdwq[eqcpup->hdwq].hba_eq; + } - /* Allocate SCSI SLI4 CQ/WQs */ + /* Allocate IO Path SLI4 CQ/WQs */ for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { - if (lpfc_alloc_fcp_wq_cq(phba, idx)) + if (lpfc_alloc_io_wq_cq(phba, idx)) goto out_error; } - /* Allocate NVME SLI4 CQ/WQs */ - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { - if (lpfc_alloc_nvme_wq_cq(phba, idx)) - goto out_error; - } - - if (phba->nvmet_support) { - for (idx = 0; idx < phba->cfg_nvmet_mrq; idx++) { - cpu = lpfc_find_cpu_handle(phba, idx, - LPFC_FIND_BY_HDWQ); - qdesc = lpfc_sli4_queue_alloc( - phba, + if (phba->nvmet_support) { + for (idx = 0; idx < phba->cfg_nvmet_mrq; idx++) { + cpu = lpfc_find_cpu_handle(phba, idx, + LPFC_FIND_BY_HDWQ); + qdesc = lpfc_sli4_queue_alloc(phba, LPFC_DEFAULT_PAGE_SIZE, phba->sli4_hba.cq_esize, phba->sli4_hba.cq_ecount, cpu); - if (!qdesc) { - lpfc_printf_log( - phba, KERN_ERR, LOG_INIT, + if (!qdesc) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3142 Failed allocate NVME " "CQ Set (%d)\n", idx); - goto out_error; - } - qdesc->qe_valid = 1; - qdesc->hdwq = idx; - qdesc->chann = cpu; - phba->sli4_hba.nvmet_cqset[idx] = qdesc; + goto out_error; } + qdesc->qe_valid = 1; + qdesc->hdwq = idx; + qdesc->chann = cpu; + phba->sli4_hba.nvmet_cqset[idx] = qdesc; } } @@ -8926,7 +8912,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) goto out_error; } qdesc->qe_valid = 1; - qdesc->chann = 0; + qdesc->chann = cpu; phba->sli4_hba.els_cq = qdesc; @@ -8944,7 +8930,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) "0505 Failed allocate slow-path MQ\n"); goto out_error; } - qdesc->chann = 0; + qdesc->chann = cpu; phba->sli4_hba.mbx_wq = qdesc; /* @@ -8960,7 +8946,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) "0504 Failed allocate slow-path ELS WQ\n"); goto out_error; } - qdesc->chann = 0; + qdesc->chann = cpu; phba->sli4_hba.els_wq = qdesc; list_add_tail(&qdesc->wq_list, &phba->sli4_hba.lpfc_wq_list); @@ -8974,7 +8960,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) "6079 Failed allocate NVME LS CQ\n"); goto out_error; } - qdesc->chann = 0; + qdesc->chann = cpu; qdesc->qe_valid = 1; phba->sli4_hba.nvmels_cq = qdesc; @@ -8987,7 +8973,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) "6080 Failed allocate NVME LS WQ\n"); goto out_error; } - qdesc->chann = 0; + qdesc->chann = cpu; phba->sli4_hba.nvmels_wq = qdesc; list_add_tail(&qdesc->wq_list, &phba->sli4_hba.lpfc_wq_list); } @@ -9069,7 +9055,6 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) } } -#if defined(BUILD_NVME) /* Clear NVME stats */ if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { @@ -9077,7 +9062,6 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) sizeof(phba->sli4_hba.hdwq[idx].nvme_cstat)); } } -#endif /* Clear SCSI stats */ if (phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) { @@ -9122,22 +9106,28 @@ static inline void lpfc_sli4_release_hdwq(struct lpfc_hba *phba) { struct lpfc_sli4_hdw_queue *hdwq; + struct lpfc_queue *eq; uint32_t idx; hdwq = phba->sli4_hba.hdwq; - for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { - if (idx < phba->cfg_irq_chann) - lpfc_sli4_queue_free(hdwq[idx].hba_eq); - hdwq[idx].hba_eq = NULL; - lpfc_sli4_queue_free(hdwq[idx].fcp_cq); - lpfc_sli4_queue_free(hdwq[idx].nvme_cq); - lpfc_sli4_queue_free(hdwq[idx].fcp_wq); - lpfc_sli4_queue_free(hdwq[idx].nvme_wq); - hdwq[idx].fcp_cq = NULL; - hdwq[idx].nvme_cq = NULL; - hdwq[idx].fcp_wq = NULL; - hdwq[idx].nvme_wq = NULL; + /* Loop thru all Hardware Queues */ + for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { + /* Free the CQ/WQ corresponding to the Hardware Queue */ + lpfc_sli4_queue_free(hdwq[idx].io_cq); + lpfc_sli4_queue_free(hdwq[idx].io_wq); + hdwq[idx].io_cq = NULL; + hdwq[idx].io_wq = NULL; + if (phba->cfg_xpsgl && !phba->nvmet_support) + lpfc_free_sgl_per_hdwq(phba, &hdwq[idx]); + lpfc_free_cmd_rsp_buf_per_hdwq(phba, &hdwq[idx]); + } + /* Loop thru all IRQ vectors */ + for (idx = 0; idx < phba->cfg_irq_chann; idx++) { + /* Free the EQ corresponding to the IRQ vector */ + eq = phba->sli4_hba.hba_eq_hdl[idx].eq; + lpfc_sli4_queue_free(eq); + phba->sli4_hba.hba_eq_hdl[idx].eq = NULL; } } @@ -9316,21 +9306,21 @@ static void lpfc_setup_cq_lookup(struct lpfc_hba *phba) { struct lpfc_queue *eq, *childq; - struct lpfc_sli4_hdw_queue *qp; int qidx; - qp = phba->sli4_hba.hdwq; memset(phba->sli4_hba.cq_lookup, 0, (sizeof(struct lpfc_queue *) * (phba->sli4_hba.cq_max + 1))); + /* Loop thru all IRQ vectors */ for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) { - eq = qp[qidx].hba_eq; + /* Get the EQ corresponding to the IRQ vector */ + eq = phba->sli4_hba.hba_eq_hdl[qidx].eq; if (!eq) continue; + /* Loop through all CQs associated with that EQ */ list_for_each_entry(childq, &eq->child_list, list) { if (childq->queue_id > phba->sli4_hba.cq_max) continue; - if ((childq->subtype == LPFC_FCP) || - (childq->subtype == LPFC_NVME)) + if (childq->subtype == LPFC_IO) phba->sli4_hba.cq_lookup[childq->queue_id] = childq; } @@ -9354,9 +9344,10 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) { uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; + struct lpfc_vector_map_info *cpup; struct lpfc_sli4_hdw_queue *qp; LPFC_MBOXQ_t *mboxq; - int qidx; + int qidx, cpu; uint32_t length, usdelay; int rc = -ENOMEM; @@ -9417,57 +9408,60 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) rc = -ENOMEM; goto out_error; } + + /* Loop thru all IRQ vectors */ for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) { - if (!qp[qidx].hba_eq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0522 Fast-path EQ (%d) not " - "allocated\n", qidx); - rc = -ENOMEM; - goto out_destroy; - } - rc = lpfc_eq_create(phba, qp[qidx].hba_eq, - phba->cfg_fcp_imax); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0523 Failed setup of fast-path EQ " - "(%d), rc = 0x%x\n", qidx, - (uint32_t)rc); - goto out_destroy; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2584 HBA EQ setup: queue[%d]-id=%d\n", qidx, - qp[qidx].hba_eq->queue_id); - } + /* Create HBA Event Queues (EQs) in order */ + for_each_present_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { - rc = lpfc_create_wq_cq(phba, - qp[qidx].hba_eq, - qp[qidx].nvme_cq, - qp[qidx].nvme_wq, - &phba->sli4_hba.hdwq[qidx].nvme_cq_map, - qidx, LPFC_NVME); + /* Look for the CPU thats using that vector with + * LPFC_CPU_FIRST_IRQ set. + */ + if (!(cpup->flag & LPFC_CPU_FIRST_IRQ)) + continue; + if (qidx != cpup->eq) + continue; + + /* Create an EQ for that vector */ + rc = lpfc_eq_create(phba, qp[cpup->hdwq].hba_eq, + phba->cfg_fcp_imax); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "6123 Failed to setup fastpath " - "NVME WQ/CQ (%d), rc = 0x%x\n", - qidx, (uint32_t)rc); + "0523 Failed setup of fast-path" + " EQ (%d), rc = 0x%x\n", + cpup->eq, (uint32_t)rc); goto out_destroy; } + + /* Save the EQ for that vector in the hba_eq_hdl */ + phba->sli4_hba.hba_eq_hdl[cpup->eq].eq = + qp[cpup->hdwq].hba_eq; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2584 HBA EQ setup: queue[%d]-id=%d\n", + cpup->eq, + qp[cpup->hdwq].hba_eq->queue_id); } } + /* Loop thru all Hardware Queues */ for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { + cpu = lpfc_find_cpu_handle(phba, qidx, LPFC_FIND_BY_HDWQ); + cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* Create the CQ/WQ corresponding to the Hardware Queue */ rc = lpfc_create_wq_cq(phba, - qp[qidx].hba_eq, - qp[qidx].fcp_cq, - qp[qidx].fcp_wq, - &phba->sli4_hba.hdwq[qidx].fcp_cq_map, - qidx, LPFC_FCP); + phba->sli4_hba.hdwq[cpup->hdwq].hba_eq, + qp[qidx].io_cq, + qp[qidx].io_wq, + &phba->sli4_hba.hdwq[qidx].io_cq_map, + qidx, + LPFC_IO); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0535 Failed to setup fastpath " - "FCP WQ/CQ (%d), rc = 0x%x\n", + "IO WQ/CQ (%d), rc = 0x%x\n", qidx, (uint32_t)rc); goto out_destroy; } @@ -9711,6 +9705,7 @@ void lpfc_sli4_queue_unset(struct lpfc_hba *phba) { struct lpfc_sli4_hdw_queue *qp; + struct lpfc_queue *eq; int qidx; /* Unset mailbox command work queue */ @@ -9762,14 +9757,18 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba) /* Unset fast-path SLI4 queues */ if (phba->sli4_hba.hdwq) { + /* Loop thru all Hardware Queues */ for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { + /* Destroy the CQ/WQ corresponding to Hardware Queue */ qp = &phba->sli4_hba.hdwq[qidx]; - lpfc_wq_destroy(phba, qp->fcp_wq); - lpfc_wq_destroy(phba, qp->nvme_wq); - lpfc_cq_destroy(phba, qp->fcp_cq); - lpfc_cq_destroy(phba, qp->nvme_cq); - if (qidx < phba->cfg_irq_chann) - lpfc_eq_destroy(phba, qp->hba_eq); + lpfc_wq_destroy(phba, qp->io_wq); + lpfc_cq_destroy(phba, qp->io_cq); + } + /* Loop thru all IRQ vectors */ + for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) { + /* Destroy the EQ corresponding to the IRQ vector */ + eq = phba->sli4_hba.hba_eq_hdl[qidx].eq; + lpfc_eq_destroy(phba, eq); } } @@ -10559,11 +10558,12 @@ lpfc_sli_disable_intr(struct lpfc_hba *phba) } /** - * lpfc_find_cpu_handle - Find the CPU that corresponds to the specified EQ + * lpfc_find_cpu_handle - Find the CPU that corresponds to the specified Queue * @phba: pointer to lpfc hba data structure. * @id: EQ vector index or Hardware Queue index * @match: LPFC_FIND_BY_EQ = match by EQ * LPFC_FIND_BY_HDWQ = match by Hardware Queue + * Return the CPU that matches the selection criteria */ static uint16_t lpfc_find_cpu_handle(struct lpfc_hba *phba, uint16_t id, int match) @@ -10571,40 +10571,27 @@ lpfc_find_cpu_handle(struct lpfc_hba *phba, uint16_t id, int match) struct lpfc_vector_map_info *cpup; int cpu; - /* Find the desired phys_id for the specified EQ */ + /* Loop through all CPUs */ for_each_present_cpu(cpu) { cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* If we are matching by EQ, there may be multiple CPUs using + * using the same vector, so select the one with + * LPFC_CPU_FIRST_IRQ set. + */ if ((match == LPFC_FIND_BY_EQ) && + (cpup->flag & LPFC_CPU_FIRST_IRQ) && (cpup->irq != LPFC_VECTOR_MAP_EMPTY) && (cpup->eq == id)) return cpu; + + /* If matching by HDWQ, select the first CPU that matches */ if ((match == LPFC_FIND_BY_HDWQ) && (cpup->hdwq == id)) return cpu; } return 0; } -/** - * lpfc_find_eq_handle - Find the EQ that corresponds to the specified - * Hardware Queue - * @phba: pointer to lpfc hba data structure. - * @hdwq: Hardware Queue index - */ -static uint16_t -lpfc_find_eq_handle(struct lpfc_hba *phba, uint16_t hdwq) -{ - struct lpfc_vector_map_info *cpup; - int cpu; - - /* Find the desired phys_id for the specified EQ */ - for_each_present_cpu(cpu) { - cpup = &phba->sli4_hba.cpu_map[cpu]; - if (cpup->hdwq == hdwq) - return cpup->eq; - } - return 0; -} - #ifdef CONFIG_X86 /** * lpfc_find_hyper - Determine if the CPU map entry is hyper-threaded @@ -10645,24 +10632,31 @@ lpfc_find_hyper(struct lpfc_hba *phba, int cpu, static void lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) { - int i, cpu, idx; + int i, cpu, idx, next_idx, new_cpu, start_cpu, first_cpu; int max_phys_id, min_phys_id; int max_core_id, min_core_id; struct lpfc_vector_map_info *cpup; + struct lpfc_vector_map_info *new_cpup; const struct cpumask *maskp; #ifdef CONFIG_X86 struct cpuinfo_x86 *cpuinfo; #endif /* Init cpu_map array */ - memset(phba->sli4_hba.cpu_map, 0xff, - (sizeof(struct lpfc_vector_map_info) * - phba->sli4_hba.num_possible_cpu)); + for_each_possible_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + cpup->phys_id = LPFC_VECTOR_MAP_EMPTY; + cpup->core_id = LPFC_VECTOR_MAP_EMPTY; + cpup->hdwq = LPFC_VECTOR_MAP_EMPTY; + cpup->eq = LPFC_VECTOR_MAP_EMPTY; + cpup->irq = LPFC_VECTOR_MAP_EMPTY; + cpup->flag = 0; + } max_phys_id = 0; - min_phys_id = 0xffff; + min_phys_id = LPFC_VECTOR_MAP_EMPTY; max_core_id = 0; - min_core_id = 0xffff; + min_core_id = LPFC_VECTOR_MAP_EMPTY; /* Update CPU map with physical id and core id of each CPU */ for_each_present_cpu(cpu) { @@ -10671,18 +10665,17 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) cpuinfo = &cpu_data(cpu); cpup->phys_id = cpuinfo->phys_proc_id; cpup->core_id = cpuinfo->cpu_core_id; - cpup->hyper = lpfc_find_hyper(phba, cpu, - cpup->phys_id, cpup->core_id); + if (lpfc_find_hyper(phba, cpu, cpup->phys_id, cpup->core_id)) + cpup->flag |= LPFC_CPU_MAP_HYPER; #else /* No distinction between CPUs for other platforms */ cpup->phys_id = 0; cpup->core_id = cpu; - cpup->hyper = 0; #endif lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3328 CPU physid %d coreid %d\n", - cpup->phys_id, cpup->core_id); + "3328 CPU %d physid %d coreid %d flag x%x\n", + cpu, cpup->phys_id, cpup->core_id, cpup->flag); if (cpup->phys_id > max_phys_id) max_phys_id = cpup->phys_id; @@ -10703,23 +10696,269 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) eqi->icnt = 0; } + /* This loop sets up all CPUs that are affinitized with a + * irq vector assigned to the driver. All affinitized CPUs + * will get a link to that vectors IRQ and EQ. + * + * NULL affinity mask handling: + * If irq count is greater than one, log an error message. + * If the null mask is received for the first irq, find the + * first present cpu, and assign the eq index to ensure at + * least one EQ is assigned. + */ for (idx = 0; idx < phba->cfg_irq_chann; idx++) { + /* Get a CPU mask for all CPUs affinitized to this vector */ maskp = pci_irq_get_affinity(phba->pcidev, idx); - if (!maskp) - continue; + if (!maskp) { + if (phba->cfg_irq_chann > 1) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3329 No affinity mask found " + "for vector %d (%d)\n", + idx, phba->cfg_irq_chann); + if (!idx) { + cpu = cpumask_first(cpu_present_mask); + cpup = &phba->sli4_hba.cpu_map[cpu]; + cpup->eq = idx; + cpup->irq = pci_irq_vector(phba->pcidev, idx); + cpup->flag |= LPFC_CPU_FIRST_IRQ; + } + break; + } + i = 0; + /* Loop through all CPUs associated with vector idx */ for_each_cpu_and(cpu, maskp, cpu_present_mask) { + /* Set the EQ index and IRQ for that vector */ cpup = &phba->sli4_hba.cpu_map[cpu]; cpup->eq = idx; - cpup->hdwq = idx; cpup->irq = pci_irq_vector(phba->pcidev, idx); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + /* If this is the first CPU thats assigned to this + * vector, set LPFC_CPU_FIRST_IRQ. + */ + if (!i) + cpup->flag |= LPFC_CPU_FIRST_IRQ; + i++; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3336 Set Affinity: CPU %d " - "hdwq %d irq %d\n", - cpu, cpup->hdwq, cpup->irq); + "irq %d eq %d flag x%x\n", + cpu, cpup->irq, cpup->eq, cpup->flag); + } + } + + /* After looking at each irq vector assigned to this pcidev, its + * possible to see that not ALL CPUs have been accounted for. + * Next we will set any unassigned (unaffinitized) cpu map + * entries to a IRQ on the same phys_id. + */ + first_cpu = cpumask_first(cpu_present_mask); + start_cpu = first_cpu; + + for_each_present_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* Is this CPU entry unassigned */ + if (cpup->eq == LPFC_VECTOR_MAP_EMPTY) { + /* Mark CPU as IRQ not assigned by the kernel */ + cpup->flag |= LPFC_CPU_MAP_UNASSIGN; + + /* If so, find a new_cpup thats on the the SAME + * phys_id as cpup. start_cpu will start where we + * left off so all unassigned entries don't get assgined + * the IRQ of the first entry. + */ + new_cpu = start_cpu; + for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { + new_cpup = &phba->sli4_hba.cpu_map[new_cpu]; + if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) && + (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY) && + (new_cpup->phys_id == cpup->phys_id)) + goto found_same; + new_cpu = cpumask_next( + new_cpu, cpu_present_mask); + if (new_cpu == nr_cpumask_bits) + new_cpu = first_cpu; + } + /* At this point, we leave the CPU as unassigned */ + continue; +found_same: + /* We found a matching phys_id, so copy the IRQ info */ + cpup->eq = new_cpup->eq; + cpup->irq = new_cpup->irq; + + /* Bump start_cpu to the next slot to minmize the + * chance of having multiple unassigned CPU entries + * selecting the same IRQ. + */ + start_cpu = cpumask_next(new_cpu, cpu_present_mask); + if (start_cpu == nr_cpumask_bits) + start_cpu = first_cpu; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "3337 Set Affinity: CPU %d " + "irq %d from id %d same " + "phys_id (%d)\n", + cpu, cpup->irq, new_cpu, cpup->phys_id); + } + } + + /* Set any unassigned cpu map entries to a IRQ on any phys_id */ + start_cpu = first_cpu; + + for_each_present_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* Is this entry unassigned */ + if (cpup->eq == LPFC_VECTOR_MAP_EMPTY) { + /* Mark it as IRQ not assigned by the kernel */ + cpup->flag |= LPFC_CPU_MAP_UNASSIGN; + + /* If so, find a new_cpup thats on ANY phys_id + * as the cpup. start_cpu will start where we + * left off so all unassigned entries don't get + * assigned the IRQ of the first entry. + */ + new_cpu = start_cpu; + for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { + new_cpup = &phba->sli4_hba.cpu_map[new_cpu]; + if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) && + (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY)) + goto found_any; + new_cpu = cpumask_next( + new_cpu, cpu_present_mask); + if (new_cpu == nr_cpumask_bits) + new_cpu = first_cpu; + } + /* We should never leave an entry unassigned */ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3339 Set Affinity: CPU %d " + "irq %d UNASSIGNED\n", + cpup->hdwq, cpup->irq); + continue; +found_any: + /* We found an available entry, copy the IRQ info */ + cpup->eq = new_cpup->eq; + cpup->irq = new_cpup->irq; + + /* Bump start_cpu to the next slot to minmize the + * chance of having multiple unassigned CPU entries + * selecting the same IRQ. + */ + start_cpu = cpumask_next(new_cpu, cpu_present_mask); + if (start_cpu == nr_cpumask_bits) + start_cpu = first_cpu; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "3338 Set Affinity: CPU %d " + "irq %d from id %d (%d/%d)\n", + cpu, cpup->irq, new_cpu, + new_cpup->phys_id, new_cpup->core_id); + } + } + + /* Assign hdwq indices that are unique across all cpus in the map + * that are also FIRST_CPUs. + */ + idx = 0; + for_each_present_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* Only FIRST IRQs get a hdwq index assignment. */ + if (!(cpup->flag & LPFC_CPU_FIRST_IRQ)) + continue; + + /* 1 to 1, the first LPFC_CPU_FIRST_IRQ cpus to a unique hdwq */ + cpup->hdwq = idx; + idx++; + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3333 Set Affinity: CPU %d (phys %d core %d): " + "hdwq %d eq %d irq %d flg x%x\n", + cpu, cpup->phys_id, cpup->core_id, + cpup->hdwq, cpup->eq, cpup->irq, cpup->flag); + } + /* Finally we need to associate a hdwq with each cpu_map entry + * This will be 1 to 1 - hdwq to cpu, unless there are less + * hardware queues then CPUs. For that case we will just round-robin + * the available hardware queues as they get assigned to CPUs. + * The next_idx is the idx from the FIRST_CPU loop above to account + * for irq_chann < hdwq. The idx is used for round-robin assignments + * and needs to start at 0. + */ + next_idx = idx; + start_cpu = 0; + idx = 0; + for_each_present_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + + /* FIRST cpus are already mapped. */ + if (cpup->flag & LPFC_CPU_FIRST_IRQ) + continue; + + /* If the cfg_irq_chann < cfg_hdw_queue, set the hdwq + * of the unassigned cpus to the next idx so that all + * hdw queues are fully utilized. + */ + if (next_idx < phba->cfg_hdw_queue) { + cpup->hdwq = next_idx; + next_idx++; + continue; + } + + /* Not a First CPU and all hdw_queues are used. Reuse a + * Hardware Queue for another CPU, so be smart about it + * and pick one that has its IRQ/EQ mapped to the same phys_id + * (CPU package) and core_id. + */ + new_cpu = start_cpu; + for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { + new_cpup = &phba->sli4_hba.cpu_map[new_cpu]; + if (new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY && + new_cpup->phys_id == cpup->phys_id && + new_cpup->core_id == cpup->core_id) { + goto found_hdwq; + } + new_cpu = cpumask_next(new_cpu, cpu_present_mask); + if (new_cpu == nr_cpumask_bits) + new_cpu = first_cpu; } + + /* If we can't match both phys_id and core_id, + * settle for just a phys_id match. + */ + new_cpu = start_cpu; + for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { + new_cpup = &phba->sli4_hba.cpu_map[new_cpu]; + if (new_cpup->hdwq != LPFC_VECTOR_MAP_EMPTY && + new_cpup->phys_id == cpup->phys_id) + goto found_hdwq; + + new_cpu = cpumask_next(new_cpu, cpu_present_mask); + if (new_cpu == nr_cpumask_bits) + new_cpu = first_cpu; + } + + /* Otherwise just round robin on cfg_hdw_queue */ + cpup->hdwq = idx % phba->cfg_hdw_queue; + idx++; + goto logit; + found_hdwq: + /* We found an available entry, copy the IRQ info */ + start_cpu = cpumask_next(new_cpu, cpu_present_mask); + if (start_cpu == nr_cpumask_bits) + start_cpu = first_cpu; + cpup->hdwq = new_cpup->hdwq; + logit: + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3335 Set Affinity: CPU %d (phys %d core %d): " + "hdwq %d eq %d irq %d flg x%x\n", + cpu, cpup->phys_id, cpup->core_id, + cpup->hdwq, cpup->eq, cpup->irq, cpup->flag); } + + /* The cpu_map array will be used later during initialization + * when EQ / CQ / WQs are allocated and configured. + */ return; } @@ -10805,10 +11044,10 @@ vec_fail_out: * @phba: pointer to lpfc hba data structure. * * This routine is invoked to enable the MSI interrupt mode to device with - * SLI-4 interface spec. The kernel function pci_enable_msi() is called - * to enable the MSI vector. The device driver is responsible for calling - * the request_irq() to register MSI vector with a interrupt the handler, - * which is done in this function. + * SLI-4 interface spec. The kernel function pci_alloc_irq_vectors() is + * called to enable the MSI vector. The device driver is responsible for + * calling the request_irq() to register MSI vector with a interrupt the + * handler, which is done in this function. * * Return codes * 0 - successful @@ -10819,20 +11058,21 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) { int rc, index; - rc = pci_enable_msi(phba->pcidev); - if (!rc) + rc = pci_alloc_irq_vectors(phba->pcidev, 1, 1, + PCI_IRQ_MSI | PCI_IRQ_AFFINITY); + if (rc > 0) lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0487 PCI enable MSI mode success.\n"); else { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0488 PCI enable MSI mode failed (%d)\n", rc); - return rc; + return rc ? rc : -1; } rc = request_irq(phba->pcidev->irq, lpfc_sli4_intr_handler, 0, LPFC_DRIVER_NAME, phba); if (rc) { - pci_disable_msi(phba->pcidev); + pci_free_irq_vectors(phba->pcidev); lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0490 MSI request_irq failed (%d)\n", rc); return rc; @@ -10998,11 +11238,10 @@ static void lpfc_sli4_xri_exchange_busy_wait(struct lpfc_hba *phba) { struct lpfc_sli4_hdw_queue *qp; - int idx, ccnt, fcnt; + int idx, ccnt; int wait_time = 0; int io_xri_cmpl = 1; int nvmet_xri_cmpl = 1; - int fcp_xri_cmpl = 1; int els_xri_cmpl = list_empty(&phba->sli4_hba.lpfc_abts_els_sgl_list); /* Driver just aborted IOs during the hba_unset process. Pause @@ -11016,32 +11255,21 @@ lpfc_sli4_xri_exchange_busy_wait(struct lpfc_hba *phba) lpfc_nvme_wait_for_io_drain(phba); ccnt = 0; - fcnt = 0; for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { qp = &phba->sli4_hba.hdwq[idx]; - fcp_xri_cmpl = list_empty( - &qp->lpfc_abts_scsi_buf_list); - if (!fcp_xri_cmpl) /* if list is NOT empty */ - fcnt++; - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - io_xri_cmpl = list_empty( - &qp->lpfc_abts_nvme_buf_list); - if (!io_xri_cmpl) /* if list is NOT empty */ - ccnt++; - } + io_xri_cmpl = list_empty(&qp->lpfc_abts_io_buf_list); + if (!io_xri_cmpl) /* if list is NOT empty */ + ccnt++; } if (ccnt) io_xri_cmpl = 0; - if (fcnt) - fcp_xri_cmpl = 0; if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { nvmet_xri_cmpl = list_empty(&phba->sli4_hba.lpfc_abts_nvmet_ctx_list); } - while (!fcp_xri_cmpl || !els_xri_cmpl || !io_xri_cmpl || - !nvmet_xri_cmpl) { + while (!els_xri_cmpl || !io_xri_cmpl || !nvmet_xri_cmpl) { if (wait_time > LPFC_XRI_EXCH_BUSY_WAIT_TMO) { if (!nvmet_xri_cmpl) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, @@ -11050,12 +11278,7 @@ lpfc_sli4_xri_exchange_busy_wait(struct lpfc_hba *phba) wait_time/1000); if (!io_xri_cmpl) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "6100 NVME XRI exchange busy " - "wait time: %d seconds.\n", - wait_time/1000); - if (!fcp_xri_cmpl) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2877 FCP XRI exchange busy " + "6100 IO XRI exchange busy " "wait time: %d seconds.\n", wait_time/1000); if (!els_xri_cmpl) @@ -11071,24 +11294,15 @@ lpfc_sli4_xri_exchange_busy_wait(struct lpfc_hba *phba) } ccnt = 0; - fcnt = 0; for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { qp = &phba->sli4_hba.hdwq[idx]; - fcp_xri_cmpl = list_empty( - &qp->lpfc_abts_scsi_buf_list); - if (!fcp_xri_cmpl) /* if list is NOT empty */ - fcnt++; - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - io_xri_cmpl = list_empty( - &qp->lpfc_abts_nvme_buf_list); - if (!io_xri_cmpl) /* if list is NOT empty */ - ccnt++; - } + io_xri_cmpl = list_empty( + &qp->lpfc_abts_io_buf_list); + if (!io_xri_cmpl) /* if list is NOT empty */ + ccnt++; } if (ccnt) io_xri_cmpl = 0; - if (fcnt) - fcp_xri_cmpl = 0; if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { nvmet_xri_cmpl = list_empty( @@ -11331,24 +11545,56 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) mbx_sli4_parameters); phba->sli4_hba.extents_in_use = bf_get(cfg_ext, mbx_sli4_parameters); phba->sli4_hba.rpi_hdrs_in_use = bf_get(cfg_hdrr, mbx_sli4_parameters); - phba->nvme_support = (bf_get(cfg_nvme, mbx_sli4_parameters) && - bf_get(cfg_xib, mbx_sli4_parameters)); - - if ((phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP) || - !phba->nvme_support) { - phba->nvme_support = 0; - phba->nvmet_support = 0; - phba->cfg_nvmet_mrq = 0; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_NVME, - "6101 Disabling NVME support: " - "Not supported by firmware: %d %d\n", - bf_get(cfg_nvme, mbx_sli4_parameters), - bf_get(cfg_xib, mbx_sli4_parameters)); - - /* If firmware doesn't support NVME, just use SCSI support */ - if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP)) - return -ENODEV; - phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP; + + /* Check for Extended Pre-Registered SGL support */ + phba->cfg_xpsgl = bf_get(cfg_xpsgl, mbx_sli4_parameters); + + /* Check for firmware nvme support */ + rc = (bf_get(cfg_nvme, mbx_sli4_parameters) && + bf_get(cfg_xib, mbx_sli4_parameters)); + + if (rc) { + /* Save this to indicate the Firmware supports NVME */ + sli4_params->nvme = 1; + + /* Firmware NVME support, check driver FC4 NVME support */ + if (phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_NVME, + "6133 Disabling NVME support: " + "FC4 type not supported: x%x\n", + phba->cfg_enable_fc4_type); + goto fcponly; + } + } else { + /* No firmware NVME support, check driver FC4 NVME support */ + sli4_params->nvme = 0; + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_NVME, + "6101 Disabling NVME support: Not " + "supported by firmware (%d %d) x%x\n", + bf_get(cfg_nvme, mbx_sli4_parameters), + bf_get(cfg_xib, mbx_sli4_parameters), + phba->cfg_enable_fc4_type); +fcponly: + phba->nvme_support = 0; + phba->nvmet_support = 0; + phba->cfg_nvmet_mrq = 0; + phba->cfg_nvme_seg_cnt = 0; + + /* If no FC4 type support, move to just SCSI support */ + if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP)) + return -ENODEV; + phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP; + } + } + + /* If the NVME FC4 type is enabled, scale the sg_seg_cnt to + * accommodate 512K and 1M IOs in a single nvme buf and supply + * enough NVME LS iocb buffers for larger connectivity counts. + */ + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { + phba->cfg_sg_seg_cnt = LPFC_MAX_NVME_SEG_CNT; + phba->cfg_iocb_cnt = 5; } /* Only embed PBDE for if_type 6, PBDE support requires xib be set */ @@ -11415,6 +11661,14 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) else phba->mds_diags_support = 0; + /* + * Check if the SLI port supports NSLER + */ + if (bf_get(cfg_nsler, mbx_sli4_parameters)) + phba->nsler = 1; + else + phba->nsler = 0; + return 0; } @@ -11843,7 +12097,7 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) lpfc_scsi_dev_block(phba); /* Flush all driver's outstanding SCSI I/Os as we are to reset */ - lpfc_sli_flush_fcp_rings(phba); + lpfc_sli_flush_io_rings(phba); /* stop all timers */ lpfc_stop_hba_timers(phba); @@ -11873,7 +12127,7 @@ lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba) lpfc_stop_hba_timers(phba); /* Clean up all driver's outstanding SCSI I/Os */ - lpfc_sli_flush_fcp_rings(phba); + lpfc_sli_flush_io_rings(phba); } /** @@ -12645,12 +12899,8 @@ lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba) /* Block all SCSI devices' I/Os on the host */ lpfc_scsi_dev_block(phba); - /* Flush all driver's outstanding SCSI I/Os as we are to reset */ - lpfc_sli_flush_fcp_rings(phba); - - /* Flush the outstanding NVME IOs if fc4 type enabled. */ - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) - lpfc_sli_flush_nvme_rings(phba); + /* Flush all driver's outstanding I/Os as we are to reset */ + lpfc_sli_flush_io_rings(phba); /* stop all timers */ lpfc_stop_hba_timers(phba); @@ -12681,12 +12931,8 @@ lpfc_sli4_prep_dev_for_perm_failure(struct lpfc_hba *phba) /* stop all timers */ lpfc_stop_hba_timers(phba); - /* Clean up all driver's outstanding SCSI I/Os */ - lpfc_sli_flush_fcp_rings(phba); - - /* Flush the outstanding NVME IOs if fc4 type enabled. */ - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) - lpfc_sli_flush_nvme_rings(phba); + /* Clean up all driver's outstanding I/Os */ + lpfc_sli_flush_io_rings(phba); } /** @@ -13227,19 +13473,6 @@ lpfc_exit(void) pci_unregister_driver(&lpfc_driver); fc_release_transport(lpfc_transport_template); fc_release_transport(lpfc_vport_transport_template); - if (_dump_buf_data) { - printk(KERN_ERR "9062 BLKGRD: freeing %lu pages for " - "_dump_buf_data at 0x%p\n", - (1L << _dump_buf_data_order), _dump_buf_data); - free_pages((unsigned long)_dump_buf_data, _dump_buf_data_order); - } - - if (_dump_buf_dif) { - printk(KERN_ERR "9049 BLKGRD: freeing %lu pages for " - "_dump_buf_dif at 0x%p\n", - (1L << _dump_buf_dif_order), _dump_buf_dif); - free_pages((unsigned long)_dump_buf_dif, _dump_buf_dif_order); - } idr_destroy(&lpfc_hba_index); } diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 66191fa35f63..ae09bb863497 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -72,8 +72,8 @@ lpfc_mem_alloc_active_rrq_pool_s4(struct lpfc_hba *phba) { * lpfc_mem_alloc - create and allocate all PCI and memory pools * @phba: HBA to allocate pools for * - * Description: Creates and allocates PCI pools lpfc_sg_dma_buf_pool, - * lpfc_mbuf_pool, lpfc_hrb_pool. Creates and allocates kmalloc-backed mempools + * Description: Creates and allocates PCI pools lpfc_mbuf_pool, + * lpfc_hrb_pool. Creates and allocates kmalloc-backed mempools * for LPFC_MBOXQ_t and lpfc_nodelist. Also allocates the VPI bitmask. * * Notes: Not interrupt-safe. Must be called with no locks held. If any @@ -89,36 +89,12 @@ lpfc_mem_alloc(struct lpfc_hba *phba, int align) struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool; int i; - if (phba->sli_rev == LPFC_SLI_REV4) { - /* Calculate alignment */ - if (phba->cfg_sg_dma_buf_size < SLI4_PAGE_SIZE) - i = phba->cfg_sg_dma_buf_size; - else - i = SLI4_PAGE_SIZE; - - phba->lpfc_sg_dma_buf_pool = - dma_pool_create("lpfc_sg_dma_buf_pool", - &phba->pcidev->dev, - phba->cfg_sg_dma_buf_size, - i, 0); - if (!phba->lpfc_sg_dma_buf_pool) - goto fail; - - } else { - phba->lpfc_sg_dma_buf_pool = - dma_pool_create("lpfc_sg_dma_buf_pool", - &phba->pcidev->dev, phba->cfg_sg_dma_buf_size, - align, 0); - - if (!phba->lpfc_sg_dma_buf_pool) - goto fail; - } phba->lpfc_mbuf_pool = dma_pool_create("lpfc_mbuf_pool", &phba->pcidev->dev, LPFC_BPL_SIZE, align, 0); if (!phba->lpfc_mbuf_pool) - goto fail_free_dma_buf_pool; + goto fail; pool->elements = kmalloc_array(LPFC_MBUF_POOL_SIZE, sizeof(struct lpfc_dmabuf), @@ -208,9 +184,6 @@ fail_free_drb_pool: fail_free_lpfc_mbuf_pool: dma_pool_destroy(phba->lpfc_mbuf_pool); phba->lpfc_mbuf_pool = NULL; - fail_free_dma_buf_pool: - dma_pool_destroy(phba->lpfc_sg_dma_buf_pool); - phba->lpfc_sg_dma_buf_pool = NULL; fail: return -ENOMEM; } @@ -248,25 +221,22 @@ lpfc_mem_free(struct lpfc_hba *phba) /* Free HBQ pools */ lpfc_sli_hbqbuf_free_all(phba); - if (phba->lpfc_nvmet_drb_pool) - dma_pool_destroy(phba->lpfc_nvmet_drb_pool); + dma_pool_destroy(phba->lpfc_nvmet_drb_pool); phba->lpfc_nvmet_drb_pool = NULL; - if (phba->lpfc_drb_pool) - dma_pool_destroy(phba->lpfc_drb_pool); + + dma_pool_destroy(phba->lpfc_drb_pool); phba->lpfc_drb_pool = NULL; - if (phba->lpfc_hrb_pool) - dma_pool_destroy(phba->lpfc_hrb_pool); + + dma_pool_destroy(phba->lpfc_hrb_pool); phba->lpfc_hrb_pool = NULL; - if (phba->txrdy_payload_pool) - dma_pool_destroy(phba->txrdy_payload_pool); + + dma_pool_destroy(phba->txrdy_payload_pool); phba->txrdy_payload_pool = NULL; - if (phba->lpfc_hbq_pool) - dma_pool_destroy(phba->lpfc_hbq_pool); + dma_pool_destroy(phba->lpfc_hbq_pool); phba->lpfc_hbq_pool = NULL; - if (phba->rrq_pool) - mempool_destroy(phba->rrq_pool); + mempool_destroy(phba->rrq_pool); phba->rrq_pool = NULL; /* Free NLP memory pool */ @@ -290,10 +260,6 @@ lpfc_mem_free(struct lpfc_hba *phba) dma_pool_destroy(phba->lpfc_mbuf_pool); phba->lpfc_mbuf_pool = NULL; - /* Free DMA buffer memory pool */ - dma_pool_destroy(phba->lpfc_sg_dma_buf_pool); - phba->lpfc_sg_dma_buf_pool = NULL; - /* Free Device Data memory pool */ if (phba->device_data_mem_pool) { /* Ensure all objects have been returned to the pool */ @@ -366,6 +332,13 @@ lpfc_mem_free_all(struct lpfc_hba *phba) /* Free and destroy all the allocated memory pools */ lpfc_mem_free(phba); + /* Free DMA buffer memory pool */ + dma_pool_destroy(phba->lpfc_sg_dma_buf_pool); + phba->lpfc_sg_dma_buf_pool = NULL; + + dma_pool_destroy(phba->lpfc_cmd_rsp_buf_pool); + phba->lpfc_cmd_rsp_buf_pool = NULL; + /* Free the iocb lookup array */ kfree(psli->iocbq_lookup); psli->iocbq_lookup = NULL; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 59252bfca14e..fc6e4546d738 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -614,7 +614,7 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } out: /* If we are authenticated, move to the proper state */ - if (ndlp->nlp_type & NLP_FCP_TARGET) + if (ndlp->nlp_type & (NLP_FCP_TARGET | NLP_NVME_TARGET)) lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); else lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); @@ -799,9 +799,15 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (npr->writeXferRdyDis) ndlp->nlp_flag |= NLP_FIRSTBURST; } - if (npr->Retry) + if (npr->Retry && ndlp->nlp_type & + (NLP_FCP_INITIATOR | NLP_FCP_TARGET)) ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; + if (npr->Retry && phba->nsler && + ndlp->nlp_type & (NLP_NVME_INITIATOR | NLP_NVME_TARGET)) + ndlp->nlp_nvme_info |= NLP_NVME_NSLER; + + /* If this driver is in nvme target mode, set the ndlp's fc4 * type to NVME provided the PRLI response claims NVME FC4 * type. Target mode does not issue gft_id so doesn't get @@ -845,9 +851,9 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (!(vport->fc_flag & FC_PT2PT)) { /* Check config parameter use-adisc or FCP-2 */ - if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) || + if (vport->cfg_use_adisc && ((vport->fc_flag & FC_RSCN_MODE) || ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) && - (ndlp->nlp_type & NLP_FCP_TARGET))) { + (ndlp->nlp_type & NLP_FCP_TARGET)))) { spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_ADISC; spin_unlock_irq(shost->host_lock); @@ -885,7 +891,7 @@ lpfc_release_rpi(struct lpfc_hba *phba, struct lpfc_vport *vport, lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "1435 release_rpi SKIP UNREG x%x on " "NPort x%x deferred x%x flg x%x " - "Data: %p\n", + "Data: x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_defer_did, ndlp->nlp_flag, ndlp); @@ -1661,6 +1667,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, LPFC_MBOXQ_t *mb; LPFC_MBOXQ_t *nextmb; struct lpfc_dmabuf *mp; + struct lpfc_nodelist *ns_ndlp; cmdiocb = (struct lpfc_iocbq *) arg; @@ -1693,6 +1700,13 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, } spin_unlock_irq(&phba->hbalock); + /* software abort if any GID_FT is outstanding */ + if (vport->cfg_enable_fc4_type != LPFC_ENABLE_FCP) { + ns_ndlp = lpfc_findnode_did(vport, NameServer_DID); + if (ns_ndlp && NLP_CHK_NODE_ACT(ns_ndlp)) + lpfc_els_abort(phba, ns_ndlp); + } + lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } @@ -1814,7 +1828,11 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE); - lpfc_issue_els_prli(vport, ndlp, 0); + if (lpfc_issue_els_prli(vport, ndlp, 0)) { + lpfc_issue_els_logo(vport, ndlp, 0); + ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + } } else { if ((vport->fc_flag & FC_PT2PT) && phba->nvmet_support) phba->targetport->port_id = vport->fc_myDID; @@ -2012,6 +2030,11 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (bf_get_be32(prli_init, nvpr)) ndlp->nlp_type |= NLP_NVME_INITIATOR; + if (phba->nsler && bf_get_be32(prli_nsler, nvpr)) + ndlp->nlp_nvme_info |= NLP_NVME_NSLER; + else + ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER; + /* Target driver cannot solicit NVME FB. */ if (bf_get_be32(prli_tgt, nvpr)) { /* Complete the nvme target roles. The transport @@ -2891,18 +2914,21 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *, uint32_t); uint32_t got_ndlp = 0; + uint32_t data1; if (lpfc_nlp_get(ndlp)) got_ndlp = 1; cur_state = ndlp->nlp_state; + data1 = (((uint32_t)ndlp->nlp_fc4_type << 16) | + ((uint32_t)ndlp->nlp_type)); /* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0211 DSM in event x%x on NPort x%x in " "state %d rpi x%x Data: x%x x%x\n", evt, ndlp->nlp_DID, cur_state, ndlp->nlp_rpi, - ndlp->nlp_flag, ndlp->nlp_fc4_type); + ndlp->nlp_flag, data1); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, "DSM in: evt:%d ste:%d did:x%x", @@ -2913,10 +2939,13 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* DSM out state <rc> on NPort <nlp_DID> */ if (got_ndlp) { + data1 = (((uint32_t)ndlp->nlp_fc4_type << 16) | + ((uint32_t)ndlp->nlp_type)); lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0212 DSM out state %d on NPort x%x " - "rpi x%x Data: x%x\n", - rc, ndlp->nlp_DID, ndlp->nlp_rpi, ndlp->nlp_flag); + "rpi x%x Data: x%x x%x\n", + rc, ndlp->nlp_DID, ndlp->nlp_rpi, ndlp->nlp_flag, + data1); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, "DSM out: ste:%d did:x%x flg:x%x", diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index fdd16d9f55a1..a227e36cbdc2 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -247,7 +247,7 @@ lpfc_nvme_create_queue(struct nvme_fc_local_port *pnvme_lport, lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME, "6073 Binding %s HdwQueue %d (cpu %d) to " - "hdw_queue %d qhandle %p\n", str, + "hdw_queue %d qhandle x%px\n", str, qidx, qhandle->cpu_id, qhandle->index, qhandle); *handle = (void *)qhandle; return 0; @@ -282,7 +282,7 @@ lpfc_nvme_delete_queue(struct nvme_fc_local_port *pnvme_lport, vport = lport->vport; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME, - "6001 ENTER. lpfc_pnvme %p, qidx x%x qhandle %p\n", + "6001 ENTER. lpfc_pnvme x%px, qidx x%x qhandle x%px\n", lport, qidx, handle); kfree(handle); } @@ -293,7 +293,7 @@ lpfc_nvme_localport_delete(struct nvme_fc_local_port *localport) struct lpfc_nvme_lport *lport = localport->private; lpfc_printf_vlog(lport->vport, KERN_INFO, LOG_NVME, - "6173 localport %p delete complete\n", + "6173 localport x%px delete complete\n", lport); /* release any threads waiting for the unreg to complete */ @@ -332,7 +332,7 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) * calling state machine to remove the node. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, - "6146 remoteport delete of remoteport %p\n", + "6146 remoteport delete of remoteport x%px\n", remoteport); spin_lock_irq(&vport->phba->hbalock); @@ -383,8 +383,8 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, ndlp = (struct lpfc_nodelist *)cmdwqe->context1; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6047 nvme cmpl Enter " - "Data %p DID %x Xri: %x status %x reason x%x cmd:%p " - "lsreg:%p bmp:%p ndlp:%p\n", + "Data %px DID %x Xri: %x status %x reason x%x " + "cmd:x%px lsreg:x%px bmp:x%px ndlp:x%px\n", pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0, cmdwqe->sli4_xritag, status, (wcqe->parameter & 0xffff), @@ -404,7 +404,7 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, else lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, "6046 nvme cmpl without done call back? " - "Data %p DID %x Xri: %x status %x\n", + "Data %px DID %x Xri: %x status %x\n", pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0, cmdwqe->sli4_xritag, status); if (ndlp) { @@ -436,6 +436,7 @@ lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, return 1; wqe = &genwqe->wqe; + /* Initialize only 64 bytes */ memset(wqe, 0, sizeof(union lpfc_wqe)); genwqe->context3 = (uint8_t *)bmp; @@ -516,7 +517,8 @@ lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, /* Issue GEN REQ WQE for NPORT <did> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "6050 Issue GEN REQ WQE to NPORT x%x " - "Data: x%x x%x wq:%p lsreq:%p bmp:%p xmit:%d 1st:%d\n", + "Data: x%x x%x wq:x%px lsreq:x%px bmp:x%px " + "xmit:%d 1st:%d\n", ndlp->nlp_DID, genwqe->iotag, vport->port_state, genwqe, pnvme_lsreq, bmp, xmit_len, first_len); @@ -594,7 +596,7 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, ndlp = rport->ndlp; if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR, - "6051 Remoteport %p, rport has invalid ndlp. " + "6051 Remoteport x%px, rport has invalid ndlp. " "Failing LS Req\n", pnvme_rport); return -ENODEV; } @@ -646,10 +648,10 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, /* Expand print to include key fields. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, - "6149 Issue LS Req to DID 0x%06x lport %p, rport %p " - "lsreq%p rqstlen:%d rsplen:%d %pad %pad\n", - ndlp->nlp_DID, - pnvme_lport, pnvme_rport, + "6149 Issue LS Req to DID 0x%06x lport x%px, " + "rport x%px lsreq x%px rqstlen:%d rsplen:%d " + "%pad %pad\n", + ndlp->nlp_DID, pnvme_lport, pnvme_rport, pnvme_lsreq, pnvme_lsreq->rqstlen, pnvme_lsreq->rsplen, &pnvme_lsreq->rqstdma, &pnvme_lsreq->rspdma); @@ -665,8 +667,8 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, if (ret != WQE_SUCCESS) { atomic_inc(&lport->xmt_ls_err); lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, - "6052 EXIT. issue ls wqe failed lport %p, " - "rport %p lsreq%p Status %x DID %x\n", + "6052 EXIT. issue ls wqe failed lport x%px, " + "rport x%px lsreq x%px Status %x DID %x\n", pnvme_lport, pnvme_rport, pnvme_lsreq, ret, ndlp->nlp_DID); lpfc_mbuf_free(vport->phba, bmp->virt, bmp->phys); @@ -723,7 +725,7 @@ lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport, /* Expand print to include key fields. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_ABTS, - "6040 ENTER. lport %p, rport %p lsreq %p rqstlen:%d " + "6040 ENTER. lport x%px, rport x%px lsreq x%px rqstlen:%d " "rsplen:%d %pad %pad\n", pnvme_lport, pnvme_rport, pnvme_lsreq, pnvme_lsreq->rqstlen, @@ -984,8 +986,8 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, if (!lpfc_ncmd->nvmeCmd) { spin_unlock(&lpfc_ncmd->buf_lock); lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR, - "6066 Missing cmpl ptrs: lpfc_ncmd %p, " - "nvmeCmd %p\n", + "6066 Missing cmpl ptrs: lpfc_ncmd x%px, " + "nvmeCmd x%px\n", lpfc_ncmd, lpfc_ncmd->nvmeCmd); /* Release the lpfc_ncmd regardless of the missing elements. */ @@ -998,9 +1000,9 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, idx = lpfc_ncmd->cur_iocbq.hba_wqidx; phba->sli4_hba.hdwq[idx].nvme_cstat.io_cmpls++; - if (vport->localport) { + if (unlikely(status && vport->localport)) { lport = (struct lpfc_nvme_lport *)vport->localport->private; - if (lport && status) { + if (lport) { if (bf_get(lpfc_wcqe_c_xb, wcqe)) atomic_inc(&lport->cmpl_fcp_xb); atomic_inc(&lport->cmpl_fcp_err); @@ -1100,8 +1102,8 @@ lpfc_nvme_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn, if (lpfc_ncmd->result == IOERR_ABORT_REQUESTED) lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, - "6032 Delay Aborted cmd %p " - "nvme cmd %p, xri x%x, " + "6032 Delay Aborted cmd x%px " + "nvme cmd x%px, xri x%x, " "xb %d\n", lpfc_ncmd, nCmd, lpfc_ncmd->cur_iocbq.sli4_xritag, @@ -1140,7 +1142,7 @@ out_err: phba->ktime_last_cmd = lpfc_ncmd->ts_data_nvme; lpfc_nvme_ktime(phba, lpfc_ncmd); } - if (phba->cpucheck_on & LPFC_CHECK_NVME_IO) { + if (unlikely(phba->cpucheck_on & LPFC_CHECK_NVME_IO)) { uint32_t cpu; idx = lpfc_ncmd->cur_iocbq.hba_wqidx; cpu = raw_smp_processor_id(); @@ -1253,6 +1255,9 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, sizeof(uint32_t) * 8); cstat->control_requests++; } + + if (pnode->nlp_nvme_info & NLP_NVME_NSLER) + bf_set(wqe_erp, &wqe->generic.wqe_com, 1); /* * Finish initializing those WQE fields that are independent * of the nvme_cmnd request_buffer @@ -1304,14 +1309,16 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, struct nvmefc_fcp_req *nCmd = lpfc_ncmd->nvmeCmd; union lpfc_wqe128 *wqe = &lpfc_ncmd->cur_iocbq.wqe; struct sli4_sge *sgl = lpfc_ncmd->dma_sgl; + struct sli4_hybrid_sgl *sgl_xtra = NULL; struct scatterlist *data_sg; struct sli4_sge *first_data_sgl; struct ulp_bde64 *bde; - dma_addr_t physaddr; + dma_addr_t physaddr = 0; uint32_t num_bde = 0; - uint32_t dma_len; + uint32_t dma_len = 0; uint32_t dma_offset = 0; - int nseg, i; + int nseg, i, j; + bool lsp_just_set = false; /* Fix up the command and response DMA stuff. */ lpfc_nvme_adj_fcp_sgls(vport, lpfc_ncmd, nCmd); @@ -1348,6 +1355,9 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, */ nseg = nCmd->sg_cnt; data_sg = nCmd->first_sgl; + + /* for tracking the segment boundaries */ + j = 2; for (i = 0; i < nseg; i++) { if (data_sg == NULL) { lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, @@ -1356,23 +1366,76 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport, lpfc_ncmd->seg_cnt = 0; return 1; } - physaddr = data_sg->dma_address; - dma_len = data_sg->length; - sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr)); - sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr)); - sgl->word2 = le32_to_cpu(sgl->word2); - if ((num_bde + 1) == nseg) + + sgl->word2 = 0; + if ((num_bde + 1) == nseg) { bf_set(lpfc_sli4_sge_last, sgl, 1); - else + bf_set(lpfc_sli4_sge_type, sgl, + LPFC_SGE_TYPE_DATA); + } else { bf_set(lpfc_sli4_sge_last, sgl, 0); - bf_set(lpfc_sli4_sge_offset, sgl, dma_offset); - bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); - sgl->word2 = cpu_to_le32(sgl->word2); - sgl->sge_len = cpu_to_le32(dma_len); - - dma_offset += dma_len; - data_sg = sg_next(data_sg); - sgl++; + + /* expand the segment */ + if (!lsp_just_set && + !((j + 1) % phba->border_sge_num) && + ((nseg - 1) != i)) { + /* set LSP type */ + bf_set(lpfc_sli4_sge_type, sgl, + LPFC_SGE_TYPE_LSP); + + sgl_xtra = lpfc_get_sgl_per_hdwq( + phba, lpfc_ncmd); + + if (unlikely(!sgl_xtra)) { + lpfc_ncmd->seg_cnt = 0; + return 1; + } + sgl->addr_lo = cpu_to_le32(putPaddrLow( + sgl_xtra->dma_phys_sgl)); + sgl->addr_hi = cpu_to_le32(putPaddrHigh( + sgl_xtra->dma_phys_sgl)); + + } else { + bf_set(lpfc_sli4_sge_type, sgl, + LPFC_SGE_TYPE_DATA); + } + } + + if (!(bf_get(lpfc_sli4_sge_type, sgl) & + LPFC_SGE_TYPE_LSP)) { + if ((nseg - 1) == i) + bf_set(lpfc_sli4_sge_last, sgl, 1); + + physaddr = data_sg->dma_address; + dma_len = data_sg->length; + sgl->addr_lo = cpu_to_le32( + putPaddrLow(physaddr)); + sgl->addr_hi = cpu_to_le32( + putPaddrHigh(physaddr)); + + bf_set(lpfc_sli4_sge_offset, sgl, dma_offset); + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->sge_len = cpu_to_le32(dma_len); + + dma_offset += dma_len; + data_sg = sg_next(data_sg); + + sgl++; + + lsp_just_set = false; + } else { + sgl->word2 = cpu_to_le32(sgl->word2); + + sgl->sge_len = cpu_to_le32( + phba->cfg_sg_dma_buf_size); + + sgl = (struct sli4_sge *)sgl_xtra->dma_sgl; + i = i - 1; + + lsp_just_set = true; + } + + j++; } if (phba->cfg_enable_pbde) { /* Use PBDE support for first SGL only, offset == 0 */ @@ -1474,7 +1537,7 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, goto out_fail; } - if (vport->load_flag & FC_UNLOADING) { + if (unlikely(vport->load_flag & FC_UNLOADING)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, "6124 Fail IO, Driver unload\n"); atomic_inc(&lport->xmt_fcp_err); @@ -1505,8 +1568,8 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport, ndlp = rport->ndlp; if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_NVME_IOERR, - "6053 Fail IO, ndlp not ready: rport %p " - "ndlp %p, DID x%06x\n", + "6053 Busy IO, ndlp not ready: rport x%px " + "ndlp x%px, DID x%06x\n", rport, ndlp, pnvme_rport->port_id); atomic_inc(&lport->xmt_fcp_err); ret = -EBUSY; @@ -1758,7 +1821,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, /* Announce entry to new IO submit field. */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_ABTS, "6002 Abort Request to rport DID x%06x " - "for nvme_fc_req %p\n", + "for nvme_fc_req x%px\n", pnvme_rport->port_id, pnvme_fcreq); @@ -1767,7 +1830,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, */ spin_lock_irqsave(&phba->hbalock, flags); /* driver queued commands are in process of being flushed */ - if (phba->hba_flag & HBA_NVME_IOQ_FLUSH) { + if (phba->hba_flag & HBA_IOQ_FLUSH) { spin_unlock_irqrestore(&phba->hbalock, flags); lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, "6139 Driver in reset cleanup - flushing " @@ -1805,8 +1868,8 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, if (lpfc_nbuf->nvmeCmd != pnvme_fcreq) { lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, "6143 NVME req mismatch: " - "lpfc_nbuf %p nvmeCmd %p, " - "pnvme_fcreq %p. Skipping Abort xri x%x\n", + "lpfc_nbuf x%px nvmeCmd x%px, " + "pnvme_fcreq x%px. Skipping Abort xri x%x\n", lpfc_nbuf, lpfc_nbuf->nvmeCmd, pnvme_fcreq, nvmereq_wqe->sli4_xritag); goto out_unlock; @@ -1815,7 +1878,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, /* Don't abort IOs no longer on the pending queue. */ if (!(nvmereq_wqe->iocb_flag & LPFC_IO_ON_TXCMPLQ)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, - "6142 NVME IO req %p not queued - skipping " + "6142 NVME IO req x%px not queued - skipping " "abort req xri x%x\n", pnvme_fcreq, nvmereq_wqe->sli4_xritag); goto out_unlock; @@ -1830,8 +1893,8 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, if (nvmereq_wqe->iocb_flag & LPFC_DRIVER_ABORTED) { lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, "6144 Outstanding NVME I/O Abort Request " - "still pending on nvme_fcreq %p, " - "lpfc_ncmd %p xri x%x\n", + "still pending on nvme_fcreq x%px, " + "lpfc_ncmd %px xri x%x\n", pnvme_fcreq, lpfc_nbuf, nvmereq_wqe->sli4_xritag); goto out_unlock; @@ -1841,7 +1904,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, if (!abts_buf) { lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, "6136 No available abort wqes. Skipping " - "Abts req for nvme_fcreq %p xri x%x\n", + "Abts req for nvme_fcreq x%px xri x%x\n", pnvme_fcreq, nvmereq_wqe->sli4_xritag); goto out_unlock; } @@ -1855,7 +1918,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, /* WQEs are reused. Clear stale data and set key fields to * zero like ia, iaab, iaar, xri_tag, and ctxt_tag. */ - memset(abts_wqe, 0, sizeof(union lpfc_wqe)); + memset(abts_wqe, 0, sizeof(*abts_wqe)); bf_set(abort_cmd_criteria, &abts_wqe->abort_cmd, T_XRI_TAG); /* word 7 */ @@ -1892,7 +1955,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, if (ret_val) { lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, "6137 Failed abts issue_wqe with status x%x " - "for nvme_fcreq %p.\n", + "for nvme_fcreq x%px.\n", ret_val, pnvme_fcreq); lpfc_sli_release_iocbq(phba, abts_buf); return; @@ -1982,7 +2045,7 @@ lpfc_get_nvme_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, sgl->word2 = cpu_to_le32(sgl->word2); /* Fill in word 3 / sgl_len during cmd submission */ - /* Initialize WQE */ + /* Initialize 64 bytes only */ memset(wqe, 0, sizeof(union lpfc_wqe)); if (lpfc_ndlp_check_qdepth(phba, ndlp)) { @@ -2028,11 +2091,11 @@ lpfc_release_nvme_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd) lpfc_ncmd->cur_iocbq.sli4_xritag, lpfc_ncmd->cur_iocbq.iotag); - spin_lock_irqsave(&qp->abts_nvme_buf_list_lock, iflag); + spin_lock_irqsave(&qp->abts_io_buf_list_lock, iflag); list_add_tail(&lpfc_ncmd->list, - &qp->lpfc_abts_nvme_buf_list); + &qp->lpfc_abts_io_buf_list); qp->abts_nvme_io_bufs++; - spin_unlock_irqrestore(&qp->abts_nvme_buf_list_lock, iflag); + spin_unlock_irqrestore(&qp->abts_io_buf_list_lock, iflag); } else lpfc_release_io_buf(phba, (struct lpfc_io_buf *)lpfc_ncmd, qp); } @@ -2095,8 +2158,8 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) if (!ret) { lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME | LOG_NVME_DISC, "6005 Successfully registered local " - "NVME port num %d, localP %p, private %p, " - "sg_seg %d\n", + "NVME port num %d, localP x%px, private " + "x%px, sg_seg %d\n", localport->port_num, localport, localport->private, lpfc_nvme_template.max_sgl_segments); @@ -2143,7 +2206,9 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, struct completion *lport_unreg_cmp) { u32 wait_tmo; - int ret; + int ret, i, pending = 0; + struct lpfc_sli_ring *pring; + struct lpfc_hba *phba = vport->phba; /* Host transport has to clean up and confirm requiring an indefinite * wait. Print a message if a 10 second wait expires and renew the @@ -2153,16 +2218,24 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport, while (true) { ret = wait_for_completion_timeout(lport_unreg_cmp, wait_tmo); if (unlikely(!ret)) { + pending = 0; + for (i = 0; i < phba->cfg_hdw_queue; i++) { + pring = phba->sli4_hba.hdwq[i].io_wq->pring; + if (!pring) + continue; + if (pring->txcmplq_cnt) + pending += pring->txcmplq_cnt; + } lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_IOERR, - "6176 Lport %p Localport %p wait " - "timed out. Renewing.\n", - lport, vport->localport); + "6176 Lport x%px Localport x%px wait " + "timed out. Pending %d. Renewing.\n", + lport, vport->localport, pending); continue; } break; } lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR, - "6177 Lport %p Localport %p Complete Success\n", + "6177 Lport x%px Localport x%px Complete Success\n", lport, vport->localport); } #endif @@ -2193,7 +2266,7 @@ lpfc_nvme_destroy_localport(struct lpfc_vport *vport) lport = (struct lpfc_nvme_lport *)localport->private; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME, - "6011 Destroying NVME localport %p\n", + "6011 Destroying NVME localport x%px\n", localport); /* lport's rport list is clear. Unregister @@ -2243,12 +2316,12 @@ lpfc_nvme_update_localport(struct lpfc_vport *vport) lport = (struct lpfc_nvme_lport *)localport->private; if (!lport) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_NVME, - "6171 Update NVME fail. localP %p, No lport\n", + "6171 Update NVME fail. localP x%px, No lport\n", localport); return; } lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME, - "6012 Update NVME lport %p did x%x\n", + "6012 Update NVME lport x%px did x%x\n", localport, vport->fc_myDID); localport->port_id = vport->fc_myDID; @@ -2258,7 +2331,7 @@ lpfc_nvme_update_localport(struct lpfc_vport *vport) localport->port_role = FC_PORT_ROLE_NVME_INITIATOR; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, - "6030 bound lport %p to DID x%06x\n", + "6030 bound lport x%px to DID x%06x\n", lport, localport->port_id); #endif } @@ -2307,9 +2380,13 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) spin_lock_irq(&vport->phba->hbalock); oldrport = lpfc_ndlp_get_nrport(ndlp); - spin_unlock_irq(&vport->phba->hbalock); - if (!oldrport) + if (oldrport) { + prev_ndlp = oldrport->ndlp; + spin_unlock_irq(&vport->phba->hbalock); + } else { + spin_unlock_irq(&vport->phba->hbalock); lpfc_nlp_get(ndlp); + } ret = nvme_fc_register_remoteport(localport, &rpinfo, &remote_port); if (!ret) { @@ -2328,25 +2405,34 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* New remoteport record does not guarantee valid * host private memory area. */ - prev_ndlp = oldrport->ndlp; if (oldrport == remote_port->private) { /* Same remoteport - ndlp should match. * Just reuse. */ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NVME_DISC, - "6014 Rebinding lport to " - "remoteport %p wwpn 0x%llx, " - "Data: x%x x%x %p %p x%x x%06x\n", + "6014 Rebind lport to current " + "remoteport x%px wwpn 0x%llx, " + "Data: x%x x%x x%px x%px x%x " + " x%06x\n", remote_port, remote_port->port_name, remote_port->port_id, remote_port->port_role, - prev_ndlp, + oldrport->ndlp, ndlp, ndlp->nlp_type, ndlp->nlp_DID); - return 0; + + /* It's a complete rebind only if the driver + * is registering with the same ndlp. Otherwise + * the driver likely executed a node swap + * prior to this registration and the ndlp to + * remoteport binding needs to be redone. + */ + if (prev_ndlp == ndlp) + return 0; + } /* Sever the ndlp<->rport association @@ -2380,10 +2466,10 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) spin_unlock_irq(&vport->phba->hbalock); lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC | LOG_NODE, - "6022 Binding new rport to " - "lport %p Remoteport %p rport %p WWNN 0x%llx, " + "6022 Bind lport x%px to remoteport x%px " + "rport x%px WWNN 0x%llx, " "Rport WWPN 0x%llx DID " - "x%06x Role x%x, ndlp %p prev_ndlp %p\n", + "x%06x Role x%x, ndlp %p prev_ndlp x%px\n", lport, remote_port, rport, rpinfo.node_name, rpinfo.port_name, rpinfo.port_id, rpinfo.port_role, @@ -2413,20 +2499,23 @@ void lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { #if (IS_ENABLED(CONFIG_NVME_FC)) - struct lpfc_nvme_rport *rport; - struct nvme_fc_remote_port *remoteport; + struct lpfc_nvme_rport *nrport; + struct nvme_fc_remote_port *remoteport = NULL; - rport = ndlp->nrport; + spin_lock_irq(&vport->phba->hbalock); + nrport = lpfc_ndlp_get_nrport(ndlp); + if (nrport) + remoteport = nrport->remoteport; + spin_unlock_irq(&vport->phba->hbalock); lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, "6170 Rescan NPort DID x%06x type x%x " - "state x%x rport %p\n", - ndlp->nlp_DID, ndlp->nlp_type, ndlp->nlp_state, rport); - if (!rport) - goto input_err; - remoteport = rport->remoteport; - if (!remoteport) - goto input_err; + "state x%x nrport x%px remoteport x%px\n", + ndlp->nlp_DID, ndlp->nlp_type, ndlp->nlp_state, + nrport, remoteport); + + if (!nrport || !remoteport) + goto rescan_exit; /* Only rescan if we are an NVME target in the MAPPED state */ if (remoteport->port_role & FC_PORT_ROLE_NVME_DISCOVERY && @@ -2439,10 +2528,10 @@ lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ndlp->nlp_DID, remoteport->port_state); } return; -input_err: - lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, - "6169 State error: lport %p, rport%p FCID x%06x\n", - vport->localport, ndlp->rport, ndlp->nlp_DID); + rescan_exit: + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, + "6169 Skip NVME Rport Rescan, NVME remoteport " + "unregistered\n"); #endif } @@ -2489,7 +2578,7 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) goto input_err; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, - "6033 Unreg nvme remoteport %p, portname x%llx, " + "6033 Unreg nvme remoteport x%px, portname x%llx, " "port_id x%06x, portstate x%x port type x%x\n", remoteport, remoteport->port_name, remoteport->port_id, remoteport->port_state, @@ -2527,7 +2616,7 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) input_err: #endif lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, - "6168 State error: lport %p, rport%p FCID x%06x\n", + "6168 State error: lport x%px, rport x%px FCID x%06x\n", vport->localport, ndlp->rport, ndlp->nlp_DID); } @@ -2535,6 +2624,7 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * lpfc_sli4_nvme_xri_aborted - Fast-path process of NVME xri abort * @phba: pointer to lpfc hba data structure. * @axri: pointer to the fcp xri abort wcqe structure. + * @lpfc_ncmd: The nvme job structure for the request being aborted. * * This routine is invoked by the worker thread to process a SLI4 fast-path * NVME aborted xri. Aborted NVME IO commands are completed to the transport @@ -2542,59 +2632,33 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) **/ void lpfc_sli4_nvme_xri_aborted(struct lpfc_hba *phba, - struct sli4_wcqe_xri_aborted *axri, int idx) + struct sli4_wcqe_xri_aborted *axri, + struct lpfc_io_buf *lpfc_ncmd) { uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); - struct lpfc_io_buf *lpfc_ncmd, *next_lpfc_ncmd; struct nvmefc_fcp_req *nvme_cmd = NULL; - struct lpfc_nodelist *ndlp; - struct lpfc_sli4_hdw_queue *qp; - unsigned long iflag = 0; + struct lpfc_nodelist *ndlp = lpfc_ncmd->ndlp; - if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) - return; - qp = &phba->sli4_hba.hdwq[idx]; - spin_lock_irqsave(&phba->hbalock, iflag); - spin_lock(&qp->abts_nvme_buf_list_lock); - list_for_each_entry_safe(lpfc_ncmd, next_lpfc_ncmd, - &qp->lpfc_abts_nvme_buf_list, list) { - if (lpfc_ncmd->cur_iocbq.sli4_xritag == xri) { - list_del_init(&lpfc_ncmd->list); - qp->abts_nvme_io_bufs--; - lpfc_ncmd->flags &= ~LPFC_SBUF_XBUSY; - lpfc_ncmd->status = IOSTAT_SUCCESS; - spin_unlock(&qp->abts_nvme_buf_list_lock); - - spin_unlock_irqrestore(&phba->hbalock, iflag); - ndlp = lpfc_ncmd->ndlp; - if (ndlp) - lpfc_sli4_abts_err_handler(phba, ndlp, axri); - - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6311 nvme_cmd %p xri x%x tag x%x " - "abort complete and xri released\n", - lpfc_ncmd->nvmeCmd, xri, - lpfc_ncmd->cur_iocbq.iotag); - - /* Aborted NVME commands are required to not complete - * before the abort exchange command fully completes. - * Once completed, it is available via the put list. - */ - if (lpfc_ncmd->nvmeCmd) { - nvme_cmd = lpfc_ncmd->nvmeCmd; - nvme_cmd->done(nvme_cmd); - lpfc_ncmd->nvmeCmd = NULL; - } - lpfc_release_nvme_buf(phba, lpfc_ncmd); - return; - } - } - spin_unlock(&qp->abts_nvme_buf_list_lock); - spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6312 XRI Aborted xri x%x not found\n", xri); + if (ndlp) + lpfc_sli4_abts_err_handler(phba, ndlp, axri); + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6311 nvme_cmd %p xri x%x tag x%x abort complete and " + "xri released\n", + lpfc_ncmd->nvmeCmd, xri, + lpfc_ncmd->cur_iocbq.iotag); + + /* Aborted NVME commands are required to not complete + * before the abort exchange command fully completes. + * Once completed, it is available via the put list. + */ + if (lpfc_ncmd->nvmeCmd) { + nvme_cmd = lpfc_ncmd->nvmeCmd; + nvme_cmd->done(nvme_cmd); + lpfc_ncmd->nvmeCmd = NULL; + } + lpfc_release_nvme_buf(phba, lpfc_ncmd); } /** @@ -2616,13 +2680,13 @@ lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba) if (phba->sli_rev < LPFC_SLI_REV4 || !phba->sli4_hba.hdwq) return; - /* Cycle through all NVME rings and make sure all outstanding + /* Cycle through all IO rings and make sure all outstanding * WQEs have been removed from the txcmplqs. */ for (i = 0; i < phba->cfg_hdw_queue; i++) { - if (!phba->sli4_hba.hdwq[i].nvme_wq) + if (!phba->sli4_hba.hdwq[i].io_wq) continue; - pring = phba->sli4_hba.hdwq[i].nvme_wq->pring; + pring = phba->sli4_hba.hdwq[i].io_wq->pring; if (!pring) continue; @@ -2643,3 +2707,50 @@ lpfc_nvme_wait_for_io_drain(struct lpfc_hba *phba) } } } + +void +lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn) +{ +#if (IS_ENABLED(CONFIG_NVME_FC)) + struct lpfc_io_buf *lpfc_ncmd; + struct nvmefc_fcp_req *nCmd; + struct lpfc_nvme_fcpreq_priv *freqpriv; + + if (!pwqeIn->context1) { + lpfc_sli_release_iocbq(phba, pwqeIn); + return; + } + /* For abort iocb just return, IO iocb will do a done call */ + if (bf_get(wqe_cmnd, &pwqeIn->wqe.gen_req.wqe_com) == + CMD_ABORT_XRI_CX) { + lpfc_sli_release_iocbq(phba, pwqeIn); + return; + } + lpfc_ncmd = (struct lpfc_io_buf *)pwqeIn->context1; + + spin_lock(&lpfc_ncmd->buf_lock); + if (!lpfc_ncmd->nvmeCmd) { + spin_unlock(&lpfc_ncmd->buf_lock); + lpfc_release_nvme_buf(phba, lpfc_ncmd); + return; + } + + nCmd = lpfc_ncmd->nvmeCmd; + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, + "6194 NVME Cancel xri %x\n", + lpfc_ncmd->cur_iocbq.sli4_xritag); + + nCmd->transferred_length = 0; + nCmd->rcv_rsplen = 0; + nCmd->status = NVME_SC_INTERNAL; + freqpriv = nCmd->private; + freqpriv->nvme_buf = NULL; + lpfc_ncmd->nvmeCmd = NULL; + + spin_unlock(&lpfc_ncmd->buf_lock); + nCmd->done(nCmd); + + /* Call release with XB=1 to queue the IO into the abort list. */ + lpfc_release_nvme_buf(phba, lpfc_ncmd); +#endif +} diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 06170824a69b..9884228800a5 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -220,19 +220,68 @@ lpfc_nvmet_cmd_template(void) /* Word 12, 13, 14, 15 - is zero */ } +#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) +static struct lpfc_nvmet_rcv_ctx * +lpfc_nvmet_get_ctx_for_xri(struct lpfc_hba *phba, u16 xri) +{ + struct lpfc_nvmet_rcv_ctx *ctxp; + unsigned long iflag; + bool found = false; + + spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag); + list_for_each_entry(ctxp, &phba->sli4_hba.t_active_ctx_list, list) { + if (ctxp->ctxbuf->sglq->sli4_xritag != xri) + continue; + + found = true; + break; + } + spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag); + if (found) + return ctxp; + + return NULL; +} + +static struct lpfc_nvmet_rcv_ctx * +lpfc_nvmet_get_ctx_for_oxid(struct lpfc_hba *phba, u16 oxid, u32 sid) +{ + struct lpfc_nvmet_rcv_ctx *ctxp; + unsigned long iflag; + bool found = false; + + spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag); + list_for_each_entry(ctxp, &phba->sli4_hba.t_active_ctx_list, list) { + if (ctxp->oxid != oxid || ctxp->sid != sid) + continue; + + found = true; + break; + } + spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag); + if (found) + return ctxp; + + return NULL; +} +#endif + static void lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp) { lockdep_assert_held(&ctxp->ctxlock); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6313 NVMET Defer ctx release xri x%x flg x%x\n", + "6313 NVMET Defer ctx release oxid x%x flg x%x\n", ctxp->oxid, ctxp->flag); if (ctxp->flag & LPFC_NVMET_CTX_RLS) return; ctxp->flag |= LPFC_NVMET_CTX_RLS; + spin_lock(&phba->sli4_hba.t_active_list_lock); + list_del(&ctxp->list); + spin_unlock(&phba->sli4_hba.t_active_list_lock); spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); list_add_tail(&ctxp->list, &phba->sli4_hba.lpfc_abts_nvmet_ctx_list); spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); @@ -343,16 +392,23 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) } if (ctxp->rqb_buffer) { - nvmebuf = ctxp->rqb_buffer; spin_lock_irqsave(&ctxp->ctxlock, iflag); - ctxp->rqb_buffer = NULL; - if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) { - ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ; - spin_unlock_irqrestore(&ctxp->ctxlock, iflag); - nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf); + nvmebuf = ctxp->rqb_buffer; + /* check if freed in another path whilst acquiring lock */ + if (nvmebuf) { + ctxp->rqb_buffer = NULL; + if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) { + ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ; + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + nvmebuf->hrq->rqbp->rqb_free_buffer(phba, + nvmebuf); + } else { + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + /* repost */ + lpfc_rq_buf_free(phba, &nvmebuf->hbuf); + } } else { spin_unlock_irqrestore(&ctxp->ctxlock, iflag); - lpfc_rq_buf_free(phba, &nvmebuf->hbuf); /* repost */ } } ctxp->state = LPFC_NVMET_STE_FREE; @@ -388,8 +444,9 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) spin_lock_init(&ctxp->ctxlock); #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (ctxp->ts_cmd_nvme) { - ctxp->ts_cmd_nvme = ktime_get_ns(); + /* NOTE: isr time stamp is stale when context is re-assigned*/ + if (ctxp->ts_isr_cmd) { + ctxp->ts_cmd_nvme = 0; ctxp->ts_nvme_data = 0; ctxp->ts_data_wqput = 0; ctxp->ts_isr_data = 0; @@ -402,9 +459,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) #endif atomic_inc(&tgtp->rcv_fcp_cmd_in); - /* flag new work queued, replacement buffer has already - * been reposted - */ + /* Indicate that a replacement buffer has been posted */ spin_lock_irqsave(&ctxp->ctxlock, iflag); ctxp->flag |= LPFC_NVMET_CTX_REUSE_WQ; spin_unlock_irqrestore(&ctxp->ctxlock, iflag); @@ -433,6 +488,9 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) * Use the CPU context list, from the MRQ the IO was received on * (ctxp->idx), to save context structure. */ + spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag); + list_del_init(&ctxp->list); + spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag); cpu = raw_smp_processor_id(); infop = lpfc_get_ctx_list(phba, cpu, ctxp->idx); spin_lock_irqsave(&infop->nvmet_ctx_list_lock, iflag); @@ -700,8 +758,10 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, } lpfc_printf_log(phba, KERN_INFO, logerr, - "6315 IO Error Cmpl xri x%x: %x/%x XBUSY:x%x\n", - ctxp->oxid, status, result, ctxp->flag); + "6315 IO Error Cmpl oxid: x%x xri: x%x %x/%x " + "XBUSY:x%x\n", + ctxp->oxid, ctxp->ctxbuf->sglq->sli4_xritag, + status, result, ctxp->flag); } else { rsp->fcp_error = NVME_SC_SUCCESS; @@ -849,7 +909,6 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, * before freeing ctxp and iocbq. */ lpfc_in_buf_free(phba, &nvmebuf->dbuf); - ctxp->rqb_buffer = 0; atomic_inc(&nvmep->xmt_ls_rsp); return 0; } @@ -922,7 +981,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, (ctxp->state == LPFC_NVMET_STE_ABORT)) { atomic_inc(&lpfc_nvmep->xmt_fcp_drop); lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6102 IO xri x%x aborted\n", + "6102 IO oxid x%x aborted\n", ctxp->oxid); rc = -ENXIO; goto aerr; @@ -967,7 +1026,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, * WQE release CQE */ ctxp->flag |= LPFC_NVMET_DEFER_WQFULL; - wq = ctxp->hdwq->nvme_wq; + wq = ctxp->hdwq->io_wq; pring = wq->pring; spin_lock_irqsave(&pring->ring_lock, iflags); list_add_tail(&nvmewqeq->list, &wq->wqfull_list); @@ -1022,7 +1081,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, ctxp->hdwq = &phba->sli4_hba.hdwq[0]; lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6103 NVMET Abort op: oxri x%x flg x%x ste %d\n", + "6103 NVMET Abort op: oxid x%x flg x%x ste %d\n", ctxp->oxid, ctxp->flag, ctxp->state); lpfc_nvmeio_data(phba, "NVMET FCP ABRT: xri x%x flg x%x ste x%x\n", @@ -1035,7 +1094,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, /* Since iaab/iaar are NOT set, we need to check * if the firmware is in process of aborting IO */ - if (ctxp->flag & LPFC_NVMET_XBUSY) { + if (ctxp->flag & (LPFC_NVMET_XBUSY | LPFC_NVMET_ABORT_OP)) { spin_unlock_irqrestore(&ctxp->ctxlock, flags); return; } @@ -1045,7 +1104,7 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, spin_unlock_irqrestore(&ctxp->ctxlock, flags); lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid, ctxp->oxid); - wq = ctxp->hdwq->nvme_wq; + wq = ctxp->hdwq->io_wq; lpfc_nvmet_wqfull_flush(phba, wq, ctxp); return; } @@ -1098,6 +1157,7 @@ lpfc_nvmet_xmt_fcp_release(struct nvmet_fc_target_port *tgtport, ctxp->state, aborting); atomic_inc(&lpfc_nvmep->xmt_fcp_release); + ctxp->flag &= ~LPFC_NVMET_TNOTIFY; if (aborting) return; @@ -1122,7 +1182,7 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, if (!nvmebuf) { lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, - "6425 Defer rcv: no buffer xri x%x: " + "6425 Defer rcv: no buffer oxid x%x: " "flg %x ste %x\n", ctxp->oxid, ctxp->flag, ctxp->state); return; @@ -1377,7 +1437,7 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) infop = lpfc_get_ctx_list(phba, i, j); lpfc_printf_log(phba, KERN_INFO, LOG_NVME | LOG_INIT, "6408 TOTAL NVMET ctx for CPU %d " - "MRQ %d: cnt %d nextcpu %p\n", + "MRQ %d: cnt %d nextcpu x%px\n", i, j, infop->nvmet_ctx_list_cnt, infop->nvmet_ctx_next_cpu); } @@ -1440,7 +1500,7 @@ lpfc_nvmet_create_targetport(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, "6026 Registered NVME " - "targetport: %p, private %p " + "targetport: x%px, private x%px " "portnm %llx nodenm %llx segs %d qs %d\n", phba->targetport, tgtp, pinfo.port_name, pinfo.node_name, @@ -1495,7 +1555,7 @@ lpfc_nvmet_update_targetport(struct lpfc_hba *phba) return 0; lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME, - "6007 Update NVMET port %p did x%x\n", + "6007 Update NVMET port x%px did x%x\n", phba->targetport, vport->fc_myDID); phba->targetport->port_id = vport->fc_myDID; @@ -1514,10 +1574,12 @@ void lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri) { +#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; struct lpfc_nvmet_tgtport *tgtp; + struct nvmefc_tgt_fcp_req *req = NULL; struct lpfc_nodelist *ndlp; unsigned long iflag = 0; int rrq_empty = 0; @@ -1548,7 +1610,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, */ if (ctxp->flag & LPFC_NVMET_CTX_RLS && !(ctxp->flag & LPFC_NVMET_ABORT_OP)) { - list_del(&ctxp->list); + list_del_init(&ctxp->list); released = true; } ctxp->flag &= ~LPFC_NVMET_XBUSY; @@ -1568,7 +1630,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, } lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6318 XB aborted oxid %x flg x%x (%x)\n", + "6318 XB aborted oxid x%x flg x%x (%x)\n", ctxp->oxid, ctxp->flag, released); if (released) lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf); @@ -1579,6 +1641,33 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, } spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); + + ctxp = lpfc_nvmet_get_ctx_for_xri(phba, xri); + if (ctxp) { + /* + * Abort already done by FW, so BA_ACC sent. + * However, the transport may be unaware. + */ + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6323 NVMET Rcv ABTS xri x%x ctxp state x%x " + "flag x%x oxid x%x rxid x%x\n", + xri, ctxp->state, ctxp->flag, ctxp->oxid, + rxid); + + spin_lock_irqsave(&ctxp->ctxlock, iflag); + ctxp->flag |= LPFC_NVMET_ABTS_RCV; + ctxp->state = LPFC_NVMET_STE_ABORT; + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + + lpfc_nvmeio_data(phba, + "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", + xri, raw_smp_processor_id(), 0); + + req = &ctxp->ctx.fcp_req; + if (req) + nvmet_fc_rcv_fcp_abort(phba->targetport, req); + } +#endif } int @@ -1589,19 +1678,23 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, struct lpfc_hba *phba = vport->phba; struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; struct nvmefc_tgt_fcp_req *rsp; - uint16_t xri; + uint32_t sid; + uint16_t oxid, xri; unsigned long iflag = 0; - xri = be16_to_cpu(fc_hdr->fh_ox_id); + sid = sli4_sid_from_fc_hdr(fc_hdr); + oxid = be16_to_cpu(fc_hdr->fh_ox_id); spin_lock_irqsave(&phba->hbalock, iflag); spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); list_for_each_entry_safe(ctxp, next_ctxp, &phba->sli4_hba.lpfc_abts_nvmet_ctx_list, list) { - if (ctxp->ctxbuf->sglq->sli4_xritag != xri) + if (ctxp->oxid != oxid || ctxp->sid != sid) continue; + xri = ctxp->ctxbuf->sglq->sli4_xritag; + spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); @@ -1626,11 +1719,89 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_nvmeio_data(phba, "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", - xri, raw_smp_processor_id(), 1); + /* check the wait list */ + if (phba->sli4_hba.nvmet_io_wait_cnt) { + struct rqb_dmabuf *nvmebuf; + struct fc_frame_header *fc_hdr_tmp; + u32 sid_tmp; + u16 oxid_tmp; + bool found = false; + + spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag); + + /* match by oxid and s_id */ + list_for_each_entry(nvmebuf, + &phba->sli4_hba.lpfc_nvmet_io_wait_list, + hbuf.list) { + fc_hdr_tmp = (struct fc_frame_header *) + (nvmebuf->hbuf.virt); + oxid_tmp = be16_to_cpu(fc_hdr_tmp->fh_ox_id); + sid_tmp = sli4_sid_from_fc_hdr(fc_hdr_tmp); + if (oxid_tmp != oxid || sid_tmp != sid) + continue; + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6321 NVMET Rcv ABTS oxid x%x from x%x " + "is waiting for a ctxp\n", + oxid, sid); + + list_del_init(&nvmebuf->hbuf.list); + phba->sli4_hba.nvmet_io_wait_cnt--; + found = true; + break; + } + spin_unlock_irqrestore(&phba->sli4_hba.nvmet_io_wait_lock, + iflag); + + /* free buffer since already posted a new DMA buffer to RQ */ + if (found) { + nvmebuf->hrq->rqbp->rqb_free_buffer(phba, nvmebuf); + /* Respond with BA_ACC accordingly */ + lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1); + return 0; + } + } + + /* check active list */ + ctxp = lpfc_nvmet_get_ctx_for_oxid(phba, oxid, sid); + if (ctxp) { + xri = ctxp->ctxbuf->sglq->sli4_xritag; + + spin_lock_irqsave(&ctxp->ctxlock, iflag); + ctxp->flag |= (LPFC_NVMET_ABTS_RCV | LPFC_NVMET_ABORT_OP); + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + + lpfc_nvmeio_data(phba, + "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", + xri, raw_smp_processor_id(), 0); + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6322 NVMET Rcv ABTS:acc oxid x%x xri x%x " + "flag x%x state x%x\n", + ctxp->oxid, xri, ctxp->flag, ctxp->state); + + if (ctxp->flag & LPFC_NVMET_TNOTIFY) { + /* Notify the transport */ + nvmet_fc_rcv_fcp_abort(phba->targetport, + &ctxp->ctx.fcp_req); + } else { + cancel_work_sync(&ctxp->ctxbuf->defer_work); + spin_lock_irqsave(&ctxp->ctxlock, iflag); + lpfc_nvmet_defer_release(phba, ctxp); + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + } + lpfc_nvmet_sol_fcp_issue_abort(phba, ctxp, ctxp->sid, + ctxp->oxid); + + lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 1); + return 0; + } + + lpfc_nvmeio_data(phba, "NVMET ABTS RCV: oxid x%x CPU %02x rjt %d\n", + oxid, raw_smp_processor_id(), 1); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6320 NVMET Rcv ABTS:rjt xri x%x\n", xri); + "6320 NVMET Rcv ABTS:rjt oxid x%x\n", oxid); /* Respond with BA_RJT accordingly */ lpfc_sli4_seq_abort_rsp(vport, fc_hdr, 0); @@ -1714,6 +1885,18 @@ lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, spin_unlock_irqrestore(&pring->ring_lock, iflags); return; } + if (rc == WQE_SUCCESS) { +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (ctxp->ts_cmd_nvme) { + if (ctxp->ctx.fcp_req.op == NVMET_FCOP_RSP) + ctxp->ts_status_wqput = ktime_get_ns(); + else + ctxp->ts_data_wqput = ktime_get_ns(); + } +#endif + } else { + WARN_ON(rc); + } } wq->q_flag &= ~HBA_NVMET_WQFULL; spin_unlock_irqrestore(&pring->ring_lock, iflags); @@ -1735,7 +1918,7 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) if (phba->targetport) { tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { - wq = phba->sli4_hba.hdwq[qidx].nvme_wq; + wq = phba->sli4_hba.hdwq[qidx].io_wq; lpfc_nvmet_wqfull_flush(phba, wq, NULL); } tgtp->tport_unreg_cmp = &tport_unreg_cmp; @@ -1743,7 +1926,7 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) if (!wait_for_completion_timeout(tgtp->tport_unreg_cmp, msecs_to_jiffies(LPFC_NVMET_WAIT_TMO))) lpfc_printf_log(phba, KERN_ERR, LOG_NVME, - "6179 Unreg targetport %p timeout " + "6179 Unreg targetport x%px timeout " "reached.\n", phba->targetport); lpfc_nvmet_cleanup_io_context(phba); } @@ -1879,8 +2062,20 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) return; } + if (ctxp->flag & LPFC_NVMET_ABTS_RCV) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6324 IO oxid x%x aborted\n", + ctxp->oxid); + return; + } + payload = (uint32_t *)(nvmebuf->dbuf.virt); tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + ctxp->flag |= LPFC_NVMET_TNOTIFY; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (ctxp->ts_isr_cmd) + ctxp->ts_cmd_nvme = ktime_get_ns(); +#endif /* * The calling sequence should be: * nvmet_fc_rcv_fcp_req->lpfc_nvmet_xmt_fcp_op/cmp- req->done @@ -1930,6 +2125,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) phba->sli4_hba.nvmet_mrq_data[qno], 1, qno); return; } + ctxp->flag &= ~LPFC_NVMET_TNOTIFY; atomic_inc(&tgtp->rcv_fcp_cmd_drop); lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, "2582 FCP Drop IO x%x: err x%x: x%x x%x x%x\n", @@ -2019,6 +2215,8 @@ lpfc_nvmet_replenish_context(struct lpfc_hba *phba, * @phba: pointer to lpfc hba data structure. * @idx: relative index of MRQ vector * @nvmebuf: pointer to lpfc nvme command HBQ data structure. + * @isr_timestamp: in jiffies. + * @cqflag: cq processing information regarding workload. * * This routine is used for processing the WQE associated with a unsolicited * event. It first determines whether there is an existing ndlp that matches @@ -2031,7 +2229,8 @@ static void lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, uint32_t idx, struct rqb_dmabuf *nvmebuf, - uint64_t isr_timestamp) + uint64_t isr_timestamp, + uint8_t cqflag) { struct lpfc_nvmet_rcv_ctx *ctxp; struct lpfc_nvmet_tgtport *tgtp; @@ -2118,6 +2317,9 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, sid = sli4_sid_from_fc_hdr(fc_hdr); ctxp = (struct lpfc_nvmet_rcv_ctx *)ctx_buf->context; + spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag); + list_add_tail(&ctxp->list, &phba->sli4_hba.t_active_ctx_list); + spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag); if (ctxp->state != LPFC_NVMET_STE_FREE) { lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, "6414 NVMET Context corrupt %d %d oxid x%x\n", @@ -2140,24 +2342,41 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, spin_lock_init(&ctxp->ctxlock); #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (isr_timestamp) { + if (isr_timestamp) ctxp->ts_isr_cmd = isr_timestamp; - ctxp->ts_cmd_nvme = ktime_get_ns(); - ctxp->ts_nvme_data = 0; - ctxp->ts_data_wqput = 0; - ctxp->ts_isr_data = 0; - ctxp->ts_data_nvme = 0; - ctxp->ts_nvme_status = 0; - ctxp->ts_status_wqput = 0; - ctxp->ts_isr_status = 0; - ctxp->ts_status_nvme = 0; - } else { - ctxp->ts_cmd_nvme = 0; - } + ctxp->ts_cmd_nvme = 0; + ctxp->ts_nvme_data = 0; + ctxp->ts_data_wqput = 0; + ctxp->ts_isr_data = 0; + ctxp->ts_data_nvme = 0; + ctxp->ts_nvme_status = 0; + ctxp->ts_status_wqput = 0; + ctxp->ts_isr_status = 0; + ctxp->ts_status_nvme = 0; #endif atomic_inc(&tgtp->rcv_fcp_cmd_in); - lpfc_nvmet_process_rcv_fcp_req(ctx_buf); + /* check for cq processing load */ + if (!cqflag) { + lpfc_nvmet_process_rcv_fcp_req(ctx_buf); + return; + } + + if (!queue_work(phba->wq, &ctx_buf->defer_work)) { + atomic_inc(&tgtp->rcv_fcp_cmd_drop); + lpfc_printf_log(phba, KERN_ERR, LOG_NVME, + "6325 Unable to queue work for oxid x%x. " + "FCP Drop IO [x%x x%x x%x]\n", + ctxp->oxid, + atomic_read(&tgtp->rcv_fcp_cmd_in), + atomic_read(&tgtp->rcv_fcp_cmd_out), + atomic_read(&tgtp->xmt_fcp_release)); + + spin_lock_irqsave(&ctxp->ctxlock, iflag); + lpfc_nvmet_defer_release(phba, ctxp); + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, sid, oxid); + } } /** @@ -2194,6 +2413,8 @@ lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * @phba: pointer to lpfc hba data structure. * @idx: relative index of MRQ vector * @nvmebuf: pointer to received nvme data structure. + * @isr_timestamp: in jiffies. + * @cqflag: cq processing information regarding workload. * * This routine is used to process an unsolicited event received from a SLI * (Service Level Interface) ring. The actual processing of the data buffer @@ -2205,14 +2426,14 @@ void lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint32_t idx, struct rqb_dmabuf *nvmebuf, - uint64_t isr_timestamp) + uint64_t isr_timestamp, + uint8_t cqflag) { if (phba->nvmet_support == 0) { lpfc_rq_buf_free(phba, &nvmebuf->hbuf); return; } - lpfc_nvmet_unsol_fcp_buffer(phba, idx, nvmebuf, - isr_timestamp); + lpfc_nvmet_unsol_fcp_buffer(phba, idx, nvmebuf, isr_timestamp, cqflag); } /** @@ -2679,8 +2900,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, nvmewqe->drvrTimeout = (phba->fc_ratov * 3) + LPFC_DRVR_TIMEOUT; nvmewqe->context1 = ndlp; - for (i = 0; i < rsp->sg_cnt; i++) { - sgel = &rsp->sg[i]; + for_each_sg(rsp->sg, sgel, rsp->sg_cnt, i) { physaddr = sg_dma_address(sgel); cnt = sg_dma_len(sgel); sgl->addr_hi = putPaddrHigh(physaddr); @@ -2750,7 +2970,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, if ((ctxp->flag & LPFC_NVMET_CTX_RLS) && !(ctxp->flag & LPFC_NVMET_XBUSY)) { spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - list_del(&ctxp->list); + list_del_init(&ctxp->list); spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); released = true; } @@ -2759,7 +2979,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, atomic_inc(&tgtp->xmt_abort_rsp); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6165 ABORT cmpl: xri x%x flg x%x (%d) " + "6165 ABORT cmpl: oxid x%x flg x%x (%d) " "WCQE: %08x %08x %08x %08x\n", ctxp->oxid, ctxp->flag, released, wcqe->word0, wcqe->total_data_placed, @@ -2834,7 +3054,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, if ((ctxp->flag & LPFC_NVMET_CTX_RLS) && !(ctxp->flag & LPFC_NVMET_XBUSY)) { spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - list_del(&ctxp->list); + list_del_init(&ctxp->list); spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); released = true; } @@ -2843,7 +3063,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, atomic_inc(&tgtp->xmt_abort_rsp); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6316 ABTS cmpl xri x%x flg x%x (%x) " + "6316 ABTS cmpl oxid x%x flg x%x (%x) " "WCQE: %08x %08x %08x %08x\n", ctxp->oxid, ctxp->flag, released, wcqe->word0, wcqe->total_data_placed, @@ -2889,7 +3109,7 @@ lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, atomic_inc(&tgtp->xmt_ls_abort_cmpl); lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, - "6083 Abort cmpl: ctx %p WCQE:%08x %08x %08x %08x\n", + "6083 Abort cmpl: ctx x%px WCQE:%08x %08x %08x %08x\n", ctxp, wcqe->word0, wcqe->total_data_placed, result, wcqe->word3); @@ -3075,7 +3295,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, */ spin_lock_irqsave(&phba->hbalock, flags); /* driver queued commands are in process of being flushed */ - if (phba->hba_flag & HBA_NVME_IOQ_FLUSH) { + if (phba->hba_flag & HBA_IOQ_FLUSH) { spin_unlock_irqrestore(&phba->hbalock, flags); atomic_inc(&tgtp->xmt_abort_rsp_error); lpfc_printf_log(phba, KERN_ERR, LOG_NVME, @@ -3110,7 +3330,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, /* WQEs are reused. Clear stale data and set key fields to * zero like ia, iaab, iaar, xri_tag, and ctxt_tag. */ - memset(abts_wqe, 0, sizeof(union lpfc_wqe)); + memset(abts_wqe, 0, sizeof(*abts_wqe)); /* word 3 */ bf_set(abort_cmd_criteria, &abts_wqe->abort_cmd, T_XRI_TAG); @@ -3214,7 +3434,7 @@ aerr: spin_lock_irqsave(&ctxp->ctxlock, flags); if (ctxp->flag & LPFC_NVMET_CTX_RLS) { spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); - list_del(&ctxp->list); + list_del_init(&ctxp->list); spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); released = true; } @@ -3223,8 +3443,9 @@ aerr: atomic_inc(&tgtp->xmt_abort_rsp_error); lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, - "6135 Failed to Issue ABTS for oxid x%x. Status x%x\n", - ctxp->oxid, rc); + "6135 Failed to Issue ABTS for oxid x%x. Status x%x " + "(%x)\n", + ctxp->oxid, rc, released); if (released) lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf); return 1; diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h index 2f3f603d94c4..8ff67deac10a 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.h +++ b/drivers/scsi/lpfc/lpfc_nvmet.h @@ -140,6 +140,7 @@ struct lpfc_nvmet_rcv_ctx { #define LPFC_NVMET_ABTS_RCV 0x10 /* ABTS received on exchange */ #define LPFC_NVMET_CTX_REUSE_WQ 0x20 /* ctx reused via WQ */ #define LPFC_NVMET_DEFER_WQFULL 0x40 /* Waiting on a free WQE */ +#define LPFC_NVMET_TNOTIFY 0x80 /* notify transport of abts */ struct rqb_dmabuf *rqb_buffer; struct lpfc_nvmet_ctxbuf *ctxbuf; struct lpfc_sli4_hdw_queue *hdwq; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index ba996fbde89b..6822cd9ff8f1 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -53,8 +53,6 @@ #define LPFC_RESET_WAIT 2 #define LPFC_ABORT_WAIT 2 -int _dump_buf_done = 1; - static char *dif_op_str[] = { "PROT_NORMAL", "PROT_READ_INSERT", @@ -89,63 +87,6 @@ lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *psb); static int lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc); -static void -lpfc_debug_save_data(struct lpfc_hba *phba, struct scsi_cmnd *cmnd) -{ - void *src, *dst; - struct scatterlist *sgde = scsi_sglist(cmnd); - - if (!_dump_buf_data) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9050 BLKGRD: ERROR %s _dump_buf_data is NULL\n", - __func__); - return; - } - - - if (!sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9051 BLKGRD: ERROR: data scatterlist is null\n"); - return; - } - - dst = (void *) _dump_buf_data; - while (sgde) { - src = sg_virt(sgde); - memcpy(dst, src, sgde->length); - dst += sgde->length; - sgde = sg_next(sgde); - } -} - -static void -lpfc_debug_save_dif(struct lpfc_hba *phba, struct scsi_cmnd *cmnd) -{ - void *src, *dst; - struct scatterlist *sgde = scsi_prot_sglist(cmnd); - - if (!_dump_buf_dif) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9052 BLKGRD: ERROR %s _dump_buf_data is NULL\n", - __func__); - return; - } - - if (!sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9053 BLKGRD: ERROR: prot scatterlist is null\n"); - return; - } - - dst = _dump_buf_dif; - while (sgde) { - src = sg_virt(sgde); - memcpy(dst, src, sgde->length); - dst += sgde->length; - sgde = sg_next(sgde); - } -} - static inline unsigned lpfc_cmd_blksize(struct scsi_cmnd *sc) { @@ -537,29 +478,32 @@ lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *vport) for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { qp = &phba->sli4_hba.hdwq[idx]; - spin_lock(&qp->abts_scsi_buf_list_lock); + spin_lock(&qp->abts_io_buf_list_lock); list_for_each_entry_safe(psb, next_psb, - &qp->lpfc_abts_scsi_buf_list, list) { + &qp->lpfc_abts_io_buf_list, list) { + if (psb->cur_iocbq.iocb_flag == LPFC_IO_NVME) + continue; + if (psb->rdata && psb->rdata->pnode && psb->rdata->pnode->vport == vport) psb->rdata = NULL; } - spin_unlock(&qp->abts_scsi_buf_list_lock); + spin_unlock(&qp->abts_io_buf_list_lock); } spin_unlock_irqrestore(&phba->hbalock, iflag); } /** - * lpfc_sli4_fcp_xri_aborted - Fast-path process of fcp xri abort + * lpfc_sli4_io_xri_aborted - Fast-path process of fcp xri abort * @phba: pointer to lpfc hba data structure. * @axri: pointer to the fcp xri abort wcqe structure. * * This routine is invoked by the worker thread to process a SLI4 fast-path - * FCP aborted xri. + * FCP or NVME aborted xri. **/ void -lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, - struct sli4_wcqe_xri_aborted *axri, int idx) +lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, + struct sli4_wcqe_xri_aborted *axri, int idx) { uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); @@ -577,16 +521,23 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, qp = &phba->sli4_hba.hdwq[idx]; spin_lock_irqsave(&phba->hbalock, iflag); - spin_lock(&qp->abts_scsi_buf_list_lock); + spin_lock(&qp->abts_io_buf_list_lock); list_for_each_entry_safe(psb, next_psb, - &qp->lpfc_abts_scsi_buf_list, list) { + &qp->lpfc_abts_io_buf_list, list) { if (psb->cur_iocbq.sli4_xritag == xri) { - list_del(&psb->list); - qp->abts_scsi_io_bufs--; + list_del_init(&psb->list); psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; - spin_unlock( - &qp->abts_scsi_buf_list_lock); + if (psb->cur_iocbq.iocb_flag == LPFC_IO_NVME) { + qp->abts_nvme_io_bufs--; + spin_unlock(&qp->abts_io_buf_list_lock); + spin_unlock_irqrestore(&phba->hbalock, iflag); + lpfc_sli4_nvme_xri_aborted(phba, axri, psb); + return; + } + qp->abts_scsi_io_bufs--; + spin_unlock(&qp->abts_io_buf_list_lock); + if (psb->rdata && psb->rdata->pnode) ndlp = psb->rdata->pnode; else @@ -605,12 +556,12 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, return; } } - spin_unlock(&qp->abts_scsi_buf_list_lock); + spin_unlock(&qp->abts_io_buf_list_lock); for (i = 1; i <= phba->sli.last_iotag; i++) { iocbq = phba->sli.iocbq_lookup[i]; - if (!(iocbq->iocb_flag & LPFC_IO_FCP) || - (iocbq->iocb_flag & LPFC_IO_LIBDFC)) + if (!(iocbq->iocb_flag & LPFC_IO_FCP) || + (iocbq->iocb_flag & LPFC_IO_LIBDFC)) continue; if (iocbq->sli4_xritag != xri) continue; @@ -685,8 +636,9 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, IOCB_t *iocb; dma_addr_t pdma_phys_fcp_rsp; dma_addr_t pdma_phys_fcp_cmd; - uint32_t sgl_size, cpu, idx; + uint32_t cpu, idx; int tag; + struct fcp_cmd_rsp_buf *tmp = NULL; cpu = raw_smp_processor_id(); if (cmnd && phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ) { @@ -704,9 +656,6 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, return NULL; } - sgl_size = phba->cfg_sg_dma_buf_size - - (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp)); - /* Setup key fields in buffer that may have been changed * if other protocols used this buffer. */ @@ -721,9 +670,12 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, #ifdef CONFIG_SCSI_LPFC_DEBUG_FS lpfc_cmd->prot_data_type = 0; #endif - lpfc_cmd->fcp_cmnd = (lpfc_cmd->data + sgl_size); - lpfc_cmd->fcp_rsp = (struct fcp_rsp *)((uint8_t *)lpfc_cmd->fcp_cmnd + - sizeof(struct fcp_cmnd)); + tmp = lpfc_get_cmd_rsp_buf_per_hdwq(phba, lpfc_cmd); + if (!tmp) + return NULL; + + lpfc_cmd->fcp_cmnd = tmp->fcp_cmnd; + lpfc_cmd->fcp_rsp = tmp->fcp_rsp; /* * The first two SGEs are the FCP_CMD and FCP_RSP. @@ -731,7 +683,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, * first two and leave the rest for queuecommand. */ sgl = (struct sli4_sge *)lpfc_cmd->dma_sgl; - pdma_phys_fcp_cmd = (lpfc_cmd->dma_handle + sgl_size); + pdma_phys_fcp_cmd = tmp->fcp_cmd_rsp_dma_handle; sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd)); sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd)); sgl->word2 = le32_to_cpu(sgl->word2); @@ -835,11 +787,11 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *psb) qp = psb->hdwq; if (psb->exch_busy) { - spin_lock_irqsave(&qp->abts_scsi_buf_list_lock, iflag); + spin_lock_irqsave(&qp->abts_io_buf_list_lock, iflag); psb->pCmd = NULL; - list_add_tail(&psb->list, &qp->lpfc_abts_scsi_buf_list); + list_add_tail(&psb->list, &qp->lpfc_abts_io_buf_list); qp->abts_scsi_io_bufs++; - spin_unlock_irqrestore(&qp->abts_scsi_buf_list_lock, iflag); + spin_unlock_irqrestore(&qp->abts_io_buf_list_lock, iflag); } else { lpfc_release_io_buf(phba, (struct lpfc_io_buf *)psb, qp); } @@ -918,9 +870,10 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) "dma_map_sg. Config %d, seg_cnt %d\n", __func__, phba->cfg_sg_seg_cnt, lpfc_cmd->seg_cnt); + WARN_ON_ONCE(lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt); lpfc_cmd->seg_cnt = 0; scsi_dma_unmap(scsi_cmnd); - return 1; + return 2; } /* @@ -1774,7 +1727,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, if (!sgpe || !sgde) { lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "9020 Invalid s/g entry: data=0x%p prot=0x%p\n", + "9020 Invalid s/g entry: data=x%px prot=x%px\n", sgpe, sgde); return 0; } @@ -1989,7 +1942,8 @@ out: **/ static int lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, - struct sli4_sge *sgl, int datasegcnt) + struct sli4_sge *sgl, int datasegcnt, + struct lpfc_io_buf *lpfc_cmd) { struct scatterlist *sgde = NULL; /* s/g data entry */ struct sli4_sge_diseed *diseed = NULL; @@ -2003,6 +1957,9 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint32_t checking = 1; uint32_t dma_len; uint32_t dma_offset = 0; + struct sli4_hybrid_sgl *sgl_xtra = NULL; + int j; + bool lsp_just_set = false; status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop); if (status) @@ -2062,23 +2019,64 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, sgl++; /* assumption: caller has already run dma_map_sg on command data */ - scsi_for_each_sg(sc, sgde, datasegcnt, i) { - physaddr = sg_dma_address(sgde); - dma_len = sg_dma_len(sgde); - sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr)); - sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr)); - if ((i + 1) == datasegcnt) - bf_set(lpfc_sli4_sge_last, sgl, 1); - else - bf_set(lpfc_sli4_sge_last, sgl, 0); - bf_set(lpfc_sli4_sge_offset, sgl, dma_offset); - bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); + sgde = scsi_sglist(sc); + j = 3; + for (i = 0; i < datasegcnt; i++) { + /* clear it */ + sgl->word2 = 0; - sgl->sge_len = cpu_to_le32(dma_len); - dma_offset += dma_len; + /* do we need to expand the segment */ + if (!lsp_just_set && !((j + 1) % phba->border_sge_num) && + ((datasegcnt - 1) != i)) { + /* set LSP type */ + bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_LSP); + + sgl_xtra = lpfc_get_sgl_per_hdwq(phba, lpfc_cmd); + + if (unlikely(!sgl_xtra)) { + lpfc_cmd->seg_cnt = 0; + return 0; + } + sgl->addr_lo = cpu_to_le32(putPaddrLow( + sgl_xtra->dma_phys_sgl)); + sgl->addr_hi = cpu_to_le32(putPaddrHigh( + sgl_xtra->dma_phys_sgl)); + + } else { + bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); + } + + if (!(bf_get(lpfc_sli4_sge_type, sgl) & LPFC_SGE_TYPE_LSP)) { + if ((datasegcnt - 1) == i) + bf_set(lpfc_sli4_sge_last, sgl, 1); + physaddr = sg_dma_address(sgde); + dma_len = sg_dma_len(sgde); + sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr)); + sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr)); + + bf_set(lpfc_sli4_sge_offset, sgl, dma_offset); + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->sge_len = cpu_to_le32(dma_len); + + dma_offset += dma_len; + sgde = sg_next(sgde); + + sgl++; + num_sge++; + lsp_just_set = false; + + } else { + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->sge_len = cpu_to_le32(phba->cfg_sg_dma_buf_size); + + sgl = (struct sli4_sge *)sgl_xtra->dma_sgl; + i = i - 1; + + lsp_just_set = true; + } + + j++; - sgl++; - num_sge++; } out: @@ -2124,7 +2122,8 @@ out: **/ static int lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, - struct sli4_sge *sgl, int datacnt, int protcnt) + struct sli4_sge *sgl, int datacnt, int protcnt, + struct lpfc_io_buf *lpfc_cmd) { struct scatterlist *sgde = NULL; /* s/g data entry */ struct scatterlist *sgpe = NULL; /* s/g prot entry */ @@ -2146,14 +2145,15 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, #endif uint32_t checking = 1; uint32_t dma_offset = 0; - int num_sge = 0; + int num_sge = 0, j = 2; + struct sli4_hybrid_sgl *sgl_xtra = NULL; sgpe = scsi_prot_sglist(sc); sgde = scsi_sglist(sc); if (!sgpe || !sgde) { lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "9082 Invalid s/g entry: data=0x%p prot=0x%p\n", + "9082 Invalid s/g entry: data=x%px prot=x%px\n", sgpe, sgde); return 0; } @@ -2179,9 +2179,37 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, split_offset = 0; do { /* Check to see if we ran out of space */ - if (num_sge >= (phba->cfg_total_seg_cnt - 2)) + if ((num_sge >= (phba->cfg_total_seg_cnt - 2)) && + !(phba->cfg_xpsgl)) return num_sge + 3; + /* DISEED and DIF have to be together */ + if (!((j + 1) % phba->border_sge_num) || + !((j + 2) % phba->border_sge_num) || + !((j + 3) % phba->border_sge_num)) { + sgl->word2 = 0; + + /* set LSP type */ + bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_LSP); + + sgl_xtra = lpfc_get_sgl_per_hdwq(phba, lpfc_cmd); + + if (unlikely(!sgl_xtra)) { + goto out; + } else { + sgl->addr_lo = cpu_to_le32(putPaddrLow( + sgl_xtra->dma_phys_sgl)); + sgl->addr_hi = cpu_to_le32(putPaddrHigh( + sgl_xtra->dma_phys_sgl)); + } + + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->sge_len = cpu_to_le32(phba->cfg_sg_dma_buf_size); + + sgl = (struct sli4_sge *)sgl_xtra->dma_sgl; + j = 0; + } + /* setup DISEED with what we have */ diseed = (struct sli4_sge_diseed *) sgl; memset(diseed, 0, sizeof(struct sli4_sge_diseed)); @@ -2228,7 +2256,9 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, /* advance sgl and increment bde count */ num_sge++; + sgl++; + j++; /* setup the first BDE that points to protection buffer */ protphysaddr = sg_dma_address(sgpe) + protgroup_offset; @@ -2243,6 +2273,7 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, sgl->addr_hi = le32_to_cpu(putPaddrHigh(protphysaddr)); sgl->addr_lo = le32_to_cpu(putPaddrLow(protphysaddr)); sgl->word2 = cpu_to_le32(sgl->word2); + sgl->sge_len = 0; protgrp_blks = protgroup_len / 8; protgrp_bytes = protgrp_blks * blksize; @@ -2263,9 +2294,14 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, /* setup SGE's for data blocks associated with DIF data */ pgdone = 0; subtotal = 0; /* total bytes processed for current prot grp */ + + sgl++; + j++; + while (!pgdone) { /* Check to see if we ran out of space */ - if (num_sge >= phba->cfg_total_seg_cnt) + if ((num_sge >= phba->cfg_total_seg_cnt) && + !phba->cfg_xpsgl) return num_sge + 1; if (!sgde) { @@ -2274,60 +2310,101 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, __func__); return 0; } - sgl++; - dataphysaddr = sg_dma_address(sgde) + split_offset; - remainder = sg_dma_len(sgde) - split_offset; + if (!((j + 1) % phba->border_sge_num)) { + sgl->word2 = 0; - if ((subtotal + remainder) <= protgrp_bytes) { - /* we can use this whole buffer */ - dma_len = remainder; - split_offset = 0; + /* set LSP type */ + bf_set(lpfc_sli4_sge_type, sgl, + LPFC_SGE_TYPE_LSP); - if ((subtotal + remainder) == protgrp_bytes) - pgdone = 1; + sgl_xtra = lpfc_get_sgl_per_hdwq(phba, + lpfc_cmd); + + if (unlikely(!sgl_xtra)) { + goto out; + } else { + sgl->addr_lo = cpu_to_le32( + putPaddrLow(sgl_xtra->dma_phys_sgl)); + sgl->addr_hi = cpu_to_le32( + putPaddrHigh(sgl_xtra->dma_phys_sgl)); + } + + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->sge_len = cpu_to_le32( + phba->cfg_sg_dma_buf_size); + + sgl = (struct sli4_sge *)sgl_xtra->dma_sgl; } else { - /* must split this buffer with next prot grp */ - dma_len = protgrp_bytes - subtotal; - split_offset += dma_len; - } + dataphysaddr = sg_dma_address(sgde) + + split_offset; - subtotal += dma_len; + remainder = sg_dma_len(sgde) - split_offset; - sgl->addr_lo = cpu_to_le32(putPaddrLow(dataphysaddr)); - sgl->addr_hi = cpu_to_le32(putPaddrHigh(dataphysaddr)); - bf_set(lpfc_sli4_sge_last, sgl, 0); - bf_set(lpfc_sli4_sge_offset, sgl, dma_offset); - bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); + if ((subtotal + remainder) <= protgrp_bytes) { + /* we can use this whole buffer */ + dma_len = remainder; + split_offset = 0; - sgl->sge_len = cpu_to_le32(dma_len); - dma_offset += dma_len; + if ((subtotal + remainder) == + protgrp_bytes) + pgdone = 1; + } else { + /* must split this buffer with next + * prot grp + */ + dma_len = protgrp_bytes - subtotal; + split_offset += dma_len; + } - num_sge++; - curr_data++; + subtotal += dma_len; - if (split_offset) - break; + sgl->word2 = 0; + sgl->addr_lo = cpu_to_le32(putPaddrLow( + dataphysaddr)); + sgl->addr_hi = cpu_to_le32(putPaddrHigh( + dataphysaddr)); + bf_set(lpfc_sli4_sge_last, sgl, 0); + bf_set(lpfc_sli4_sge_offset, sgl, dma_offset); + bf_set(lpfc_sli4_sge_type, sgl, + LPFC_SGE_TYPE_DATA); - /* Move to the next s/g segment if possible */ - sgde = sg_next(sgde); + sgl->sge_len = cpu_to_le32(dma_len); + dma_offset += dma_len; + + num_sge++; + curr_data++; + + if (split_offset) { + sgl++; + j++; + break; + } + + /* Move to the next s/g segment if possible */ + sgde = sg_next(sgde); + + sgl++; + } + + j++; } if (protgroup_offset) { /* update the reference tag */ reftag += protgrp_blks; - sgl++; continue; } /* are we done ? */ if (curr_prot == protcnt) { + /* mark the last SGL */ + sgl--; bf_set(lpfc_sli4_sge_last, sgl, 1); alldone = 1; } else if (curr_prot < protcnt) { /* advance to next prot buffer */ sgpe = sg_next(sgpe); - sgl++; /* update the reference tag */ reftag += protgrp_blks; @@ -2430,7 +2507,10 @@ lpfc_bg_scsi_adjust_dl(struct lpfc_hba *phba, * * This is the protection/DIF aware version of * lpfc_scsi_prep_dma_buf(). It may be a good idea to combine the - * two functions eventually, but for now, it's here + * two functions eventually, but for now, it's here. + * RETURNS 0 - SUCCESS, + * 1 - Failed DMA map, retry. + * 2 - Invalid scsi cmd or prot-type. Do not rety. **/ static int lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, @@ -2444,6 +2524,7 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, int datasegcnt, protsegcnt, datadir = scsi_cmnd->sc_data_direction; int prot_group_type = 0; int fcpdl; + int ret = 1; struct lpfc_vport *vport = phba->pport; /* @@ -2467,8 +2548,11 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, lpfc_cmd->seg_cnt = datasegcnt; /* First check if data segment count from SCSI Layer is good */ - if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) + if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { + WARN_ON_ONCE(lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt); + ret = 2; goto err; + } prot_group_type = lpfc_prot_group_type(phba, scsi_cmnd); @@ -2476,14 +2560,18 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, case LPFC_PG_TYPE_NO_DIF: /* Here we need to add a PDE5 and PDE6 to the count */ - if ((lpfc_cmd->seg_cnt + 2) > phba->cfg_total_seg_cnt) + if ((lpfc_cmd->seg_cnt + 2) > phba->cfg_total_seg_cnt) { + ret = 2; goto err; + } num_bde = lpfc_bg_setup_bpl(phba, scsi_cmnd, bpl, datasegcnt); /* we should have 2 or more entries in buffer list */ - if (num_bde < 2) + if (num_bde < 2) { + ret = 2; goto err; + } break; case LPFC_PG_TYPE_DIF_BUF: @@ -2507,15 +2595,19 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, * protection data segment. */ if ((lpfc_cmd->prot_seg_cnt * 4) > - (phba->cfg_total_seg_cnt - 2)) + (phba->cfg_total_seg_cnt - 2)) { + ret = 2; goto err; + } num_bde = lpfc_bg_setup_bpl_prot(phba, scsi_cmnd, bpl, datasegcnt, protsegcnt); /* we should have 3 or more entries in buffer list */ if ((num_bde < 3) || - (num_bde > phba->cfg_total_seg_cnt)) + (num_bde > phba->cfg_total_seg_cnt)) { + ret = 2; goto err; + } break; case LPFC_PG_TYPE_INVALID: @@ -2526,7 +2618,7 @@ lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, lpfc_printf_log(phba, KERN_ERR, LOG_FCP, "9022 Unexpected protection group %i\n", prot_group_type); - return 1; + return 2; } } @@ -2576,7 +2668,7 @@ err: lpfc_cmd->seg_cnt = 0; lpfc_cmd->prot_seg_cnt = 0; - return 1; + return ret; } /* @@ -2809,26 +2901,6 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd, uint32_t bgstat = bgf->bgstat; uint64_t failing_sector = 0; - spin_lock(&_dump_buf_lock); - if (!_dump_buf_done) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9070 BLKGRD: Saving" - " Data for %u blocks to debugfs\n", - (cmd->cmnd[7] << 8 | cmd->cmnd[8])); - lpfc_debug_save_data(phba, cmd); - - /* If we have a prot sgl, save the DIF buffer */ - if (lpfc_prot_group_type(phba, cmd) == - LPFC_PG_TYPE_DIF_BUF) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9071 BLKGRD: " - "Saving DIF for %u blocks to debugfs\n", - (cmd->cmnd[7] << 8 | cmd->cmnd[8])); - lpfc_debug_save_dif(phba, cmd); - } - - _dump_buf_done = 1; - } - spin_unlock(&_dump_buf_lock); - if (lpfc_bgs_get_invalid_prof(bgstat)) { cmd->result = DID_ERROR << 16; lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_BG, @@ -2962,7 +3034,8 @@ out: * field of @lpfc_cmd for device with SLI-4 interface spec. * * Return codes: - * 1 - Error + * 2 - Error - Do not retry + * 1 - Error - Retry * 0 - Success **/ static int @@ -2978,8 +3051,10 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) uint32_t num_bde = 0; uint32_t dma_len; uint32_t dma_offset = 0; - int nseg; + int nseg, i, j; struct ulp_bde64 *bde; + bool lsp_just_set = false; + struct sli4_hybrid_sgl *sgl_xtra = NULL; /* * There are three possibilities here - use scatter-gather segment, use @@ -3006,15 +3081,17 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) sgl += 1; first_data_sgl = sgl; lpfc_cmd->seg_cnt = nseg; - if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { + if (!phba->cfg_xpsgl && + lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9074 BLKGRD:" " %s: Too many sg segments from " "dma_map_sg. Config %d, seg_cnt %d\n", __func__, phba->cfg_sg_seg_cnt, lpfc_cmd->seg_cnt); + WARN_ON_ONCE(lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt); lpfc_cmd->seg_cnt = 0; scsi_dma_unmap(scsi_cmnd); - return 1; + return 2; } /* @@ -3026,22 +3103,80 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) * the IOCB. If it can't then the BDEs get added to a BPL as it * does for SLI-2 mode. */ - scsi_for_each_sg(scsi_cmnd, sgel, nseg, num_bde) { - physaddr = sg_dma_address(sgel); - dma_len = sg_dma_len(sgel); - sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr)); - sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr)); - sgl->word2 = le32_to_cpu(sgl->word2); - if ((num_bde + 1) == nseg) + + /* for tracking segment boundaries */ + sgel = scsi_sglist(scsi_cmnd); + j = 2; + for (i = 0; i < nseg; i++) { + sgl->word2 = 0; + if ((num_bde + 1) == nseg) { bf_set(lpfc_sli4_sge_last, sgl, 1); - else + bf_set(lpfc_sli4_sge_type, sgl, + LPFC_SGE_TYPE_DATA); + } else { bf_set(lpfc_sli4_sge_last, sgl, 0); - bf_set(lpfc_sli4_sge_offset, sgl, dma_offset); - bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); - sgl->word2 = cpu_to_le32(sgl->word2); - sgl->sge_len = cpu_to_le32(dma_len); - dma_offset += dma_len; - sgl++; + + /* do we need to expand the segment */ + if (!lsp_just_set && + !((j + 1) % phba->border_sge_num) && + ((nseg - 1) != i)) { + /* set LSP type */ + bf_set(lpfc_sli4_sge_type, sgl, + LPFC_SGE_TYPE_LSP); + + sgl_xtra = lpfc_get_sgl_per_hdwq( + phba, lpfc_cmd); + + if (unlikely(!sgl_xtra)) { + lpfc_cmd->seg_cnt = 0; + scsi_dma_unmap(scsi_cmnd); + return 1; + } + sgl->addr_lo = cpu_to_le32(putPaddrLow( + sgl_xtra->dma_phys_sgl)); + sgl->addr_hi = cpu_to_le32(putPaddrHigh( + sgl_xtra->dma_phys_sgl)); + + } else { + bf_set(lpfc_sli4_sge_type, sgl, + LPFC_SGE_TYPE_DATA); + } + } + + if (!(bf_get(lpfc_sli4_sge_type, sgl) & + LPFC_SGE_TYPE_LSP)) { + if ((nseg - 1) == i) + bf_set(lpfc_sli4_sge_last, sgl, 1); + + physaddr = sg_dma_address(sgel); + dma_len = sg_dma_len(sgel); + sgl->addr_lo = cpu_to_le32(putPaddrLow( + physaddr)); + sgl->addr_hi = cpu_to_le32(putPaddrHigh( + physaddr)); + + bf_set(lpfc_sli4_sge_offset, sgl, dma_offset); + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->sge_len = cpu_to_le32(dma_len); + + dma_offset += dma_len; + sgel = sg_next(sgel); + + sgl++; + lsp_just_set = false; + + } else { + sgl->word2 = cpu_to_le32(sgl->word2); + sgl->sge_len = cpu_to_le32( + phba->cfg_sg_dma_buf_size); + + sgl = (struct sli4_sge *)sgl_xtra->dma_sgl; + i = i - 1; + + lsp_just_set = true; + } + + j++; } /* * Setup the first Payload BDE. For FCoE we just key off @@ -3110,6 +3245,10 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) * This is the protection/DIF aware version of * lpfc_scsi_prep_dma_buf(). It may be a good idea to combine the * two functions eventually, but for now, it's here + * Return codes: + * 2 - Error - Do not retry + * 1 - Error - Retry + * 0 - Success **/ static int lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, @@ -3123,6 +3262,7 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, int datasegcnt, protsegcnt, datadir = scsi_cmnd->sc_data_direction; int prot_group_type = 0; int fcpdl; + int ret = 1; struct lpfc_vport *vport = phba->pport; /* @@ -3152,23 +3292,33 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, lpfc_cmd->seg_cnt = datasegcnt; /* First check if data segment count from SCSI Layer is good */ - if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) + if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt && + !phba->cfg_xpsgl) { + WARN_ON_ONCE(lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt); + ret = 2; goto err; + } prot_group_type = lpfc_prot_group_type(phba, scsi_cmnd); switch (prot_group_type) { case LPFC_PG_TYPE_NO_DIF: /* Here we need to add a DISEED to the count */ - if ((lpfc_cmd->seg_cnt + 1) > phba->cfg_total_seg_cnt) + if (((lpfc_cmd->seg_cnt + 1) > + phba->cfg_total_seg_cnt) && + !phba->cfg_xpsgl) { + ret = 2; goto err; + } num_sge = lpfc_bg_setup_sgl(phba, scsi_cmnd, sgl, - datasegcnt); + datasegcnt, lpfc_cmd); /* we should have 2 or more entries in buffer list */ - if (num_sge < 2) + if (num_sge < 2) { + ret = 2; goto err; + } break; case LPFC_PG_TYPE_DIF_BUF: @@ -3190,17 +3340,23 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, * There is a minimun of 3 SGEs used for every * protection data segment. */ - if ((lpfc_cmd->prot_seg_cnt * 3) > - (phba->cfg_total_seg_cnt - 2)) + if (((lpfc_cmd->prot_seg_cnt * 3) > + (phba->cfg_total_seg_cnt - 2)) && + !phba->cfg_xpsgl) { + ret = 2; goto err; + } num_sge = lpfc_bg_setup_sgl_prot(phba, scsi_cmnd, sgl, - datasegcnt, protsegcnt); + datasegcnt, protsegcnt, lpfc_cmd); /* we should have 3 or more entries in buffer list */ - if ((num_sge < 3) || - (num_sge > phba->cfg_total_seg_cnt)) + if (num_sge < 3 || + (num_sge > phba->cfg_total_seg_cnt && + !phba->cfg_xpsgl)) { + ret = 2; goto err; + } break; case LPFC_PG_TYPE_INVALID: @@ -3211,7 +3367,7 @@ lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, lpfc_printf_log(phba, KERN_ERR, LOG_FCP, "9083 Unexpected protection group %i\n", prot_group_type); - return 1; + return 2; } } @@ -3273,7 +3429,7 @@ err: lpfc_cmd->seg_cnt = 0; lpfc_cmd->prot_seg_cnt = 0; - return 1; + return ret; } /** @@ -3839,7 +3995,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, uint32_t *lp = (uint32_t *)cmd->sense_buffer; lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "0710 Iodone <%d/%llu> cmd %p, error " + "0710 Iodone <%d/%llu> cmd x%px, error " "x%x SNS x%x x%x Data: x%x x%x\n", cmd->device->id, cmd->device->lun, cmd, cmd->result, *lp, *(lp + 3), cmd->retries, @@ -3879,10 +4035,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, */ spin_lock(&lpfc_cmd->buf_lock); lpfc_cmd->cur_iocbq.iocb_flag &= ~LPFC_DRIVER_ABORTED; - if (lpfc_cmd->waitq) { + if (lpfc_cmd->waitq) wake_up(lpfc_cmd->waitq); - lpfc_cmd->waitq = NULL; - } spin_unlock(&lpfc_cmd->buf_lock); lpfc_release_scsi_buf(phba, lpfc_cmd); @@ -4456,8 +4610,12 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) err = lpfc_scsi_prep_dma_buf(phba, lpfc_cmd); } - if (err) + if (err == 2) { + cmnd->result = DID_ERROR << 16; + goto out_fail_command_release_buf; + } else if (err) { goto out_host_busy_free_buf; + } lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); @@ -4528,6 +4686,9 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) out_tgt_busy: return SCSI_MLQUEUE_TARGET_BUSY; + out_fail_command_release_buf: + lpfc_release_scsi_buf(phba, lpfc_cmd); + out_fail_command: cmnd->scsi_done(cmnd); return 0; @@ -4570,7 +4731,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) spin_lock_irqsave(&phba->hbalock, flags); /* driver queued commands are in process of being flushed */ - if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) { + if (phba->hba_flag & HBA_IOQ_FLUSH) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "3168 SCSI Layer abort requested I/O has been " "flushed by LLD.\n"); @@ -4591,7 +4752,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) iocb = &lpfc_cmd->cur_iocbq; if (phba->sli_rev == LPFC_SLI_REV4) { - pring_s4 = phba->sli4_hba.hdwq[iocb->hba_wqidx].fcp_wq->pring; + pring_s4 = phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring; if (!pring_s4) { ret = FAILED; goto out_unlock_buf; @@ -4718,6 +4879,9 @@ wait_for_cmpl: iocb->sli4_xritag, ret, cmnd->device->id, cmnd->device->lun); } + + lpfc_cmd->waitq = NULL; + spin_unlock(&lpfc_cmd->buf_lock); goto out; @@ -4797,7 +4961,12 @@ lpfc_check_fcp_rsp(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd) rsp_info, rsp_len, rsp_info_code); - if ((fcprsp->rspStatus2&RSP_LEN_VALID) && (rsp_len == 8)) { + /* If FCP_RSP_LEN_VALID bit is one, then the FCP_RSP_LEN + * field specifies the number of valid bytes of FCP_RSP_INFO. + * The FCP_RSP_LEN field shall be set to 0x04 or 0x08 + */ + if ((fcprsp->rspStatus2 & RSP_LEN_VALID) && + ((rsp_len == 8) || (rsp_len == 4))) { switch (rsp_info_code) { case RSP_NO_FAILURE: lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, @@ -4950,7 +5119,7 @@ lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd) rdata = lpfc_rport_data_from_scsi_device(cmnd->device); if (!rdata) { lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "0797 Tgt Map rport failure: rdata x%p\n", rdata); + "0797 Tgt Map rport failure: rdata x%px\n", rdata); return FAILED; } pnode = rdata->pnode; @@ -5048,7 +5217,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) rdata = lpfc_rport_data_from_scsi_device(cmnd->device); if (!rdata || !rdata->pnode) { lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0798 Device Reset rdata failure: rdata x%p\n", + "0798 Device Reset rdata failure: rdata x%px\n", rdata); return FAILED; } @@ -5060,7 +5229,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) status = lpfc_chk_tgt_mapped(vport, cmnd); if (status == FAILED) { lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0721 Device Reset rport failure: rdata x%p\n", rdata); + "0721 Device Reset rport failure: rdata x%px\n", rdata); return FAILED; } @@ -5119,7 +5288,7 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) rdata = lpfc_rport_data_from_scsi_device(cmnd->device); if (!rdata || !rdata->pnode) { lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0799 Target Reset rdata failure: rdata x%p\n", + "0799 Target Reset rdata failure: rdata x%px\n", rdata); return FAILED; } @@ -5131,7 +5300,7 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) status = lpfc_chk_tgt_mapped(vport, cmnd); if (status == FAILED) { lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0722 Target Reset rport failure: rdata x%p\n", rdata); + "0722 Target Reset rport failure: rdata x%px\n", rdata); if (pnode) { spin_lock_irq(shost->host_lock); pnode->nlp_flag &= ~NLP_NPR_ADISC; @@ -5289,18 +5458,20 @@ lpfc_host_reset_handler(struct scsi_cmnd *cmnd) lpfc_offline(phba); rc = lpfc_sli_brdrestart(phba); if (rc) - ret = FAILED; + goto error; + rc = lpfc_online(phba); if (rc) - ret = FAILED; + goto error; + lpfc_unblock_mgmt_io(phba); - if (ret == FAILED) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "3323 Failed host reset, bring it offline\n"); - lpfc_sli4_offline_eratt(phba); - } return ret; +error: + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "3323 Failed host reset\n"); + lpfc_unblock_mgmt_io(phba); + return FAILED; } /** @@ -5741,7 +5912,7 @@ lpfc_enable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, /* Create an lun info structure and add to list of luns */ lun_info = lpfc_create_device_data(phba, vport_wwpn, target_wwpn, lun, - pri, false); + pri, true); if (lun_info) { lun_info->oas_enabled = true; lun_info->priority = pri; @@ -5864,7 +6035,7 @@ struct scsi_host_template lpfc_template_no_hr = { .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, .cmd_per_lun = LPFC_CMD_PER_LUN, .shost_attrs = lpfc_hba_attrs, - .max_sectors = 0xFFFF, + .max_sectors = 0xFFFFFFFF, .vendor_id = LPFC_NL_VENDOR_ID, .change_queue_depth = scsi_change_queue_depth, .track_queue_depth = 1, diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4329cc44bb55..614f78dddafe 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -108,7 +108,7 @@ lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) * endianness. This function can be called with or without * lock. **/ -void +static void lpfc_sli4_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt) { uint64_t *src = srcp; @@ -1391,9 +1391,12 @@ lpfc_sli_cancel_iocbs(struct lpfc_hba *phba, struct list_head *iocblist, while (!list_empty(iocblist)) { list_remove_head(iocblist, piocb, struct lpfc_iocbq, list); - if (!piocb->iocb_cmpl) - lpfc_sli_release_iocbq(phba, piocb); - else { + if (!piocb->iocb_cmpl) { + if (piocb->iocb_flag & LPFC_IO_NVME) + lpfc_nvme_cancel_iocb(phba, piocb); + else + lpfc_sli_release_iocbq(phba, piocb); + } else { piocb->iocb.ulpStatus = ulpstatus; piocb->iocb.un.ulpWord[4] = ulpWord4; (piocb->iocb_cmpl) (phba, piocb, piocb); @@ -2426,6 +2429,20 @@ lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) return; } +static void +__lpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ + unsigned long iflags; + + if (ndlp->nlp_flag & NLP_RELEASE_RPI) { + lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); + spin_lock_irqsave(&vport->phba->ndlp_lock, iflags); + ndlp->nlp_flag &= ~NLP_RELEASE_RPI; + ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; + spin_unlock_irqrestore(&vport->phba->ndlp_lock, iflags); + } + ndlp->nlp_flag &= ~NLP_UNREG_INP; +} /** * lpfc_sli_def_mbox_cmpl - Default mailbox completion handler @@ -2497,7 +2514,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport, KERN_INFO, LOG_MBOX | LOG_DISCOVERY, "1438 UNREG cmpl deferred mbox x%x " - "on NPort x%x Data: x%x x%x %p\n", + "on NPort x%x Data: x%x x%x %px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_defer_did, ndlp); @@ -2507,7 +2524,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp->nlp_defer_did = NLP_EVT_NOTHING_PENDING; lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); } else { - ndlp->nlp_flag &= ~NLP_UNREG_INP; + __lpfc_sli_rpi_release(vport, ndlp); } pmb->ctx_ndlp = NULL; } @@ -2555,7 +2572,7 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport, KERN_INFO, LOG_MBOX | LOG_SLI, "0010 UNREG_LOGIN vpi:%x " "rpi:%x DID:%x defer x%x flg x%x " - "map:%x %p\n", + "map:%x %px\n", vport->vpi, ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_defer_did, ndlp->nlp_flag, @@ -2573,7 +2590,7 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport, KERN_INFO, LOG_DISCOVERY, "4111 UNREG cmpl deferred " "clr x%x on " - "NPort x%x Data: x%x %p\n", + "NPort x%x Data: x%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_defer_did, ndlp); ndlp->nlp_flag &= ~NLP_UNREG_INP; @@ -2582,7 +2599,7 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_issue_els_plogi( vport, ndlp->nlp_DID, 0); } else { - ndlp->nlp_flag &= ~NLP_UNREG_INP; + __lpfc_sli_rpi_release(vport, ndlp); } } } @@ -2695,7 +2712,7 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) /* Mailbox cmd <cmd> Cmpl <cmpl> */ lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, - "(%d):0307 Mailbox cmd x%x (x%x/x%x) Cmpl x%p " + "(%d):0307 Mailbox cmd x%x (x%x/x%x) Cmpl %ps " "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x " "x%x x%x x%x\n", pmb->vport ? pmb->vport->vpi : 0, @@ -3961,7 +3978,7 @@ lpfc_sli_abort_fcp_rings(struct lpfc_hba *phba) /* Look on all the FCP Rings for the iotag */ if (phba->sli_rev >= LPFC_SLI_REV4) { for (i = 0; i < phba->cfg_hdw_queue; i++) { - pring = phba->sli4_hba.hdwq[i].fcp_wq->pring; + pring = phba->sli4_hba.hdwq[i].io_wq->pring; lpfc_sli_abort_iocb_ring(phba, pring); } } else { @@ -3971,17 +3988,17 @@ lpfc_sli_abort_fcp_rings(struct lpfc_hba *phba) } /** - * lpfc_sli_flush_fcp_rings - flush all iocbs in the fcp ring + * lpfc_sli_flush_io_rings - flush all iocbs in the IO ring * @phba: Pointer to HBA context object. * - * This function flushes all iocbs in the fcp ring and frees all the iocb + * This function flushes all iocbs in the IO ring and frees all the iocb * objects in txq and txcmplq. This function will not issue abort iocbs * for all the iocb commands in txcmplq, they will just be returned with * IOERR_SLI_DOWN. This function is invoked with EEH when device's PCI * slot has been permanently disabled. **/ void -lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) +lpfc_sli_flush_io_rings(struct lpfc_hba *phba) { LIST_HEAD(txq); LIST_HEAD(txcmplq); @@ -3992,13 +4009,13 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); /* Indicate the I/O queues are flushed */ - phba->hba_flag |= HBA_FCP_IOQ_FLUSH; + phba->hba_flag |= HBA_IOQ_FLUSH; spin_unlock_irq(&phba->hbalock); /* Look on all the FCP Rings for the iotag */ if (phba->sli_rev >= LPFC_SLI_REV4) { for (i = 0; i < phba->cfg_hdw_queue; i++) { - pring = phba->sli4_hba.hdwq[i].fcp_wq->pring; + pring = phba->sli4_hba.hdwq[i].io_wq->pring; spin_lock_irq(&pring->ring_lock); /* Retrieve everything on txq */ @@ -4046,56 +4063,6 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) } /** - * lpfc_sli_flush_nvme_rings - flush all wqes in the nvme rings - * @phba: Pointer to HBA context object. - * - * This function flushes all wqes in the nvme rings and frees all resources - * in the txcmplq. This function does not issue abort wqes for the IO - * commands in txcmplq, they will just be returned with - * IOERR_SLI_DOWN. This function is invoked with EEH when device's PCI - * slot has been permanently disabled. - **/ -void -lpfc_sli_flush_nvme_rings(struct lpfc_hba *phba) -{ - LIST_HEAD(txcmplq); - struct lpfc_sli_ring *pring; - uint32_t i; - struct lpfc_iocbq *piocb, *next_iocb; - - if ((phba->sli_rev < LPFC_SLI_REV4) || - !(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) - return; - - /* Hint to other driver operations that a flush is in progress. */ - spin_lock_irq(&phba->hbalock); - phba->hba_flag |= HBA_NVME_IOQ_FLUSH; - spin_unlock_irq(&phba->hbalock); - - /* Cycle through all NVME rings and complete each IO with - * a local driver reason code. This is a flush so no - * abort exchange to FW. - */ - for (i = 0; i < phba->cfg_hdw_queue; i++) { - pring = phba->sli4_hba.hdwq[i].nvme_wq->pring; - - spin_lock_irq(&pring->ring_lock); - list_for_each_entry_safe(piocb, next_iocb, - &pring->txcmplq, list) - piocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; - /* Retrieve everything on the txcmplq */ - list_splice_init(&pring->txcmplq, &txcmplq); - pring->txcmplq_cnt = 0; - spin_unlock_irq(&pring->ring_lock); - - /* Flush the txcmpq &&&PAE */ - lpfc_sli_cancel_iocbs(phba, &txcmplq, - IOSTAT_LOCAL_REJECT, - IOERR_SLI_DOWN); - } -} - -/** * lpfc_sli_brdready_s3 - Check for sli3 host ready status * @phba: Pointer to HBA context object. * @mask: Bit mask to be checked. @@ -4495,7 +4462,7 @@ lpfc_sli_brdreset(struct lpfc_hba *phba) * checking during resets the device. The caller is not required to hold * any locks. * - * This function returns 0 always. + * This function returns 0 on success else returns negative error code. **/ int lpfc_sli4_brdreset(struct lpfc_hba *phba) @@ -4652,8 +4619,10 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED; rc = lpfc_sli4_brdreset(phba); - if (rc) - return rc; + if (rc) { + phba->link_state = LPFC_HBA_ERROR; + goto hba_down_queue; + } spin_lock_irq(&phba->hbalock); phba->pport->stopped = 0; @@ -4668,6 +4637,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) if (hba_aer_enabled) pci_disable_pcie_error_reporting(phba->pcidev); +hba_down_queue: lpfc_hba_down_post(phba); lpfc_sli4_queue_destroy(phba); @@ -5571,6 +5541,7 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) int qidx; struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba; struct lpfc_sli4_hdw_queue *qp; + struct lpfc_queue *eq; sli4_hba->sli4_write_cq_db(phba, sli4_hba->mbx_cq, 0, LPFC_QUEUE_REARM); sli4_hba->sli4_write_cq_db(phba, sli4_hba->els_cq, 0, LPFC_QUEUE_REARM); @@ -5578,18 +5549,22 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) sli4_hba->sli4_write_cq_db(phba, sli4_hba->nvmels_cq, 0, LPFC_QUEUE_REARM); - qp = sli4_hba->hdwq; if (sli4_hba->hdwq) { + /* Loop thru all Hardware Queues */ for (qidx = 0; qidx < phba->cfg_hdw_queue; qidx++) { - sli4_hba->sli4_write_cq_db(phba, qp[qidx].fcp_cq, 0, - LPFC_QUEUE_REARM); - sli4_hba->sli4_write_cq_db(phba, qp[qidx].nvme_cq, 0, - LPFC_QUEUE_REARM); + qp = &sli4_hba->hdwq[qidx]; + /* ARM the corresponding CQ */ + sli4_hba->sli4_write_cq_db(phba, qp->io_cq, 0, + LPFC_QUEUE_REARM); } - for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) - sli4_hba->sli4_write_eq_db(phba, qp[qidx].hba_eq, - 0, LPFC_QUEUE_REARM); + /* Loop thru all IRQ vectors */ + for (qidx = 0; qidx < phba->cfg_irq_chann; qidx++) { + eq = sli4_hba->hba_eq_hdl[qidx].eq; + /* ARM the corresponding EQ */ + sli4_hba->sli4_write_eq_db(phba, eq, + 0, LPFC_QUEUE_REARM); + } } if (phba->nvmet_support) { @@ -7236,7 +7211,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) else phba->hba_flag &= ~HBA_FIP_SUPPORT; - phba->hba_flag &= ~HBA_FCP_IOQ_FLUSH; + phba->hba_flag &= ~HBA_IOQ_FLUSH; if (phba->sli_rev != LPFC_SLI_REV4) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, @@ -7875,26 +7850,28 @@ lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba) * and will process all the completions associated with the eq for the * mailbox completion queue. **/ -bool +static bool lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba) { struct lpfc_sli4_hba *sli4_hba = &phba->sli4_hba; uint32_t eqidx; struct lpfc_queue *fpeq = NULL; + struct lpfc_queue *eq; bool mbox_pending; if (unlikely(!phba) || (phba->sli_rev != LPFC_SLI_REV4)) return false; - /* Find the eq associated with the mcq */ - - if (sli4_hba->hdwq) - for (eqidx = 0; eqidx < phba->cfg_irq_chann; eqidx++) - if (sli4_hba->hdwq[eqidx].hba_eq->queue_id == - sli4_hba->mbx_cq->assoc_qid) { - fpeq = sli4_hba->hdwq[eqidx].hba_eq; + /* Find the EQ associated with the mbox CQ */ + if (sli4_hba->hdwq) { + for (eqidx = 0; eqidx < phba->cfg_irq_chann; eqidx++) { + eq = phba->sli4_hba.hba_eq_hdl[eqidx].eq; + if (eq && eq->queue_id == sli4_hba->mbx_cq->assoc_qid) { + fpeq = eq; break; } + } + } if (!fpeq) return false; @@ -7963,7 +7940,7 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) /* Mbox cmd <mbxCommand> timeout */ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0310 Mailbox command x%x timeout Data: x%x x%x x%p\n", + "0310 Mailbox command x%x timeout Data: x%x x%x x%px\n", mb->mbxCommand, phba->pport->port_state, phba->sli.sli_flag, @@ -9324,11 +9301,9 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, memset(wqe, 0, sizeof(union lpfc_wqe128)); /* Some of the fields are in the right position already */ memcpy(wqe, &iocbq->iocb, sizeof(union lpfc_wqe)); - if (iocbq->iocb.ulpCommand != CMD_SEND_FRAME) { - /* The ct field has moved so reset */ - wqe->generic.wqe_com.word7 = 0; - wqe->generic.wqe_com.word10 = 0; - } + /* The ct field has moved so reset */ + wqe->generic.wqe_com.word7 = 0; + wqe->generic.wqe_com.word10 = 0; abort_tag = (uint32_t) iocbq->iotag; xritag = iocbq->sli4_xritag; @@ -9787,7 +9762,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, * we re-construct this WQE here based on information in * iocbq from scratch. */ - memset(wqe, 0, sizeof(union lpfc_wqe)); + memset(wqe, 0, sizeof(*wqe)); /* OX_ID is invariable to who sent ABTS to CT exchange */ bf_set(xmit_bls_rsp64_oxid, &wqe->xmit_bls_rsp, bf_get(lpfc_abts_oxid, &iocbq->iocb.un.bls_rsp)); @@ -9834,6 +9809,15 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, break; case CMD_SEND_FRAME: + bf_set(wqe_cmnd, &wqe->generic.wqe_com, CMD_SEND_FRAME); + bf_set(wqe_sof, &wqe->generic.wqe_com, 0x2E); /* SOF byte */ + bf_set(wqe_eof, &wqe->generic.wqe_com, 0x41); /* EOF byte */ + bf_set(wqe_lenloc, &wqe->generic.wqe_com, 1); + bf_set(wqe_xbl, &wqe->generic.wqe_com, 1); + bf_set(wqe_dbde, &wqe->generic.wqe_com, 1); + bf_set(wqe_xc, &wqe->generic.wqe_com, 1); + bf_set(wqe_cmd_type, &wqe->generic.wqe_com, 0xA); + bf_set(wqe_cqid, &wqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); bf_set(wqe_xri_tag, &wqe->generic.wqe_com, xritag); bf_set(wqe_reqtag, &wqe->generic.wqe_com, iocbq->iotag); return 0; @@ -9895,7 +9879,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, /* Get the WQ */ if ((piocb->iocb_flag & LPFC_IO_FCP) || (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) { - wq = phba->sli4_hba.hdwq[piocb->hba_wqidx].fcp_wq; + wq = phba->sli4_hba.hdwq[piocb->hba_wqidx].io_wq; } else { wq = phba->sli4_hba.els_wq; } @@ -10042,7 +10026,7 @@ lpfc_sli4_calc_ring(struct lpfc_hba *phba, struct lpfc_iocbq *piocb) lpfc_cmd = (struct lpfc_io_buf *)piocb->context1; piocb->hba_wqidx = lpfc_cmd->hdwq_no; } - return phba->sli4_hba.hdwq[piocb->hba_wqidx].fcp_wq->pring; + return phba->sli4_hba.hdwq[piocb->hba_wqidx].io_wq->pring; } else { if (unlikely(!phba->sli4_hba.els_wq)) return NULL; @@ -10495,7 +10479,7 @@ lpfc_sli4_queue_init(struct lpfc_hba *phba) INIT_LIST_HEAD(&psli->mboxq_cmpl); /* Initialize list headers for txq and txcmplq as double linked lists */ for (i = 0; i < phba->cfg_hdw_queue; i++) { - pring = phba->sli4_hba.hdwq[i].fcp_wq->pring; + pring = phba->sli4_hba.hdwq[i].io_wq->pring; pring->flag = 0; pring->ringno = LPFC_FCP_RING; pring->txcmplq_cnt = 0; @@ -10514,16 +10498,6 @@ lpfc_sli4_queue_init(struct lpfc_hba *phba) spin_lock_init(&pring->ring_lock); if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { - for (i = 0; i < phba->cfg_hdw_queue; i++) { - pring = phba->sli4_hba.hdwq[i].nvme_wq->pring; - pring->flag = 0; - pring->ringno = LPFC_FCP_RING; - pring->txcmplq_cnt = 0; - INIT_LIST_HEAD(&pring->txq); - INIT_LIST_HEAD(&pring->txcmplq); - INIT_LIST_HEAD(&pring->iocb_continueq); - spin_lock_init(&pring->ring_lock); - } pring = phba->sli4_hba.nvmels_wq->pring; pring->flag = 0; pring->ringno = LPFC_ELS_RING; @@ -10787,9 +10761,9 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) pring = qp->pring; if (!pring) continue; - spin_lock_irq(&pring->ring_lock); + spin_lock(&pring->ring_lock); list_splice_init(&pring->txq, &completions); - spin_unlock_irq(&pring->ring_lock); + spin_unlock(&pring->ring_lock); if (pring == phba->sli4_hba.els_wq->pring) { pring->flag |= LPFC_DEFERRED_RING_EVENT; /* Set the lpfc data pending flag */ @@ -10970,7 +10944,7 @@ lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, spin_unlock_irq(&phba->hbalock); lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0402 Cannot find virtual addr for buffer tag on " - "ring %d Data x%lx x%p x%p x%x\n", + "ring %d Data x%lx x%px x%px x%x\n", pring->ringno, (unsigned long) tag, slp->next, slp->prev, pring->postbufq_cnt); @@ -11014,7 +10988,7 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, spin_unlock_irq(&phba->hbalock); lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0410 Cannot find virtual addr for mapped buf on " - "ring %d Data x%llx x%p x%p x%x\n", + "ring %d Data x%llx x%px x%px x%x\n", pring->ringno, (unsigned long long)phys, slp->next, slp->prev, pring->postbufq_cnt); return NULL; @@ -11069,13 +11043,16 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, abort_iocb = phba->sli.iocbq_lookup[abort_context]; lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_SLI, - "0327 Cannot abort els iocb %p " + "0327 Cannot abort els iocb x%px " "with tag %x context %x, abort status %x, " "abort code %x\n", abort_iocb, abort_iotag, abort_context, irsp->ulpStatus, irsp->un.ulpWord[4]); spin_unlock_irq(&phba->hbalock); + if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT && + irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) + lpfc_sli_release_iocbq(phba, abort_iocb); } release_iocb: lpfc_sli_release_iocbq(phba, cmdiocb); @@ -11484,7 +11461,7 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, int i; /* all I/Os are in process of being flushed */ - if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) + if (phba->hba_flag & HBA_IOQ_FLUSH) return errcnt; for (i = 1; i <= phba->sli.last_iotag; i++) { @@ -11594,7 +11571,7 @@ lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, spin_lock_irqsave(&phba->hbalock, iflags); /* all I/Os are in process of being flushed */ - if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) { + if (phba->hba_flag & HBA_IOQ_FLUSH) { spin_unlock_irqrestore(&phba->hbalock, iflags); return 0; } @@ -11618,7 +11595,7 @@ lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, if (phba->sli_rev == LPFC_SLI_REV4) { pring_s4 = - phba->sli4_hba.hdwq[iocbq->hba_wqidx].fcp_wq->pring; + phba->sli4_hba.hdwq[iocbq->hba_wqidx].io_wq->pring; if (!pring_s4) { spin_unlock(&lpfc_cmd->buf_lock); continue; @@ -13327,8 +13304,13 @@ lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, unsigned long iflags; switch (cq->subtype) { - case LPFC_FCP: - lpfc_sli4_fcp_xri_aborted(phba, wcqe, cq->hdwq); + case LPFC_IO: + lpfc_sli4_io_xri_aborted(phba, wcqe, cq->hdwq); + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { + /* Notify aborted XRI for NVME work queue */ + if (phba->nvmet_support) + lpfc_sli4_nvmet_xri_aborted(phba, wcqe); + } workposted = false; break; case LPFC_NVME_LS: /* NVME LS uses ELS resources */ @@ -13346,15 +13328,6 @@ lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, spin_unlock_irqrestore(&phba->hbalock, iflags); workposted = true; break; - case LPFC_NVME: - /* Notify aborted XRI for NVME work queue */ - if (phba->nvmet_support) - lpfc_sli4_nvmet_xri_aborted(phba, wcqe); - else - lpfc_sli4_nvme_xri_aborted(phba, wcqe, cq->hdwq); - - workposted = false; - break; default: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0603 Invalid CQ subtype %d: " @@ -13605,14 +13578,9 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq, goto rearm_and_exit; /* Process all the entries to the CQ */ + cq->q_flag = 0; cqe = lpfc_sli4_cq_get(cq); while (cqe) { -#if defined(CONFIG_SCSI_LPFC_DEBUG_FS) && defined(BUILD_NVME) - if (phba->ktime_on) - cq->isr_timestamp = ktime_get_ns(); - else - cq->isr_timestamp = 0; -#endif workposted |= handler(phba, cq, cqe); __lpfc_sli4_consume_cqe(phba, cq, cqe); @@ -13626,6 +13594,9 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq, consumed = 0; } + if (count == LPFC_NVMET_CQ_NOTIFY) + cq->q_flag |= HBA_NVMET_CQ_NOTIFY; + cqe = lpfc_sli4_cq_get(cq); } if (count >= phba->cfg_cq_poll_threshold) { @@ -13684,7 +13655,7 @@ __lpfc_sli4_sp_process_cq(struct lpfc_queue *cq) &delay); break; case LPFC_WCQ: - if (cq->subtype == LPFC_FCP || cq->subtype == LPFC_NVME) + if (cq->subtype == LPFC_IO) workposted |= __lpfc_sli4_process_cq(phba, cq, lpfc_sli4_fp_handle_cqe, &delay); @@ -13941,10 +13912,10 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, goto drop; if (fc_hdr->fh_type == FC_TYPE_FCP) { - dma_buf->bytes_recv = bf_get(lpfc_rcqe_length, rcqe); + dma_buf->bytes_recv = bf_get(lpfc_rcqe_length, rcqe); lpfc_nvmet_unsol_fcp_event( - phba, idx, dma_buf, - cq->isr_timestamp); + phba, idx, dma_buf, cq->isr_timestamp, + cq->q_flag & HBA_NVMET_CQ_NOTIFY); return false; } drop: @@ -14001,10 +13972,7 @@ lpfc_sli4_fp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, cq->CQ_wq++; /* Process the WQ complete event */ phba->last_completion_time = jiffies; - if ((cq->subtype == LPFC_FCP) || (cq->subtype == LPFC_NVME)) - lpfc_sli4_fp_handle_fcp_wcqe(phba, cq, - (struct lpfc_wcqe_complete *)&wcqe); - if (cq->subtype == LPFC_NVME_LS) + if (cq->subtype == LPFC_IO || cq->subtype == LPFC_NVME_LS) lpfc_sli4_fp_handle_fcp_wcqe(phba, cq, (struct lpfc_wcqe_complete *)&wcqe); break; @@ -14110,6 +14078,12 @@ process_cq: } work_cq: +#if defined(CONFIG_SCSI_LPFC_DEBUG_FS) + if (phba->ktime_on) + cq->isr_timestamp = ktime_get_ns(); + else + cq->isr_timestamp = 0; +#endif if (!queue_work_on(cq->chann, phba->wq, &cq->irqwork)) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0363 Cannot schedule soft IRQ " @@ -14236,7 +14210,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) return IRQ_NONE; /* Get to the EQ struct associated with this vector */ - fpeq = phba->sli4_hba.hdwq[hba_eqidx].hba_eq; + fpeq = phba->sli4_hba.hba_eq_hdl[hba_eqidx].eq; if (unlikely(!fpeq)) return IRQ_NONE; @@ -14521,7 +14495,7 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, /* set values by EQ_DELAY register if supported */ if (phba->sli.sli_flag & LPFC_SLI_USE_EQDR) { for (qidx = startq; qidx < phba->cfg_irq_chann; qidx++) { - eq = phba->sli4_hba.hdwq[qidx].hba_eq; + eq = phba->sli4_hba.hba_eq_hdl[qidx].eq; if (!eq) continue; @@ -14530,7 +14504,6 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, if (++cnt >= numq) break; } - return; } @@ -14558,7 +14531,7 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq, dmult = LPFC_DMULT_MAX; for (qidx = startq; qidx < phba->cfg_irq_chann; qidx++) { - eq = phba->sli4_hba.hdwq[qidx].hba_eq; + eq = phba->sli4_hba.hba_eq_hdl[qidx].eq; if (!eq) continue; eq->q_mode = usdelay; @@ -14660,8 +14633,10 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0360 Unsupported EQ count. (%d)\n", eq->entry_count); - if (eq->entry_count < 256) - return -EINVAL; + if (eq->entry_count < 256) { + status = -EINVAL; + goto out; + } /* fall through - otherwise default to smallest count */ case 256: bf_set(lpfc_eq_context_count, &eq_create->u.request.context, @@ -14713,7 +14688,7 @@ lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint32_t imax) eq->host_index = 0; eq->notify_interval = LPFC_EQ_NOTIFY_INTRVL; eq->max_proc_limit = LPFC_EQ_MAX_PROC_LIMIT; - +out: mempool_free(mbox, phba->mbox_mem_pool); return status; } @@ -16904,6 +16879,8 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr) struct fc_vft_header *fc_vft_hdr; uint32_t *header = (uint32_t *) fc_hdr; +#define FC_RCTL_MDS_DIAGS 0xF4 + switch (fc_hdr->fh_r_ctl) { case FC_RCTL_DD_UNCAT: /* uncategorized information */ case FC_RCTL_DD_SOL_DATA: /* solicited data */ @@ -17431,7 +17408,6 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport, icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; ctiocb->context1 = lpfc_nlp_get(ndlp); - ctiocb->iocb_cmpl = NULL; ctiocb->vport = phba->pport; ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_rsp_cmpl; ctiocb->sli4_lxritag = NO_XRI; @@ -17914,6 +17890,17 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->cq_event.cqe.rcqe_cmpl); + if (fc_hdr->fh_r_ctl == 0xF4 && fc_hdr->fh_type == 0xFF) { + vport = phba->pport; + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2023 MDS Loopback %d bytes\n", + bf_get(lpfc_rcqe_length, + &dmabuf->cq_event.cqe.rcqe_cmpl)); + /* Handle MDS Loopback frames */ + lpfc_sli4_handle_mds_loopback(vport, dmabuf); + return; + } + /* d_id this frame is directed to */ did = sli4_did_from_fc_hdr(fc_hdr); @@ -18197,6 +18184,10 @@ __lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi) if (test_and_clear_bit(rpi, phba->sli4_hba.rpi_bmask)) { phba->sli4_hba.rpi_count--; phba->sli4_hba.max_cfg_param.rpi_used--; + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2016 rpi %x not inuse\n", + rpi); } } @@ -19447,7 +19438,7 @@ lpfc_drain_txq(struct lpfc_hba *phba) if (phba->link_flag & LS_MDS_LOOPBACK) { /* MDS WQE are posted only to first WQ*/ - wq = phba->sli4_hba.hdwq[0].fcp_wq; + wq = phba->sli4_hba.hdwq[0].io_wq; if (unlikely(!wq)) return 0; pring = wq->pring; @@ -19698,10 +19689,10 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, /* NVME_FCREQ and NVME_ABTS requests */ if (pwqe->iocb_flag & LPFC_IO_NVME) { /* Get the IO distribution (hba_wqidx) for WQ assignment. */ - wq = qp->nvme_wq; + wq = qp->io_wq; pring = wq->pring; - bf_set(wqe_cqid, &wqe->generic.wqe_com, qp->nvme_cq_map); + bf_set(wqe_cqid, &wqe->generic.wqe_com, qp->io_cq_map); lpfc_qp_spin_lock_irqsave(&pring->ring_lock, iflags, qp, wq_access); @@ -19718,7 +19709,7 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, /* NVMET requests */ if (pwqe->iocb_flag & LPFC_IO_NVMET) { /* Get the IO distribution (hba_wqidx) for WQ assignment. */ - wq = qp->nvme_wq; + wq = qp->io_wq; pring = wq->pring; ctxp = pwqe->context2; @@ -19729,7 +19720,7 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, } bf_set(wqe_xri_tag, &pwqe->wqe.xmit_bls_rsp.wqe_com, pwqe->sli4_xritag); - bf_set(wqe_cqid, &wqe->generic.wqe_com, qp->nvme_cq_map); + bf_set(wqe_cqid, &wqe->generic.wqe_com, qp->io_cq_map); lpfc_qp_spin_lock_irqsave(&pring->ring_lock, iflags, qp, wq_access); @@ -19776,9 +19767,7 @@ void lpfc_snapshot_mxp(struct lpfc_hba *phba, u32 hwqid) if (multixri_pool->stat_snapshot_taken == LPFC_MXP_SNAPSHOT_TAKEN) { pvt_pool = &qp->p_multixri_pool->pvt_pool; pbl_pool = &qp->p_multixri_pool->pbl_pool; - txcmplq_cnt = qp->fcp_wq->pring->txcmplq_cnt; - if (qp->nvme_wq) - txcmplq_cnt += qp->nvme_wq->pring->txcmplq_cnt; + txcmplq_cnt = qp->io_wq->pring->txcmplq_cnt; multixri_pool->stat_pbl_count = pbl_pool->count; multixri_pool->stat_pvt_count = pvt_pool->count; @@ -19848,12 +19837,9 @@ void lpfc_adjust_high_watermark(struct lpfc_hba *phba, u32 hwqid) watermark_max = xri_limit; watermark_min = xri_limit / 2; - txcmplq_cnt = qp->fcp_wq->pring->txcmplq_cnt; + txcmplq_cnt = qp->io_wq->pring->txcmplq_cnt; abts_io_bufs = qp->abts_scsi_io_bufs; - if (qp->nvme_wq) { - txcmplq_cnt += qp->nvme_wq->pring->txcmplq_cnt; - abts_io_bufs += qp->abts_nvme_io_bufs; - } + abts_io_bufs += qp->abts_nvme_io_bufs; new_watermark = txcmplq_cnt + abts_io_bufs; new_watermark = min(watermark_max, new_watermark); @@ -20128,12 +20114,9 @@ void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd, pbl_pool = &qp->p_multixri_pool->pbl_pool; pvt_pool = &qp->p_multixri_pool->pvt_pool; - txcmplq_cnt = qp->fcp_wq->pring->txcmplq_cnt; + txcmplq_cnt = qp->io_wq->pring->txcmplq_cnt; abts_io_bufs = qp->abts_scsi_io_bufs; - if (qp->nvme_wq) { - txcmplq_cnt += qp->nvme_wq->pring->txcmplq_cnt; - abts_io_bufs += qp->abts_nvme_io_bufs; - } + abts_io_bufs += qp->abts_nvme_io_bufs; xri_owned = pvt_pool->count + txcmplq_cnt + abts_io_bufs; xri_limit = qp->p_multixri_pool->xri_limit; @@ -20174,6 +20157,13 @@ void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd, spin_unlock_irqrestore(&qp->io_buf_list_put_lock, iflag); } + + if (phba->cfg_xpsgl && !phba->nvmet_support && + !list_empty(&lpfc_ncmd->dma_sgl_xtra_list)) + lpfc_put_sgl_per_hdwq(phba, lpfc_ncmd); + + if (!list_empty(&lpfc_ncmd->dma_cmd_rsp_list)) + lpfc_put_cmd_rsp_buf_per_hdwq(phba, lpfc_ncmd); } /** @@ -20388,3 +20378,288 @@ struct lpfc_io_buf *lpfc_get_io_buf(struct lpfc_hba *phba, return lpfc_cmd; } + +/** + * lpfc_get_sgl_per_hdwq - Get one SGL chunk from hdwq's pool + * @phba: The HBA for which this call is being executed. + * @lpfc_buf: IO buf structure to append the SGL chunk + * + * This routine gets one SGL chunk buffer from hdwq's SGL chunk pool, + * and will allocate an SGL chunk if the pool is empty. + * + * Return codes: + * NULL - Error + * Pointer to sli4_hybrid_sgl - Success + **/ +struct sli4_hybrid_sgl * +lpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf) +{ + struct sli4_hybrid_sgl *list_entry = NULL; + struct sli4_hybrid_sgl *tmp = NULL; + struct sli4_hybrid_sgl *allocated_sgl = NULL; + struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq; + struct list_head *buf_list = &hdwq->sgl_list; + + spin_lock_irq(&hdwq->hdwq_lock); + + if (likely(!list_empty(buf_list))) { + /* break off 1 chunk from the sgl_list */ + list_for_each_entry_safe(list_entry, tmp, + buf_list, list_node) { + list_move_tail(&list_entry->list_node, + &lpfc_buf->dma_sgl_xtra_list); + break; + } + } else { + /* allocate more */ + spin_unlock_irq(&hdwq->hdwq_lock); + tmp = kmalloc_node(sizeof(*tmp), GFP_ATOMIC, + cpu_to_node(smp_processor_id())); + if (!tmp) { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "8353 error kmalloc memory for HDWQ " + "%d %s\n", + lpfc_buf->hdwq_no, __func__); + return NULL; + } + + tmp->dma_sgl = dma_pool_alloc(phba->lpfc_sg_dma_buf_pool, + GFP_ATOMIC, &tmp->dma_phys_sgl); + if (!tmp->dma_sgl) { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "8354 error pool_alloc memory for HDWQ " + "%d %s\n", + lpfc_buf->hdwq_no, __func__); + kfree(tmp); + return NULL; + } + + spin_lock_irq(&hdwq->hdwq_lock); + list_add_tail(&tmp->list_node, &lpfc_buf->dma_sgl_xtra_list); + } + + allocated_sgl = list_last_entry(&lpfc_buf->dma_sgl_xtra_list, + struct sli4_hybrid_sgl, + list_node); + + spin_unlock_irq(&hdwq->hdwq_lock); + + return allocated_sgl; +} + +/** + * lpfc_put_sgl_per_hdwq - Put one SGL chunk into hdwq pool + * @phba: The HBA for which this call is being executed. + * @lpfc_buf: IO buf structure with the SGL chunk + * + * This routine puts one SGL chunk buffer into hdwq's SGL chunk pool. + * + * Return codes: + * 0 - Success + * -EINVAL - Error + **/ +int +lpfc_put_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf) +{ + int rc = 0; + struct sli4_hybrid_sgl *list_entry = NULL; + struct sli4_hybrid_sgl *tmp = NULL; + struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq; + struct list_head *buf_list = &hdwq->sgl_list; + + spin_lock_irq(&hdwq->hdwq_lock); + + if (likely(!list_empty(&lpfc_buf->dma_sgl_xtra_list))) { + list_for_each_entry_safe(list_entry, tmp, + &lpfc_buf->dma_sgl_xtra_list, + list_node) { + list_move_tail(&list_entry->list_node, + buf_list); + } + } else { + rc = -EINVAL; + } + + spin_unlock_irq(&hdwq->hdwq_lock); + return rc; +} + +/** + * lpfc_free_sgl_per_hdwq - Free all SGL chunks of hdwq pool + * @phba: phba object + * @hdwq: hdwq to cleanup sgl buff resources on + * + * This routine frees all SGL chunks of hdwq SGL chunk pool. + * + * Return codes: + * None + **/ +void +lpfc_free_sgl_per_hdwq(struct lpfc_hba *phba, + struct lpfc_sli4_hdw_queue *hdwq) +{ + struct list_head *buf_list = &hdwq->sgl_list; + struct sli4_hybrid_sgl *list_entry = NULL; + struct sli4_hybrid_sgl *tmp = NULL; + + spin_lock_irq(&hdwq->hdwq_lock); + + /* Free sgl pool */ + list_for_each_entry_safe(list_entry, tmp, + buf_list, list_node) { + dma_pool_free(phba->lpfc_sg_dma_buf_pool, + list_entry->dma_sgl, + list_entry->dma_phys_sgl); + list_del(&list_entry->list_node); + kfree(list_entry); + } + + spin_unlock_irq(&hdwq->hdwq_lock); +} + +/** + * lpfc_get_cmd_rsp_buf_per_hdwq - Get one CMD/RSP buffer from hdwq + * @phba: The HBA for which this call is being executed. + * @lpfc_buf: IO buf structure to attach the CMD/RSP buffer + * + * This routine gets one CMD/RSP buffer from hdwq's CMD/RSP pool, + * and will allocate an CMD/RSP buffer if the pool is empty. + * + * Return codes: + * NULL - Error + * Pointer to fcp_cmd_rsp_buf - Success + **/ +struct fcp_cmd_rsp_buf * +lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, + struct lpfc_io_buf *lpfc_buf) +{ + struct fcp_cmd_rsp_buf *list_entry = NULL; + struct fcp_cmd_rsp_buf *tmp = NULL; + struct fcp_cmd_rsp_buf *allocated_buf = NULL; + struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq; + struct list_head *buf_list = &hdwq->cmd_rsp_buf_list; + + spin_lock_irq(&hdwq->hdwq_lock); + + if (likely(!list_empty(buf_list))) { + /* break off 1 chunk from the list */ + list_for_each_entry_safe(list_entry, tmp, + buf_list, + list_node) { + list_move_tail(&list_entry->list_node, + &lpfc_buf->dma_cmd_rsp_list); + break; + } + } else { + /* allocate more */ + spin_unlock_irq(&hdwq->hdwq_lock); + tmp = kmalloc_node(sizeof(*tmp), GFP_ATOMIC, + cpu_to_node(smp_processor_id())); + if (!tmp) { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "8355 error kmalloc memory for HDWQ " + "%d %s\n", + lpfc_buf->hdwq_no, __func__); + return NULL; + } + + tmp->fcp_cmnd = dma_pool_alloc(phba->lpfc_cmd_rsp_buf_pool, + GFP_ATOMIC, + &tmp->fcp_cmd_rsp_dma_handle); + + if (!tmp->fcp_cmnd) { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "8356 error pool_alloc memory for HDWQ " + "%d %s\n", + lpfc_buf->hdwq_no, __func__); + kfree(tmp); + return NULL; + } + + tmp->fcp_rsp = (struct fcp_rsp *)((uint8_t *)tmp->fcp_cmnd + + sizeof(struct fcp_cmnd)); + + spin_lock_irq(&hdwq->hdwq_lock); + list_add_tail(&tmp->list_node, &lpfc_buf->dma_cmd_rsp_list); + } + + allocated_buf = list_last_entry(&lpfc_buf->dma_cmd_rsp_list, + struct fcp_cmd_rsp_buf, + list_node); + + spin_unlock_irq(&hdwq->hdwq_lock); + + return allocated_buf; +} + +/** + * lpfc_put_cmd_rsp_buf_per_hdwq - Put one CMD/RSP buffer into hdwq pool + * @phba: The HBA for which this call is being executed. + * @lpfc_buf: IO buf structure with the CMD/RSP buf + * + * This routine puts one CMD/RSP buffer into executing CPU's CMD/RSP pool. + * + * Return codes: + * 0 - Success + * -EINVAL - Error + **/ +int +lpfc_put_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, + struct lpfc_io_buf *lpfc_buf) +{ + int rc = 0; + struct fcp_cmd_rsp_buf *list_entry = NULL; + struct fcp_cmd_rsp_buf *tmp = NULL; + struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq; + struct list_head *buf_list = &hdwq->cmd_rsp_buf_list; + + spin_lock_irq(&hdwq->hdwq_lock); + + if (likely(!list_empty(&lpfc_buf->dma_cmd_rsp_list))) { + list_for_each_entry_safe(list_entry, tmp, + &lpfc_buf->dma_cmd_rsp_list, + list_node) { + list_move_tail(&list_entry->list_node, + buf_list); + } + } else { + rc = -EINVAL; + } + + spin_unlock_irq(&hdwq->hdwq_lock); + return rc; +} + +/** + * lpfc_free_cmd_rsp_buf_per_hdwq - Free all CMD/RSP chunks of hdwq pool + * @phba: phba object + * @hdwq: hdwq to cleanup cmd rsp buff resources on + * + * This routine frees all CMD/RSP buffers of hdwq's CMD/RSP buf pool. + * + * Return codes: + * None + **/ +void +lpfc_free_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, + struct lpfc_sli4_hdw_queue *hdwq) +{ + struct list_head *buf_list = &hdwq->cmd_rsp_buf_list; + struct fcp_cmd_rsp_buf *list_entry = NULL; + struct fcp_cmd_rsp_buf *tmp = NULL; + + spin_lock_irq(&hdwq->hdwq_lock); + + /* Free cmd_rsp buf pool */ + list_for_each_entry_safe(list_entry, tmp, + buf_list, + list_node) { + dma_pool_free(phba->lpfc_cmd_rsp_buf_pool, + list_entry->fcp_cmnd, + list_entry->fcp_cmd_rsp_dma_handle); + list_del(&list_entry->list_node); + kfree(list_entry); + } + + spin_unlock_irq(&hdwq->hdwq_lock); +} diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 467b8270f7fd..37fbcb46387e 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -365,9 +365,18 @@ struct lpfc_io_buf { /* Common fields */ struct list_head list; void *data; + dma_addr_t dma_handle; dma_addr_t dma_phys_sgl; - struct sli4_sge *dma_sgl; + + struct sli4_sge *dma_sgl; /* initial segment chunk */ + + /* linked list of extra sli4_hybrid_sge */ + struct list_head dma_sgl_xtra_list; + + /* list head for fcp_cmd_rsp buf */ + struct list_head dma_cmd_rsp_list; + struct lpfc_iocbq cur_iocbq; struct lpfc_sli4_hdw_queue *hdwq; uint16_t hdwq_no; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 8e4fd1a98023..0d4882a9e634 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -44,8 +44,10 @@ #define LPFC_HBA_HDWQ_MAX 128 #define LPFC_HBA_HDWQ_DEF 0 -/* Common buffer size to accomidate SCSI and NVME IO buffers */ -#define LPFC_COMMON_IO_BUF_SZ 768 +/* FCP MQ queue count limiting */ +#define LPFC_FCP_MQ_THRESHOLD_MIN 0 +#define LPFC_FCP_MQ_THRESHOLD_MAX 256 +#define LPFC_FCP_MQ_THRESHOLD_DEF 8 /* * Provide the default FCF Record attributes used by the driver @@ -109,9 +111,8 @@ enum lpfc_sli4_queue_type { enum lpfc_sli4_queue_subtype { LPFC_NONE, LPFC_MBOX, - LPFC_FCP, + LPFC_IO, LPFC_ELS, - LPFC_NVME, LPFC_NVMET, LPFC_NVME_LS, LPFC_USOL @@ -197,6 +198,8 @@ struct lpfc_queue { #define LPFC_DB_LIST_FORMAT 0x02 uint8_t q_flag; #define HBA_NVMET_WQFULL 0x1 /* We hit WQ Full condition for NVMET */ +#define HBA_NVMET_CQ_NOTIFY 0x1 /* LPFC_NVMET_CQ_NOTIFY CQEs this EQE */ +#define LPFC_NVMET_CQ_NOTIFY 4 void __iomem *db_regaddr; uint16_t dpp_enable; uint16_t dpp_id; @@ -450,6 +453,7 @@ struct lpfc_hba_eq_hdl { uint32_t idx; char handler_name[LPFC_SLI4_HANDLER_NAME_SZ]; struct lpfc_hba *phba; + struct lpfc_queue *eq; }; /*BB Credit recovery value*/ @@ -512,6 +516,7 @@ struct lpfc_pc_sli4_params { #define LPFC_WQ_SZ64_SUPPORT 1 #define LPFC_WQ_SZ128_SUPPORT 2 uint8_t wqpcnt; + uint8_t nvme; }; #define LPFC_CQ_4K_PAGE_SZ 0x1 @@ -546,7 +551,10 @@ struct lpfc_vector_map_info { uint16_t irq; uint16_t eq; uint16_t hdwq; - uint16_t hyper; + uint16_t flag; +#define LPFC_CPU_MAP_HYPER 0x1 +#define LPFC_CPU_MAP_UNASSIGN 0x2 +#define LPFC_CPU_FIRST_IRQ 0x4 }; #define LPFC_VECTOR_MAP_EMPTY 0xffff @@ -634,22 +642,17 @@ struct lpfc_eq_intr_info { struct lpfc_sli4_hdw_queue { /* Pointers to the constructed SLI4 queues */ struct lpfc_queue *hba_eq; /* Event queues for HBA */ - struct lpfc_queue *fcp_cq; /* Fast-path FCP compl queue */ - struct lpfc_queue *nvme_cq; /* Fast-path NVME compl queue */ - struct lpfc_queue *fcp_wq; /* Fast-path FCP work queue */ - struct lpfc_queue *nvme_wq; /* Fast-path NVME work queue */ - uint16_t fcp_cq_map; - uint16_t nvme_cq_map; + struct lpfc_queue *io_cq; /* Fast-path FCP & NVME compl queue */ + struct lpfc_queue *io_wq; /* Fast-path FCP & NVME work queue */ + uint16_t io_cq_map; /* Keep track of IO buffers for this hardware queue */ spinlock_t io_buf_list_get_lock; /* Common buf alloc list lock */ struct list_head lpfc_io_buf_list_get; spinlock_t io_buf_list_put_lock; /* Common buf free list lock */ struct list_head lpfc_io_buf_list_put; - spinlock_t abts_scsi_buf_list_lock; /* list of aborted SCSI IOs */ - struct list_head lpfc_abts_scsi_buf_list; - spinlock_t abts_nvme_buf_list_lock; /* list of aborted NVME IOs */ - struct list_head lpfc_abts_nvme_buf_list; + spinlock_t abts_io_buf_list_lock; /* list of aborted IOs */ + struct list_head lpfc_abts_io_buf_list; uint32_t total_io_bufs; uint32_t get_io_bufs; uint32_t put_io_bufs; @@ -673,6 +676,13 @@ struct lpfc_sli4_hdw_queue { uint32_t cpucheck_xmt_io[LPFC_CHECK_CPU_CNT]; uint32_t cpucheck_cmpl_io[LPFC_CHECK_CPU_CNT]; #endif + + /* Per HDWQ pool resources */ + struct list_head sgl_list; + struct list_head cmd_rsp_buf_list; + + /* Lock for syncing Per HDWQ pool resources */ + spinlock_t hdwq_lock; }; #ifdef LPFC_HDWQ_LOCK_STAT @@ -838,11 +848,13 @@ struct lpfc_sli4_hba { struct lpfc_queue **cq_lookup; struct list_head lpfc_els_sgl_list; struct list_head lpfc_abts_els_sgl_list; - spinlock_t abts_scsi_buf_list_lock; /* list of aborted SCSI IOs */ - struct list_head lpfc_abts_scsi_buf_list; + spinlock_t abts_io_buf_list_lock; /* list of aborted SCSI IOs */ + struct list_head lpfc_abts_io_buf_list; struct list_head lpfc_nvmet_sgl_list; spinlock_t abts_nvmet_buf_list_lock; /* list of aborted NVMET IOs */ struct list_head lpfc_abts_nvmet_ctx_list; + spinlock_t t_active_list_lock; /* list of active NVMET IOs */ + struct list_head t_active_ctx_list; struct list_head lpfc_nvmet_io_wait_list; struct lpfc_nvmet_ctx_info *nvmet_ctx_info; struct lpfc_sglq **lpfc_sglq_active_list; @@ -1042,10 +1054,11 @@ int lpfc_sli4_resume_rpi(struct lpfc_nodelist *, void (*)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *); void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *); void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *); -void lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *, - struct sli4_wcqe_xri_aborted *, int); void lpfc_sli4_nvme_xri_aborted(struct lpfc_hba *phba, - struct sli4_wcqe_xri_aborted *axri, int idx); + struct sli4_wcqe_xri_aborted *axri, + struct lpfc_io_buf *lpfc_ncmd); +void lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, + struct sli4_wcqe_xri_aborted *axri, int idx); void lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, struct sli4_wcqe_xri_aborted *axri); void lpfc_sli4_els_xri_aborted(struct lpfc_hba *, @@ -1080,6 +1093,17 @@ int lpfc_sli4_post_status_check(struct lpfc_hba *); uint8_t lpfc_sli_config_mbox_subsys_get(struct lpfc_hba *, LPFC_MBOXQ_t *); uint8_t lpfc_sli_config_mbox_opcode_get(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_sli4_ras_dma_free(struct lpfc_hba *phba); +struct sli4_hybrid_sgl *lpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, + struct lpfc_io_buf *buf); +struct fcp_cmd_rsp_buf *lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, + struct lpfc_io_buf *buf); +int lpfc_put_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *buf); +int lpfc_put_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, + struct lpfc_io_buf *buf); +void lpfc_free_sgl_per_hdwq(struct lpfc_hba *phba, + struct lpfc_sli4_hdw_queue *hdwq); +void lpfc_free_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, + struct lpfc_sli4_hdw_queue *hdwq); static inline void *lpfc_sli4_qe(struct lpfc_queue *q, uint16_t idx) { return q->q_pgs[idx / q->entry_cnt_per_pg] + diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 220a932fe943..b8aae31ffda3 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "12.2.0.2" +#define LPFC_DRIVER_VERSION "12.4.0.0" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 343bc71d4615..b76646357980 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -527,9 +527,11 @@ disable_vport(struct fc_vport *fc_vport) * scsi_host_put() to release the vport. */ lpfc_mbx_unreg_vpi(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; - spin_unlock_irq(shost->host_lock); + if (phba->sli_rev == LPFC_SLI_REV4) { + spin_lock_irq(shost->host_lock); + vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; + spin_unlock_irq(shost->host_lock); + } lpfc_vport_set_state(vport, FC_VPORT_DISABLED); lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index dba9517d9553..9c5566217ef6 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -4,6 +4,8 @@ * * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov> * + * Copyright 2019 Finn Thain + * * derived in part from: */ /* @@ -12,6 +14,7 @@ * Copyright 1995, Russell King */ +#include <linux/delay.h> #include <linux/types.h> #include <linux/module.h> #include <linux/ioport.h> @@ -22,6 +25,7 @@ #include <asm/hwtest.h> #include <asm/io.h> +#include <asm/macintosh.h> #include <asm/macints.h> #include <asm/setup.h> @@ -53,7 +57,7 @@ static int setup_cmd_per_lun = -1; module_param(setup_cmd_per_lun, int, 0); static int setup_sg_tablesize = -1; module_param(setup_sg_tablesize, int, 0); -static int setup_use_pdma = -1; +static int setup_use_pdma = 512; module_param(setup_use_pdma, int, 0); static int setup_hostid = -1; module_param(setup_hostid, int, 0); @@ -90,223 +94,318 @@ static int __init mac_scsi_setup(char *str) __setup("mac5380=", mac_scsi_setup); #endif /* !MODULE */ -/* Pseudo DMA asm originally by Ove Edlund */ - -#define CP_IO_TO_MEM(s,d,n) \ -__asm__ __volatile__ \ - (" cmp.w #4,%2\n" \ - " bls 8f\n" \ - " move.w %1,%%d0\n" \ - " neg.b %%d0\n" \ - " and.w #3,%%d0\n" \ - " sub.w %%d0,%2\n" \ - " bra 2f\n" \ - " 1: move.b (%0),(%1)+\n" \ - " 2: dbf %%d0,1b\n" \ - " move.w %2,%%d0\n" \ - " lsr.w #5,%%d0\n" \ - " bra 4f\n" \ - " 3: move.l (%0),(%1)+\n" \ - "31: move.l (%0),(%1)+\n" \ - "32: move.l (%0),(%1)+\n" \ - "33: move.l (%0),(%1)+\n" \ - "34: move.l (%0),(%1)+\n" \ - "35: move.l (%0),(%1)+\n" \ - "36: move.l (%0),(%1)+\n" \ - "37: move.l (%0),(%1)+\n" \ - " 4: dbf %%d0,3b\n" \ - " move.w %2,%%d0\n" \ - " lsr.w #2,%%d0\n" \ - " and.w #7,%%d0\n" \ - " bra 6f\n" \ - " 5: move.l (%0),(%1)+\n" \ - " 6: dbf %%d0,5b\n" \ - " and.w #3,%2\n" \ - " bra 8f\n" \ - " 7: move.b (%0),(%1)+\n" \ - " 8: dbf %2,7b\n" \ - " moveq.l #0, %2\n" \ - " 9: \n" \ - ".section .fixup,\"ax\"\n" \ - " .even\n" \ - "91: moveq.l #1, %2\n" \ - " jra 9b\n" \ - "94: moveq.l #4, %2\n" \ - " jra 9b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 1b,91b\n" \ - " .long 3b,94b\n" \ - " .long 31b,94b\n" \ - " .long 32b,94b\n" \ - " .long 33b,94b\n" \ - " .long 34b,94b\n" \ - " .long 35b,94b\n" \ - " .long 36b,94b\n" \ - " .long 37b,94b\n" \ - " .long 5b,94b\n" \ - " .long 7b,91b\n" \ - ".previous" \ - : "=a"(s), "=a"(d), "=d"(n) \ - : "0"(s), "1"(d), "2"(n) \ - : "d0") +/* + * According to "Inside Macintosh: Devices", Mac OS requires disk drivers to + * specify the number of bytes between the delays expected from a SCSI target. + * This allows the operating system to "prevent bus errors when a target fails + * to deliver the next byte within the processor bus error timeout period." + * Linux SCSI drivers lack knowledge of the timing behaviour of SCSI targets + * so bus errors are unavoidable. + * + * If a MOVE.B instruction faults, we assume that zero bytes were transferred + * and simply retry. That assumption probably depends on target behaviour but + * seems to hold up okay. The NOP provides synchronization: without it the + * fault can sometimes occur after the program counter has moved past the + * offending instruction. Post-increment addressing can't be used. + */ + +#define MOVE_BYTE(operands) \ + asm volatile ( \ + "1: moveb " operands " \n" \ + "11: nop \n" \ + " addq #1,%0 \n" \ + " subq #1,%1 \n" \ + "40: \n" \ + " \n" \ + ".section .fixup,\"ax\" \n" \ + ".even \n" \ + "90: movel #1, %2 \n" \ + " jra 40b \n" \ + ".previous \n" \ + " \n" \ + ".section __ex_table,\"a\" \n" \ + ".align 4 \n" \ + ".long 1b,90b \n" \ + ".long 11b,90b \n" \ + ".previous \n" \ + : "+a" (addr), "+r" (n), "+r" (result) : "a" (io)) + +/* + * If a MOVE.W (or MOVE.L) instruction faults, it cannot be retried because + * the residual byte count would be uncertain. In that situation the MOVE_WORD + * macro clears n in the fixup section to abort the transfer. + */ + +#define MOVE_WORD(operands) \ + asm volatile ( \ + "1: movew " operands " \n" \ + "11: nop \n" \ + " subq #2,%1 \n" \ + "40: \n" \ + " \n" \ + ".section .fixup,\"ax\" \n" \ + ".even \n" \ + "90: movel #0, %1 \n" \ + " movel #2, %2 \n" \ + " jra 40b \n" \ + ".previous \n" \ + " \n" \ + ".section __ex_table,\"a\" \n" \ + ".align 4 \n" \ + ".long 1b,90b \n" \ + ".long 11b,90b \n" \ + ".previous \n" \ + : "+a" (addr), "+r" (n), "+r" (result) : "a" (io)) + +#define MOVE_16_WORDS(operands) \ + asm volatile ( \ + "1: movew " operands " \n" \ + "2: movew " operands " \n" \ + "3: movew " operands " \n" \ + "4: movew " operands " \n" \ + "5: movew " operands " \n" \ + "6: movew " operands " \n" \ + "7: movew " operands " \n" \ + "8: movew " operands " \n" \ + "9: movew " operands " \n" \ + "10: movew " operands " \n" \ + "11: movew " operands " \n" \ + "12: movew " operands " \n" \ + "13: movew " operands " \n" \ + "14: movew " operands " \n" \ + "15: movew " operands " \n" \ + "16: movew " operands " \n" \ + "17: nop \n" \ + " subl #32,%1 \n" \ + "40: \n" \ + " \n" \ + ".section .fixup,\"ax\" \n" \ + ".even \n" \ + "90: movel #0, %1 \n" \ + " movel #2, %2 \n" \ + " jra 40b \n" \ + ".previous \n" \ + " \n" \ + ".section __ex_table,\"a\" \n" \ + ".align 4 \n" \ + ".long 1b,90b \n" \ + ".long 2b,90b \n" \ + ".long 3b,90b \n" \ + ".long 4b,90b \n" \ + ".long 5b,90b \n" \ + ".long 6b,90b \n" \ + ".long 7b,90b \n" \ + ".long 8b,90b \n" \ + ".long 9b,90b \n" \ + ".long 10b,90b \n" \ + ".long 11b,90b \n" \ + ".long 12b,90b \n" \ + ".long 13b,90b \n" \ + ".long 14b,90b \n" \ + ".long 15b,90b \n" \ + ".long 16b,90b \n" \ + ".long 17b,90b \n" \ + ".previous \n" \ + : "+a" (addr), "+r" (n), "+r" (result) : "a" (io)) + +#define MAC_PDMA_DELAY 32 + +static inline int mac_pdma_recv(void __iomem *io, unsigned char *start, int n) +{ + unsigned char *addr = start; + int result = 0; + + if (n >= 1) { + MOVE_BYTE("%3@,%0@"); + if (result) + goto out; + } + if (n >= 1 && ((unsigned long)addr & 1)) { + MOVE_BYTE("%3@,%0@"); + if (result) + goto out; + } + while (n >= 32) + MOVE_16_WORDS("%3@,%0@+"); + while (n >= 2) + MOVE_WORD("%3@,%0@+"); + if (result) + return start - addr; /* Negated to indicate uncertain length */ + if (n == 1) + MOVE_BYTE("%3@,%0@"); +out: + return addr - start; +} + +static inline int mac_pdma_send(unsigned char *start, void __iomem *io, int n) +{ + unsigned char *addr = start; + int result = 0; + + if (n >= 1) { + MOVE_BYTE("%0@,%3@"); + if (result) + goto out; + } + if (n >= 1 && ((unsigned long)addr & 1)) { + MOVE_BYTE("%0@,%3@"); + if (result) + goto out; + } + while (n >= 32) + MOVE_16_WORDS("%0@+,%3@"); + while (n >= 2) + MOVE_WORD("%0@+,%3@"); + if (result) + return start - addr; /* Negated to indicate uncertain length */ + if (n == 1) + MOVE_BYTE("%0@,%3@"); +out: + return addr - start; +} + +/* The "SCSI DMA" chip on the IIfx implements this register. */ +#define CTRL_REG 0x8 +#define CTRL_INTERRUPTS_ENABLE BIT(1) +#define CTRL_HANDSHAKE_MODE BIT(3) + +static inline void write_ctrl_reg(struct NCR5380_hostdata *hostdata, u32 value) +{ + out_be32(hostdata->io + (CTRL_REG << 4), value); +} static inline int macscsi_pread(struct NCR5380_hostdata *hostdata, unsigned char *dst, int len) { u8 __iomem *s = hostdata->pdma_io + (INPUT_DATA_REG << 4); unsigned char *d = dst; - int n = len; - int transferred; + int result = 0; + + hostdata->pdma_residual = len; while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_DRQ | BASR_PHASE_MATCH, BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) { - CP_IO_TO_MEM(s, d, n); + int bytes; + + if (macintosh_config->ident == MAC_MODEL_IIFX) + write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE | + CTRL_INTERRUPTS_ENABLE); - transferred = d - dst - n; - hostdata->pdma_residual = len - transferred; + bytes = mac_pdma_recv(s, d, min(hostdata->pdma_residual, 512)); - /* No bus error. */ - if (n == 0) - return 0; + if (bytes > 0) { + d += bytes; + hostdata->pdma_residual -= bytes; + } + + if (hostdata->pdma_residual == 0) + goto out; - /* Target changed phase early? */ if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, - BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0) - scmd_printk(KERN_ERR, hostdata->connected, + BUS_AND_STATUS_REG, BASR_ACK, + BASR_ACK, HZ / 64) < 0) + scmd_printk(KERN_DEBUG, hostdata->connected, "%s: !REQ and !ACK\n", __func__); if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) - return 0; + goto out; + + if (bytes == 0) + udelay(MAC_PDMA_DELAY); + + if (bytes >= 0) + continue; dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host, - "%s: bus error (%d/%d)\n", __func__, transferred, len); + "%s: bus error (%d/%d)\n", __func__, d - dst, len); NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - d = dst + transferred; - n = len - transferred; + result = -1; + goto out; } scmd_printk(KERN_ERR, hostdata->connected, "%s: phase mismatch or !DRQ\n", __func__); NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - return -1; + result = -1; +out: + if (macintosh_config->ident == MAC_MODEL_IIFX) + write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE); + return result; } - -#define CP_MEM_TO_IO(s,d,n) \ -__asm__ __volatile__ \ - (" cmp.w #4,%2\n" \ - " bls 8f\n" \ - " move.w %0,%%d0\n" \ - " neg.b %%d0\n" \ - " and.w #3,%%d0\n" \ - " sub.w %%d0,%2\n" \ - " bra 2f\n" \ - " 1: move.b (%0)+,(%1)\n" \ - " 2: dbf %%d0,1b\n" \ - " move.w %2,%%d0\n" \ - " lsr.w #5,%%d0\n" \ - " bra 4f\n" \ - " 3: move.l (%0)+,(%1)\n" \ - "31: move.l (%0)+,(%1)\n" \ - "32: move.l (%0)+,(%1)\n" \ - "33: move.l (%0)+,(%1)\n" \ - "34: move.l (%0)+,(%1)\n" \ - "35: move.l (%0)+,(%1)\n" \ - "36: move.l (%0)+,(%1)\n" \ - "37: move.l (%0)+,(%1)\n" \ - " 4: dbf %%d0,3b\n" \ - " move.w %2,%%d0\n" \ - " lsr.w #2,%%d0\n" \ - " and.w #7,%%d0\n" \ - " bra 6f\n" \ - " 5: move.l (%0)+,(%1)\n" \ - " 6: dbf %%d0,5b\n" \ - " and.w #3,%2\n" \ - " bra 8f\n" \ - " 7: move.b (%0)+,(%1)\n" \ - " 8: dbf %2,7b\n" \ - " moveq.l #0, %2\n" \ - " 9: \n" \ - ".section .fixup,\"ax\"\n" \ - " .even\n" \ - "91: moveq.l #1, %2\n" \ - " jra 9b\n" \ - "94: moveq.l #4, %2\n" \ - " jra 9b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 1b,91b\n" \ - " .long 3b,94b\n" \ - " .long 31b,94b\n" \ - " .long 32b,94b\n" \ - " .long 33b,94b\n" \ - " .long 34b,94b\n" \ - " .long 35b,94b\n" \ - " .long 36b,94b\n" \ - " .long 37b,94b\n" \ - " .long 5b,94b\n" \ - " .long 7b,91b\n" \ - ".previous" \ - : "=a"(s), "=a"(d), "=d"(n) \ - : "0"(s), "1"(d), "2"(n) \ - : "d0") - static inline int macscsi_pwrite(struct NCR5380_hostdata *hostdata, unsigned char *src, int len) { unsigned char *s = src; u8 __iomem *d = hostdata->pdma_io + (OUTPUT_DATA_REG << 4); - int n = len; - int transferred; + int result = 0; + + hostdata->pdma_residual = len; while (!NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_DRQ | BASR_PHASE_MATCH, BASR_DRQ | BASR_PHASE_MATCH, HZ / 64)) { - CP_MEM_TO_IO(s, d, n); + int bytes; - transferred = s - src - n; - hostdata->pdma_residual = len - transferred; + if (macintosh_config->ident == MAC_MODEL_IIFX) + write_ctrl_reg(hostdata, CTRL_HANDSHAKE_MODE | + CTRL_INTERRUPTS_ENABLE); - /* Target changed phase early? */ - if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, - BUS_AND_STATUS_REG, BASR_ACK, BASR_ACK, HZ / 64) < 0) - scmd_printk(KERN_ERR, hostdata->connected, - "%s: !REQ and !ACK\n", __func__); - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) - return 0; + bytes = mac_pdma_send(s, d, min(hostdata->pdma_residual, 512)); + + if (bytes > 0) { + s += bytes; + hostdata->pdma_residual -= bytes; + } - /* No bus error. */ - if (n == 0) { + if (hostdata->pdma_residual == 0) { if (NCR5380_poll_politely(hostdata, TARGET_COMMAND_REG, TCR_LAST_BYTE_SENT, - TCR_LAST_BYTE_SENT, HZ / 64) < 0) + TCR_LAST_BYTE_SENT, + HZ / 64) < 0) { scmd_printk(KERN_ERR, hostdata->connected, "%s: Last Byte Sent timeout\n", __func__); - return 0; + result = -1; + } + goto out; } + if (NCR5380_poll_politely2(hostdata, STATUS_REG, SR_REQ, SR_REQ, + BUS_AND_STATUS_REG, BASR_ACK, + BASR_ACK, HZ / 64) < 0) + scmd_printk(KERN_DEBUG, hostdata->connected, + "%s: !REQ and !ACK\n", __func__); + if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) + goto out; + + if (bytes == 0) + udelay(MAC_PDMA_DELAY); + + if (bytes >= 0) + continue; + dsprintk(NDEBUG_PSEUDO_DMA, hostdata->host, - "%s: bus error (%d/%d)\n", __func__, transferred, len); + "%s: bus error (%d/%d)\n", __func__, s - src, len); NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - s = src + transferred; - n = len - transferred; + result = -1; + goto out; } scmd_printk(KERN_ERR, hostdata->connected, "%s: phase mismatch or !DRQ\n", __func__); NCR5380_dprint(NDEBUG_PSEUDO_DMA, hostdata->host); - - return -1; + result = -1; +out: + if (macintosh_config->ident == MAC_MODEL_IIFX) + write_ctrl_reg(hostdata, CTRL_INTERRUPTS_ENABLE); + return result; } static int macscsi_dma_xfer_len(struct NCR5380_hostdata *hostdata, struct scsi_cmnd *cmd) { if (hostdata->flags & FLAG_NO_PSEUDO_DMA || - cmd->SCp.this_residual < 16) + cmd->SCp.this_residual < setup_use_pdma) return 0; return cmd->SCp.this_residual; diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 45a66048801b..ff6d4aa92421 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4183,11 +4183,11 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) */ if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ && pdev->subsystem_device == 0xC000) - return -ENODEV; + goto out_disable_device; /* Now check the magic signature byte */ pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic); if (magic != HBA_SIGNATURE_471 && magic != HBA_SIGNATURE) - return -ENODEV; + goto out_disable_device; /* Ok it is probably a megaraid */ } diff --git a/drivers/scsi/megaraid/Kconfig.megaraid b/drivers/scsi/megaraid/Kconfig.megaraid index e630e41dc843..2adc2afd9f91 100644 --- a/drivers/scsi/megaraid/Kconfig.megaraid +++ b/drivers/scsi/megaraid/Kconfig.megaraid @@ -79,6 +79,7 @@ config MEGARAID_LEGACY config MEGARAID_SAS tristate "LSI Logic MegaRAID SAS RAID Module" depends on PCI && SCSI + select IRQ_POLL help Module for LSI Logic's SAS based RAID controllers. To compile this driver as a module, choose 'm' here. diff --git a/drivers/scsi/megaraid/Makefile b/drivers/scsi/megaraid/Makefile index 6e74d21227a5..12177e4cae65 100644 --- a/drivers/scsi/megaraid/Makefile +++ b/drivers/scsi/megaraid/Makefile @@ -3,4 +3,4 @@ obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o obj-$(CONFIG_MEGARAID_SAS) += megaraid_sas.o megaraid_sas-objs := megaraid_sas_base.o megaraid_sas_fusion.o \ - megaraid_sas_fp.o + megaraid_sas_fp.o megaraid_sas_debugfs.o diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index fe9a785b7b6f..a6e788c02ff4 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -21,8 +21,8 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "07.707.51.00-rc1" -#define MEGASAS_RELDATE "February 7, 2019" +#define MEGASAS_VERSION "07.710.50.00-rc1" +#define MEGASAS_RELDATE "June 28, 2019" /* * Device IDs @@ -52,6 +52,10 @@ #define PCI_DEVICE_ID_LSI_AERO_10E2 0x10e2 #define PCI_DEVICE_ID_LSI_AERO_10E5 0x10e5 #define PCI_DEVICE_ID_LSI_AERO_10E6 0x10e6 +#define PCI_DEVICE_ID_LSI_AERO_10E0 0x10e0 +#define PCI_DEVICE_ID_LSI_AERO_10E3 0x10e3 +#define PCI_DEVICE_ID_LSI_AERO_10E4 0x10e4 +#define PCI_DEVICE_ID_LSI_AERO_10E7 0x10e7 /* * Intel HBA SSDIDs @@ -123,6 +127,8 @@ #define MFI_RESET_ADAPTER 0x00000002 #define MEGAMFI_FRAME_SIZE 64 +#define MFI_STATE_FAULT_CODE 0x0FFF0000 +#define MFI_STATE_FAULT_SUBCODE 0x0000FF00 /* * During FW init, clear pending cmds & reset state using inbound_msg_0 * @@ -190,6 +196,7 @@ enum MFI_CMD_OP { MFI_CMD_SMP = 0x7, MFI_CMD_STP = 0x8, MFI_CMD_NVME = 0x9, + MFI_CMD_TOOLBOX = 0xa, MFI_CMD_OP_COUNT, MFI_CMD_INVALID = 0xff }; @@ -1449,7 +1456,39 @@ struct megasas_ctrl_info { u8 reserved6[64]; - u32 rsvdForAdptOp[64]; + struct { + #if defined(__BIG_ENDIAN_BITFIELD) + u32 reserved:19; + u32 support_pci_lane_margining: 1; + u32 support_psoc_update:1; + u32 support_force_personality_change:1; + u32 support_fde_type_mix:1; + u32 support_snap_dump:1; + u32 support_nvme_tm:1; + u32 support_oce_only:1; + u32 support_ext_mfg_vpd:1; + u32 support_pcie:1; + u32 support_cvhealth_info:1; + u32 support_profile_change:2; + u32 mr_config_ext2_supported:1; + #else + u32 mr_config_ext2_supported:1; + u32 support_profile_change:2; + u32 support_cvhealth_info:1; + u32 support_pcie:1; + u32 support_ext_mfg_vpd:1; + u32 support_oce_only:1; + u32 support_nvme_tm:1; + u32 support_snap_dump:1; + u32 support_fde_type_mix:1; + u32 support_force_personality_change:1; + u32 support_psoc_update:1; + u32 support_pci_lane_margining: 1; + u32 reserved:19; + #endif + } adapter_operations5; + + u32 rsvdForAdptOp[63]; u8 reserved7[3]; @@ -1483,7 +1522,9 @@ struct megasas_ctrl_info { #define MEGASAS_FW_BUSY 1 /* Driver's internal Logging levels*/ -#define OCR_LOGS (1 << 0) +#define OCR_DEBUG (1 << 0) +#define TM_DEBUG (1 << 1) +#define LD_PD_DEBUG (1 << 2) #define SCAN_PD_CHANNEL 0x1 #define SCAN_VD_CHANNEL 0x2 @@ -1559,6 +1600,7 @@ enum FW_BOOT_CONTEXT { #define MFI_IO_TIMEOUT_SECS 180 #define MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF (5 * HZ) #define MEGASAS_OCR_SETTLE_TIME_VF (1000 * 30) +#define MEGASAS_SRIOV_MAX_RESET_TRIES_VF 1 #define MEGASAS_ROUTINE_WAIT_TIME_VF 300 #define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000 #define MFI_REPLY_GEN2_MESSAGE_INTERRUPT 0x00000001 @@ -1583,7 +1625,10 @@ enum FW_BOOT_CONTEXT { #define MR_CAN_HANDLE_SYNC_CACHE_OFFSET 0X01000000 +#define MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET (1 << 24) + #define MR_CAN_HANDLE_64_BIT_DMA_OFFSET (1 << 25) +#define MR_INTR_COALESCING_SUPPORT_OFFSET (1 << 26) #define MEGASAS_WATCHDOG_THREAD_INTERVAL 1000 #define MEGASAS_WAIT_FOR_NEXT_DMA_MSECS 20 @@ -1762,7 +1807,7 @@ struct megasas_init_frame { __le32 pad_0; /*0Ch */ __le16 flags; /*10h */ - __le16 reserved_3; /*12h */ + __le16 replyqueue_mask; /*12h */ __le32 data_xfer_len; /*14h */ __le32 queue_info_new_phys_addr_lo; /*18h */ @@ -2160,6 +2205,10 @@ struct megasas_aen_event { struct megasas_irq_context { struct megasas_instance *instance; u32 MSIxIndex; + u32 os_irq; + struct irq_poll irqpoll; + bool irq_poll_scheduled; + bool irq_line_enable; }; struct MR_DRV_SYSTEM_INFO { @@ -2190,6 +2239,23 @@ enum MR_PD_TYPE { #define MR_DEFAULT_NVME_MDTS_KB 128 #define MR_NVME_PAGE_SIZE_MASK 0x000000FF +/*Aero performance parameters*/ +#define MR_HIGH_IOPS_QUEUE_COUNT 8 +#define MR_DEVICE_HIGH_IOPS_DEPTH 8 +#define MR_HIGH_IOPS_BATCH_COUNT 16 + +enum MR_PERF_MODE { + MR_BALANCED_PERF_MODE = 0, + MR_IOPS_PERF_MODE = 1, + MR_LATENCY_PERF_MODE = 2, +}; + +#define MEGASAS_PERF_MODE_2STR(mode) \ + ((mode) == MR_BALANCED_PERF_MODE ? "Balanced" : \ + (mode) == MR_IOPS_PERF_MODE ? "IOPS" : \ + (mode) == MR_LATENCY_PERF_MODE ? "Latency" : \ + "Unknown") + struct megasas_instance { unsigned int *reply_map; @@ -2246,6 +2312,7 @@ struct megasas_instance { u32 secure_jbod_support; u32 support_morethan256jbod; /* FW support for more than 256 PD/JBOD */ bool use_seqnum_jbod_fp; /* Added for PD sequence */ + bool smp_affinity_enable; spinlock_t crashdump_lock; struct megasas_register_set __iomem *reg_set; @@ -2263,6 +2330,7 @@ struct megasas_instance { u16 ldio_threshold; u16 cur_can_queue; u32 max_sectors_per_req; + bool msix_load_balance; struct megasas_aen_event *ev; struct megasas_cmd **cmd_list; @@ -2290,15 +2358,13 @@ struct megasas_instance { struct pci_dev *pdev; u32 unique_id; u32 fw_support_ieee; + u32 threshold_reply_count; atomic_t fw_outstanding; atomic_t ldio_outstanding; atomic_t fw_reset_no_pci_access; - atomic_t ieee_sgl; - atomic_t prp_sgl; - atomic_t sge_holes_type1; - atomic_t sge_holes_type2; - atomic_t sge_holes_type3; + atomic64_t total_io_count; + atomic64_t high_iops_outstanding; struct megasas_instance_template *instancet; struct tasklet_struct isr_tasklet; @@ -2363,11 +2429,22 @@ struct megasas_instance { u8 adapter_type; bool consistent_mask_64bit; bool support_nvme_passthru; + bool enable_sdev_max_qd; u8 task_abort_tmo; u8 max_reset_tmo; u8 snapdump_wait_time; +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; + struct dentry *raidmap_dump; +#endif u8 enable_fw_dev_list; + bool atomic_desc_support; + bool support_seqnum_jbod_fp; + bool support_pci_lane_margining; + u8 low_latency_index_start; + int perf_mode; }; + struct MR_LD_VF_MAP { u32 size; union MR_LD_REF ref; @@ -2623,4 +2700,9 @@ void megasas_fusion_stop_watchdog(struct megasas_instance *instance); void megasas_set_dma_settings(struct megasas_instance *instance, struct megasas_dcmd_frame *dcmd, dma_addr_t dma_addr, u32 dma_len); +int megasas_adp_reset_wait_for_ready(struct megasas_instance *instance, + bool do_adp_reset, + int ocr_context); +int megasas_irqpoll(struct irq_poll *irqpoll, int budget); +void megasas_dump_fusion_io(struct scsi_cmnd *scmd); #endif /*LSI_MEGARAID_SAS_H */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 3dd1df472dc6..42cf38c1ea99 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -36,12 +36,14 @@ #include <linux/mutex.h> #include <linux/poll.h> #include <linux/vmalloc.h> +#include <linux/irq_poll.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> +#include <scsi/scsi_dbg.h> #include "megaraid_sas_fusion.h" #include "megaraid_sas.h" @@ -50,47 +52,67 @@ * Will be set in megasas_init_mfi if user does not provide */ static unsigned int max_sectors; -module_param_named(max_sectors, max_sectors, int, 0); +module_param_named(max_sectors, max_sectors, int, 0444); MODULE_PARM_DESC(max_sectors, "Maximum number of sectors per IO command"); static int msix_disable; -module_param(msix_disable, int, S_IRUGO); +module_param(msix_disable, int, 0444); MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0"); static unsigned int msix_vectors; -module_param(msix_vectors, int, S_IRUGO); +module_param(msix_vectors, int, 0444); MODULE_PARM_DESC(msix_vectors, "MSI-X max vector count. Default: Set by FW"); static int allow_vf_ioctls; -module_param(allow_vf_ioctls, int, S_IRUGO); +module_param(allow_vf_ioctls, int, 0444); MODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0"); static unsigned int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH; -module_param(throttlequeuedepth, int, S_IRUGO); +module_param(throttlequeuedepth, int, 0444); MODULE_PARM_DESC(throttlequeuedepth, "Adapter queue depth when throttled due to I/O timeout. Default: 16"); unsigned int resetwaittime = MEGASAS_RESET_WAIT_TIME; -module_param(resetwaittime, int, S_IRUGO); +module_param(resetwaittime, int, 0444); MODULE_PARM_DESC(resetwaittime, "Wait time in (1-180s) after I/O timeout before resetting adapter. Default: 180s"); int smp_affinity_enable = 1; -module_param(smp_affinity_enable, int, S_IRUGO); +module_param(smp_affinity_enable, int, 0444); MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)"); int rdpq_enable = 1; -module_param(rdpq_enable, int, S_IRUGO); +module_param(rdpq_enable, int, 0444); MODULE_PARM_DESC(rdpq_enable, "Allocate reply queue in chunks for large queue depth enable/disable Default: enable(1)"); unsigned int dual_qdepth_disable; -module_param(dual_qdepth_disable, int, S_IRUGO); +module_param(dual_qdepth_disable, int, 0444); MODULE_PARM_DESC(dual_qdepth_disable, "Disable dual queue depth feature. Default: 0"); unsigned int scmd_timeout = MEGASAS_DEFAULT_CMD_TIMEOUT; -module_param(scmd_timeout, int, S_IRUGO); +module_param(scmd_timeout, int, 0444); MODULE_PARM_DESC(scmd_timeout, "scsi command timeout (10-90s), default 90s. See megasas_reset_timer."); +int perf_mode = -1; +module_param(perf_mode, int, 0444); +MODULE_PARM_DESC(perf_mode, "Performance mode (only for Aero adapters), options:\n\t\t" + "0 - balanced: High iops and low latency queues are allocated &\n\t\t" + "interrupt coalescing is enabled only on high iops queues\n\t\t" + "1 - iops: High iops queues are not allocated &\n\t\t" + "interrupt coalescing is enabled on all queues\n\t\t" + "2 - latency: High iops queues are not allocated &\n\t\t" + "interrupt coalescing is disabled on all queues\n\t\t" + "default mode is 'balanced'" + ); + +int event_log_level = MFI_EVT_CLASS_CRITICAL; +module_param(event_log_level, int, 0644); +MODULE_PARM_DESC(event_log_level, "Asynchronous event logging level- range is: -2(CLASS_DEBUG) to 4(CLASS_DEAD), Default: 2(CLASS_CRITICAL)"); + +unsigned int enable_sdev_max_qd; +module_param(enable_sdev_max_qd, int, 0444); +MODULE_PARM_DESC(enable_sdev_max_qd, "Enable sdev max qd as can_queue. Default: 0"); + MODULE_LICENSE("GPL"); MODULE_VERSION(MEGASAS_VERSION); MODULE_AUTHOR("megaraidlinux.pdl@broadcom.com"); @@ -154,6 +176,10 @@ static struct pci_device_id megasas_pci_table[] = { {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E2)}, {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E5)}, {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E6)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E0)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E3)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E4)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_AERO_10E7)}, {} }; @@ -170,10 +196,17 @@ static u32 support_poll_for_event; u32 megasas_dbg_lvl; static u32 support_device_change; static bool support_nvme_encapsulation; +static bool support_pci_lane_margining; /* define lock for aen poll */ spinlock_t poll_aen_lock; +extern struct dentry *megasas_debugfs_root; +extern void megasas_init_debugfs(void); +extern void megasas_exit_debugfs(void); +extern void megasas_setup_debugfs(struct megasas_instance *instance); +extern void megasas_destroy_debugfs(struct megasas_instance *instance); + void megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, u8 alt_status); @@ -255,7 +288,7 @@ void megasas_set_dma_settings(struct megasas_instance *instance, } } -void +static void megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd) { instance->instancet->fire_cmd(instance, @@ -379,7 +412,13 @@ megasas_decode_evt(struct megasas_instance *instance) union megasas_evt_class_locale class_locale; class_locale.word = le32_to_cpu(evt_detail->cl.word); - if (class_locale.members.class >= MFI_EVT_CLASS_CRITICAL) + if ((event_log_level < MFI_EVT_CLASS_DEBUG) || + (event_log_level > MFI_EVT_CLASS_DEAD)) { + printk(KERN_WARNING "megaraid_sas: provided event log level is out of range, setting it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n"); + event_log_level = MFI_EVT_CLASS_CRITICAL; + } + + if (class_locale.members.class >= event_log_level) dev_info(&instance->pdev->dev, "%d (%s/0x%04x/%s) - %s\n", le32_to_cpu(evt_detail->seq_num), format_timestamp(le32_to_cpu(evt_detail->time_stamp)), @@ -1098,8 +1137,9 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance, ret = wait_event_timeout(instance->int_cmd_wait_q, cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ); if (!ret) { - dev_err(&instance->pdev->dev, "Failed from %s %d DCMD Timed out\n", - __func__, __LINE__); + dev_err(&instance->pdev->dev, + "DCMD(opcode: 0x%x) is timed out, func:%s\n", + cmd->frame->dcmd.opcode, __func__); return DCMD_TIMEOUT; } } else @@ -1128,6 +1168,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd; struct megasas_abort_frame *abort_fr; int ret = 0; + u32 opcode; cmd = megasas_get_cmd(instance); @@ -1163,8 +1204,10 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance, ret = wait_event_timeout(instance->abort_cmd_wait_q, cmd->cmd_status_drv != MFI_STAT_INVALID_STATUS, timeout * HZ); if (!ret) { - dev_err(&instance->pdev->dev, "Failed from %s %d Abort Timed out\n", - __func__, __LINE__); + opcode = cmd_to_abort->frame->dcmd.opcode; + dev_err(&instance->pdev->dev, + "Abort(to be aborted DCMD opcode: 0x%x) is timed out func:%s\n", + opcode, __func__); return DCMD_TIMEOUT; } } else @@ -1902,26 +1945,19 @@ megasas_set_nvme_device_properties(struct scsi_device *sdev, u32 max_io_size) blk_queue_virt_boundary(sdev->request_queue, mr_nvme_pg_size - 1); } - /* - * megasas_set_static_target_properties - - * Device property set by driver are static and it is not required to be - * updated after OCR. - * - * set io timeout - * set device queue depth - * set nvme device properties. see - megasas_set_nvme_device_properties + * megasas_set_fw_assisted_qd - + * set device queue depth to can_queue + * set device queue depth to fw assisted qd * * @sdev: scsi device * @is_target_prop true, if fw provided target properties. */ -static void megasas_set_static_target_properties(struct scsi_device *sdev, +static void megasas_set_fw_assisted_qd(struct scsi_device *sdev, bool is_target_prop) { - u16 target_index = 0; u8 interface_type; u32 device_qd = MEGASAS_DEFAULT_CMD_PER_LUN; - u32 max_io_size_kb = MR_DEFAULT_NVME_MDTS_KB; u32 tgt_device_qd; struct megasas_instance *instance; struct MR_PRIV_DEVICE *mr_device_priv_data; @@ -1930,13 +1966,6 @@ static void megasas_set_static_target_properties(struct scsi_device *sdev, mr_device_priv_data = sdev->hostdata; interface_type = mr_device_priv_data->interface_type; - /* - * The RAID firmware may require extended timeouts. - */ - blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ); - - target_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id; - switch (interface_type) { case SAS_PD: device_qd = MEGASAS_SAS_QD; @@ -1954,18 +1983,49 @@ static void megasas_set_static_target_properties(struct scsi_device *sdev, if (tgt_device_qd && (tgt_device_qd <= instance->host->can_queue)) device_qd = tgt_device_qd; + } - /* max_io_size_kb will be set to non zero for - * nvme based vd and syspd. - */ + if (instance->enable_sdev_max_qd && interface_type != UNKNOWN_DRIVE) + device_qd = instance->host->can_queue; + + scsi_change_queue_depth(sdev, device_qd); +} + +/* + * megasas_set_static_target_properties - + * Device property set by driver are static and it is not required to be + * updated after OCR. + * + * set io timeout + * set device queue depth + * set nvme device properties. see - megasas_set_nvme_device_properties + * + * @sdev: scsi device + * @is_target_prop true, if fw provided target properties. + */ +static void megasas_set_static_target_properties(struct scsi_device *sdev, + bool is_target_prop) +{ + u32 max_io_size_kb = MR_DEFAULT_NVME_MDTS_KB; + struct megasas_instance *instance; + + instance = megasas_lookup_instance(sdev->host->host_no); + + /* + * The RAID firmware may require extended timeouts. + */ + blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ); + + /* max_io_size_kb will be set to non zero for + * nvme based vd and syspd. + */ + if (is_target_prop) max_io_size_kb = le32_to_cpu(instance->tgt_prop->max_io_size_kb); - } if (instance->nvme_page_size && max_io_size_kb) megasas_set_nvme_device_properties(sdev, (max_io_size_kb << 10)); - scsi_change_queue_depth(sdev, device_qd); - + megasas_set_fw_assisted_qd(sdev, is_target_prop); } @@ -2211,7 +2271,7 @@ megasas_internal_reset_defer_cmds(struct megasas_instance *instance); static void process_fw_state_change_wq(struct work_struct *work); -void megasas_do_ocr(struct megasas_instance *instance) +static void megasas_do_ocr(struct megasas_instance *instance) { if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) || (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) || @@ -2822,21 +2882,108 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) } /** - * megasas_dump_frame - This function will dump MPT/MFI frame + * megasas_dump - This function will print hexdump of provided buffer. + * @buf: Buffer to be dumped + * @sz: Size in bytes + * @format: Different formats of dumping e.g. format=n will + * cause only 'n' 32 bit words to be dumped in a single + * line. */ -static inline void -megasas_dump_frame(void *mpi_request, int sz) +inline void +megasas_dump(void *buf, int sz, int format) { int i; - __le32 *mfp = (__le32 *)mpi_request; + __le32 *buf_loc = (__le32 *)buf; + + for (i = 0; i < (sz / sizeof(__le32)); i++) { + if ((i % format) == 0) { + if (i != 0) + printk(KERN_CONT "\n"); + printk(KERN_CONT "%08x: ", (i * 4)); + } + printk(KERN_CONT "%08x ", le32_to_cpu(buf_loc[i])); + } + printk(KERN_CONT "\n"); +} + +/** + * megasas_dump_reg_set - This function will print hexdump of register set + * @buf: Buffer to be dumped + * @sz: Size in bytes + * @format: Different formats of dumping e.g. format=n will + * cause only 'n' 32 bit words to be dumped in a + * single line. + */ +inline void +megasas_dump_reg_set(void __iomem *reg_set) +{ + unsigned int i, sz = 256; + u32 __iomem *reg = (u32 __iomem *)reg_set; + + for (i = 0; i < (sz / sizeof(u32)); i++) + printk("%08x: %08x\n", (i * 4), readl(®[i])); +} + +/** + * megasas_dump_fusion_io - This function will print key details + * of SCSI IO + * @scmd: SCSI command pointer of SCSI IO + */ +void +megasas_dump_fusion_io(struct scsi_cmnd *scmd) +{ + struct megasas_cmd_fusion *cmd; + union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; + struct megasas_instance *instance; + + cmd = (struct megasas_cmd_fusion *)scmd->SCp.ptr; + instance = (struct megasas_instance *)scmd->device->host->hostdata; + + scmd_printk(KERN_INFO, scmd, + "scmd: (0x%p) retries: 0x%x allowed: 0x%x\n", + scmd, scmd->retries, scmd->allowed); + scsi_print_command(scmd); - printk(KERN_INFO "IO request frame:\n\t"); - for (i = 0; i < sz / sizeof(__le32); i++) { - if (i && ((i % 8) == 0)) - printk("\n\t"); - printk("%08x ", le32_to_cpu(mfp[i])); + if (cmd) { + req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc; + scmd_printk(KERN_INFO, scmd, "Request descriptor details:\n"); + scmd_printk(KERN_INFO, scmd, + "RequestFlags:0x%x MSIxIndex:0x%x SMID:0x%x LMID:0x%x DevHandle:0x%x\n", + req_desc->SCSIIO.RequestFlags, + req_desc->SCSIIO.MSIxIndex, req_desc->SCSIIO.SMID, + req_desc->SCSIIO.LMID, req_desc->SCSIIO.DevHandle); + + printk(KERN_INFO "IO request frame:\n"); + megasas_dump(cmd->io_request, + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE, 8); + printk(KERN_INFO "Chain frame:\n"); + megasas_dump(cmd->sg_frame, + instance->max_chain_frame_sz, 8); } - printk("\n"); + +} + +/* + * megasas_dump_sys_regs - This function will dump system registers through + * sysfs. + * @reg_set: Pointer to System register set. + * @buf: Buffer to which output is to be written. + * @return: Number of bytes written to buffer. + */ +static inline ssize_t +megasas_dump_sys_regs(void __iomem *reg_set, char *buf) +{ + unsigned int i, sz = 256; + int bytes_wrote = 0; + char *loc = (char *)buf; + u32 __iomem *reg = (u32 __iomem *)reg_set; + + for (i = 0; i < sz / sizeof(u32); i++) { + bytes_wrote += snprintf(loc + bytes_wrote, PAGE_SIZE, + "%08x: %08x\n", (i * 4), + readl(®[i])); + } + return bytes_wrote; } /** @@ -2850,24 +2997,20 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd) instance = (struct megasas_instance *)scmd->device->host->hostdata; scmd_printk(KERN_INFO, scmd, - "Controller reset is requested due to IO timeout\n" - "SCSI command pointer: (%p)\t SCSI host state: %d\t" - " SCSI host busy: %d\t FW outstanding: %d\n", - scmd, scmd->device->host->shost_state, + "OCR is requested due to IO timeout!!\n"); + + scmd_printk(KERN_INFO, scmd, + "SCSI host state: %d SCSI host busy: %d FW outstanding: %d\n", + scmd->device->host->shost_state, scsi_host_busy(scmd->device->host), atomic_read(&instance->fw_outstanding)); - /* * First wait for all commands to complete */ if (instance->adapter_type == MFI_SERIES) { ret = megasas_generic_reset(scmd); } else { - struct megasas_cmd_fusion *cmd; - cmd = (struct megasas_cmd_fusion *)scmd->SCp.ptr; - if (cmd) - megasas_dump_frame(cmd->io_request, - MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE); + megasas_dump_fusion_io(scmd); ret = megasas_reset_fusion(scmd->device->host, SCSIIO_TIMEOUT_OCR); } @@ -3017,7 +3160,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) } static ssize_t -megasas_fw_crash_buffer_store(struct device *cdev, +fw_crash_buffer_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3036,15 +3179,15 @@ megasas_fw_crash_buffer_store(struct device *cdev, } static ssize_t -megasas_fw_crash_buffer_show(struct device *cdev, +fw_crash_buffer_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); struct megasas_instance *instance = (struct megasas_instance *) shost->hostdata; u32 size; - unsigned long buff_addr; unsigned long dmachunk = CRASH_DMA_BUF_SIZE; + unsigned long chunk_left_bytes; unsigned long src_addr; unsigned long flags; u32 buff_offset; @@ -3060,8 +3203,6 @@ megasas_fw_crash_buffer_show(struct device *cdev, return -EINVAL; } - buff_addr = (unsigned long) buf; - if (buff_offset > (instance->fw_crash_buffer_size * dmachunk)) { dev_err(&instance->pdev->dev, "Firmware crash dump offset is out of range\n"); @@ -3070,6 +3211,8 @@ megasas_fw_crash_buffer_show(struct device *cdev, } size = (instance->fw_crash_buffer_size * dmachunk) - buff_offset; + chunk_left_bytes = dmachunk - (buff_offset % dmachunk); + size = (size > chunk_left_bytes) ? chunk_left_bytes : size; size = (size >= PAGE_SIZE) ? (PAGE_SIZE - 1) : size; src_addr = (unsigned long)instance->crash_buf[buff_offset / dmachunk] + @@ -3081,7 +3224,7 @@ megasas_fw_crash_buffer_show(struct device *cdev, } static ssize_t -megasas_fw_crash_buffer_size_show(struct device *cdev, +fw_crash_buffer_size_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3093,7 +3236,7 @@ megasas_fw_crash_buffer_size_show(struct device *cdev, } static ssize_t -megasas_fw_crash_state_store(struct device *cdev, +fw_crash_state_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3128,7 +3271,7 @@ megasas_fw_crash_state_store(struct device *cdev, } static ssize_t -megasas_fw_crash_state_show(struct device *cdev, +fw_crash_state_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3139,14 +3282,14 @@ megasas_fw_crash_state_show(struct device *cdev, } static ssize_t -megasas_page_size_show(struct device *cdev, +page_size_show(struct device *cdev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%ld\n", (unsigned long)PAGE_SIZE - 1); } static ssize_t -megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr, +ldio_outstanding_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3156,7 +3299,7 @@ megasas_ldio_outstanding_show(struct device *cdev, struct device_attribute *attr } static ssize_t -megasas_fw_cmds_outstanding_show(struct device *cdev, +fw_cmds_outstanding_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3165,26 +3308,91 @@ megasas_fw_cmds_outstanding_show(struct device *cdev, return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&instance->fw_outstanding)); } -static DEVICE_ATTR(fw_crash_buffer, S_IRUGO | S_IWUSR, - megasas_fw_crash_buffer_show, megasas_fw_crash_buffer_store); -static DEVICE_ATTR(fw_crash_buffer_size, S_IRUGO, - megasas_fw_crash_buffer_size_show, NULL); -static DEVICE_ATTR(fw_crash_state, S_IRUGO | S_IWUSR, - megasas_fw_crash_state_show, megasas_fw_crash_state_store); -static DEVICE_ATTR(page_size, S_IRUGO, - megasas_page_size_show, NULL); -static DEVICE_ATTR(ldio_outstanding, S_IRUGO, - megasas_ldio_outstanding_show, NULL); -static DEVICE_ATTR(fw_cmds_outstanding, S_IRUGO, - megasas_fw_cmds_outstanding_show, NULL); - -struct device_attribute *megaraid_host_attrs[] = { +static ssize_t +enable_sdev_max_qd_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata; + + return snprintf(buf, PAGE_SIZE, "%d\n", instance->enable_sdev_max_qd); +} + +static ssize_t +enable_sdev_max_qd_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct megasas_instance *instance = (struct megasas_instance *)shost->hostdata; + u32 val = 0; + bool is_target_prop; + int ret_target_prop = DCMD_FAILED; + struct scsi_device *sdev; + + if (kstrtou32(buf, 0, &val) != 0) { + pr_err("megasas: could not set enable_sdev_max_qd\n"); + return -EINVAL; + } + + mutex_lock(&instance->reset_mutex); + if (val) + instance->enable_sdev_max_qd = true; + else + instance->enable_sdev_max_qd = false; + + shost_for_each_device(sdev, shost) { + ret_target_prop = megasas_get_target_prop(instance, sdev); + is_target_prop = (ret_target_prop == DCMD_SUCCESS) ? true : false; + megasas_set_fw_assisted_qd(sdev, is_target_prop); + } + mutex_unlock(&instance->reset_mutex); + + return strlen(buf); +} + +static ssize_t +dump_system_regs_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct megasas_instance *instance = + (struct megasas_instance *)shost->hostdata; + + return megasas_dump_sys_regs(instance->reg_set, buf); +} + +static ssize_t +raid_map_id_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct megasas_instance *instance = + (struct megasas_instance *)shost->hostdata; + + return snprintf(buf, PAGE_SIZE, "%ld\n", + (unsigned long)instance->map_id); +} + +static DEVICE_ATTR_RW(fw_crash_buffer); +static DEVICE_ATTR_RO(fw_crash_buffer_size); +static DEVICE_ATTR_RW(fw_crash_state); +static DEVICE_ATTR_RO(page_size); +static DEVICE_ATTR_RO(ldio_outstanding); +static DEVICE_ATTR_RO(fw_cmds_outstanding); +static DEVICE_ATTR_RW(enable_sdev_max_qd); +static DEVICE_ATTR_RO(dump_system_regs); +static DEVICE_ATTR_RO(raid_map_id); + +static struct device_attribute *megaraid_host_attrs[] = { &dev_attr_fw_crash_buffer_size, &dev_attr_fw_crash_buffer, &dev_attr_fw_crash_state, &dev_attr_page_size, &dev_attr_ldio_outstanding, &dev_attr_fw_cmds_outstanding, + &dev_attr_enable_sdev_max_qd, + &dev_attr_dump_system_regs, + &dev_attr_raid_map_id, NULL, }; @@ -3207,6 +3415,7 @@ static struct scsi_host_template megasas_template = { .shost_attrs = megaraid_host_attrs, .bios_param = megasas_bios_param, .change_queue_depth = scsi_change_queue_depth, + .max_segment_size = 0xffffffff, .no_write_same = 1, }; @@ -3368,6 +3577,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, case MFI_CMD_SMP: case MFI_CMD_STP: case MFI_CMD_NVME: + case MFI_CMD_TOOLBOX: megasas_complete_int_cmd(instance, cmd); break; @@ -3776,7 +3986,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) int i; u8 max_wait; u32 fw_state; - u32 cur_state; u32 abs_state, curr_abs_state; abs_state = instance->instancet->read_fw_status_reg(instance); @@ -3791,13 +4000,18 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) switch (fw_state) { case MFI_STATE_FAULT: - dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW in FAULT state!!\n"); + dev_printk(KERN_ERR, &instance->pdev->dev, + "FW in FAULT state, Fault code:0x%x subcode:0x%x func:%s\n", + abs_state & MFI_STATE_FAULT_CODE, + abs_state & MFI_STATE_FAULT_SUBCODE, __func__); if (ocr) { max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_FAULT; break; - } else + } else { + dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n"); + megasas_dump_reg_set(instance->reg_set); return -ENODEV; + } case MFI_STATE_WAIT_HANDSHAKE: /* @@ -3817,7 +4031,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) &instance->reg_set->inbound_doorbell); max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_WAIT_HANDSHAKE; break; case MFI_STATE_BOOT_MESSAGE_PENDING: @@ -3833,7 +4046,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) &instance->reg_set->inbound_doorbell); max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_BOOT_MESSAGE_PENDING; break; case MFI_STATE_OPERATIONAL: @@ -3866,7 +4078,6 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) &instance->reg_set->inbound_doorbell); max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_OPERATIONAL; break; case MFI_STATE_UNDEFINED: @@ -3874,37 +4085,33 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) * This state should not last for more than 2 seconds */ max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_UNDEFINED; break; case MFI_STATE_BB_INIT: max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_BB_INIT; break; case MFI_STATE_FW_INIT: max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_FW_INIT; break; case MFI_STATE_FW_INIT_2: max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_FW_INIT_2; break; case MFI_STATE_DEVICE_SCAN: max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_DEVICE_SCAN; break; case MFI_STATE_FLUSH_CACHE: max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_FLUSH_CACHE; break; default: dev_printk(KERN_DEBUG, &instance->pdev->dev, "Unknown state 0x%x\n", fw_state); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n"); + megasas_dump_reg_set(instance->reg_set); return -ENODEV; } @@ -3927,6 +4134,8 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) if (curr_abs_state == abs_state) { dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW state [%d] hasn't changed " "in %d secs\n", fw_state, max_wait); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "System Register set:\n"); + megasas_dump_reg_set(instance->reg_set); return -ENODEV; } @@ -3990,23 +4199,12 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) { int i; u16 max_cmd; - u32 sge_sz; u32 frame_count; struct megasas_cmd *cmd; max_cmd = instance->max_mfi_cmds; /* - * Size of our frame is 64 bytes for MFI frame, followed by max SG - * elements and finally SCSI_SENSE_BUFFERSIZE bytes for sense buffer - */ - sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) : - sizeof(struct megasas_sge32); - - if (instance->flag_ieee) - sge_sz = sizeof(struct megasas_sge_skinny); - - /* * For MFI controllers. * max_num_sge = 60 * max_sge_sz = 16 byte (sizeof megasas_sge_skinny) @@ -4255,8 +4453,10 @@ megasas_get_pd_info(struct megasas_instance *instance, struct scsi_device *sdev) switch (dcmd_timeout_ocr_possible(instance)) { case INITIATE_OCR: cmd->flags |= DRV_DCMD_SKIP_REFIRE; + mutex_unlock(&instance->reset_mutex); megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR); + mutex_lock(&instance->reset_mutex); break; case KILL_ADAPTER: megaraid_sas_kill_hba(instance); @@ -4292,7 +4492,6 @@ megasas_get_pd_list(struct megasas_instance *instance) struct megasas_dcmd_frame *dcmd; struct MR_PD_LIST *ci; struct MR_PD_ADDRESS *pd_addr; - dma_addr_t ci_h = 0; if (instance->pd_list_not_supported) { dev_info(&instance->pdev->dev, "MR_DCMD_PD_LIST_QUERY " @@ -4301,7 +4500,6 @@ megasas_get_pd_list(struct megasas_instance *instance) } ci = instance->pd_list_buf; - ci_h = instance->pd_list_buf_h; cmd = megasas_get_cmd(instance); @@ -4374,6 +4572,9 @@ megasas_get_pd_list(struct megasas_instance *instance) case DCMD_SUCCESS: pd_addr = ci->addr; + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, "%s, sysPD count: 0x%x\n", + __func__, le32_to_cpu(ci->count)); if ((le32_to_cpu(ci->count) > (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) @@ -4389,6 +4590,11 @@ megasas_get_pd_list(struct megasas_instance *instance) pd_addr->scsiDevType; instance->local_pd_list[le16_to_cpu(pd_addr->deviceId)].driveState = MR_PD_STATE_SYSTEM; + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, + "PD%d: targetID: 0x%03x deviceType:0x%x\n", + pd_index, le16_to_cpu(pd_addr->deviceId), + pd_addr->scsiDevType); pd_addr++; } @@ -4492,6 +4698,10 @@ megasas_get_ld_list(struct megasas_instance *instance) break; case DCMD_SUCCESS: + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n", + __func__, ld_count); + if (ld_count > instance->fw_supported_vd_count) break; @@ -4501,6 +4711,10 @@ megasas_get_ld_list(struct megasas_instance *instance) if (ci->ldList[ld_index].state != 0) { ids = ci->ldList[ld_index].ref.targetId; instance->ld_ids[ids] = ci->ldList[ld_index].ref.targetId; + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, + "LD%d: targetID: 0x%03x\n", + ld_index, ids); } } @@ -4604,6 +4818,10 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type) case DCMD_SUCCESS: tgtid_count = le32_to_cpu(ci->count); + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, "%s, LD count: 0x%x\n", + __func__, tgtid_count); + if ((tgtid_count > (instance->fw_supported_vd_count))) break; @@ -4611,6 +4829,9 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type) for (ld_index = 0; ld_index < tgtid_count; ld_index++) { ids = ci->targetId[ld_index]; instance->ld_ids[ids] = ci->targetId[ld_index]; + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, "LD%d: targetID: 0x%03x\n", + ld_index, ci->targetId[ld_index]); } break; @@ -4690,6 +4911,13 @@ megasas_host_device_list_query(struct megasas_instance *instance, */ count = le32_to_cpu(ci->count); + if (count > (MEGASAS_MAX_PD + MAX_LOGICAL_DRIVES_EXT)) + break; + + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, "%s, Device count: 0x%x\n", + __func__, count); + memset(instance->local_pd_list, 0, MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)); memset(instance->ld_ids, 0xff, MAX_LOGICAL_DRIVES_EXT); @@ -4701,8 +4929,16 @@ megasas_host_device_list_query(struct megasas_instance *instance, ci->host_device_list[i].scsi_type; instance->local_pd_list[target_id].driveState = MR_PD_STATE_SYSTEM; + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, + "Device %d: PD targetID: 0x%03x deviceType:0x%x\n", + i, target_id, ci->host_device_list[i].scsi_type); } else { instance->ld_ids[target_id] = target_id; + if (megasas_dbg_lvl & LD_PD_DEBUG) + dev_info(&instance->pdev->dev, + "Device %d: LD targetID: 0x%03x\n", + i, target_id); } } @@ -4714,8 +4950,10 @@ megasas_host_device_list_query(struct megasas_instance *instance, switch (dcmd_timeout_ocr_possible(instance)) { case INITIATE_OCR: cmd->flags |= DRV_DCMD_SKIP_REFIRE; + mutex_unlock(&instance->reset_mutex); megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR); + mutex_lock(&instance->reset_mutex); break; case KILL_ADAPTER: megaraid_sas_kill_hba(instance); @@ -4863,8 +5101,10 @@ void megasas_get_snapdump_properties(struct megasas_instance *instance) switch (dcmd_timeout_ocr_possible(instance)) { case INITIATE_OCR: cmd->flags |= DRV_DCMD_SKIP_REFIRE; + mutex_unlock(&instance->reset_mutex); megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR); + mutex_lock(&instance->reset_mutex); break; case KILL_ADAPTER: megaraid_sas_kill_hba(instance); @@ -4943,6 +5183,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance) le32_to_cpus((u32 *)&ci->adapterOperations2); le32_to_cpus((u32 *)&ci->adapterOperations3); le16_to_cpus((u16 *)&ci->adapter_operations4); + le32_to_cpus((u32 *)&ci->adapter_operations5); /* Update the latest Ext VD info. * From Init path, store current firmware details. @@ -4950,12 +5191,14 @@ megasas_get_ctrl_info(struct megasas_instance *instance) * in case of Firmware upgrade without system reboot. */ megasas_update_ext_vd_details(instance); - instance->use_seqnum_jbod_fp = + instance->support_seqnum_jbod_fp = ci->adapterOperations3.useSeqNumJbodFP; instance->support_morethan256jbod = ci->adapter_operations4.support_pd_map_target_id; instance->support_nvme_passthru = ci->adapter_operations4.support_nvme_passthru; + instance->support_pci_lane_margining = + ci->adapter_operations5.support_pci_lane_margining; instance->task_abort_tmo = ci->TaskAbortTO; instance->max_reset_tmo = ci->MaxResetTO; @@ -4987,6 +5230,10 @@ megasas_get_ctrl_info(struct megasas_instance *instance) dev_info(&instance->pdev->dev, "FW provided TM TaskAbort/Reset timeout\t: %d secs/%d secs\n", instance->task_abort_tmo, instance->max_reset_tmo); + dev_info(&instance->pdev->dev, "JBOD sequence map support\t: %s\n", + instance->support_seqnum_jbod_fp ? "Yes" : "No"); + dev_info(&instance->pdev->dev, "PCI Lane Margining support\t: %s\n", + instance->support_pci_lane_margining ? "Yes" : "No"); break; @@ -4994,8 +5241,10 @@ megasas_get_ctrl_info(struct megasas_instance *instance) switch (dcmd_timeout_ocr_possible(instance)) { case INITIATE_OCR: cmd->flags |= DRV_DCMD_SKIP_REFIRE; + mutex_unlock(&instance->reset_mutex); megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR); + mutex_lock(&instance->reset_mutex); break; case KILL_ADAPTER: megaraid_sas_kill_hba(instance); @@ -5262,6 +5511,25 @@ fail_alloc_cmds: return 1; } +static +void megasas_setup_irq_poll(struct megasas_instance *instance) +{ + struct megasas_irq_context *irq_ctx; + u32 count, i; + + count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; + + /* Initialize IRQ poll */ + for (i = 0; i < count; i++) { + irq_ctx = &instance->irq_context[i]; + irq_ctx->os_irq = pci_irq_vector(instance->pdev, i); + irq_ctx->irq_poll_scheduled = false; + irq_poll_init(&irq_ctx->irqpoll, + instance->threshold_reply_count, + megasas_irqpoll); + } +} + /* * megasas_setup_irqs_ioapic - register legacy interrupts. * @instance: Adapter soft state @@ -5286,6 +5554,8 @@ megasas_setup_irqs_ioapic(struct megasas_instance *instance) __func__, __LINE__); return -1; } + instance->perf_mode = MR_LATENCY_PERF_MODE; + instance->low_latency_index_start = 0; return 0; } @@ -5320,6 +5590,7 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe) &instance->irq_context[j]); /* Retry irq register for IO_APIC*/ instance->msix_vectors = 0; + instance->msix_load_balance = false; if (is_probe) { pci_free_irq_vectors(instance->pdev); return megasas_setup_irqs_ioapic(instance); @@ -5328,6 +5599,7 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe) } } } + return 0; } @@ -5340,6 +5612,16 @@ static void megasas_destroy_irqs(struct megasas_instance *instance) { int i; + int count; + struct megasas_irq_context *irq_ctx; + + count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; + if (instance->adapter_type != MFI_SERIES) { + for (i = 0; i < count; i++) { + irq_ctx = &instance->irq_context[i]; + irq_poll_disable(&irq_ctx->irqpoll); + } + } if (instance->msix_vectors) for (i = 0; i < instance->msix_vectors; i++) { @@ -5368,10 +5650,12 @@ megasas_setup_jbod_map(struct megasas_instance *instance) pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + (sizeof(struct MR_PD_CFG_SEQ) * (MAX_PHYSICAL_DEVICES - 1)); + instance->use_seqnum_jbod_fp = + instance->support_seqnum_jbod_fp; if (reset_devices || !fusion || - !instance->ctrl_info_buf->adapterOperations3.useSeqNumJbodFP) { + !instance->support_seqnum_jbod_fp) { dev_info(&instance->pdev->dev, - "Jbod map is not supported %s %d\n", + "JBOD sequence map is disabled %s %d\n", __func__, __LINE__); instance->use_seqnum_jbod_fp = false; return; @@ -5410,9 +5694,11 @@ skip_alloc: static void megasas_setup_reply_map(struct megasas_instance *instance) { const struct cpumask *mask; - unsigned int queue, cpu; + unsigned int queue, cpu, low_latency_index_start; + + low_latency_index_start = instance->low_latency_index_start; - for (queue = 0; queue < instance->msix_vectors; queue++) { + for (queue = low_latency_index_start; queue < instance->msix_vectors; queue++) { mask = pci_irq_get_affinity(instance->pdev, queue); if (!mask) goto fallback; @@ -5423,8 +5709,14 @@ static void megasas_setup_reply_map(struct megasas_instance *instance) return; fallback: - for_each_possible_cpu(cpu) - instance->reply_map[cpu] = cpu % instance->msix_vectors; + queue = low_latency_index_start; + for_each_possible_cpu(cpu) { + instance->reply_map[cpu] = queue; + if (queue == (instance->msix_vectors - 1)) + queue = low_latency_index_start; + else + queue++; + } } /** @@ -5461,6 +5753,89 @@ int megasas_get_device_list(struct megasas_instance *instance) return SUCCESS; } + +/** + * megasas_set_high_iops_queue_affinity_hint - Set affinity hint for high IOPS queues + * @instance: Adapter soft state + * return: void + */ +static inline void +megasas_set_high_iops_queue_affinity_hint(struct megasas_instance *instance) +{ + int i; + int local_numa_node; + + if (instance->perf_mode == MR_BALANCED_PERF_MODE) { + local_numa_node = dev_to_node(&instance->pdev->dev); + + for (i = 0; i < instance->low_latency_index_start; i++) + irq_set_affinity_hint(pci_irq_vector(instance->pdev, i), + cpumask_of_node(local_numa_node)); + } +} + +static int +__megasas_alloc_irq_vectors(struct megasas_instance *instance) +{ + int i, irq_flags; + struct irq_affinity desc = { .pre_vectors = instance->low_latency_index_start }; + struct irq_affinity *descp = &desc; + + irq_flags = PCI_IRQ_MSIX; + + if (instance->smp_affinity_enable) + irq_flags |= PCI_IRQ_AFFINITY; + else + descp = NULL; + + i = pci_alloc_irq_vectors_affinity(instance->pdev, + instance->low_latency_index_start, + instance->msix_vectors, irq_flags, descp); + + return i; +} + +/** + * megasas_alloc_irq_vectors - Allocate IRQ vectors/enable MSI-x vectors + * @instance: Adapter soft state + * return: void + */ +static void +megasas_alloc_irq_vectors(struct megasas_instance *instance) +{ + int i; + unsigned int num_msix_req; + + i = __megasas_alloc_irq_vectors(instance); + + if ((instance->perf_mode == MR_BALANCED_PERF_MODE) && + (i != instance->msix_vectors)) { + if (instance->msix_vectors) + pci_free_irq_vectors(instance->pdev); + /* Disable Balanced IOPS mode and try realloc vectors */ + instance->perf_mode = MR_LATENCY_PERF_MODE; + instance->low_latency_index_start = 1; + num_msix_req = num_online_cpus() + instance->low_latency_index_start; + + instance->msix_vectors = min(num_msix_req, + instance->msix_vectors); + + i = __megasas_alloc_irq_vectors(instance); + + } + + dev_info(&instance->pdev->dev, + "requested/available msix %d/%d\n", instance->msix_vectors, i); + + if (i > 0) + instance->msix_vectors = i; + else + instance->msix_vectors = 0; + + if (instance->smp_affinity_enable) + megasas_set_high_iops_queue_affinity_hint(instance); +} + /** * megasas_init_fw - Initializes the FW * @instance: Adapter soft state @@ -5474,12 +5849,15 @@ static int megasas_init_fw(struct megasas_instance *instance) u32 max_sectors_2, tmp_sectors, msix_enable; u32 scratch_pad_1, scratch_pad_2, scratch_pad_3, status_reg; resource_size_t base_addr; + void *base_addr_phys; struct megasas_ctrl_info *ctrl_info = NULL; unsigned long bar_list; - int i, j, loop, fw_msix_count = 0; + int i, j, loop; struct IOV_111 *iovPtr; struct fusion_context *fusion; - bool do_adp_reset = true; + bool intr_coalescing; + unsigned int num_msix_req; + u16 lnksta, speed; fusion = instance->ctrl_context; @@ -5500,6 +5878,11 @@ static int megasas_init_fw(struct megasas_instance *instance) goto fail_ioremap; } + base_addr_phys = &base_addr; + dev_printk(KERN_DEBUG, &instance->pdev->dev, + "BAR:0x%lx BAR's base_addr(phys):%pa mapped virt_addr:0x%p\n", + instance->bar, base_addr_phys, instance->reg_set); + if (instance->adapter_type != MFI_SERIES) instance->instancet = &megasas_instance_template_fusion; else { @@ -5526,29 +5909,35 @@ static int megasas_init_fw(struct megasas_instance *instance) } if (megasas_transition_to_ready(instance, 0)) { - if (instance->adapter_type >= INVADER_SERIES) { + dev_info(&instance->pdev->dev, + "Failed to transition controller to ready from %s!\n", + __func__); + if (instance->adapter_type != MFI_SERIES) { status_reg = instance->instancet->read_fw_status_reg( instance); - do_adp_reset = status_reg & MFI_RESET_ADAPTER; - } - - if (do_adp_reset) { + if (status_reg & MFI_RESET_ADAPTER) { + if (megasas_adp_reset_wait_for_ready + (instance, true, 0) == FAILED) + goto fail_ready_state; + } else { + goto fail_ready_state; + } + } else { atomic_set(&instance->fw_reset_no_pci_access, 1); instance->instancet->adp_reset (instance, instance->reg_set); atomic_set(&instance->fw_reset_no_pci_access, 0); - dev_info(&instance->pdev->dev, - "FW restarted successfully from %s!\n", - __func__); /*waiting for about 30 second before retry*/ ssleep(30); if (megasas_transition_to_ready(instance, 0)) goto fail_ready_state; - } else { - goto fail_ready_state; } + + dev_info(&instance->pdev->dev, + "FW restarted successfully from %s!\n", + __func__); } megasas_init_ctrl_params(instance); @@ -5573,11 +5962,23 @@ static int megasas_init_fw(struct megasas_instance *instance) MR_MAX_RAID_MAP_SIZE_MASK); } + instance->enable_sdev_max_qd = enable_sdev_max_qd; + + switch (instance->adapter_type) { + case VENTURA_SERIES: + fusion->pcie_bw_limitation = true; + break; + case AERO_SERIES: + fusion->r56_div_offload = true; + break; + default: + break; + } + /* Check if MSI-X is supported while in ready state */ msix_enable = (instance->instancet->read_fw_status_reg(instance) & 0x4000000) >> 0x1a; if (msix_enable && !msix_disable) { - int irq_flags = PCI_IRQ_MSIX; scratch_pad_1 = megasas_readl (instance, &instance->reg_set->outbound_scratch_pad_1); @@ -5587,7 +5988,6 @@ static int megasas_init_fw(struct megasas_instance *instance) /* Thunderbolt Series*/ instance->msix_vectors = (scratch_pad_1 & MR_MAX_REPLY_QUEUES_OFFSET) + 1; - fw_msix_count = instance->msix_vectors; } else { instance->msix_vectors = ((scratch_pad_1 & MR_MAX_REPLY_QUEUES_EXT_OFFSET) @@ -5616,7 +6016,13 @@ static int megasas_init_fw(struct megasas_instance *instance) if (rdpq_enable) instance->is_rdpq = (scratch_pad_1 & MR_RDPQ_MODE_OFFSET) ? 1 : 0; - fw_msix_count = instance->msix_vectors; + + if (instance->adapter_type >= INVADER_SERIES && + !instance->msix_combined) { + instance->msix_load_balance = true; + instance->smp_affinity_enable = false; + } + /* Save 1-15 reply post index address to local memory * Index 0 is already saved from reg offset * MPI2_REPLY_POST_HOST_INDEX_OFFSET @@ -5629,22 +6035,91 @@ static int megasas_init_fw(struct megasas_instance *instance) + (loop * 0x10)); } } + + dev_info(&instance->pdev->dev, + "firmware supports msix\t: (%d)", + instance->msix_vectors); if (msix_vectors) instance->msix_vectors = min(msix_vectors, instance->msix_vectors); } else /* MFI adapters */ instance->msix_vectors = 1; - /* Don't bother allocating more MSI-X vectors than cpus */ - instance->msix_vectors = min(instance->msix_vectors, - (unsigned int)num_online_cpus()); - if (smp_affinity_enable) - irq_flags |= PCI_IRQ_AFFINITY; - i = pci_alloc_irq_vectors(instance->pdev, 1, - instance->msix_vectors, irq_flags); - if (i > 0) - instance->msix_vectors = i; + + + /* + * For Aero (if some conditions are met), driver will configure a + * few additional reply queues with interrupt coalescing enabled. + * These queues with interrupt coalescing enabled are called + * High IOPS queues and rest of reply queues (based on number of + * logical CPUs) are termed as Low latency queues. + * + * Total Number of reply queues = High IOPS queues + low latency queues + * + * For rest of fusion adapters, 1 additional reply queue will be + * reserved for management commands, rest of reply queues + * (based on number of logical CPUs) will be used for IOs and + * referenced as IO queues. + * Total Number of reply queues = 1 + IO queues + * + * MFI adapters supports single MSI-x so single reply queue + * will be used for IO and management commands. + */ + + intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ? + true : false; + if (intr_coalescing && + (num_online_cpus() >= MR_HIGH_IOPS_QUEUE_COUNT) && + (instance->msix_vectors == MEGASAS_MAX_MSIX_QUEUES)) + instance->perf_mode = MR_BALANCED_PERF_MODE; else - instance->msix_vectors = 0; + instance->perf_mode = MR_LATENCY_PERF_MODE; + + + if (instance->adapter_type == AERO_SERIES) { + pcie_capability_read_word(instance->pdev, PCI_EXP_LNKSTA, &lnksta); + speed = lnksta & PCI_EXP_LNKSTA_CLS; + + /* + * For Aero, if PCIe link speed is <16 GT/s, then driver should operate + * in latency perf mode and enable R1 PCI bandwidth algorithm + */ + if (speed < 0x4) { + instance->perf_mode = MR_LATENCY_PERF_MODE; + fusion->pcie_bw_limitation = true; + } + + /* + * Performance mode settings provided through module parameter-perf_mode will + * take affect only for: + * 1. Aero family of adapters. + * 2. When user sets module parameter- perf_mode in range of 0-2. + */ + if ((perf_mode >= MR_BALANCED_PERF_MODE) && + (perf_mode <= MR_LATENCY_PERF_MODE)) + instance->perf_mode = perf_mode; + /* + * If intr coalescing is not supported by controller FW, then IOPS + * and Balanced modes are not feasible. + */ + if (!intr_coalescing) + instance->perf_mode = MR_LATENCY_PERF_MODE; + + } + + if (instance->perf_mode == MR_BALANCED_PERF_MODE) + instance->low_latency_index_start = + MR_HIGH_IOPS_QUEUE_COUNT; + else + instance->low_latency_index_start = 1; + + num_msix_req = num_online_cpus() + instance->low_latency_index_start; + + instance->msix_vectors = min(num_msix_req, + instance->msix_vectors); + + megasas_alloc_irq_vectors(instance); + if (!instance->msix_vectors) + instance->msix_load_balance = false; } /* * MSI-X host index 0 is common for all adapter. @@ -5669,8 +6144,6 @@ static int megasas_init_fw(struct megasas_instance *instance) megasas_setup_reply_map(instance); dev_info(&instance->pdev->dev, - "firmware supports msix\t: (%d)", fw_msix_count); - dev_info(&instance->pdev->dev, "current msix/online cpus\t: (%d/%d)\n", instance->msix_vectors, (unsigned int)num_online_cpus()); dev_info(&instance->pdev->dev, @@ -5707,6 +6180,9 @@ static int megasas_init_fw(struct megasas_instance *instance) megasas_setup_irqs_ioapic(instance)) goto fail_init_adapter; + if (instance->adapter_type != MFI_SERIES) + megasas_setup_irq_poll(instance); + instance->instancet->enable_intr(instance); dev_info(&instance->pdev->dev, "INIT adapter done\n"); @@ -5833,8 +6309,8 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->UnevenSpanSupport ? "yes" : "no"); dev_info(&instance->pdev->dev, "firmware crash dump : %s\n", instance->crash_dump_drv_support ? "yes" : "no"); - dev_info(&instance->pdev->dev, "jbod sync map : %s\n", - instance->use_seqnum_jbod_fp ? "yes" : "no"); + dev_info(&instance->pdev->dev, "JBOD sequence map : %s\n", + instance->use_seqnum_jbod_fp ? "enabled" : "disabled"); instance->max_sectors_per_req = instance->max_num_sge * SGE_BUFFER_SIZE / 512; @@ -6155,7 +6631,8 @@ megasas_get_target_prop(struct megasas_instance *instance, int ret; struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; - u16 targetId = (sdev->channel % 2) + sdev->id; + u16 targetId = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + + sdev->id; cmd = megasas_get_cmd(instance); @@ -6197,8 +6674,10 @@ megasas_get_target_prop(struct megasas_instance *instance, switch (dcmd_timeout_ocr_possible(instance)) { case INITIATE_OCR: cmd->flags |= DRV_DCMD_SKIP_REFIRE; + mutex_unlock(&instance->reset_mutex); megasas_reset_fusion(instance->host, MFI_IO_TIMEOUT_OCR); + mutex_lock(&instance->reset_mutex); break; case KILL_ADAPTER: megaraid_sas_kill_hba(instance); @@ -6748,6 +7227,7 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance) INIT_LIST_HEAD(&instance->internal_reset_pending_q); atomic_set(&instance->fw_outstanding, 0); + atomic64_set(&instance->total_io_count, 0); init_waitqueue_head(&instance->int_cmd_wait_q); init_waitqueue_head(&instance->abort_cmd_wait_q); @@ -6770,6 +7250,8 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance) instance->last_time = 0; instance->disableOnlineCtrlReset = 1; instance->UnevenSpanSupport = 0; + instance->smp_affinity_enable = smp_affinity_enable ? true : false; + instance->msix_load_balance = false; if (instance->adapter_type != MFI_SERIES) INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq); @@ -6791,6 +7273,12 @@ static int megasas_probe_one(struct pci_dev *pdev, u16 control = 0; switch (pdev->device) { + case PCI_DEVICE_ID_LSI_AERO_10E0: + case PCI_DEVICE_ID_LSI_AERO_10E3: + case PCI_DEVICE_ID_LSI_AERO_10E4: + case PCI_DEVICE_ID_LSI_AERO_10E7: + dev_err(&pdev->dev, "Adapter is in non secure mode\n"); + return 1; case PCI_DEVICE_ID_LSI_AERO_10E1: case PCI_DEVICE_ID_LSI_AERO_10E5: dev_info(&pdev->dev, "Adapter is in configurable secure mode\n"); @@ -6910,6 +7398,8 @@ static int megasas_probe_one(struct pci_dev *pdev, goto fail_start_aen; } + megasas_setup_debugfs(instance); + /* Get current SR-IOV LD/VF affiliation */ if (instance->requestorId) megasas_get_ld_vf_affiliation(instance, 1); @@ -7041,13 +7531,17 @@ static void megasas_shutdown_controller(struct megasas_instance *instance, static int megasas_suspend(struct pci_dev *pdev, pm_message_t state) { - struct Scsi_Host *host; struct megasas_instance *instance; instance = pci_get_drvdata(pdev); - host = instance->host; + + if (!instance) + return 0; + instance->unload = 1; + dev_info(&pdev->dev, "%s is called\n", __func__); + /* Shutdown SR-IOV heartbeat timer */ if (instance->requestorId && !instance->skip_heartbeat_timer_del) del_timer_sync(&instance->sriov_heartbeat_timer); @@ -7097,11 +7591,16 @@ megasas_resume(struct pci_dev *pdev) int irq_flags = PCI_IRQ_LEGACY; instance = pci_get_drvdata(pdev); + + if (!instance) + return 0; + host = instance->host; pci_set_power_state(pdev, PCI_D0); pci_enable_wake(pdev, PCI_D0, 0); pci_restore_state(pdev); + dev_info(&pdev->dev, "%s is called\n", __func__); /* * PCI prepping: enable device set bus mastering and dma mask */ @@ -7133,7 +7632,7 @@ megasas_resume(struct pci_dev *pdev) /* Now re-enable MSI-X */ if (instance->msix_vectors) { irq_flags = PCI_IRQ_MSIX; - if (smp_affinity_enable) + if (instance->smp_affinity_enable) irq_flags |= PCI_IRQ_AFFINITY; } rval = pci_alloc_irq_vectors(instance->pdev, 1, @@ -7171,6 +7670,9 @@ megasas_resume(struct pci_dev *pdev) megasas_setup_irqs_ioapic(instance)) goto fail_init_mfi; + if (instance->adapter_type != MFI_SERIES) + megasas_setup_irq_poll(instance); + /* Re-launch SR-IOV heartbeat timer */ if (instance->requestorId) { if (!megasas_sriov_start_heartbeat(instance, 0)) @@ -7261,6 +7763,10 @@ static void megasas_detach_one(struct pci_dev *pdev) u32 pd_seq_map_sz; instance = pci_get_drvdata(pdev); + + if (!instance) + return; + host = instance->host; fusion = instance->ctrl_context; @@ -7374,6 +7880,8 @@ skip_firing_dcmds: megasas_free_ctrl_mem(instance); + megasas_destroy_debugfs(instance); + scsi_host_put(host); pci_disable_device(pdev); @@ -7387,6 +7895,9 @@ static void megasas_shutdown(struct pci_dev *pdev) { struct megasas_instance *instance = pci_get_drvdata(pdev); + if (!instance) + return; + instance->unload = 1; if (megasas_wait_for_adapter_operational(instance)) @@ -7532,7 +8043,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, if ((ioc->frame.hdr.cmd >= MFI_CMD_OP_COUNT) || ((ioc->frame.hdr.cmd == MFI_CMD_NVME) && - !instance->support_nvme_passthru)) { + !instance->support_nvme_passthru) || + ((ioc->frame.hdr.cmd == MFI_CMD_TOOLBOX) && + !instance->support_pci_lane_margining)) { dev_err(&instance->pdev->dev, "Received invalid ioctl command 0x%x\n", ioc->frame.hdr.cmd); @@ -7568,10 +8081,13 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, opcode = le32_to_cpu(cmd->frame->dcmd.opcode); if (opcode == MR_DCMD_CTRL_SHUTDOWN) { + mutex_lock(&instance->reset_mutex); if (megasas_get_ctrl_info(instance) != DCMD_SUCCESS) { megasas_return_cmd(instance, cmd); + mutex_unlock(&instance->reset_mutex); return -1; } + mutex_unlock(&instance->reset_mutex); } if (opcode == MR_DRIVER_SET_APP_CRASHDUMP_MODE) { @@ -8013,6 +8529,14 @@ support_nvme_encapsulation_show(struct device_driver *dd, char *buf) static DRIVER_ATTR_RO(support_nvme_encapsulation); +static ssize_t +support_pci_lane_margining_show(struct device_driver *dd, char *buf) +{ + return sprintf(buf, "%u\n", support_pci_lane_margining); +} + +static DRIVER_ATTR_RO(support_pci_lane_margining); + static inline void megasas_remove_scsi_device(struct scsi_device *sdev) { sdev_printk(KERN_INFO, sdev, "SCSI device is removed\n"); @@ -8161,7 +8685,7 @@ megasas_aen_polling(struct work_struct *work) struct megasas_instance *instance = ev->instance; union megasas_evt_class_locale class_locale; int event_type = 0; - u32 seq_num, wait_time = MEGASAS_RESET_WAIT_TIME; + u32 seq_num; int error; u8 dcmd_ret = DCMD_SUCCESS; @@ -8171,10 +8695,6 @@ megasas_aen_polling(struct work_struct *work) return; } - /* Adjust event workqueue thread wait time for VF mode */ - if (instance->requestorId) - wait_time = MEGASAS_ROUTINE_WAIT_TIME_VF; - /* Don't run the event workqueue thread if OCR is running */ mutex_lock(&instance->reset_mutex); @@ -8286,6 +8806,7 @@ static int __init megasas_init(void) support_poll_for_event = 2; support_device_change = 1; support_nvme_encapsulation = true; + support_pci_lane_margining = true; memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info)); @@ -8301,6 +8822,8 @@ static int __init megasas_init(void) megasas_mgmt_majorno = rval; + megasas_init_debugfs(); + /* * Register ourselves as PCI hotplug module */ @@ -8311,6 +8834,12 @@ static int __init megasas_init(void) goto err_pcidrv; } + if ((event_log_level < MFI_EVT_CLASS_DEBUG) || + (event_log_level > MFI_EVT_CLASS_DEAD)) { + pr_warn("megaraid_sas: provided event log level is out of range, setting it to default 2(CLASS_CRITICAL), permissible range is: -2 to 4\n"); + event_log_level = MFI_EVT_CLASS_CRITICAL; + } + rval = driver_create_file(&megasas_pci_driver.driver, &driver_attr_version); if (rval) @@ -8340,8 +8869,17 @@ static int __init megasas_init(void) if (rval) goto err_dcf_support_nvme_encapsulation; + rval = driver_create_file(&megasas_pci_driver.driver, + &driver_attr_support_pci_lane_margining); + if (rval) + goto err_dcf_support_pci_lane_margining; + return rval; +err_dcf_support_pci_lane_margining: + driver_remove_file(&megasas_pci_driver.driver, + &driver_attr_support_nvme_encapsulation); + err_dcf_support_nvme_encapsulation: driver_remove_file(&megasas_pci_driver.driver, &driver_attr_support_device_change); @@ -8360,6 +8898,7 @@ err_dcf_rel_date: err_dcf_attr_ver: pci_unregister_driver(&megasas_pci_driver); err_pcidrv: + megasas_exit_debugfs(); unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl"); return rval; } @@ -8380,8 +8919,11 @@ static void __exit megasas_exit(void) driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version); driver_remove_file(&megasas_pci_driver.driver, &driver_attr_support_nvme_encapsulation); + driver_remove_file(&megasas_pci_driver.driver, + &driver_attr_support_pci_lane_margining); pci_unregister_driver(&megasas_pci_driver); + megasas_exit_debugfs(); unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl"); } diff --git a/drivers/scsi/megaraid/megaraid_sas_debugfs.c b/drivers/scsi/megaraid/megaraid_sas_debugfs.c new file mode 100644 index 000000000000..c69760775efa --- /dev/null +++ b/drivers/scsi/megaraid/megaraid_sas_debugfs.c @@ -0,0 +1,179 @@ +/* + * Linux MegaRAID driver for SAS based RAID controllers + * + * Copyright (c) 2003-2018 LSI Corporation. + * Copyright (c) 2003-2018 Avago Technologies. + * Copyright (c) 2003-2018 Broadcom Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authors: Broadcom Inc. + * Kashyap Desai <kashyap.desai@broadcom.com> + * Sumit Saxena <sumit.saxena@broadcom.com> + * Shivasharan S <shivasharan.srikanteshwara@broadcom.com> + * + * Send feedback to: megaraidlinux.pdl@broadcom.com + */ +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/compat.h> +#include <linux/irq_poll.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> + +#include "megaraid_sas_fusion.h" +#include "megaraid_sas.h" + +#ifdef CONFIG_DEBUG_FS +#include <linux/debugfs.h> + +struct dentry *megasas_debugfs_root; + +static ssize_t +megasas_debugfs_read(struct file *filp, char __user *ubuf, size_t cnt, + loff_t *ppos) +{ + struct megasas_debugfs_buffer *debug = filp->private_data; + + if (!debug || !debug->buf) + return 0; + + return simple_read_from_buffer(ubuf, cnt, ppos, debug->buf, debug->len); +} + +static int +megasas_debugfs_raidmap_open(struct inode *inode, struct file *file) +{ + struct megasas_instance *instance = inode->i_private; + struct megasas_debugfs_buffer *debug; + struct fusion_context *fusion; + + fusion = instance->ctrl_context; + + debug = kzalloc(sizeof(struct megasas_debugfs_buffer), GFP_KERNEL); + if (!debug) + return -ENOMEM; + + debug->buf = (void *)fusion->ld_drv_map[(instance->map_id & 1)]; + debug->len = fusion->drv_map_sz; + file->private_data = debug; + + return 0; +} + +static int +megasas_debugfs_release(struct inode *inode, struct file *file) +{ + struct megasas_debug_buffer *debug = file->private_data; + + if (!debug) + return 0; + + file->private_data = NULL; + kfree(debug); + return 0; +} + +static const struct file_operations megasas_debugfs_raidmap_fops = { + .owner = THIS_MODULE, + .open = megasas_debugfs_raidmap_open, + .read = megasas_debugfs_read, + .release = megasas_debugfs_release, +}; + +/* + * megasas_init_debugfs : Create debugfs root for megaraid_sas driver + */ +void megasas_init_debugfs(void) +{ + megasas_debugfs_root = debugfs_create_dir("megaraid_sas", NULL); + if (!megasas_debugfs_root) + pr_info("Cannot create debugfs root\n"); +} + +/* + * megasas_exit_debugfs : Remove debugfs root for megaraid_sas driver + */ +void megasas_exit_debugfs(void) +{ + debugfs_remove_recursive(megasas_debugfs_root); +} + +/* + * megasas_setup_debugfs : Setup debugfs per Fusion adapter + * instance: Soft instance of adapter + */ +void +megasas_setup_debugfs(struct megasas_instance *instance) +{ + char name[64]; + struct fusion_context *fusion; + + fusion = instance->ctrl_context; + + if (fusion) { + snprintf(name, sizeof(name), + "scsi_host%d", instance->host->host_no); + if (!instance->debugfs_root) { + instance->debugfs_root = + debugfs_create_dir(name, megasas_debugfs_root); + if (!instance->debugfs_root) { + dev_err(&instance->pdev->dev, + "Cannot create per adapter debugfs directory\n"); + return; + } + } + + snprintf(name, sizeof(name), "raidmap_dump"); + instance->raidmap_dump = + debugfs_create_file(name, S_IRUGO, + instance->debugfs_root, instance, + &megasas_debugfs_raidmap_fops); + if (!instance->raidmap_dump) { + dev_err(&instance->pdev->dev, + "Cannot create raidmap debugfs file\n"); + debugfs_remove(instance->debugfs_root); + return; + } + } + +} + +/* + * megasas_destroy_debugfs : Destroy debugfs per Fusion adapter + * instance: Soft instance of adapter + */ +void megasas_destroy_debugfs(struct megasas_instance *instance) +{ + debugfs_remove_recursive(instance->debugfs_root); +} + +#else +void megasas_init_debugfs(void) +{ +} +void megasas_exit_debugfs(void) +{ +} +void megasas_setup_debugfs(struct megasas_instance *instance) +{ +} +void megasas_destroy_debugfs(struct megasas_instance *instance) +{ +} +#endif /*CONFIG_DEBUG_FS*/ diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 12637606c46d..50b8c1b12767 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -33,6 +33,7 @@ #include <linux/compat.h> #include <linux/blkdev.h> #include <linux/poll.h> +#include <linux/irq_poll.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -45,7 +46,7 @@ #define LB_PENDING_CMDS_DEFAULT 4 static unsigned int lb_pending_cmds = LB_PENDING_CMDS_DEFAULT; -module_param(lb_pending_cmds, int, S_IRUGO); +module_param(lb_pending_cmds, int, 0444); MODULE_PARM_DESC(lb_pending_cmds, "Change raid-1 load balancing outstanding " "threshold. Valid Values are 1-128. Default: 4"); @@ -889,6 +890,77 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, } /* + * mr_get_phy_params_r56_rmw - Calculate parameters for R56 CTIO write operation + * @instance: Adapter soft state + * @ld: LD index + * @stripNo: Strip Number + * @io_info: IO info structure pointer + * pRAID_Context: RAID context pointer + * map: RAID map pointer + * + * This routine calculates the logical arm, data Arm, row number and parity arm + * for R56 CTIO write operation. + */ +static void mr_get_phy_params_r56_rmw(struct megasas_instance *instance, + u32 ld, u64 stripNo, + struct IO_REQUEST_INFO *io_info, + struct RAID_CONTEXT_G35 *pRAID_Context, + struct MR_DRV_RAID_MAP_ALL *map) +{ + struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); + u8 span, dataArms, arms, dataArm, logArm; + s8 rightmostParityArm, PParityArm; + u64 rowNum; + u64 *pdBlock = &io_info->pdBlock; + + dataArms = raid->rowDataSize; + arms = raid->rowSize; + + rowNum = mega_div64_32(stripNo, dataArms); + /* parity disk arm, first arm is 0 */ + rightmostParityArm = (arms - 1) - mega_mod64(rowNum, arms); + + /* logical arm within row */ + logArm = mega_mod64(stripNo, dataArms); + /* physical arm for data */ + dataArm = mega_mod64((rightmostParityArm + 1 + logArm), arms); + + if (raid->spanDepth == 1) { + span = 0; + } else { + span = (u8)MR_GetSpanBlock(ld, rowNum, pdBlock, map); + if (span == SPAN_INVALID) + return; + } + + if (raid->level == 6) { + /* P Parity arm, note this can go negative adjust if negative */ + PParityArm = (arms - 2) - mega_mod64(rowNum, arms); + + if (PParityArm < 0) + PParityArm += arms; + + /* rightmostParityArm is P-Parity for RAID 5 and Q-Parity for RAID */ + pRAID_Context->flow_specific.r56_arm_map = rightmostParityArm; + pRAID_Context->flow_specific.r56_arm_map |= + (u16)(PParityArm << RAID_CTX_R56_P_ARM_SHIFT); + } else { + pRAID_Context->flow_specific.r56_arm_map |= + (u16)(rightmostParityArm << RAID_CTX_R56_P_ARM_SHIFT); + } + + pRAID_Context->reg_lock_row_lba = cpu_to_le64(rowNum); + pRAID_Context->flow_specific.r56_arm_map |= + (u16)(logArm << RAID_CTX_R56_LOG_ARM_SHIFT); + cpu_to_le16s(&pRAID_Context->flow_specific.r56_arm_map); + pRAID_Context->span_arm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | dataArm; + pRAID_Context->raid_flags = (MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD << + MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT); + + return; +} + +/* ****************************************************************************** * * MR_BuildRaidContext function @@ -954,6 +1026,7 @@ MR_BuildRaidContext(struct megasas_instance *instance, stripSize = 1 << raid->stripeShift; stripe_mask = stripSize-1; + io_info->data_arms = raid->rowDataSize; /* * calculate starting row and stripe, and number of strips and rows @@ -1095,6 +1168,13 @@ MR_BuildRaidContext(struct megasas_instance *instance, /* save pointer to raid->LUN array */ *raidLUN = raid->LUN; + /* Aero R5/6 Division Offload for WRITE */ + if (fusion->r56_div_offload && (raid->level >= 5) && !isRead) { + mr_get_phy_params_r56_rmw(instance, ld, start_strip, io_info, + (struct RAID_CONTEXT_G35 *)pRAID_Context, + map); + return true; + } /*Get Phy Params only if FP capable, or else leave it to MR firmware to do the calculation.*/ diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 4dfa0685a86c..e301458bcbae 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -35,6 +35,7 @@ #include <linux/poll.h> #include <linux/vmalloc.h> #include <linux/workqueue.h> +#include <linux/irq_poll.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -87,6 +88,62 @@ extern u32 megasas_readl(struct megasas_instance *instance, const volatile void __iomem *addr); /** + * megasas_adp_reset_wait_for_ready - initiate chip reset and wait for + * controller to come to ready state + * @instance - adapter's soft state + * @do_adp_reset - If true, do a chip reset + * @ocr_context - If called from OCR context this will + * be set to 1, else 0 + * + * This function initates a chip reset followed by a wait for controller to + * transition to ready state. + * During this, driver will block all access to PCI config space from userspace + */ +int +megasas_adp_reset_wait_for_ready(struct megasas_instance *instance, + bool do_adp_reset, + int ocr_context) +{ + int ret = FAILED; + + /* + * Block access to PCI config space from userspace + * when diag reset is initiated from driver + */ + if (megasas_dbg_lvl & OCR_DEBUG) + dev_info(&instance->pdev->dev, + "Block access to PCI config space %s %d\n", + __func__, __LINE__); + + pci_cfg_access_lock(instance->pdev); + + if (do_adp_reset) { + if (instance->instancet->adp_reset + (instance, instance->reg_set)) + goto out; + } + + /* Wait for FW to become ready */ + if (megasas_transition_to_ready(instance, ocr_context)) { + dev_warn(&instance->pdev->dev, + "Failed to transition controller to ready for scsi%d.\n", + instance->host->host_no); + goto out; + } + + ret = SUCCESS; +out: + if (megasas_dbg_lvl & OCR_DEBUG) + dev_info(&instance->pdev->dev, + "Unlock access to PCI config space %s %d\n", + __func__, __LINE__); + + pci_cfg_access_unlock(instance->pdev); + + return ret; +} + +/** * megasas_check_same_4gb_region - check if allocation * crosses same 4GB boundary or not * @instance - adapter's soft instance @@ -133,7 +190,8 @@ megasas_enable_intr_fusion(struct megasas_instance *instance) writel(~MFI_FUSION_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask); /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_mask); + dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n", + __func__, readl(®s->outbound_intr_mask)); } /** @@ -144,14 +202,14 @@ void megasas_disable_intr_fusion(struct megasas_instance *instance) { u32 mask = 0xFFFFFFFF; - u32 status; struct megasas_register_set __iomem *regs; regs = instance->reg_set; instance->mask_interrupts = 1; writel(mask, ®s->outbound_intr_mask); /* Dummy readl to force pci flush */ - status = readl(®s->outbound_intr_mask); + dev_info(&instance->pdev->dev, "%s is called outbound_intr_mask:0x%08x\n", + __func__, readl(®s->outbound_intr_mask)); } int @@ -207,21 +265,17 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance, } /** - * megasas_fire_cmd_fusion - Sends command to the FW - * @instance: Adapter soft state - * @req_desc: 64bit Request descriptor - * - * Perform PCI Write. + * megasas_write_64bit_req_desc - PCI writes 64bit request descriptor + * @instance: Adapter soft state + * @req_desc: 64bit Request descriptor */ - static void -megasas_fire_cmd_fusion(struct megasas_instance *instance, +megasas_write_64bit_req_desc(struct megasas_instance *instance, union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc) { #if defined(writeq) && defined(CONFIG_64BIT) u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) | le32_to_cpu(req_desc->u.low)); - writeq(req_data, &instance->reg_set->inbound_low_queue_port); #else unsigned long flags; @@ -235,6 +289,25 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance, } /** + * megasas_fire_cmd_fusion - Sends command to the FW + * @instance: Adapter soft state + * @req_desc: 32bit or 64bit Request descriptor + * + * Perform PCI Write. AERO SERIES supports 32 bit Descriptor. + * Prior to AERO_SERIES support 64 bit Descriptor. + */ +static void +megasas_fire_cmd_fusion(struct megasas_instance *instance, + union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc) +{ + if (instance->atomic_desc_support) + writel(le32_to_cpu(req_desc->u.low), + &instance->reg_set->inbound_single_queue_port); + else + megasas_write_64bit_req_desc(instance, req_desc); +} + +/** * megasas_fusion_update_can_queue - Do all Adapter Queue depth related calculations here * @instance: Adapter soft state * fw_boot_context: Whether this function called during probe or after OCR @@ -250,9 +323,6 @@ megasas_fusion_update_can_queue(struct megasas_instance *instance, int fw_boot_c { u16 cur_max_fw_cmds = 0; u16 ldio_threshold = 0; - struct megasas_register_set __iomem *reg_set; - - reg_set = instance->reg_set; /* ventura FW does not fill outbound_scratch_pad_2 with queue depth */ if (instance->adapter_type < VENTURA_SERIES) @@ -464,7 +534,7 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance) return 0; } -int +static int megasas_alloc_cmdlist_fusion(struct megasas_instance *instance) { u32 max_mpt_cmd, i, j; @@ -503,7 +573,8 @@ megasas_alloc_cmdlist_fusion(struct megasas_instance *instance) return 0; } -int + +static int megasas_alloc_request_fusion(struct megasas_instance *instance) { struct fusion_context *fusion; @@ -584,7 +655,7 @@ retry_alloc: return 0; } -int +static int megasas_alloc_reply_fusion(struct megasas_instance *instance) { int i, count; @@ -661,7 +732,7 @@ megasas_alloc_reply_fusion(struct megasas_instance *instance) return 0; } -int +static int megasas_alloc_rdpq_fusion(struct megasas_instance *instance) { int i, j, k, msix_count; @@ -843,7 +914,7 @@ megasas_free_reply_fusion(struct megasas_instance *instance) { * and is used as SMID of the cmd. * SMID value range is from 1 to max_fw_cmds. */ -int +static int megasas_alloc_cmds_fusion(struct megasas_instance *instance) { int i; @@ -924,6 +995,7 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd, { int i; struct megasas_header *frame_hdr = &cmd->frame->hdr; + u32 status_reg; u32 msecs = seconds * 1000; @@ -933,6 +1005,12 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd, for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i += 20) { rmb(); msleep(20); + if (!(i % 5000)) { + status_reg = instance->instancet->read_fw_status_reg(instance) + & MFI_STATE_MASK; + if (status_reg == MFI_STATE_FAULT) + break; + } } if (frame_hdr->cmd_status == MFI_STAT_INVALID_STATUS) @@ -966,6 +1044,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) u32 scratch_pad_1; ktime_t time; bool cur_fw_64bit_dma_capable; + bool cur_intr_coalescing; fusion = instance->ctrl_context; @@ -999,6 +1078,16 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) goto fail_fw_init; } + cur_intr_coalescing = (scratch_pad_1 & MR_INTR_COALESCING_SUPPORT_OFFSET) ? + true : false; + + if ((instance->low_latency_index_start == + MR_HIGH_IOPS_QUEUE_COUNT) && cur_intr_coalescing) + instance->perf_mode = MR_BALANCED_PERF_MODE; + + dev_info(&instance->pdev->dev, "Performance mode :%s\n", + MEGASAS_PERF_MODE_2STR(instance->perf_mode)); + instance->fw_sync_cache_support = (scratch_pad_1 & MR_CAN_HANDLE_SYNC_CACHE_OFFSET) ? 1 : 0; dev_info(&instance->pdev->dev, "FW supports sync cache\t: %s\n", @@ -1083,6 +1172,22 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) cpu_to_le32(lower_32_bits(ioc_init_handle)); init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST)); + /* + * Each bit in replyqueue_mask represents one group of MSI-x vectors + * (each group has 8 vectors) + */ + switch (instance->perf_mode) { + case MR_BALANCED_PERF_MODE: + init_frame->replyqueue_mask = + cpu_to_le16(~(~0 << instance->low_latency_index_start/8)); + break; + case MR_IOPS_PERF_MODE: + init_frame->replyqueue_mask = + cpu_to_le16(~(~0 << instance->msix_vectors/8)); + break; + } + + req_desc.u.low = cpu_to_le32(lower_32_bits(cmd->frame_phys_addr)); req_desc.u.high = cpu_to_le32(upper_32_bits(cmd->frame_phys_addr)); req_desc.MFAIo.RequestFlags = @@ -1101,7 +1206,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) break; } - megasas_fire_cmd_fusion(instance, &req_desc); + /* For AERO also, IOC_INIT requires 64 bit descriptor write */ + megasas_write_64bit_req_desc(instance, &req_desc); wait_and_poll(instance, cmd, MFI_IO_TIMEOUT_SECS); @@ -1111,6 +1217,17 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) goto fail_fw_init; } + if (instance->adapter_type >= AERO_SERIES) { + scratch_pad_1 = megasas_readl + (instance, &instance->reg_set->outbound_scratch_pad_1); + + instance->atomic_desc_support = + (scratch_pad_1 & MR_ATOMIC_DESCRIPTOR_SUPPORT_OFFSET) ? 1 : 0; + + dev_info(&instance->pdev->dev, "FW supports atomic descriptor\t: %s\n", + instance->atomic_desc_support ? "Yes" : "No"); + } + return 0; fail_fw_init: @@ -1133,7 +1250,7 @@ fail_fw_init: int megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) { int ret = 0; - u32 pd_seq_map_sz; + size_t pd_seq_map_sz; struct megasas_cmd *cmd; struct megasas_dcmd_frame *dcmd; struct fusion_context *fusion = instance->ctrl_context; @@ -1142,9 +1259,7 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) { pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id & 1)]; pd_seq_h = fusion->pd_seq_phys[(instance->pd_seq_map_id & 1)]; - pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + - (sizeof(struct MR_PD_CFG_SEQ) * - (MAX_PHYSICAL_DEVICES - 1)); + pd_seq_map_sz = struct_size(pd_sync, seq, MAX_PHYSICAL_DEVICES - 1); cmd = megasas_get_cmd(instance); if (!cmd) { @@ -1619,12 +1734,13 @@ static inline void megasas_free_ioc_init_cmd(struct megasas_instance *instance) * * This is the main function for initializing firmware. */ -u32 +static u32 megasas_init_adapter_fusion(struct megasas_instance *instance) { struct fusion_context *fusion; u32 scratch_pad_1; int i = 0, count; + u32 status_reg; fusion = instance->ctrl_context; @@ -1707,8 +1823,21 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) if (megasas_alloc_cmds_fusion(instance)) goto fail_alloc_cmds; - if (megasas_ioc_init_fusion(instance)) - goto fail_ioc_init; + if (megasas_ioc_init_fusion(instance)) { + status_reg = instance->instancet->read_fw_status_reg(instance); + if (((status_reg & MFI_STATE_MASK) == MFI_STATE_FAULT) && + (status_reg & MFI_RESET_ADAPTER)) { + /* Do a chip reset and then retry IOC INIT once */ + if (megasas_adp_reset_wait_for_ready + (instance, true, 0) == FAILED) + goto fail_ioc_init; + + if (megasas_ioc_init_fusion(instance)) + goto fail_ioc_init; + } else { + goto fail_ioc_init; + } + } megasas_display_intel_branding(instance); if (megasas_get_ctrl_info(instance)) { @@ -1720,6 +1849,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) instance->flag_ieee = 1; instance->r1_ldio_hint_default = MR_R1_LDIO_PIGGYBACK_DEFAULT; + instance->threshold_reply_count = instance->max_fw_cmds / 4; fusion->fast_path_io = 0; if (megasas_allocate_raid_maps(instance)) @@ -1830,7 +1960,7 @@ megasas_fusion_stop_watchdog(struct megasas_instance *instance) * @ext_status : ext status of cmd returned by FW */ -void +static void map_cmd_status(struct fusion_context *fusion, struct scsi_cmnd *scmd, u8 status, u8 ext_status, u32 data_length, u8 *sense) @@ -1970,7 +2100,6 @@ megasas_is_prp_possible(struct megasas_instance *instance, mega_mod64(sg_dma_address(sg_scmd), mr_nvme_pg_size)) { build_prp = false; - atomic_inc(&instance->sge_holes_type1); break; } } @@ -1980,7 +2109,6 @@ megasas_is_prp_possible(struct megasas_instance *instance, sg_dma_len(sg_scmd)), mr_nvme_pg_size))) { build_prp = false; - atomic_inc(&instance->sge_holes_type2); break; } } @@ -1989,7 +2117,6 @@ megasas_is_prp_possible(struct megasas_instance *instance, if (mega_mod64(sg_dma_address(sg_scmd), mr_nvme_pg_size)) { build_prp = false; - atomic_inc(&instance->sge_holes_type3); break; } } @@ -2122,7 +2249,6 @@ megasas_make_prp_nvme(struct megasas_instance *instance, struct scsi_cmnd *scmd, main_chain_element->Length = cpu_to_le32(num_prp_in_chain * sizeof(u64)); - atomic_inc(&instance->prp_sgl); return build_prp; } @@ -2197,7 +2323,6 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, memset(sgl_ptr, 0, instance->max_chain_frame_sz); } } - atomic_inc(&instance->ieee_sgl); } /** @@ -2248,7 +2373,7 @@ int megasas_make_sgl(struct megasas_instance *instance, struct scsi_cmnd *scp, * * Used to set the PD LBA in CDB for FP IOs */ -void +static void megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len, struct IO_REQUEST_INFO *io_info, struct scsi_cmnd *scp, struct MR_DRV_RAID_MAP_ALL *local_map_ptr, u32 ref_tag) @@ -2509,9 +2634,10 @@ static void megasas_stream_detect(struct megasas_instance *instance, * */ static void -megasas_set_raidflag_cpu_affinity(union RAID_CONTEXT_UNION *praid_context, - struct MR_LD_RAID *raid, bool fp_possible, - u8 is_read, u32 scsi_buff_len) +megasas_set_raidflag_cpu_affinity(struct fusion_context *fusion, + union RAID_CONTEXT_UNION *praid_context, + struct MR_LD_RAID *raid, bool fp_possible, + u8 is_read, u32 scsi_buff_len) { u8 cpu_sel = MR_RAID_CTX_CPUSEL_0; struct RAID_CONTEXT_G35 *rctx_g35; @@ -2569,11 +2695,11 @@ megasas_set_raidflag_cpu_affinity(union RAID_CONTEXT_UNION *praid_context, * vs MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS. * IO Subtype is not bitmap. */ - if ((raid->level == 1) && (!is_read)) { - if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE) - praid_context->raid_context_g35.raid_flags = - (MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT - << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT); + if ((fusion->pcie_bw_limitation) && (raid->level == 1) && (!is_read) && + (scsi_buff_len > MR_LARGE_IO_MIN_SIZE)) { + praid_context->raid_context_g35.raid_flags = + (MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT + << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT); } } @@ -2586,7 +2712,7 @@ megasas_set_raidflag_cpu_affinity(union RAID_CONTEXT_UNION *praid_context, * Prepares the io_request and chain elements (sg_frame) for IO * The IO can be for PD (Fast Path) or LD */ -void +static void megasas_build_ldio_fusion(struct megasas_instance *instance, struct scsi_cmnd *scp, struct megasas_cmd_fusion *cmd) @@ -2679,6 +2805,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, io_info.r1_alt_dev_handle = MR_DEVHANDLE_INVALID; scsi_buff_len = scsi_bufflen(scp); io_request->DataLength = cpu_to_le32(scsi_buff_len); + io_info.data_arms = 1; if (scp->sc_data_direction == DMA_FROM_DEVICE) io_info.isRead = 1; @@ -2698,8 +2825,19 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, fp_possible = (io_info.fpOkForIo > 0) ? true : false; } - cmd->request_desc->SCSIIO.MSIxIndex = - instance->reply_map[raw_smp_processor_id()]; + if ((instance->perf_mode == MR_BALANCED_PERF_MODE) && + atomic_read(&scp->device->device_busy) > + (io_info.data_arms * MR_DEVICE_HIGH_IOPS_DEPTH)) + cmd->request_desc->SCSIIO.MSIxIndex = + mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) / + MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start); + else if (instance->msix_load_balance) + cmd->request_desc->SCSIIO.MSIxIndex = + (mega_mod64(atomic64_add_return(1, &instance->total_io_count), + instance->msix_vectors)); + else + cmd->request_desc->SCSIIO.MSIxIndex = + instance->reply_map[raw_smp_processor_id()]; if (instance->adapter_type >= VENTURA_SERIES) { /* FP for Optimal raid level 1. @@ -2717,8 +2855,9 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, (instance->host->can_queue)) { fp_possible = false; atomic_dec(&instance->fw_outstanding); - } else if ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) || - (atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0)) { + } else if (fusion->pcie_bw_limitation && + ((scsi_buff_len > MR_LARGE_IO_MIN_SIZE) || + (atomic_dec_if_positive(&mrdev_priv->r1_ldio_hint) > 0))) { fp_possible = false; atomic_dec(&instance->fw_outstanding); if (scsi_buff_len > MR_LARGE_IO_MIN_SIZE) @@ -2743,7 +2882,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, /* If raid is NULL, set CPU affinity to default CPU0 */ if (raid) - megasas_set_raidflag_cpu_affinity(&io_request->RaidContext, + megasas_set_raidflag_cpu_affinity(fusion, &io_request->RaidContext, raid, fp_possible, io_info.isRead, scsi_buff_len); else @@ -2759,10 +2898,6 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, (MPI2_REQ_DESCRIPT_FLAGS_FP_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); if (instance->adapter_type == INVADER_SERIES) { - if (rctx->reg_lock_flags == REGION_TYPE_UNUSED) - cmd->request_desc->SCSIIO.RequestFlags = - (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); rctx->type = MPI2_TYPE_CUDA; rctx->nseg = 0x1; io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH); @@ -2970,50 +3105,71 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; /* If FW supports PD sequence number */ - if (instance->use_seqnum_jbod_fp && - instance->pd_list[pd_index].driveType == TYPE_DISK) { - /* TgtId must be incremented by 255 as jbod seq number is index - * below raid map - */ - /* More than 256 PD/JBOD support for Ventura */ - if (instance->support_morethan256jbod) - pRAID_Context->virtual_disk_tgt_id = - pd_sync->seq[pd_index].pd_target_id; - else - pRAID_Context->virtual_disk_tgt_id = - cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1)); - pRAID_Context->config_seq_num = pd_sync->seq[pd_index].seqNum; - io_request->DevHandle = pd_sync->seq[pd_index].devHandle; - if (instance->adapter_type >= VENTURA_SERIES) { - io_request->RaidContext.raid_context_g35.routing_flags |= - (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT); - io_request->RaidContext.raid_context_g35.nseg_type |= - (1 << RAID_CONTEXT_NSEG_SHIFT); - io_request->RaidContext.raid_context_g35.nseg_type |= - (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT); + if (instance->support_seqnum_jbod_fp) { + if (instance->use_seqnum_jbod_fp && + instance->pd_list[pd_index].driveType == TYPE_DISK) { + + /* More than 256 PD/JBOD support for Ventura */ + if (instance->support_morethan256jbod) + pRAID_Context->virtual_disk_tgt_id = + pd_sync->seq[pd_index].pd_target_id; + else + pRAID_Context->virtual_disk_tgt_id = + cpu_to_le16(device_id + + (MAX_PHYSICAL_DEVICES - 1)); + pRAID_Context->config_seq_num = + pd_sync->seq[pd_index].seqNum; + io_request->DevHandle = + pd_sync->seq[pd_index].devHandle; + if (instance->adapter_type >= VENTURA_SERIES) { + io_request->RaidContext.raid_context_g35.routing_flags |= + (1 << MR_RAID_CTX_ROUTINGFLAGS_SQN_SHIFT); + io_request->RaidContext.raid_context_g35.nseg_type |= + (1 << RAID_CONTEXT_NSEG_SHIFT); + io_request->RaidContext.raid_context_g35.nseg_type |= + (MPI2_TYPE_CUDA << RAID_CONTEXT_TYPE_SHIFT); + } else { + pRAID_Context->type = MPI2_TYPE_CUDA; + pRAID_Context->nseg = 0x1; + pRAID_Context->reg_lock_flags |= + (MR_RL_FLAGS_SEQ_NUM_ENABLE | + MR_RL_FLAGS_GRANT_DESTINATION_CUDA); + } } else { - pRAID_Context->type = MPI2_TYPE_CUDA; - pRAID_Context->nseg = 0x1; - pRAID_Context->reg_lock_flags |= - (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA); + pRAID_Context->virtual_disk_tgt_id = + cpu_to_le16(device_id + + (MAX_PHYSICAL_DEVICES - 1)); + pRAID_Context->config_seq_num = 0; + io_request->DevHandle = cpu_to_le16(0xFFFF); } - } else if (fusion->fast_path_io) { - pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); - pRAID_Context->config_seq_num = 0; - local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; - io_request->DevHandle = - local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; } else { - /* Want to send all IO via FW path */ pRAID_Context->virtual_disk_tgt_id = cpu_to_le16(device_id); pRAID_Context->config_seq_num = 0; - io_request->DevHandle = cpu_to_le16(0xFFFF); + + if (fusion->fast_path_io) { + local_map_ptr = + fusion->ld_drv_map[(instance->map_id & 1)]; + io_request->DevHandle = + local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; + } else { + io_request->DevHandle = cpu_to_le16(0xFFFF); + } } cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle; - cmd->request_desc->SCSIIO.MSIxIndex = - instance->reply_map[raw_smp_processor_id()]; + if ((instance->perf_mode == MR_BALANCED_PERF_MODE) && + atomic_read(&scmd->device->device_busy) > MR_DEVICE_HIGH_IOPS_DEPTH) + cmd->request_desc->SCSIIO.MSIxIndex = + mega_mod64((atomic64_add_return(1, &instance->high_iops_outstanding) / + MR_HIGH_IOPS_BATCH_COUNT), instance->low_latency_index_start); + else if (instance->msix_load_balance) + cmd->request_desc->SCSIIO.MSIxIndex = + (mega_mod64(atomic64_add_return(1, &instance->total_io_count), + instance->msix_vectors)); + else + cmd->request_desc->SCSIIO.MSIxIndex = + instance->reply_map[raw_smp_processor_id()]; if (!fp_possible) { /* system pd firmware path */ @@ -3053,7 +3209,7 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, * Invokes helper functions to prepare request frames * and sets flags appropriate for IO/Non-IO cmd */ -int +static int megasas_build_io_fusion(struct megasas_instance *instance, struct scsi_cmnd *scp, struct megasas_cmd_fusion *cmd) @@ -3167,9 +3323,9 @@ megasas_get_request_descriptor(struct megasas_instance *instance, u16 index) /* megasas_prepate_secondRaid1_IO * It prepares the raid 1 second IO */ -void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance, - struct megasas_cmd_fusion *cmd, - struct megasas_cmd_fusion *r1_cmd) +static void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance, + struct megasas_cmd_fusion *cmd, + struct megasas_cmd_fusion *r1_cmd) { union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc, *req_desc2 = NULL; struct fusion_context *fusion; @@ -3193,9 +3349,9 @@ void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance, r1_cmd->request_desc->SCSIIO.DevHandle = cmd->r1_alt_dev_handle; r1_cmd->io_request->DevHandle = cmd->r1_alt_dev_handle; r1_cmd->r1_alt_dev_handle = cmd->io_request->DevHandle; - cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid = + cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid = cpu_to_le16(r1_cmd->index); - r1_cmd->io_request->RaidContext.raid_context_g35.smid.peer_smid = + r1_cmd->io_request->RaidContext.raid_context_g35.flow_specific.peer_smid = cpu_to_le16(cmd->index); /*MSIxIndex of both commands request descriptors should be same*/ r1_cmd->request_desc->SCSIIO.MSIxIndex = @@ -3313,7 +3469,7 @@ megasas_complete_r1_command(struct megasas_instance *instance, rctx_g35 = &cmd->io_request->RaidContext.raid_context_g35; fusion = instance->ctrl_context; - peer_smid = le16_to_cpu(rctx_g35->smid.peer_smid); + peer_smid = le16_to_cpu(rctx_g35->flow_specific.peer_smid); r1_cmd = fusion->cmd_list[peer_smid - 1]; scmd_local = cmd->scmd; @@ -3352,8 +3508,9 @@ megasas_complete_r1_command(struct megasas_instance *instance, * @instance: Adapter soft state * Completes all commands that is in reply descriptor queue */ -int -complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) +static int +complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex, + struct megasas_irq_context *irq_context) { union MPI2_REPLY_DESCRIPTORS_UNION *desc; struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc; @@ -3486,7 +3643,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) * number of reply counts and still there are more replies in reply queue * pending to be completed */ - if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) { + if (threshold_reply_count >= instance->threshold_reply_count) { if (instance->msix_combined) writel(((MSIxIndex & 0x7) << 24) | fusion->last_reply_idx[MSIxIndex], @@ -3496,39 +3653,102 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) fusion->last_reply_idx[MSIxIndex], instance->reply_post_host_index_addr[0]); threshold_reply_count = 0; + if (irq_context) { + if (!irq_context->irq_poll_scheduled) { + irq_context->irq_poll_scheduled = true; + irq_context->irq_line_enable = true; + irq_poll_sched(&irq_context->irqpoll); + } + return num_completed; + } } } - if (!num_completed) - return IRQ_NONE; + if (num_completed) { + wmb(); + if (instance->msix_combined) + writel(((MSIxIndex & 0x7) << 24) | + fusion->last_reply_idx[MSIxIndex], + instance->reply_post_host_index_addr[MSIxIndex/8]); + else + writel((MSIxIndex << 24) | + fusion->last_reply_idx[MSIxIndex], + instance->reply_post_host_index_addr[0]); + megasas_check_and_restore_queue_depth(instance); + } + return num_completed; +} - wmb(); - if (instance->msix_combined) - writel(((MSIxIndex & 0x7) << 24) | - fusion->last_reply_idx[MSIxIndex], - instance->reply_post_host_index_addr[MSIxIndex/8]); - else - writel((MSIxIndex << 24) | - fusion->last_reply_idx[MSIxIndex], - instance->reply_post_host_index_addr[0]); - megasas_check_and_restore_queue_depth(instance); - return IRQ_HANDLED; +/** + * megasas_enable_irq_poll() - enable irqpoll + */ +static void megasas_enable_irq_poll(struct megasas_instance *instance) +{ + u32 count, i; + struct megasas_irq_context *irq_ctx; + + count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; + + for (i = 0; i < count; i++) { + irq_ctx = &instance->irq_context[i]; + irq_poll_enable(&irq_ctx->irqpoll); + } } /** * megasas_sync_irqs - Synchronizes all IRQs owned by adapter * @instance: Adapter soft state */ -void megasas_sync_irqs(unsigned long instance_addr) +static void megasas_sync_irqs(unsigned long instance_addr) { u32 count, i; struct megasas_instance *instance = (struct megasas_instance *)instance_addr; + struct megasas_irq_context *irq_ctx; count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; - for (i = 0; i < count; i++) + for (i = 0; i < count; i++) { synchronize_irq(pci_irq_vector(instance->pdev, i)); + irq_ctx = &instance->irq_context[i]; + irq_poll_disable(&irq_ctx->irqpoll); + if (irq_ctx->irq_poll_scheduled) { + irq_ctx->irq_poll_scheduled = false; + enable_irq(irq_ctx->os_irq); + } + } +} + +/** + * megasas_irqpoll() - process a queue for completed reply descriptors + * @irqpoll: IRQ poll structure associated with queue to poll. + * @budget: Threshold of reply descriptors to process per poll. + * + * Return: The number of entries processed. + */ + +int megasas_irqpoll(struct irq_poll *irqpoll, int budget) +{ + struct megasas_irq_context *irq_ctx; + struct megasas_instance *instance; + int num_entries; + + irq_ctx = container_of(irqpoll, struct megasas_irq_context, irqpoll); + instance = irq_ctx->instance; + + if (irq_ctx->irq_line_enable) { + disable_irq(irq_ctx->os_irq); + irq_ctx->irq_line_enable = false; + } + + num_entries = complete_cmd_fusion(instance, irq_ctx->MSIxIndex, irq_ctx); + if (num_entries < budget) { + irq_poll_complete(irqpoll); + irq_ctx->irq_poll_scheduled = false; + enable_irq(irq_ctx->os_irq); + } + + return num_entries; } /** @@ -3537,7 +3757,7 @@ void megasas_sync_irqs(unsigned long instance_addr) * * Tasklet to complete cmds */ -void +static void megasas_complete_cmd_dpc_fusion(unsigned long instance_addr) { struct megasas_instance *instance = @@ -3551,13 +3771,13 @@ megasas_complete_cmd_dpc_fusion(unsigned long instance_addr) return; for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++) - complete_cmd_fusion(instance, MSIxIndex); + complete_cmd_fusion(instance, MSIxIndex, NULL); } /** * megasas_isr_fusion - isr entry point */ -irqreturn_t megasas_isr_fusion(int irq, void *devp) +static irqreturn_t megasas_isr_fusion(int irq, void *devp) { struct megasas_irq_context *irq_context = devp; struct megasas_instance *instance = irq_context->instance; @@ -3566,6 +3786,11 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp) if (instance->mask_interrupts) return IRQ_NONE; +#if defined(ENABLE_IRQ_POLL) + if (irq_context->irq_poll_scheduled) + return IRQ_HANDLED; +#endif + if (!instance->msix_vectors) { mfiStatus = instance->instancet->clear_intr(instance); if (!mfiStatus) @@ -3578,7 +3803,8 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp) return IRQ_HANDLED; } - return complete_cmd_fusion(instance, irq_context->MSIxIndex); + return complete_cmd_fusion(instance, irq_context->MSIxIndex, irq_context) + ? IRQ_HANDLED : IRQ_NONE; } /** @@ -3587,7 +3813,7 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp) * mfi_cmd: megasas_cmd pointer * */ -void +static void build_mpt_mfi_pass_thru(struct megasas_instance *instance, struct megasas_cmd *mfi_cmd) { @@ -3645,7 +3871,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance, * @cmd: mfi cmd to build * */ -union MEGASAS_REQUEST_DESCRIPTOR_UNION * +static union MEGASAS_REQUEST_DESCRIPTOR_UNION * build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) { union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc = NULL; @@ -3671,7 +3897,7 @@ build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) * @cmd: mfi cmd pointer * */ -void +static void megasas_issue_dcmd_fusion(struct megasas_instance *instance, struct megasas_cmd *cmd) { @@ -3843,7 +4069,7 @@ megasas_check_reset_fusion(struct megasas_instance *instance, static inline void megasas_trigger_snap_dump(struct megasas_instance *instance) { int j; - u32 fw_state; + u32 fw_state, abs_state; if (!instance->disableOnlineCtrlReset) { dev_info(&instance->pdev->dev, "Trigger snap dump\n"); @@ -3853,11 +4079,13 @@ static inline void megasas_trigger_snap_dump(struct megasas_instance *instance) } for (j = 0; j < instance->snapdump_wait_time; j++) { - fw_state = instance->instancet->read_fw_status_reg(instance) & - MFI_STATE_MASK; + abs_state = instance->instancet->read_fw_status_reg(instance); + fw_state = abs_state & MFI_STATE_MASK; if (fw_state == MFI_STATE_FAULT) { - dev_err(&instance->pdev->dev, - "Found FW in FAULT state, after snap dump trigger\n"); + dev_printk(KERN_ERR, &instance->pdev->dev, + "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n", + abs_state & MFI_STATE_FAULT_CODE, + abs_state & MFI_STATE_FAULT_SUBCODE, __func__); return; } msleep(1000); @@ -3865,11 +4093,12 @@ static inline void megasas_trigger_snap_dump(struct megasas_instance *instance) } /* This function waits for outstanding commands on fusion to complete */ -int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance, - int reason, int *convert) +static int +megasas_wait_for_outstanding_fusion(struct megasas_instance *instance, + int reason, int *convert) { int i, outstanding, retval = 0, hb_seconds_missed = 0; - u32 fw_state; + u32 fw_state, abs_state; u32 waittime_for_io_completion; waittime_for_io_completion = @@ -3888,12 +4117,13 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance, for (i = 0; i < waittime_for_io_completion; i++) { /* Check if firmware is in fault state */ - fw_state = instance->instancet->read_fw_status_reg(instance) & - MFI_STATE_MASK; + abs_state = instance->instancet->read_fw_status_reg(instance); + fw_state = abs_state & MFI_STATE_MASK; if (fw_state == MFI_STATE_FAULT) { - dev_warn(&instance->pdev->dev, "Found FW in FAULT state," - " will reset adapter scsi%d.\n", - instance->host->host_no); + dev_printk(KERN_ERR, &instance->pdev->dev, + "FW in FAULT state Fault code:0x%x subcode:0x%x func:%s\n", + abs_state & MFI_STATE_FAULT_CODE, + abs_state & MFI_STATE_FAULT_SUBCODE, __func__); megasas_complete_cmd_dpc_fusion((unsigned long)instance); if (instance->requestorId && reason) { dev_warn(&instance->pdev->dev, "SR-IOV Found FW in FAULT" @@ -3989,7 +4219,7 @@ void megasas_reset_reply_desc(struct megasas_instance *instance) * megasas_refire_mgmt_cmd : Re-fire management commands * @instance: Controller's soft instance */ -void megasas_refire_mgmt_cmd(struct megasas_instance *instance) +static void megasas_refire_mgmt_cmd(struct megasas_instance *instance) { int j; struct megasas_cmd_fusion *cmd_fusion; @@ -4042,6 +4272,13 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance) } break; + case MFI_CMD_TOOLBOX: + if (!instance->support_pci_lane_margining) { + cmd_mfi->frame->hdr.cmd_status = MFI_STAT_INVALID_CMD; + result = COMPLETE_CMD; + } + + break; default: break; } @@ -4265,6 +4502,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle, instance->instancet->disable_intr(instance); megasas_sync_irqs((unsigned long)instance); instance->instancet->enable_intr(instance); + megasas_enable_irq_poll(instance); if (scsi_lookup->scmd == NULL) break; } @@ -4278,6 +4516,7 @@ megasas_issue_tm(struct megasas_instance *instance, u16 device_handle, megasas_sync_irqs((unsigned long)instance); rc = megasas_track_scsiio(instance, id, channel); instance->instancet->enable_intr(instance); + megasas_enable_irq_poll(instance); break; case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: @@ -4376,9 +4615,6 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd) instance = (struct megasas_instance *)scmd->device->host->hostdata; - scmd_printk(KERN_INFO, scmd, "task abort called for scmd(%p)\n", scmd); - scsi_print_command(scmd); - if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) { dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL," "SCSI host:%d\n", instance->host->host_no); @@ -4421,7 +4657,7 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd) goto out; } sdev_printk(KERN_INFO, scmd->device, - "attempting task abort! scmd(%p) tm_dev_handle 0x%x\n", + "attempting task abort! scmd(0x%p) tm_dev_handle 0x%x\n", scmd, devhandle); mr_device_priv_data->tm_busy = 1; @@ -4432,9 +4668,12 @@ int megasas_task_abort_fusion(struct scsi_cmnd *scmd) mr_device_priv_data->tm_busy = 0; mutex_unlock(&instance->reset_mutex); -out: - sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", + scmd_printk(KERN_INFO, scmd, "task abort %s!! scmd(0x%p)\n", ((ret == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); +out: + scsi_print_command(scmd); + if (megasas_dbg_lvl & TM_DEBUG) + megasas_dump_fusion_io(scmd); return ret; } @@ -4457,9 +4696,6 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd) instance = (struct megasas_instance *)scmd->device->host->hostdata; - sdev_printk(KERN_INFO, scmd->device, - "target reset called for scmd(%p)\n", scmd); - if (atomic_read(&instance->adprecovery) != MEGASAS_HBA_OPERATIONAL) { dev_err(&instance->pdev->dev, "Controller is not OPERATIONAL," "SCSI host:%d\n", instance->host->host_no); @@ -4468,8 +4704,8 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd) } if (!mr_device_priv_data) { - sdev_printk(KERN_INFO, scmd->device, "device been deleted! " - "scmd(%p)\n", scmd); + sdev_printk(KERN_INFO, scmd->device, + "device been deleted! scmd: (0x%p)\n", scmd); scmd->result = DID_NO_CONNECT << 16; ret = SUCCESS; goto out; @@ -4492,7 +4728,7 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd) } sdev_printk(KERN_INFO, scmd->device, - "attempting target reset! scmd(%p) tm_dev_handle 0x%x\n", + "attempting target reset! scmd(0x%p) tm_dev_handle: 0x%x\n", scmd, devhandle); mr_device_priv_data->tm_busy = 1; ret = megasas_issue_tm(instance, devhandle, @@ -4501,15 +4737,16 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd) mr_device_priv_data); mr_device_priv_data->tm_busy = 0; mutex_unlock(&instance->reset_mutex); -out: - scmd_printk(KERN_NOTICE, scmd, "megasas: target reset %s!!\n", + scmd_printk(KERN_NOTICE, scmd, "target reset %s!!\n", (ret == SUCCESS) ? "SUCCESS" : "FAILED"); +out: return ret; } /*SRIOV get other instance in cluster if any*/ -struct megasas_instance *megasas_get_peer_instance(struct megasas_instance *instance) +static struct +megasas_instance *megasas_get_peer_instance(struct megasas_instance *instance) { int i; @@ -4549,12 +4786,14 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) struct megasas_instance *instance; struct megasas_cmd_fusion *cmd_fusion, *r1_cmd; struct fusion_context *fusion; - u32 abs_state, status_reg, reset_adapter; + u32 abs_state, status_reg, reset_adapter, fpio_count = 0; u32 io_timeout_in_crash_mode = 0; struct scsi_cmnd *scmd_local = NULL; struct scsi_device *sdev; int ret_target_prop = DCMD_FAILED; bool is_target_prop = false; + bool do_adp_reset = true; + int max_reset_tries = MEGASAS_FUSION_MAX_RESET_TRIES; instance = (struct megasas_instance *)shost->hostdata; fusion = instance->ctrl_context; @@ -4621,7 +4860,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) if (convert) reason = 0; - if (megasas_dbg_lvl & OCR_LOGS) + if (megasas_dbg_lvl & OCR_DEBUG) dev_info(&instance->pdev->dev, "\nPending SCSI commands:\n"); /* Now return commands back to the OS */ @@ -4634,13 +4873,17 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) } scmd_local = cmd_fusion->scmd; if (cmd_fusion->scmd) { - if (megasas_dbg_lvl & OCR_LOGS) { + if (megasas_dbg_lvl & OCR_DEBUG) { sdev_printk(KERN_INFO, cmd_fusion->scmd->device, "SMID: 0x%x\n", cmd_fusion->index); - scsi_print_command(cmd_fusion->scmd); + megasas_dump_fusion_io(cmd_fusion->scmd); } + if (cmd_fusion->io_request->Function == + MPI2_FUNCTION_SCSI_IO_REQUEST) + fpio_count++; + scmd_local->result = megasas_check_mpio_paths(instance, scmd_local); @@ -4653,6 +4896,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) } } + dev_info(&instance->pdev->dev, "Outstanding fastpath IOs: %d\n", + fpio_count); + atomic_set(&instance->fw_outstanding, 0); status_reg = instance->instancet->read_fw_status_reg(instance); @@ -4664,52 +4910,45 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) dev_warn(&instance->pdev->dev, "Reset not supported" ", killing adapter scsi%d.\n", instance->host->host_no); - megaraid_sas_kill_hba(instance); - instance->skip_heartbeat_timer_del = 1; - retval = FAILED; - goto out; + goto kill_hba; } /* Let SR-IOV VF & PF sync up if there was a HB failure */ if (instance->requestorId && !reason) { msleep(MEGASAS_OCR_SETTLE_TIME_VF); - goto transition_to_ready; + do_adp_reset = false; + max_reset_tries = MEGASAS_SRIOV_MAX_RESET_TRIES_VF; } /* Now try to reset the chip */ - for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) { - - if (instance->instancet->adp_reset - (instance, instance->reg_set)) + for (i = 0; i < max_reset_tries; i++) { + /* + * Do adp reset and wait for + * controller to transition to ready + */ + if (megasas_adp_reset_wait_for_ready(instance, + do_adp_reset, 1) == FAILED) continue; -transition_to_ready: + /* Wait for FW to become ready */ if (megasas_transition_to_ready(instance, 1)) { dev_warn(&instance->pdev->dev, "Failed to transition controller to ready for " "scsi%d.\n", instance->host->host_no); - if (instance->requestorId && !reason) - goto fail_kill_adapter; - else - continue; + continue; } megasas_reset_reply_desc(instance); megasas_fusion_update_can_queue(instance, OCR_CONTEXT); if (megasas_ioc_init_fusion(instance)) { - if (instance->requestorId && !reason) - goto fail_kill_adapter; - else - continue; + continue; } if (megasas_get_ctrl_info(instance)) { dev_info(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); - megaraid_sas_kill_hba(instance); - retval = FAILED; - goto out; + goto kill_hba; } megasas_refire_mgmt_cmd(instance); @@ -4738,7 +4977,7 @@ transition_to_ready: clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); instance->instancet->enable_intr(instance); - + megasas_enable_irq_poll(instance); shost_for_each_device(sdev, shost) { if ((instance->tgt_prop) && (instance->nvme_page_size)) @@ -4750,9 +4989,9 @@ transition_to_ready: atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL); - dev_info(&instance->pdev->dev, "Interrupts are enabled and" - " controller is OPERATIONAL for scsi:%d\n", - instance->host->host_no); + dev_info(&instance->pdev->dev, + "Adapter is OPERATIONAL for scsi:%d\n", + instance->host->host_no); /* Restart SR-IOV heartbeat */ if (instance->requestorId) { @@ -4786,13 +5025,10 @@ transition_to_ready: goto out; } -fail_kill_adapter: /* Reset failed, kill the adapter */ dev_warn(&instance->pdev->dev, "Reset failed, killing " "adapter scsi%d.\n", instance->host->host_no); - megaraid_sas_kill_hba(instance); - instance->skip_heartbeat_timer_del = 1; - retval = FAILED; + goto kill_hba; } else { /* For VF: Restart HB timer if we didn't OCR */ if (instance->requestorId) { @@ -4800,8 +5036,15 @@ fail_kill_adapter: } clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); instance->instancet->enable_intr(instance); + megasas_enable_irq_poll(instance); atomic_set(&instance->adprecovery, MEGASAS_HBA_OPERATIONAL); + goto out; } +kill_hba: + megaraid_sas_kill_hba(instance); + megasas_enable_irq_poll(instance); + instance->skip_heartbeat_timer_del = 1; + retval = FAILED; out: clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); mutex_unlock(&instance->reset_mutex); @@ -4809,7 +5052,7 @@ out: } /* Fusion Crash dump collection */ -void megasas_fusion_crash_dump(struct megasas_instance *instance) +static void megasas_fusion_crash_dump(struct megasas_instance *instance) { u32 status_reg; u8 partial_copy = 0; diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 7fa73eaca1a8..c013c80fe4e6 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -75,7 +75,8 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { MR_RAID_FLAGS_IO_SUB_TYPE_RMW_P = 3, MR_RAID_FLAGS_IO_SUB_TYPE_RMW_Q = 4, MR_RAID_FLAGS_IO_SUB_TYPE_CACHE_BYPASS = 6, - MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT = 7 + MR_RAID_FLAGS_IO_SUB_TYPE_LDIO_BW_LIMIT = 7, + MR_RAID_FLAGS_IO_SUB_TYPE_R56_DIV_OFFLOAD = 8 }; /* @@ -88,7 +89,6 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { #define MEGASAS_FP_CMD_LEN 16 #define MEGASAS_FUSION_IN_RESET 0 -#define THRESHOLD_REPLY_COUNT 50 #define RAID_1_PEER_CMDS 2 #define JBOD_MAPS_COUNT 2 #define MEGASAS_REDUCE_QD_COUNT 64 @@ -140,12 +140,15 @@ struct RAID_CONTEXT_G35 { u16 timeout_value; /* 0x02 -0x03 */ u16 routing_flags; // 0x04 -0x05 routing flags u16 virtual_disk_tgt_id; /* 0x06 -0x07 */ - u64 reg_lock_row_lba; /* 0x08 - 0x0F */ + __le64 reg_lock_row_lba; /* 0x08 - 0x0F */ u32 reg_lock_length; /* 0x10 - 0x13 */ - union { - u16 next_lmid; /* 0x14 - 0x15 */ - u16 peer_smid; /* used for the raid 1/10 fp writes */ - } smid; + union { // flow specific + u16 rmw_op_index; /* 0x14 - 0x15, R5/6 RMW: rmw operation index*/ + u16 peer_smid; /* 0x14 - 0x15, R1 Write: peer smid*/ + u16 r56_arm_map; /* 0x14 - 0x15, Unused [15], LogArm[14:10], P-Arm[9:5], Q-Arm[4:0] */ + + } flow_specific; + u8 ex_status; /* 0x16 : OUT */ u8 status; /* 0x17 status */ u8 raid_flags; /* 0x18 resvd[7:6], ioSubType[5:4], @@ -236,6 +239,13 @@ union RAID_CONTEXT_UNION { #define RAID_CTX_SPANARM_SPAN_SHIFT (5) #define RAID_CTX_SPANARM_SPAN_MASK (0xE0) +/* LogArm[14:10], P-Arm[9:5], Q-Arm[4:0] */ +#define RAID_CTX_R56_Q_ARM_MASK (0x1F) +#define RAID_CTX_R56_P_ARM_SHIFT (5) +#define RAID_CTX_R56_P_ARM_MASK (0x3E0) +#define RAID_CTX_R56_LOG_ARM_SHIFT (10) +#define RAID_CTX_R56_LOG_ARM_MASK (0x7C00) + /* number of bits per index in U32 TrackStream */ #define BITS_PER_INDEX_STREAM 4 #define INVALID_STREAM_NUM 16 @@ -940,6 +950,7 @@ struct IO_REQUEST_INFO { u8 pd_after_lb; u16 r1_alt_dev_handle; /* raid 1/10 only */ bool ra_capable; + u8 data_arms; }; struct MR_LD_TARGET_SYNC { @@ -1324,7 +1335,8 @@ struct fusion_context { dma_addr_t ioc_init_request_phys; struct MPI2_IOC_INIT_REQUEST *ioc_init_request; struct megasas_cmd *ioc_init_cmd; - + bool pcie_bw_limitation; + bool r56_div_offload; }; union desc_value { @@ -1349,6 +1361,11 @@ struct MR_SNAPDUMP_PROPERTIES { u8 reserved[12]; }; +struct megasas_debugfs_buffer { + void *buf; + u32 len; +}; + void megasas_free_cmds_fusion(struct megasas_instance *instance); int megasas_ioc_init_fusion(struct megasas_instance *instance); u8 megasas_get_map_info(struct megasas_instance *instance); diff --git a/drivers/scsi/mpt3sas/mpi/mpi2.h b/drivers/scsi/mpt3sas/mpi/mpi2.h index 7efd17a3c25b..18b1e31b5eb8 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2.h @@ -9,7 +9,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.53 + * mpi2.h Version: 02.00.54 * * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 * prefix are for use only on MPI v2.5 products, and must not be used @@ -121,6 +121,7 @@ * 08-15-18 02.00.52 Bumped MPI2_HEADER_VERSION_UNIT. * 08-28-18 02.00.53 Bumped MPI2_HEADER_VERSION_UNIT. * Added MPI2_IOCSTATUS_FAILURE + * 12-17-18 02.00.54 Bumped MPI2_HEADER_VERSION_UNIT * -------------------------------------------------------------------------- */ @@ -161,7 +162,7 @@ /* Unit and Dev versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x35) +#define MPI2_HEADER_VERSION_UNIT (0x36) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index a2f4a55c51be..3a6871aecada 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -7,7 +7,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.46 + * mpi2_cnfg.h Version: 02.00.47 * * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 * prefix are for use only on MPI v2.5 products, and must not be used @@ -244,6 +244,11 @@ * Added DMDReport Delay Time defines to * PCIeIOUnitPage1 * -------------------------------------------------------------------------- + * 08-02-18 02.00.44 Added Slotx2, Slotx4 to ManPage 7. + * 08-15-18 02.00.45 Added ProductSpecific field at end of IOC Page 1 + * 08-28-18 02.00.46 Added NVMs Write Cache flag to IOUnitPage1 + * Added DMDReport Delay Time defines to PCIeIOUnitPage1 + * 12-17-18 02.00.47 Swap locations of Slotx2 and Slotx4 in ManPage 7. */ #ifndef MPI2_CNFG_H @@ -810,7 +815,8 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO { U8 Location; /*0x14 */ U8 ReceptacleID; /*0x15 */ U16 Slot; /*0x16 */ - U32 Reserved2; /*0x18 */ + U16 Slotx2; /*0x18 */ + U16 Slotx4; /*0x1A */ } MPI2_MANPAGE7_CONNECTOR_INFO, *PTR_MPI2_MANPAGE7_CONNECTOR_INFO, Mpi2ManPage7ConnectorInfo_t, @@ -1398,7 +1404,7 @@ typedef struct _MPI2_CONFIG_PAGE_IOC_1 { U8 PCIBusNum; /*0x0E */ U8 PCIDomainSegment; /*0x0F */ U32 Reserved1; /*0x10 */ - U32 Reserved2; /*0x14 */ + U32 ProductSpecific; /* 0x14 */ } MPI2_CONFIG_PAGE_IOC_1, *PTR_MPI2_CONFIG_PAGE_IOC_1, Mpi2IOCPage1_t, *pMpi2IOCPage1_t; diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_image.h b/drivers/scsi/mpt3sas/mpi/mpi2_image.h index 4959585f029d..a3f677853098 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_image.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_image.h @@ -5,7 +5,7 @@ * Name: mpi2_image.h * Description: Contains definitions for firmware and other component images * Creation Date: 04/02/2018 - * Version: 02.06.03 + * Version: 02.06.04 * * * Version History @@ -17,6 +17,8 @@ * 08-14-18 02.06.01 Corrected define for MPI26_IMAGE_HEADER_SIGNATURE0_MPI26 * 08-28-18 02.06.02 Added MPI2_EXT_IMAGE_TYPE_RDE * 09-07-18 02.06.03 Added MPI26_EVENT_PCIE_TOPO_PI_16_LANES + * 12-17-18 02.06.04 Addd MPI2_EXT_IMAGE_TYPE_PBLP + * Shorten some defines to be compatible with DOS */ #ifndef MPI2_IMAGE_H #define MPI2_IMAGE_H @@ -200,17 +202,17 @@ typedef struct _MPI26_COMPONENT_IMAGE_HEADER { #define MPI26_IMAGE_HEADER_SIGNATURE0_MPI26 (0xEB000042) /**** Definitions for Signature1 field ****/ -#define MPI26_IMAGE_HEADER_SIGNATURE1_APPLICATION (0x20505041) -#define MPI26_IMAGE_HEADER_SIGNATURE1_CBB (0x20424243) -#define MPI26_IMAGE_HEADER_SIGNATURE1_MFG (0x2047464D) -#define MPI26_IMAGE_HEADER_SIGNATURE1_BIOS (0x534F4942) -#define MPI26_IMAGE_HEADER_SIGNATURE1_HIIM (0x4D494948) -#define MPI26_IMAGE_HEADER_SIGNATURE1_HIIA (0x41494948) -#define MPI26_IMAGE_HEADER_SIGNATURE1_CPLD (0x444C5043) -#define MPI26_IMAGE_HEADER_SIGNATURE1_SPD (0x20445053) -#define MPI26_IMAGE_HEADER_SIGNATURE1_NVDATA (0x5444564E) -#define MPI26_IMAGE_HEADER_SIGNATURE1_GAS_GAUGE (0x20534147) -#define MPI26_IMAGE_HEADER_SIGNATURE1_PBLP (0x50424C50) +#define MPI26_IMAGE_HEADER_SIG1_APPLICATION (0x20505041) +#define MPI26_IMAGE_HEADER_SIG1_CBB (0x20424243) +#define MPI26_IMAGE_HEADER_SIG1_MFG (0x2047464D) +#define MPI26_IMAGE_HEADER_SIG1_BIOS (0x534F4942) +#define MPI26_IMAGE_HEADER_SIG1_HIIM (0x4D494948) +#define MPI26_IMAGE_HEADER_SIG1_HIIA (0x41494948) +#define MPI26_IMAGE_HEADER_SIG1_CPLD (0x444C5043) +#define MPI26_IMAGE_HEADER_SIG1_SPD (0x20445053) +#define MPI26_IMAGE_HEADER_SIG1_NVDATA (0x5444564E) +#define MPI26_IMAGE_HEADER_SIG1_GAS_GAUGE (0x20534147) +#define MPI26_IMAGE_HEADER_SIG1_PBLP (0x504C4250) /**** Definitions for Signature2 field ****/ #define MPI26_IMAGE_HEADER_SIGNATURE2_VALUE (0x50584546) @@ -278,6 +280,7 @@ typedef struct _MPI2_EXT_IMAGE_HEADER { #define MPI2_EXT_IMAGE_TYPE_MEGARAID (0x08) #define MPI2_EXT_IMAGE_TYPE_ENCRYPTED_HASH (0x09) #define MPI2_EXT_IMAGE_TYPE_RDE (0x0A) +#define MPI2_EXT_IMAGE_TYPE_PBLP (0x0B) #define MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC (0x80) #define MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC (0xFF) @@ -472,12 +475,12 @@ Mpi25EncryptedHashEntry_t, *pMpi25EncryptedHashEntry_t; #define MPI25_HASH_ALGORITHM_UNUSED (0x00) #define MPI25_HASH_ALGORITHM_SHA256 (0x01) -#define MPI26_HASH_ALGORITHM_VERSION_MASK (0xE0) -#define MPI26_HASH_ALGORITHM_VERSION_NONE (0x00) -#define MPI26_HASH_ALGORITHM_VERSION_SHA1 (0x20) -#define MPI26_HASH_ALGORITHM_VERSION_SHA2 (0x40) -#define MPI26_HASH_ALGORITHM_VERSION_SHA3 (0x60) -#define MPI26_HASH_ALGORITHM_SIZE_MASK (0x1F) +#define MPI26_HASH_ALGORITHM_VER_MASK (0xE0) +#define MPI26_HASH_ALGORITHM_VER_NONE (0x00) +#define MPI26_HASH_ALGORITHM_VER_SHA1 (0x20) +#define MPI26_HASH_ALGORITHM_VER_SHA2 (0x40) +#define MPI26_HASH_ALGORITHM_VER_SHA3 (0x60) +#define MPI26_HASH_ALGORITHM_SIZE_MASK (0x1F) #define MPI26_HASH_ALGORITHM_SIZE_256 (0x01) #define MPI26_HASH_ALGORITHM_SIZE_512 (0x02) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_pci.h b/drivers/scsi/mpt3sas/mpi/mpi2_pci.h index 63a09509d7d1..bb7b79cfa558 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_pci.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_pci.h @@ -6,7 +6,7 @@ * Title: MPI PCIe Attached Devices structures and definitions. * Creation Date: October 9, 2012 * - * mpi2_pci.h Version: 02.00.03 + * mpi2_pci.h Version: 02.00.04 * * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 * prefix are for use only on MPI v2.5 products, and must not be used @@ -24,6 +24,8 @@ * 07-01-16 02.00.02 Added MPI26_NVME_FLAGS_FORCE_ADMIN_ERR_RESP to * NVME Encapsulated Request. * 07-22-18 02.00.03 Updted flags field for NVME Encapsulated req + * 12-17-18 02.00.04 Added MPI26_PCIE_DEVINFO_SCSI + * Shortten some defines to be compatible with DOS * -------------------------------------------------------------------------- */ @@ -41,7 +43,7 @@ #define MPI26_PCIE_DEVINFO_NO_DEVICE (0x00000000) #define MPI26_PCIE_DEVINFO_PCI_SWITCH (0x00000001) #define MPI26_PCIE_DEVINFO_NVME (0x00000003) - +#define MPI26_PCIE_DEVINFO_SCSI (0x00000004) /**************************************************************************** * NVMe Encapsulated message @@ -75,10 +77,9 @@ typedef struct _MPI26_NVME_ENCAPSULATED_REQUEST { #define MPI26_NVME_FLAGS_SUBMISSIONQ_IO (0x0000) #define MPI26_NVME_FLAGS_SUBMISSIONQ_ADMIN (0x0010) /*Error Response Address Space */ -#define MPI26_NVME_FLAGS_MASK_ERROR_RSP_ADDR (0x000C) -#define MPI26_NVME_FLAGS_MASK_ERROR_RSP_ADDR_MASK (0x000C) -#define MPI26_NVME_FLAGS_SYSTEM_RSP_ADDR (0x0000) -#define MPI26_NVME_FLAGS_IOCCTL_RSP_ADDR (0x0008) +#define MPI26_NVME_FLAGS_ERR_RSP_ADDR_MASK (0x000C) +#define MPI26_NVME_FLAGS_ERR_RSP_ADDR_SYSTEM (0x0000) +#define MPI26_NVME_FLAGS_ERR_RSP_ADDR_IOCTL (0x0008) /* Data Direction*/ #define MPI26_NVME_FLAGS_DATADIRECTION_MASK (0x0003) #define MPI26_NVME_FLAGS_NODATATRANSFER (0x0000) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_tool.h b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h index 3f966b6796b3..17ef7f63b938 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_tool.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h @@ -7,7 +7,7 @@ * Title: MPI diagnostic tool structures and definitions * Creation Date: March 26, 2007 * - * mpi2_tool.h Version: 02.00.15 + * mpi2_tool.h Version: 02.00.16 * * Version History * --------------- @@ -40,6 +40,7 @@ * Tool Request Message. * 07-22-18 02.00.15 Added defines for new TOOLBOX_PCIE_LANE_MARGINING tool. * Added option for DeviceInfo field in ISTWI tool. + * 12-17-18 02.00.16 Shorten some defines to be compatible with DOS. * -------------------------------------------------------------------------- */ @@ -230,11 +231,11 @@ typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST { #define MPI2_TOOL_ISTWI_FLAG_PAGE_ADDR_MASK (0x07) /*MPI26 TOOLBOX Request MsgFlags defines */ -#define MPI26_TOOLBOX_REQ_MSGFLAGS_ADDRESSING_MASK (0x01) +#define MPI26_TOOL_ISTWI_MSGFLG_ADDR_MASK (0x01) /*Request uses Man Page 43 device index addressing */ -#define MPI26_TOOLBOX_REQ_MSGFLAGS_ADDRESSING_DEVINDEX (0x00) +#define MPI26_TOOL_ISTWI_MSGFLG_ADDR_INDEX (0x00) /*Request uses Man Page 43 device info struct addressing */ -#define MPI26_TOOLBOX_REQ_MSGFLAGS_ADDRESSING_DEVINFO (0x01) +#define MPI26_TOOL_ISTWI_MSGFLG_ADDR_INFO (0x01) /*Toolbox ISTWI Read Write Tool reply message */ typedef struct _MPI2_TOOLBOX_ISTWI_REPLY { @@ -403,7 +404,7 @@ Mpi2ToolboxTextDisplayRequest_t, */ /*Toolbox Backend Lane Margining Tool request message */ -typedef struct _MPI26_TOOLBOX_LANE_MARGINING_REQUEST { +typedef struct _MPI26_TOOLBOX_LANE_MARGIN_REQUEST { U8 Tool; /*0x00 */ U8 Reserved1; /*0x01 */ U8 ChainOffset; /*0x02 */ @@ -434,7 +435,7 @@ typedef struct _MPI26_TOOLBOX_LANE_MARGINING_REQUEST { /*Toolbox Backend Lane Margining Tool reply message */ -typedef struct _MPI26_TOOLBOX_LANE_MARGINING_REPLY { +typedef struct _MPI26_TOOLBOX_LANE_MARGIN_REPLY { U8 Tool; /*0x00 */ U8 Reserved1; /*0x01 */ U8 MsgLength; /*0x02 */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 8aacbd1e7db2..fea3cb6a090b 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -74,28 +74,28 @@ static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS]; #define MAX_HBA_QUEUE_DEPTH 30000 #define MAX_CHAIN_DEPTH 100000 static int max_queue_depth = -1; -module_param(max_queue_depth, int, 0); +module_param(max_queue_depth, int, 0444); MODULE_PARM_DESC(max_queue_depth, " max controller queue depth "); static int max_sgl_entries = -1; -module_param(max_sgl_entries, int, 0); +module_param(max_sgl_entries, int, 0444); MODULE_PARM_DESC(max_sgl_entries, " max sg entries "); static int msix_disable = -1; -module_param(msix_disable, int, 0); +module_param(msix_disable, int, 0444); MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); static int smp_affinity_enable = 1; -module_param(smp_affinity_enable, int, S_IRUGO); +module_param(smp_affinity_enable, int, 0444); MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disable Default: enable(1)"); static int max_msix_vectors = -1; -module_param(max_msix_vectors, int, 0); +module_param(max_msix_vectors, int, 0444); MODULE_PARM_DESC(max_msix_vectors, " max msix vectors"); static int irqpoll_weight = -1; -module_param(irqpoll_weight, int, 0); +module_param(irqpoll_weight, int, 0444); MODULE_PARM_DESC(irqpoll_weight, "irq poll weight (default= one fourth of HBA queue depth)"); @@ -103,6 +103,26 @@ static int mpt3sas_fwfault_debug; MODULE_PARM_DESC(mpt3sas_fwfault_debug, " enable detection of firmware fault and halt firmware - (default=0)"); +static int perf_mode = -1; +module_param(perf_mode, int, 0444); +MODULE_PARM_DESC(perf_mode, + "Performance mode (only for Aero/Sea Generation), options:\n\t\t" + "0 - balanced: high iops mode is enabled &\n\t\t" + "interrupt coalescing is enabled only on high iops queues,\n\t\t" + "1 - iops: high iops mode is disabled &\n\t\t" + "interrupt coalescing is enabled on all queues,\n\t\t" + "2 - latency: high iops mode is disabled &\n\t\t" + "interrupt coalescing is enabled on all queues with timeout value 0xA,\n" + "\t\tdefault - default perf_mode is 'balanced'" + ); + +enum mpt3sas_perf_mode { + MPT_PERF_MODE_DEFAULT = -1, + MPT_PERF_MODE_BALANCED = 0, + MPT_PERF_MODE_IOPS = 1, + MPT_PERF_MODE_LATENCY = 2, +}; + static int _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc); @@ -1282,7 +1302,7 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply) ack_request->EventContext = mpi_reply->EventContext; ack_request->VF_ID = 0; /* TODO */ ack_request->VP_ID = 0; - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); out: @@ -2240,6 +2260,11 @@ base_is_prp_possible(struct MPT3SAS_ADAPTER *ioc, bool build_prp = true; data_length = scsi_bufflen(scmd); + if (pcie_device && + (mpt3sas_scsih_is_pcie_scsi_device(pcie_device->device_info))) { + build_prp = false; + return build_prp; + } /* If Datalenth is <= 16K and number of SGE’s entries are <= 2 * we built IEEE SGL @@ -2683,6 +2708,8 @@ _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev) { u64 required_mask, coherent_mask; struct sysinfo s; + /* Set 63 bit DMA mask for all SAS3 and SAS35 controllers */ + int dma_mask = (ioc->hba_mpi_version_belonged > MPI2_VERSION) ? 63 : 64; if (ioc->is_mcpu_endpoint) goto try_32bit; @@ -2692,17 +2719,17 @@ _base_config_dma_addressing(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev) goto try_32bit; if (ioc->dma_mask) - coherent_mask = DMA_BIT_MASK(64); + coherent_mask = DMA_BIT_MASK(dma_mask); else coherent_mask = DMA_BIT_MASK(32); - if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) || + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(dma_mask)) || dma_set_coherent_mask(&pdev->dev, coherent_mask)) goto try_32bit; ioc->base_add_sg_single = &_base_add_sg_single_64; ioc->sge_size = sizeof(Mpi2SGESimple64_t); - ioc->dma_mask = 64; + ioc->dma_mask = dma_mask; goto out; try_32bit: @@ -2724,7 +2751,7 @@ static int _base_change_consistent_dma_mask(struct MPT3SAS_ADAPTER *ioc, struct pci_dev *pdev) { - if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(ioc->dma_mask))) { if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) return -ENODEV; } @@ -2793,6 +2820,9 @@ _base_free_irq(struct MPT3SAS_ADAPTER *ioc) list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { list_del(&reply_q->list); + if (ioc->smp_affinity_enable) + irq_set_affinity_hint(pci_irq_vector(ioc->pdev, + reply_q->msix_index), NULL); free_irq(pci_irq_vector(ioc->pdev, reply_q->msix_index), reply_q); kfree(reply_q); @@ -2857,14 +2887,13 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) { unsigned int cpu, nr_cpus, nr_msix, index = 0; struct adapter_reply_queue *reply_q; + int local_numa_node; if (!_base_is_controller_msix_enabled(ioc)) return; - ioc->msix_load_balance = false; - if (ioc->reply_queue_count < num_online_cpus()) { - ioc->msix_load_balance = true; + + if (ioc->msix_load_balance) return; - } memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz); @@ -2874,14 +2903,33 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) if (!nr_msix) return; - if (smp_affinity_enable) { + if (ioc->smp_affinity_enable) { + + /* + * set irq affinity to local numa node for those irqs + * corresponding to high iops queues. + */ + if (ioc->high_iops_queues) { + local_numa_node = dev_to_node(&ioc->pdev->dev); + for (index = 0; index < ioc->high_iops_queues; + index++) { + irq_set_affinity_hint(pci_irq_vector(ioc->pdev, + index), cpumask_of_node(local_numa_node)); + } + } + list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - const cpumask_t *mask = pci_irq_get_affinity(ioc->pdev, - reply_q->msix_index); + const cpumask_t *mask; + + if (reply_q->msix_index < ioc->high_iops_queues) + continue; + + mask = pci_irq_get_affinity(ioc->pdev, + reply_q->msix_index); if (!mask) { ioc_warn(ioc, "no affinity for msi %x\n", reply_q->msix_index); - continue; + goto fall_back; } for_each_cpu_and(cpu, mask, cpu_online_mask) { @@ -2892,12 +2940,18 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) } return; } + +fall_back: cpu = cpumask_first(cpu_online_mask); + nr_msix -= ioc->high_iops_queues; + index = 0; list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - unsigned int i, group = nr_cpus / nr_msix; + if (reply_q->msix_index < ioc->high_iops_queues) + continue; + if (cpu >= nr_cpus) break; @@ -2913,6 +2967,52 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc) } /** + * _base_check_and_enable_high_iops_queues - enable high iops mode + * @ ioc - per adapter object + * @ hba_msix_vector_count - msix vectors supported by HBA + * + * Enable high iops queues only if + * - HBA is a SEA/AERO controller and + * - MSI-Xs vector supported by the HBA is 128 and + * - total CPU count in the system >=16 and + * - loaded driver with default max_msix_vectors module parameter and + * - system booted in non kdump mode + * + * returns nothing. + */ +static void +_base_check_and_enable_high_iops_queues(struct MPT3SAS_ADAPTER *ioc, + int hba_msix_vector_count) +{ + u16 lnksta, speed; + + if (perf_mode == MPT_PERF_MODE_IOPS || + perf_mode == MPT_PERF_MODE_LATENCY) { + ioc->high_iops_queues = 0; + return; + } + + if (perf_mode == MPT_PERF_MODE_DEFAULT) { + + pcie_capability_read_word(ioc->pdev, PCI_EXP_LNKSTA, &lnksta); + speed = lnksta & PCI_EXP_LNKSTA_CLS; + + if (speed < 0x4) { + ioc->high_iops_queues = 0; + return; + } + } + + if (!reset_devices && ioc->is_aero_ioc && + hba_msix_vector_count == MPT3SAS_GEN35_MAX_MSIX_QUEUES && + num_online_cpus() >= MPT3SAS_HIGH_IOPS_REPLY_QUEUES && + max_msix_vectors == -1) + ioc->high_iops_queues = MPT3SAS_HIGH_IOPS_REPLY_QUEUES; + else + ioc->high_iops_queues = 0; +} + +/** * _base_disable_msix - disables msix * @ioc: per adapter object * @@ -2922,11 +3022,38 @@ _base_disable_msix(struct MPT3SAS_ADAPTER *ioc) { if (!ioc->msix_enable) return; - pci_disable_msix(ioc->pdev); + pci_free_irq_vectors(ioc->pdev); ioc->msix_enable = 0; } /** + * _base_alloc_irq_vectors - allocate msix vectors + * @ioc: per adapter object + * + */ +static int +_base_alloc_irq_vectors(struct MPT3SAS_ADAPTER *ioc) +{ + int i, irq_flags = PCI_IRQ_MSIX; + struct irq_affinity desc = { .pre_vectors = ioc->high_iops_queues }; + struct irq_affinity *descp = &desc; + + if (ioc->smp_affinity_enable) + irq_flags |= PCI_IRQ_AFFINITY; + else + descp = NULL; + + ioc_info(ioc, " %d %d\n", ioc->high_iops_queues, + ioc->msix_vector_count); + + i = pci_alloc_irq_vectors_affinity(ioc->pdev, + ioc->high_iops_queues, + ioc->msix_vector_count, irq_flags, descp); + + return i; +} + +/** * _base_enable_msix - enables msix, failback to io_apic * @ioc: per adapter object * @@ -2937,7 +3064,8 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) int r; int i, local_max_msix_vectors; u8 try_msix = 0; - unsigned int irq_flags = PCI_IRQ_MSIX; + + ioc->msix_load_balance = false; if (msix_disable == -1 || msix_disable == 0) try_msix = 1; @@ -2948,12 +3076,16 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) if (_base_check_enable_msix(ioc) != 0) goto try_ioapic; - ioc->reply_queue_count = min_t(int, ioc->cpu_count, + ioc_info(ioc, "MSI-X vectors supported: %d\n", ioc->msix_vector_count); + pr_info("\t no of cores: %d, max_msix_vectors: %d\n", + ioc->cpu_count, max_msix_vectors); + if (ioc->is_aero_ioc) + _base_check_and_enable_high_iops_queues(ioc, + ioc->msix_vector_count); + ioc->reply_queue_count = + min_t(int, ioc->cpu_count + ioc->high_iops_queues, ioc->msix_vector_count); - ioc_info(ioc, "MSI-X vectors supported: %d, no of cores: %d, max_msix_vectors: %d\n", - ioc->msix_vector_count, ioc->cpu_count, max_msix_vectors); - if (!ioc->rdpq_array_enable && max_msix_vectors == -1) local_max_msix_vectors = (reset_devices) ? 1 : 8; else @@ -2965,14 +3097,23 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) else if (local_max_msix_vectors == 0) goto try_ioapic; - if (ioc->msix_vector_count < ioc->cpu_count) - smp_affinity_enable = 0; + /* + * Enable msix_load_balance only if combined reply queue mode is + * disabled on SAS3 & above generation HBA devices. + */ + if (!ioc->combined_reply_queue && + ioc->hba_mpi_version_belonged != MPI2_VERSION) { + ioc->msix_load_balance = true; + } - if (smp_affinity_enable) - irq_flags |= PCI_IRQ_AFFINITY; + /* + * smp affinity setting is not need when msix load balance + * is enabled. + */ + if (ioc->msix_load_balance) + ioc->smp_affinity_enable = 0; - r = pci_alloc_irq_vectors(ioc->pdev, 1, ioc->reply_queue_count, - irq_flags); + r = _base_alloc_irq_vectors(ioc); if (r < 0) { dfailprintk(ioc, ioc_info(ioc, "pci_alloc_irq_vectors failed (r=%d) !!!\n", @@ -2991,11 +3132,15 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) } } + ioc_info(ioc, "High IOPs queues : %s\n", + ioc->high_iops_queues ? "enabled" : "disabled"); + return 0; /* failback to io_apic interrupt routing */ try_ioapic: - + ioc->high_iops_queues = 0; + ioc_info(ioc, "High IOPs queues : disabled\n"); ioc->reply_queue_count = 1; r = pci_alloc_irq_vectors(ioc->pdev, 1, 1, PCI_IRQ_LEGACY); if (r < 0) { @@ -3038,6 +3183,37 @@ mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc) } } +static int +_base_diag_reset(struct MPT3SAS_ADAPTER *ioc); + +/** + * _base_check_for_fault_and_issue_reset - check if IOC is in fault state + * and if it is in fault state then issue diag reset. + * @ioc: per adapter object + * + * Returns: 0 for success, non-zero for failure. + */ +static int +_base_check_for_fault_and_issue_reset(struct MPT3SAS_ADAPTER *ioc) +{ + u32 ioc_state; + int rc = -EFAULT; + + dinitprintk(ioc, pr_info("%s\n", __func__)); + if (ioc->pci_error_recovery) + return 0; + ioc_state = mpt3sas_base_get_iocstate(ioc, 0); + dhsprintk(ioc, pr_info("%s: ioc_state(0x%08x)\n", __func__, ioc_state)); + + if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { + mpt3sas_base_fault_info(ioc, ioc_state & + MPI2_DOORBELL_DATA_MASK); + rc = _base_diag_reset(ioc); + } + + return rc; +} + /** * mpt3sas_base_map_resources - map in controller resources (io/irq/memap) * @ioc: per adapter object @@ -3050,7 +3226,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) struct pci_dev *pdev = ioc->pdev; u32 memap_sz; u32 pio_sz; - int i, r = 0; + int i, r = 0, rc; u64 pio_chip = 0; phys_addr_t chip_phys = 0; struct adapter_reply_queue *reply_q; @@ -3111,8 +3287,11 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) _base_mask_interrupts(ioc); r = _base_get_ioc_facts(ioc); - if (r) - goto out_fail; + if (r) { + rc = _base_check_for_fault_and_issue_reset(ioc); + if (rc || (_base_get_ioc_facts(ioc))) + goto out_fail; + } if (!ioc->rdpq_array_enable_assigned) { ioc->rdpq_array_enable = ioc->rdpq_array_capable; @@ -3265,8 +3444,18 @@ mpt3sas_base_get_reply_virt_addr(struct MPT3SAS_ADAPTER *ioc, u32 phys_addr) return ioc->reply + (phys_addr - (u32)ioc->reply_dma); } +/** + * _base_get_msix_index - get the msix index + * @ioc: per adapter object + * @scmd: scsi_cmnd object + * + * returns msix index of general reply queues, + * i.e. reply queue on which IO request's reply + * should be posted by the HBA firmware. + */ static inline u8 -_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc) +_base_get_msix_index(struct MPT3SAS_ADAPTER *ioc, + struct scsi_cmnd *scmd) { /* Enables reply_queue load balancing */ if (ioc->msix_load_balance) @@ -3278,6 +3467,35 @@ _base_get_msix_index(struct MPT3SAS_ADAPTER *ioc) } /** + * _base_get_high_iops_msix_index - get the msix index of + * high iops queues + * @ioc: per adapter object + * @scmd: scsi_cmnd object + * + * Returns: msix index of high iops reply queues. + * i.e. high iops reply queue on which IO request's + * reply should be posted by the HBA firmware. + */ +static inline u8 +_base_get_high_iops_msix_index(struct MPT3SAS_ADAPTER *ioc, + struct scsi_cmnd *scmd) +{ + /** + * Round robin the IO interrupts among the high iops + * reply queues in terms of batch count 16 when outstanding + * IOs on the target device is >=8. + */ + if (atomic_read(&scmd->device->device_busy) > + MPT3SAS_DEVICE_HIGH_IOPS_DEPTH) + return base_mod64(( + atomic64_add_return(1, &ioc->high_iops_outstanding) / + MPT3SAS_HIGH_IOPS_BATCH_COUNT), + MPT3SAS_HIGH_IOPS_REPLY_QUEUES); + + return _base_get_msix_index(ioc, scmd); +} + +/** * mpt3sas_base_get_smid - obtain a free smid from internal queue * @ioc: per adapter object * @cb_idx: callback index @@ -3325,8 +3543,8 @@ mpt3sas_base_get_smid_scsiio(struct MPT3SAS_ADAPTER *ioc, u8 cb_idx, smid = tag + 1; request->cb_idx = cb_idx; - request->msix_io = _base_get_msix_index(ioc); request->smid = smid; + request->scmd = scmd; INIT_LIST_HEAD(&request->chain_list); return smid; } @@ -3380,6 +3598,7 @@ void mpt3sas_base_clear_st(struct MPT3SAS_ADAPTER *ioc, return; st->cb_idx = 0xFF; st->direct_io = 0; + st->scmd = NULL; atomic_set(&ioc->chain_lookup[st->smid - 1].chain_offset, 0); st->smid = 0; } @@ -3479,13 +3698,37 @@ _base_writeq(__u64 b, volatile void __iomem *addr, spinlock_t *writeq_lock) #endif /** + * _base_set_and_get_msix_index - get the msix index and assign to msix_io + * variable of scsi tracker + * @ioc: per adapter object + * @smid: system request message index + * + * returns msix index. + */ +static u8 +_base_set_and_get_msix_index(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ + struct scsiio_tracker *st = NULL; + + if (smid < ioc->hi_priority_smid) + st = _get_st_from_smid(ioc, smid); + + if (st == NULL) + return _base_get_msix_index(ioc, NULL); + + st->msix_io = ioc->get_msix_index_for_smlio(ioc, st->scmd); + return st->msix_io; +} + +/** * _base_put_smid_mpi_ep_scsi_io - send SCSI_IO request to firmware * @ioc: per adapter object * @smid: system request message index * @handle: device handle */ static void -_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) +_base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, + u16 smid, u16 handle) { Mpi2RequestDescriptorUnion_t descriptor; u64 *request = (u64 *)&descriptor; @@ -3498,7 +3741,7 @@ _base_put_smid_mpi_ep_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) _base_clone_mpi_to_sys_mem(mpi_req_iomem, (void *)mfp, ioc->request_sz); descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; - descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); + descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); descriptor.SCSIIO.SMID = cpu_to_le16(smid); descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); descriptor.SCSIIO.LMID = 0; @@ -3520,7 +3763,7 @@ _base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; - descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); + descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); descriptor.SCSIIO.SMID = cpu_to_le16(smid); descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); descriptor.SCSIIO.LMID = 0; @@ -3529,13 +3772,13 @@ _base_put_smid_scsi_io(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) } /** - * mpt3sas_base_put_smid_fast_path - send fast path request to firmware + * _base_put_smid_fast_path - send fast path request to firmware * @ioc: per adapter object * @smid: system request message index * @handle: device handle */ -void -mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, +static void +_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 handle) { Mpi2RequestDescriptorUnion_t descriptor; @@ -3543,7 +3786,7 @@ mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, descriptor.SCSIIO.RequestFlags = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; - descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); + descriptor.SCSIIO.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); descriptor.SCSIIO.SMID = cpu_to_le16(smid); descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); descriptor.SCSIIO.LMID = 0; @@ -3552,13 +3795,13 @@ mpt3sas_base_put_smid_fast_path(struct MPT3SAS_ADAPTER *ioc, u16 smid, } /** - * mpt3sas_base_put_smid_hi_priority - send Task Management request to firmware + * _base_put_smid_hi_priority - send Task Management request to firmware * @ioc: per adapter object * @smid: system request message index * @msix_task: msix_task will be same as msix of IO incase of task abort else 0. */ -void -mpt3sas_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid, +static void +_base_put_smid_hi_priority(struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 msix_task) { Mpi2RequestDescriptorUnion_t descriptor; @@ -3607,7 +3850,7 @@ mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid) descriptor.Default.RequestFlags = MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED; - descriptor.Default.MSIxIndex = _base_get_msix_index(ioc); + descriptor.Default.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); descriptor.Default.SMID = cpu_to_le16(smid); descriptor.Default.LMID = 0; descriptor.Default.DescriptorTypeDependent = 0; @@ -3616,12 +3859,12 @@ mpt3sas_base_put_smid_nvme_encap(struct MPT3SAS_ADAPTER *ioc, u16 smid) } /** - * mpt3sas_base_put_smid_default - Default, primarily used for config pages + * _base_put_smid_default - Default, primarily used for config pages * @ioc: per adapter object * @smid: system request message index */ -void -mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) +static void +_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) { Mpi2RequestDescriptorUnion_t descriptor; void *mpi_req_iomem; @@ -3639,7 +3882,7 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) } request = (u64 *)&descriptor; descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; - descriptor.Default.MSIxIndex = _base_get_msix_index(ioc); + descriptor.Default.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); descriptor.Default.SMID = cpu_to_le16(smid); descriptor.Default.LMID = 0; descriptor.Default.DescriptorTypeDependent = 0; @@ -3653,6 +3896,95 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) } /** + * _base_put_smid_scsi_io_atomic - send SCSI_IO request to firmware using + * Atomic Request Descriptor + * @ioc: per adapter object + * @smid: system request message index + * @handle: device handle, unused in this function, for function type match + * + * Return nothing. + */ +static void +_base_put_smid_scsi_io_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, + u16 handle) +{ + Mpi26AtomicRequestDescriptor_t descriptor; + u32 *request = (u32 *)&descriptor; + + descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; + descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); + descriptor.SMID = cpu_to_le16(smid); + + writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); +} + +/** + * _base_put_smid_fast_path_atomic - send fast path request to firmware + * using Atomic Request Descriptor + * @ioc: per adapter object + * @smid: system request message index + * @handle: device handle, unused in this function, for function type match + * Return nothing + */ +static void +_base_put_smid_fast_path_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, + u16 handle) +{ + Mpi26AtomicRequestDescriptor_t descriptor; + u32 *request = (u32 *)&descriptor; + + descriptor.RequestFlags = MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; + descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); + descriptor.SMID = cpu_to_le16(smid); + + writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); +} + +/** + * _base_put_smid_hi_priority_atomic - send Task Management request to + * firmware using Atomic Request Descriptor + * @ioc: per adapter object + * @smid: system request message index + * @msix_task: msix_task will be same as msix of IO incase of task abort else 0 + * + * Return nothing. + */ +static void +_base_put_smid_hi_priority_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid, + u16 msix_task) +{ + Mpi26AtomicRequestDescriptor_t descriptor; + u32 *request = (u32 *)&descriptor; + + descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; + descriptor.MSIxIndex = msix_task; + descriptor.SMID = cpu_to_le16(smid); + + writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); +} + +/** + * _base_put_smid_default - Default, primarily used for config pages + * use Atomic Request Descriptor + * @ioc: per adapter object + * @smid: system request message index + * + * Return nothing. + */ +static void +_base_put_smid_default_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ + Mpi26AtomicRequestDescriptor_t descriptor; + u32 *request = (u32 *)&descriptor; + + descriptor.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; + descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid); + descriptor.SMID = cpu_to_le16(smid); + + writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost); +} + +/** * _base_display_OEMs_branding - Display branding string * @ioc: per adapter object */ @@ -3952,7 +4284,7 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc) ioc->build_sg(ioc, &mpi_request->SGL, 0, 0, fwpkg_data_dma, data_length); init_completion(&ioc->base_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); /* Wait for 15 seconds */ wait_for_completion_timeout(&ioc->base_cmds.done, FW_IMG_HDR_READ_TIMEOUT*HZ); @@ -4192,6 +4524,71 @@ out: } /** + * _base_update_ioc_page1_inlinewith_perf_mode - Update IOC Page1 fields + * according to performance mode. + * @ioc : per adapter object + * + * Return nothing. + */ +static void +_base_update_ioc_page1_inlinewith_perf_mode(struct MPT3SAS_ADAPTER *ioc) +{ + Mpi2IOCPage1_t ioc_pg1; + Mpi2ConfigReply_t mpi_reply; + + mpt3sas_config_get_ioc_pg1(ioc, &mpi_reply, &ioc->ioc_pg1_copy); + memcpy(&ioc_pg1, &ioc->ioc_pg1_copy, sizeof(Mpi2IOCPage1_t)); + + switch (perf_mode) { + case MPT_PERF_MODE_DEFAULT: + case MPT_PERF_MODE_BALANCED: + if (ioc->high_iops_queues) { + ioc_info(ioc, + "Enable interrupt coalescing only for first\t" + "%d reply queues\n", + MPT3SAS_HIGH_IOPS_REPLY_QUEUES); + /* + * If 31st bit is zero then interrupt coalescing is + * enabled for all reply descriptor post queues. + * If 31st bit is set to one then user can + * enable/disable interrupt coalescing on per reply + * descriptor post queue group(8) basis. So to enable + * interrupt coalescing only on first reply descriptor + * post queue group 31st bit and zero th bit is enabled. + */ + ioc_pg1.ProductSpecific = cpu_to_le32(0x80000000 | + ((1 << MPT3SAS_HIGH_IOPS_REPLY_QUEUES/8) - 1)); + mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1); + ioc_info(ioc, "performance mode: balanced\n"); + return; + } + /* Fall through */ + case MPT_PERF_MODE_LATENCY: + /* + * Enable interrupt coalescing on all reply queues + * with timeout value 0xA + */ + ioc_pg1.CoalescingTimeout = cpu_to_le32(0xa); + ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING); + ioc_pg1.ProductSpecific = 0; + mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1); + ioc_info(ioc, "performance mode: latency\n"); + break; + case MPT_PERF_MODE_IOPS: + /* + * Enable interrupt coalescing on all reply queues. + */ + ioc_info(ioc, + "performance mode: iops with coalescing timeout: 0x%x\n", + le32_to_cpu(ioc_pg1.CoalescingTimeout)); + ioc_pg1.Flags |= cpu_to_le32(MPI2_IOCPAGE1_REPLY_COALESCING); + ioc_pg1.ProductSpecific = 0; + mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, &ioc_pg1); + break; + } +} + +/** * _base_static_config_pages - static start of day config pages * @ioc: per adapter object */ @@ -4258,6 +4655,8 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) if (ioc->iounit_pg8.NumSensors) ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors; + if (ioc->is_aero_ioc) + _base_update_ioc_page1_inlinewith_perf_mode(ioc); } /** @@ -4631,7 +5030,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) total_sz += sz; } while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count)); - if (ioc->dma_mask == 64) { + if (ioc->dma_mask > 32) { if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) { ioc_warn(ioc, "no suitable consistent DMA mask for %s\n", pci_name(ioc->pdev)); @@ -4677,6 +5076,7 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc) _base_release_memory_pools(ioc); goto retry_allocation; } + memset(ioc->request, 0, sz); if (retry_sz) ioc_err(ioc, "request pool: dma_alloc_coherent succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), total(%d kb)\n", @@ -5050,8 +5450,6 @@ _base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout) * * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell. */ -static int -_base_diag_reset(struct MPT3SAS_ADAPTER *ioc); static int _base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout) @@ -5431,7 +5829,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc, mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) ioc->ioc_link_reset_in_progress = 1; init_completion(&ioc->base_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->base_cmds.done, msecs_to_jiffies(10000)); if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || @@ -5508,9 +5906,10 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc, ioc->base_cmds.status = MPT3_CMD_PENDING; request = mpt3sas_base_get_msg_frame(ioc, smid); ioc->base_cmds.smid = smid; + memset(request, 0, ioc->request_sz); memcpy(request, mpi_request, sizeof(Mpi2SepReply_t)); init_completion(&ioc->base_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->base_cmds.done, msecs_to_jiffies(10000)); if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { @@ -5693,6 +6092,9 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc) if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE) && (!reset_devices)) ioc->rdpq_array_capable = 1; + if ((facts->IOCCapabilities & MPI26_IOCFACTS_CAPABILITY_ATOMIC_REQ) + && ioc->is_aero_ioc) + ioc->atomic_desc_capable = 1; facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word); facts->IOCRequestFrameSize = le16_to_cpu(mpi_reply.IOCRequestFrameSize); @@ -5914,7 +6316,7 @@ _base_send_port_enable(struct MPT3SAS_ADAPTER *ioc) mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; init_completion(&ioc->port_enable_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->port_enable_cmds.done, 300*HZ); if (!(ioc->port_enable_cmds.status & MPT3_CMD_COMPLETE)) { ioc_err(ioc, "%s: timeout\n", __func__); @@ -5973,7 +6375,7 @@ mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc) memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); return 0; } @@ -6089,7 +6491,7 @@ _base_event_notification(struct MPT3SAS_ADAPTER *ioc) mpi_request->EventMasks[i] = cpu_to_le32(ioc->event_masks[i]); init_completion(&ioc->base_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); if (!(ioc->base_cmds.status & MPT3_CMD_COMPLETE)) { ioc_err(ioc, "%s: timeout\n", __func__); @@ -6323,7 +6725,7 @@ _base_make_ioc_ready(struct MPT3SAS_ADAPTER *ioc, enum reset_type type) static int _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc) { - int r, i, index; + int r, i, index, rc; unsigned long flags; u32 reply_address; u16 smid; @@ -6426,8 +6828,19 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc) skip_init_reply_post_free_queue: r = _base_send_ioc_init(ioc); - if (r) - return r; + if (r) { + /* + * No need to check IOC state for fault state & issue + * diag reset during host reset. This check is need + * only during driver load time. + */ + if (!ioc->is_driver_loading) + return r; + + rc = _base_check_for_fault_and_issue_reset(ioc); + if (rc || (_base_send_ioc_init(ioc))) + return r; + } /* initialize reply free host index */ ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1; @@ -6519,7 +6932,7 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc) int mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) { - int r, i; + int r, i, rc; int cpu_id, last_cpu_id = 0; dinitprintk(ioc, ioc_info(ioc, "%s\n", __func__)); @@ -6549,6 +6962,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) } } + ioc->smp_affinity_enable = smp_affinity_enable; + ioc->rdpq_array_enable_assigned = 0; ioc->dma_mask = 0; if (ioc->is_aero_ioc) @@ -6561,14 +6976,18 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) pci_set_drvdata(ioc->pdev, ioc->shost); r = _base_get_ioc_facts(ioc); - if (r) - goto out_free_resources; + if (r) { + rc = _base_check_for_fault_and_issue_reset(ioc); + if (rc || (_base_get_ioc_facts(ioc))) + goto out_free_resources; + } switch (ioc->hba_mpi_version_belonged) { case MPI2_VERSION: ioc->build_sg_scmd = &_base_build_sg_scmd; ioc->build_sg = &_base_build_sg; ioc->build_zero_len_sge = &_base_build_zero_len_sge; + ioc->get_msix_index_for_smlio = &_base_get_msix_index; break; case MPI25_VERSION: case MPI26_VERSION: @@ -6583,15 +7002,30 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) ioc->build_nvme_prp = &_base_build_nvme_prp; ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee; ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t); - + if (ioc->high_iops_queues) + ioc->get_msix_index_for_smlio = + &_base_get_high_iops_msix_index; + else + ioc->get_msix_index_for_smlio = &_base_get_msix_index; break; } - - if (ioc->is_mcpu_endpoint) - ioc->put_smid_scsi_io = &_base_put_smid_mpi_ep_scsi_io; - else - ioc->put_smid_scsi_io = &_base_put_smid_scsi_io; - + if (ioc->atomic_desc_capable) { + ioc->put_smid_default = &_base_put_smid_default_atomic; + ioc->put_smid_scsi_io = &_base_put_smid_scsi_io_atomic; + ioc->put_smid_fast_path = + &_base_put_smid_fast_path_atomic; + ioc->put_smid_hi_priority = + &_base_put_smid_hi_priority_atomic; + } else { + ioc->put_smid_default = &_base_put_smid_default; + ioc->put_smid_fast_path = &_base_put_smid_fast_path; + ioc->put_smid_hi_priority = &_base_put_smid_hi_priority; + if (ioc->is_mcpu_endpoint) + ioc->put_smid_scsi_io = + &_base_put_smid_mpi_ep_scsi_io; + else + ioc->put_smid_scsi_io = &_base_put_smid_scsi_io; + } /* * These function pointers for other requests that don't * the require IEEE scatter gather elements. @@ -6614,8 +7048,11 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { r = _base_get_port_facts(ioc, i); - if (r) - goto out_free_resources; + if (r) { + rc = _base_check_for_fault_and_issue_reset(ioc); + if (rc || (_base_get_port_facts(ioc, i))) + goto out_free_resources; + } } r = _base_allocate_memory_pools(ioc); @@ -6737,6 +7174,13 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) if (r) goto out_free_resources; + /* + * Copy current copy of IOCFacts in prev_fw_facts + * and it will be used during online firmware upgrade. + */ + memcpy(&ioc->prev_fw_facts, &ioc->facts, + sizeof(struct mpt3sas_facts)); + ioc->non_operational_loop = 0; ioc->got_task_abort_from_ioctl = 0; return 0; @@ -6899,6 +7343,85 @@ mpt3sas_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc) } /** + * _base_check_ioc_facts_changes - Look for increase/decrease of IOCFacts + * attributes during online firmware upgrade and update the corresponding + * IOC variables accordingly. + * + * @ioc: Pointer to MPT_ADAPTER structure + */ +static int +_base_check_ioc_facts_changes(struct MPT3SAS_ADAPTER *ioc) +{ + u16 pd_handles_sz; + void *pd_handles = NULL, *blocking_handles = NULL; + void *pend_os_device_add = NULL, *device_remove_in_progress = NULL; + struct mpt3sas_facts *old_facts = &ioc->prev_fw_facts; + + if (ioc->facts.MaxDevHandle > old_facts->MaxDevHandle) { + pd_handles_sz = (ioc->facts.MaxDevHandle / 8); + if (ioc->facts.MaxDevHandle % 8) + pd_handles_sz++; + + pd_handles = krealloc(ioc->pd_handles, pd_handles_sz, + GFP_KERNEL); + if (!pd_handles) { + ioc_info(ioc, + "Unable to allocate the memory for pd_handles of sz: %d\n", + pd_handles_sz); + return -ENOMEM; + } + memset(pd_handles + ioc->pd_handles_sz, 0, + (pd_handles_sz - ioc->pd_handles_sz)); + ioc->pd_handles = pd_handles; + + blocking_handles = krealloc(ioc->blocking_handles, + pd_handles_sz, GFP_KERNEL); + if (!blocking_handles) { + ioc_info(ioc, + "Unable to allocate the memory for " + "blocking_handles of sz: %d\n", + pd_handles_sz); + return -ENOMEM; + } + memset(blocking_handles + ioc->pd_handles_sz, 0, + (pd_handles_sz - ioc->pd_handles_sz)); + ioc->blocking_handles = blocking_handles; + ioc->pd_handles_sz = pd_handles_sz; + + pend_os_device_add = krealloc(ioc->pend_os_device_add, + pd_handles_sz, GFP_KERNEL); + if (!pend_os_device_add) { + ioc_info(ioc, + "Unable to allocate the memory for pend_os_device_add of sz: %d\n", + pd_handles_sz); + return -ENOMEM; + } + memset(pend_os_device_add + ioc->pend_os_device_add_sz, 0, + (pd_handles_sz - ioc->pend_os_device_add_sz)); + ioc->pend_os_device_add = pend_os_device_add; + ioc->pend_os_device_add_sz = pd_handles_sz; + + device_remove_in_progress = krealloc( + ioc->device_remove_in_progress, pd_handles_sz, GFP_KERNEL); + if (!device_remove_in_progress) { + ioc_info(ioc, + "Unable to allocate the memory for " + "device_remove_in_progress of sz: %d\n " + , pd_handles_sz); + return -ENOMEM; + } + memset(device_remove_in_progress + + ioc->device_remove_in_progress_sz, 0, + (pd_handles_sz - ioc->device_remove_in_progress_sz)); + ioc->device_remove_in_progress = device_remove_in_progress; + ioc->device_remove_in_progress_sz = pd_handles_sz; + } + + memcpy(&ioc->prev_fw_facts, &ioc->facts, sizeof(struct mpt3sas_facts)); + return 0; +} + +/** * mpt3sas_base_hard_reset_handler - reset controller * @ioc: Pointer to MPT_ADAPTER structure * @type: FORCE_BIG_HAMMER or SOFT_RESET @@ -6961,6 +7484,13 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc, if (r) goto out; + r = _base_check_ioc_facts_changes(ioc); + if (r) { + ioc_info(ioc, + "Some of the parameters got changed in this new firmware" + " image and it requires system reboot\n"); + goto out; + } if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable) panic("%s: Issue occurred with flashing controller firmware." "Please reboot the system and ensure that the correct" diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 480219f0efc5..faca0a5e71f8 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -76,8 +76,8 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>" #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "28.100.00.00" -#define MPT3SAS_MAJOR_VERSION 28 +#define MPT3SAS_DRIVER_VERSION "31.100.00.00" +#define MPT3SAS_MAJOR_VERSION 31 #define MPT3SAS_MINOR_VERSION 100 #define MPT3SAS_BUILD_VERSION 0 #define MPT3SAS_RELEASE_VERSION 00 @@ -355,6 +355,12 @@ struct mpt3sas_nvme_cmd { #define VIRTUAL_IO_FAILED_RETRY (0x32010081) +/* High IOPs definitions */ +#define MPT3SAS_DEVICE_HIGH_IOPS_DEPTH 8 +#define MPT3SAS_HIGH_IOPS_REPLY_QUEUES 8 +#define MPT3SAS_HIGH_IOPS_BATCH_COUNT 16 +#define MPT3SAS_GEN35_MAX_MSIX_QUEUES 128 + /* OEM Specific Flags will come from OEM specific header files */ struct Mpi2ManufacturingPage10_t { MPI2_CONFIG_PAGE_HEADER Header; /* 00h */ @@ -577,6 +583,7 @@ static inline void sas_device_put(struct _sas_device *s) * @enclosure_level: The level of device's enclosure from the controller * @connector_name: ASCII value of the Connector's name * @serial_number: pointer of serial number string allocated runtime + * @access_status: Device's Access Status * @refcount: reference count for deletion */ struct _pcie_device { @@ -598,6 +605,7 @@ struct _pcie_device { u8 connector_name[4]; u8 *serial_number; u8 reset_timeout; + u8 access_status; struct kref refcount; }; /** @@ -824,6 +832,7 @@ struct chain_lookup { */ struct scsiio_tracker { u16 smid; + struct scsi_cmnd *scmd; u8 cb_idx; u8 direct_io; struct pcie_sg_list pcie_sg_list; @@ -924,6 +933,12 @@ typedef void (*PUT_SMID_IO_FP_HIP) (struct MPT3SAS_ADAPTER *ioc, u16 smid, u16 funcdep); typedef void (*PUT_SMID_DEFAULT) (struct MPT3SAS_ADAPTER *ioc, u16 smid); typedef u32 (*BASE_READ_REG) (const volatile void __iomem *addr); +/* + * To get high iops reply queue's msix index when high iops mode is enabled + * else get the msix index of general reply queues. + */ +typedef u8 (*GET_MSIX_INDEX) (struct MPT3SAS_ADAPTER *ioc, + struct scsi_cmnd *scmd); /* IOC Facts and Port Facts converted from little endian to cpu */ union mpi3_version_union { @@ -1025,11 +1040,14 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @cpu_msix_table: table for mapping cpus to msix index * @cpu_msix_table_sz: table size * @total_io_cnt: Gives total IO count, used to load balance the interrupts + * @high_iops_outstanding: used to load balance the interrupts + * within high iops reply queues * @msix_load_balance: Enables load balancing of interrupts across * the multiple MSIXs * @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands * @thresh_hold: Max number of reply descriptors processed * before updating Host Index + * @drv_support_bitmap: driver's supported feature bit map * @scsi_io_cb_idx: shost generated commands * @tm_cb_idx: task management commands * @scsih_cb_idx: scsih internal commands @@ -1051,6 +1069,7 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @event_log: event log pointer * @event_masks: events that are masked * @facts: static facts data + * @prev_fw_facts: previous fw facts data * @pfacts: static port facts data * @manu_pg0: static manufacturing page 0 * @manu_pg10: static manufacturing page 10 @@ -1147,6 +1166,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * path functions resulting in Null pointer reference followed by kernel * crash. To avoid the above race condition we use mutex syncrhonization * which ensures the syncrhonization between cli/sysfs_show path. + * @atomic_desc_capable: Atomic Request Descriptor support. + * @GET_MSIX_INDEX: Get the msix index of high iops queues. */ struct MPT3SAS_ADAPTER { struct list_head list; @@ -1206,8 +1227,12 @@ struct MPT3SAS_ADAPTER { MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; u32 non_operational_loop; atomic64_t total_io_cnt; + atomic64_t high_iops_outstanding; bool msix_load_balance; u16 thresh_hold; + u8 high_iops_queues; + u32 drv_support_bitmap; + bool enable_sdev_max_qd; /* internal commands, callback index */ u8 scsi_io_cb_idx; @@ -1257,6 +1282,7 @@ struct MPT3SAS_ADAPTER { /* static config pages */ struct mpt3sas_facts facts; + struct mpt3sas_facts prev_fw_facts; struct mpt3sas_port_facts *pfacts; Mpi2ManufacturingPage0_t manu_pg0; struct Mpi2ManufacturingPage10_t manu_pg10; @@ -1267,6 +1293,7 @@ struct MPT3SAS_ADAPTER { Mpi2IOUnitPage0_t iounit_pg0; Mpi2IOUnitPage1_t iounit_pg1; Mpi2IOUnitPage8_t iounit_pg8; + Mpi2IOCPage1_t ioc_pg1_copy; struct _boot_device req_boot_device; struct _boot_device req_alt_boot_device; @@ -1385,6 +1412,7 @@ struct MPT3SAS_ADAPTER { u8 combined_reply_queue; u8 combined_reply_index_count; + u8 smp_affinity_enable; /* reply post register index */ resource_size_t **replyPostRegisterIndex; @@ -1412,6 +1440,7 @@ struct MPT3SAS_ADAPTER { u8 hide_drives; spinlock_t diag_trigger_lock; u8 diag_trigger_active; + u8 atomic_desc_capable; BASE_READ_REG base_readl; struct SL_WH_MASTER_TRIGGER_T diag_trigger_master; struct SL_WH_EVENT_TRIGGERS_T diag_trigger_event; @@ -1422,9 +1451,14 @@ struct MPT3SAS_ADAPTER { u8 is_gen35_ioc; u8 is_aero_ioc; PUT_SMID_IO_FP_HIP put_smid_scsi_io; - + PUT_SMID_IO_FP_HIP put_smid_fast_path; + PUT_SMID_IO_FP_HIP put_smid_hi_priority; + PUT_SMID_DEFAULT put_smid_default; + GET_MSIX_INDEX get_msix_index_for_smlio; }; +#define MPT_DRV_SUPPORT_BITMAP_MEMMOVE 0x00000001 + typedef u8 (*MPT_CALLBACK)(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply); @@ -1554,6 +1588,7 @@ struct _pcie_device *mpt3sas_get_pdev_by_handle(struct MPT3SAS_ADAPTER *ioc, void mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc); struct _raid_device * mpt3sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle); +void mpt3sas_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth); /* config shared API */ u8 mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, @@ -1611,6 +1646,10 @@ int mpt3sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, int mpt3sas_config_set_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); +int mpt3sas_config_get_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2IOCPage1_t *config_page); +int mpt3sas_config_set_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t + *mpi_reply, Mpi2IOCPage1_t *config_page); int mpt3sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page); int mpt3sas_config_get_expander_pg0(struct MPT3SAS_ADAPTER *ioc, @@ -1704,4 +1743,20 @@ mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, /* NCQ Prio Handling Check */ bool scsih_ncq_prio_supp(struct scsi_device *sdev); +/** + * _scsih_is_pcie_scsi_device - determines if device is an pcie scsi device + * @device_info: bitfield providing information about the device. + * Context: none + * + * Returns 1 if scsi device. + */ +static inline int +mpt3sas_scsih_is_pcie_scsi_device(u32 device_info) +{ + if ((device_info & + MPI26_PCIE_DEVINFO_MASK_DEVICE_TYPE) == MPI26_PCIE_DEVINFO_SCSI) + return 1; + else + return 0; +} #endif /* MPT3SAS_BASE_H_INCLUDED */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index fb0a17252f86..14a1a2793dd5 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -380,7 +380,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t)); _config_display_some_debug(ioc, smid, "config_request", NULL); init_completion(&ioc->config_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->config_cmds.done, timeout*HZ); if (!(ioc->config_cmds.status & MPT3_CMD_COMPLETE)) { mpt3sas_base_check_cmd_timeout(ioc, @@ -949,6 +949,77 @@ mpt3sas_config_get_ioc_pg8(struct MPT3SAS_ADAPTER *ioc, out: return r; } +/** + * mpt3sas_config_get_ioc_pg1 - obtain ioc page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Return: 0 for success, non-zero for failure. + */ +int +mpt3sas_config_get_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage1_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} + +/** + * mpt3sas_config_set_ioc_pg1 - modify ioc page 1 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * Context: sleep. + * + * Return: 0 for success, non-zero for failure. + */ +int +mpt3sas_config_set_ioc_pg1(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage1_t *config_page) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC; + mpi_request.Header.PageNumber = 1; + mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, + sizeof(*config_page)); + out: + return r; +} /** * mpt3sas_config_get_sas_device_pg0 - obtain sas device page 0 diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index b2bb47c14d35..7d696952b376 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -596,8 +596,16 @@ _ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg, if (priv_data->sas_target->handle != handle) continue; st = scsi_cmd_priv(scmd); - tm_request->TaskMID = cpu_to_le16(st->smid); - found = 1; + + /* + * If the given TaskMID from the user space is zero, then the + * first outstanding smid will be picked up. Otherwise, + * targeted smid will be the one. + */ + if (!tm_request->TaskMID || tm_request->TaskMID == st->smid) { + tm_request->TaskMID = cpu_to_le16(st->smid); + found = 1; + } } if (!found) { @@ -654,7 +662,6 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, size_t data_in_sz = 0; long ret; u16 device_handle = MPT3SAS_INVALID_DEVICE_HANDLE; - u8 tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE; issue_reset = 0; @@ -707,6 +714,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, ioc->ctl_cmds.status = MPT3_CMD_PENDING; memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); request = mpt3sas_base_get_msg_frame(ioc, smid); + memset(request, 0, ioc->request_sz); memcpy(request, mpi_request, karg.data_sge_offset*4); ioc->ctl_cmds.smid = smid; data_out_sz = karg.data_out_size; @@ -822,7 +830,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) ioc->put_smid_scsi_io(ioc, smid, device_handle); else - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_SCSI_TASK_MGMT: @@ -859,7 +867,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, tm_request->DevHandle)); ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, data_in_dma, data_in_sz); - mpt3sas_base_put_smid_hi_priority(ioc, smid, 0); + ioc->put_smid_hi_priority(ioc, smid, 0); break; } case MPI2_FUNCTION_SMP_PASSTHROUGH: @@ -890,7 +898,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, } ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, data_in_sz); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_SATA_PASSTHROUGH: @@ -905,7 +913,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, } ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, data_in_sz); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_FW_DOWNLOAD: @@ -913,7 +921,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, { ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, data_in_sz); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_TOOLBOX: @@ -921,14 +929,38 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, Mpi2ToolboxCleanRequest_t *toolbox_request = (Mpi2ToolboxCleanRequest_t *)mpi_request; - if (toolbox_request->Tool == MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL) { + if ((toolbox_request->Tool == MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL) + || (toolbox_request->Tool == + MPI26_TOOLBOX_BACKEND_PCIE_LANE_MARGIN)) ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, data_in_sz); - } else { + else if (toolbox_request->Tool == + MPI2_TOOLBOX_MEMORY_MOVE_TOOL) { + Mpi2ToolboxMemMoveRequest_t *mem_move_request = + (Mpi2ToolboxMemMoveRequest_t *)request; + Mpi2SGESimple64_t tmp, *src = NULL, *dst = NULL; + + ioc->build_sg_mpi(ioc, psge, data_out_dma, + data_out_sz, data_in_dma, data_in_sz); + if (data_out_sz && !data_in_sz) { + dst = + (Mpi2SGESimple64_t *)&mem_move_request->SGL; + src = (void *)dst + ioc->sge_size; + + memcpy(&tmp, src, ioc->sge_size); + memcpy(src, dst, ioc->sge_size); + memcpy(dst, &tmp, ioc->sge_size); + } + if (ioc->logging_level & MPT_DEBUG_TM) { + ioc_info(ioc, + "Mpi2ToolboxMemMoveRequest_t request msg\n"); + _debug_dump_mf(mem_move_request, + ioc->request_sz/4); + } + } else ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, - data_in_dma, data_in_sz); - } - mpt3sas_base_put_smid_default(ioc, smid); + data_in_dma, data_in_sz); + ioc->put_smid_default(ioc, smid); break; } case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: @@ -948,7 +980,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, default: ioc->build_sg_mpi(ioc, psge, data_out_dma, data_out_sz, data_in_dma, data_in_sz); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); break; } @@ -1047,12 +1079,14 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, mpt3sas_halt_firmware(ioc); pcie_device = mpt3sas_get_pdev_by_handle(ioc, le16_to_cpu(mpi_request->FunctionDependent1)); - if (pcie_device && (!ioc->tm_custom_handling)) + if (pcie_device && (!ioc->tm_custom_handling) && + (!(mpt3sas_scsih_is_pcie_scsi_device( + pcie_device->device_info)))) mpt3sas_scsih_issue_locked_tm(ioc, le16_to_cpu(mpi_request->FunctionDependent1), 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 0, pcie_device->reset_timeout, - tr_method); + MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE); else mpt3sas_scsih_issue_locked_tm(ioc, le16_to_cpu(mpi_request->FunctionDependent1), @@ -1576,7 +1610,7 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, cpu_to_le32(ioc->product_specific[buffer_type][i]); init_completion(&ioc->ctl_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -1903,7 +1937,7 @@ mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, mpi_request->VP_ID = 0; init_completion(&ioc->ctl_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -2151,7 +2185,7 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg) mpi_request->VP_ID = 0; init_completion(&ioc->ctl_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->ctl_cmds.done, MPT3_IOCTL_DEFAULT_TIMEOUT*HZ); @@ -2319,6 +2353,10 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, break; } + if (karg.hdr.ioc_number != ioctl_header.ioc_number) { + ret = -EINVAL; + break; + } if (_IOC_SIZE(cmd) == sizeof(struct mpt3_ioctl_command)) { uarg = arg; ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf); @@ -2453,7 +2491,7 @@ _ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) /* scsi host attributes */ /** - * _ctl_version_fw_show - firmware version + * version_fw_show - firmware version * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2461,7 +2499,7 @@ _ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_version_fw_show(struct device *cdev, struct device_attribute *attr, +version_fw_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2473,10 +2511,10 @@ _ctl_version_fw_show(struct device *cdev, struct device_attribute *attr, (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, ioc->facts.FWVersion.Word & 0x000000FF); } -static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL); +static DEVICE_ATTR_RO(version_fw); /** - * _ctl_version_bios_show - bios version + * version_bios_show - bios version * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2484,7 +2522,7 @@ static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_version_bios_show(struct device *cdev, struct device_attribute *attr, +version_bios_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2498,10 +2536,10 @@ _ctl_version_bios_show(struct device *cdev, struct device_attribute *attr, (version & 0x0000FF00) >> 8, version & 0x000000FF); } -static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL); +static DEVICE_ATTR_RO(version_bios); /** - * _ctl_version_mpi_show - MPI (message passing interface) version + * version_mpi_show - MPI (message passing interface) version * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2509,7 +2547,7 @@ static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr, +version_mpi_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2518,10 +2556,10 @@ _ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%03x.%02x\n", ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8); } -static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL); +static DEVICE_ATTR_RO(version_mpi); /** - * _ctl_version_product_show - product name + * version_product_show - product name * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2529,7 +2567,7 @@ static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_version_product_show(struct device *cdev, struct device_attribute *attr, +version_product_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2537,10 +2575,10 @@ _ctl_version_product_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName); } -static DEVICE_ATTR(version_product, S_IRUGO, _ctl_version_product_show, NULL); +static DEVICE_ATTR_RO(version_product); /** - * _ctl_version_nvdata_persistent_show - ndvata persistent version + * version_nvdata_persistent_show - ndvata persistent version * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2548,7 +2586,7 @@ static DEVICE_ATTR(version_product, S_IRUGO, _ctl_version_product_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_version_nvdata_persistent_show(struct device *cdev, +version_nvdata_persistent_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2557,11 +2595,10 @@ _ctl_version_nvdata_persistent_show(struct device *cdev, return snprintf(buf, PAGE_SIZE, "%08xh\n", le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); } -static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, - _ctl_version_nvdata_persistent_show, NULL); +static DEVICE_ATTR_RO(version_nvdata_persistent); /** - * _ctl_version_nvdata_default_show - nvdata default version + * version_nvdata_default_show - nvdata default version * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2569,7 +2606,7 @@ static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_version_nvdata_default_show(struct device *cdev, struct device_attribute +version_nvdata_default_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2578,11 +2615,10 @@ _ctl_version_nvdata_default_show(struct device *cdev, struct device_attribute return snprintf(buf, PAGE_SIZE, "%08xh\n", le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); } -static DEVICE_ATTR(version_nvdata_default, S_IRUGO, - _ctl_version_nvdata_default_show, NULL); +static DEVICE_ATTR_RO(version_nvdata_default); /** - * _ctl_board_name_show - board name + * board_name_show - board name * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2590,7 +2626,7 @@ static DEVICE_ATTR(version_nvdata_default, S_IRUGO, * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_board_name_show(struct device *cdev, struct device_attribute *attr, +board_name_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2598,10 +2634,10 @@ _ctl_board_name_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName); } -static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL); +static DEVICE_ATTR_RO(board_name); /** - * _ctl_board_assembly_show - board assembly name + * board_assembly_show - board assembly name * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2609,7 +2645,7 @@ static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr, +board_assembly_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2617,10 +2653,10 @@ _ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly); } -static DEVICE_ATTR(board_assembly, S_IRUGO, _ctl_board_assembly_show, NULL); +static DEVICE_ATTR_RO(board_assembly); /** - * _ctl_board_tracer_show - board tracer number + * board_tracer_show - board tracer number * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2628,7 +2664,7 @@ static DEVICE_ATTR(board_assembly, S_IRUGO, _ctl_board_assembly_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr, +board_tracer_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2636,10 +2672,10 @@ _ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber); } -static DEVICE_ATTR(board_tracer, S_IRUGO, _ctl_board_tracer_show, NULL); +static DEVICE_ATTR_RO(board_tracer); /** - * _ctl_io_delay_show - io missing delay + * io_delay_show - io missing delay * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2650,7 +2686,7 @@ static DEVICE_ATTR(board_tracer, S_IRUGO, _ctl_board_tracer_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_io_delay_show(struct device *cdev, struct device_attribute *attr, +io_delay_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2658,10 +2694,10 @@ _ctl_io_delay_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay); } -static DEVICE_ATTR(io_delay, S_IRUGO, _ctl_io_delay_show, NULL); +static DEVICE_ATTR_RO(io_delay); /** - * _ctl_device_delay_show - device missing delay + * device_delay_show - device missing delay * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2672,7 +2708,7 @@ static DEVICE_ATTR(io_delay, S_IRUGO, _ctl_io_delay_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_device_delay_show(struct device *cdev, struct device_attribute *attr, +device_delay_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2680,10 +2716,10 @@ _ctl_device_delay_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay); } -static DEVICE_ATTR(device_delay, S_IRUGO, _ctl_device_delay_show, NULL); +static DEVICE_ATTR_RO(device_delay); /** - * _ctl_fw_queue_depth_show - global credits + * fw_queue_depth_show - global credits * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2693,7 +2729,7 @@ static DEVICE_ATTR(device_delay, S_IRUGO, _ctl_device_delay_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr, +fw_queue_depth_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2701,10 +2737,10 @@ _ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit); } -static DEVICE_ATTR(fw_queue_depth, S_IRUGO, _ctl_fw_queue_depth_show, NULL); +static DEVICE_ATTR_RO(fw_queue_depth); /** - * _ctl_sas_address_show - sas address + * sas_address_show - sas address * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2714,7 +2750,7 @@ static DEVICE_ATTR(fw_queue_depth, S_IRUGO, _ctl_fw_queue_depth_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr, +host_sas_address_show(struct device *cdev, struct device_attribute *attr, char *buf) { @@ -2724,11 +2760,10 @@ _ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "0x%016llx\n", (unsigned long long)ioc->sas_hba.sas_address); } -static DEVICE_ATTR(host_sas_address, S_IRUGO, - _ctl_host_sas_address_show, NULL); +static DEVICE_ATTR_RO(host_sas_address); /** - * _ctl_logging_level_show - logging level + * logging_level_show - logging level * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2736,7 +2771,7 @@ static DEVICE_ATTR(host_sas_address, S_IRUGO, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_logging_level_show(struct device *cdev, struct device_attribute *attr, +logging_level_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2745,7 +2780,7 @@ _ctl_logging_level_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level); } static ssize_t -_ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, +logging_level_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2760,11 +2795,10 @@ _ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, ioc->logging_level); return strlen(buf); } -static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show, - _ctl_logging_level_store); +static DEVICE_ATTR_RW(logging_level); /** - * _ctl_fwfault_debug_show - show/store fwfault_debug + * fwfault_debug_show - show/store fwfault_debug * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2773,7 +2807,7 @@ static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, _ctl_logging_level_show, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_fwfault_debug_show(struct device *cdev, struct device_attribute *attr, +fwfault_debug_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2782,7 +2816,7 @@ _ctl_fwfault_debug_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug); } static ssize_t -_ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr, +fwfault_debug_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2797,11 +2831,10 @@ _ctl_fwfault_debug_store(struct device *cdev, struct device_attribute *attr, ioc->fwfault_debug); return strlen(buf); } -static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, - _ctl_fwfault_debug_show, _ctl_fwfault_debug_store); +static DEVICE_ATTR_RW(fwfault_debug); /** - * _ctl_ioc_reset_count_show - ioc reset count + * ioc_reset_count_show - ioc reset count * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2811,7 +2844,7 @@ static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, +ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2819,10 +2852,10 @@ _ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "%d\n", ioc->ioc_reset_count); } -static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL); +static DEVICE_ATTR_RO(ioc_reset_count); /** - * _ctl_ioc_reply_queue_count_show - number of reply queues + * reply_queue_count_show - number of reply queues * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2832,7 +2865,7 @@ static DEVICE_ATTR(ioc_reset_count, S_IRUGO, _ctl_ioc_reset_count_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_ioc_reply_queue_count_show(struct device *cdev, +reply_queue_count_show(struct device *cdev, struct device_attribute *attr, char *buf) { u8 reply_queue_count; @@ -2847,11 +2880,10 @@ _ctl_ioc_reply_queue_count_show(struct device *cdev, return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count); } -static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show, - NULL); +static DEVICE_ATTR_RO(reply_queue_count); /** - * _ctl_BRM_status_show - Backup Rail Monitor Status + * BRM_status_show - Backup Rail Monitor Status * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2861,7 +2893,7 @@ static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show, * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, +BRM_status_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2923,7 +2955,7 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, mutex_unlock(&ioc->pci_access_mutex); return rc; } -static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL); +static DEVICE_ATTR_RO(BRM_status); struct DIAG_BUFFER_START { __le32 Size; @@ -2936,7 +2968,7 @@ struct DIAG_BUFFER_START { }; /** - * _ctl_host_trace_buffer_size_show - host buffer size (trace only) + * host_trace_buffer_size_show - host buffer size (trace only) * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2944,7 +2976,7 @@ struct DIAG_BUFFER_START { * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_host_trace_buffer_size_show(struct device *cdev, +host_trace_buffer_size_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -2976,11 +3008,10 @@ _ctl_host_trace_buffer_size_show(struct device *cdev, ioc->ring_buffer_sz = size; return snprintf(buf, PAGE_SIZE, "%d\n", size); } -static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO, - _ctl_host_trace_buffer_size_show, NULL); +static DEVICE_ATTR_RO(host_trace_buffer_size); /** - * _ctl_host_trace_buffer_show - firmware ring buffer (trace only) + * host_trace_buffer_show - firmware ring buffer (trace only) * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -2992,7 +3023,7 @@ static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO, * offset to the same attribute, it will move the pointer. */ static ssize_t -_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, +host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3024,7 +3055,7 @@ _ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, } static ssize_t -_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, +host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3037,14 +3068,13 @@ _ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, ioc->ring_buffer_offset = val; return strlen(buf); } -static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR, - _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store); +static DEVICE_ATTR_RW(host_trace_buffer); /*****************************************/ /** - * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only) + * host_trace_buffer_enable_show - firmware ring buffer (trace only) * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3054,7 +3084,7 @@ static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR, * This is a mechnism to post/release host_trace_buffers */ static ssize_t -_ctl_host_trace_buffer_enable_show(struct device *cdev, +host_trace_buffer_enable_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3072,7 +3102,7 @@ _ctl_host_trace_buffer_enable_show(struct device *cdev, } static ssize_t -_ctl_host_trace_buffer_enable_store(struct device *cdev, +host_trace_buffer_enable_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3122,14 +3152,12 @@ _ctl_host_trace_buffer_enable_store(struct device *cdev, out: return strlen(buf); } -static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR, - _ctl_host_trace_buffer_enable_show, - _ctl_host_trace_buffer_enable_store); +static DEVICE_ATTR_RW(host_trace_buffer_enable); /*********** diagnostic trigger suppport *********************************/ /** - * _ctl_diag_trigger_master_show - show the diag_trigger_master attribute + * diag_trigger_master_show - show the diag_trigger_master attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3137,7 +3165,7 @@ static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_master_show(struct device *cdev, +diag_trigger_master_show(struct device *cdev, struct device_attribute *attr, char *buf) { @@ -3154,7 +3182,7 @@ _ctl_diag_trigger_master_show(struct device *cdev, } /** - * _ctl_diag_trigger_master_store - store the diag_trigger_master attribute + * diag_trigger_master_store - store the diag_trigger_master attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3163,7 +3191,7 @@ _ctl_diag_trigger_master_show(struct device *cdev, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_master_store(struct device *cdev, +diag_trigger_master_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { @@ -3182,12 +3210,11 @@ _ctl_diag_trigger_master_store(struct device *cdev, spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); return rc; } -static DEVICE_ATTR(diag_trigger_master, S_IRUGO | S_IWUSR, - _ctl_diag_trigger_master_show, _ctl_diag_trigger_master_store); +static DEVICE_ATTR_RW(diag_trigger_master); /** - * _ctl_diag_trigger_event_show - show the diag_trigger_event attribute + * diag_trigger_event_show - show the diag_trigger_event attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3195,7 +3222,7 @@ static DEVICE_ATTR(diag_trigger_master, S_IRUGO | S_IWUSR, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_event_show(struct device *cdev, +diag_trigger_event_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3211,7 +3238,7 @@ _ctl_diag_trigger_event_show(struct device *cdev, } /** - * _ctl_diag_trigger_event_store - store the diag_trigger_event attribute + * diag_trigger_event_store - store the diag_trigger_event attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3220,7 +3247,7 @@ _ctl_diag_trigger_event_show(struct device *cdev, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_event_store(struct device *cdev, +diag_trigger_event_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { @@ -3239,12 +3266,11 @@ _ctl_diag_trigger_event_store(struct device *cdev, spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); return sz; } -static DEVICE_ATTR(diag_trigger_event, S_IRUGO | S_IWUSR, - _ctl_diag_trigger_event_show, _ctl_diag_trigger_event_store); +static DEVICE_ATTR_RW(diag_trigger_event); /** - * _ctl_diag_trigger_scsi_show - show the diag_trigger_scsi attribute + * diag_trigger_scsi_show - show the diag_trigger_scsi attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3252,7 +3278,7 @@ static DEVICE_ATTR(diag_trigger_event, S_IRUGO | S_IWUSR, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_scsi_show(struct device *cdev, +diag_trigger_scsi_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3268,7 +3294,7 @@ _ctl_diag_trigger_scsi_show(struct device *cdev, } /** - * _ctl_diag_trigger_scsi_store - store the diag_trigger_scsi attribute + * diag_trigger_scsi_store - store the diag_trigger_scsi attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3277,7 +3303,7 @@ _ctl_diag_trigger_scsi_show(struct device *cdev, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_scsi_store(struct device *cdev, +diag_trigger_scsi_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3286,21 +3312,19 @@ _ctl_diag_trigger_scsi_store(struct device *cdev, ssize_t sz; spin_lock_irqsave(&ioc->diag_trigger_lock, flags); - sz = min(sizeof(struct SL_WH_SCSI_TRIGGERS_T), count); - memset(&ioc->diag_trigger_scsi, 0, - sizeof(struct SL_WH_EVENT_TRIGGERS_T)); + sz = min(sizeof(ioc->diag_trigger_scsi), count); + memset(&ioc->diag_trigger_scsi, 0, sizeof(ioc->diag_trigger_scsi)); memcpy(&ioc->diag_trigger_scsi, buf, sz); if (ioc->diag_trigger_scsi.ValidEntries > NUM_VALID_ENTRIES) ioc->diag_trigger_scsi.ValidEntries = NUM_VALID_ENTRIES; spin_unlock_irqrestore(&ioc->diag_trigger_lock, flags); return sz; } -static DEVICE_ATTR(diag_trigger_scsi, S_IRUGO | S_IWUSR, - _ctl_diag_trigger_scsi_show, _ctl_diag_trigger_scsi_store); +static DEVICE_ATTR_RW(diag_trigger_scsi); /** - * _ctl_diag_trigger_scsi_show - show the diag_trigger_mpi attribute + * diag_trigger_scsi_show - show the diag_trigger_mpi attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3308,7 +3332,7 @@ static DEVICE_ATTR(diag_trigger_scsi, S_IRUGO | S_IWUSR, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_mpi_show(struct device *cdev, +diag_trigger_mpi_show(struct device *cdev, struct device_attribute *attr, char *buf) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3324,7 +3348,7 @@ _ctl_diag_trigger_mpi_show(struct device *cdev, } /** - * _ctl_diag_trigger_mpi_store - store the diag_trigger_mpi attribute + * diag_trigger_mpi_store - store the diag_trigger_mpi attribute * @cdev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3333,7 +3357,7 @@ _ctl_diag_trigger_mpi_show(struct device *cdev, * A sysfs 'read/write' shost attribute. */ static ssize_t -_ctl_diag_trigger_mpi_store(struct device *cdev, +diag_trigger_mpi_store(struct device *cdev, struct device_attribute *attr, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); @@ -3352,13 +3376,131 @@ _ctl_diag_trigger_mpi_store(struct device *cdev, return sz; } -static DEVICE_ATTR(diag_trigger_mpi, S_IRUGO | S_IWUSR, - _ctl_diag_trigger_mpi_show, _ctl_diag_trigger_mpi_store); +static DEVICE_ATTR_RW(diag_trigger_mpi); /*********** diagnostic trigger suppport *** END ****************************/ /*****************************************/ +/** + * drv_support_bitmap_show - driver supported feature bitmap + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +drv_support_bitmap_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "0x%08x\n", ioc->drv_support_bitmap); +} +static DEVICE_ATTR_RO(drv_support_bitmap); + +/** + * enable_sdev_max_qd_show - display whether sdev max qd is enabled/disabled + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs read/write shost attribute. This attribute is used to set the + * targets queue depth to HBA IO queue depth if this attribute is enabled. + */ +static ssize_t +enable_sdev_max_qd_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%d\n", ioc->enable_sdev_max_qd); +} + +/** + * enable_sdev_max_qd_store - Enable/disable sdev max qd + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * A sysfs read/write shost attribute. This attribute is used to set the + * targets queue depth to HBA IO queue depth if this attribute is enabled. + * If this attribute is disabled then targets will have corresponding default + * queue depth. + */ +static ssize_t +enable_sdev_max_qd_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); + struct MPT3SAS_DEVICE *sas_device_priv_data; + struct MPT3SAS_TARGET *sas_target_priv_data; + int val = 0; + struct scsi_device *sdev; + struct _raid_device *raid_device; + int qdepth; + + if (kstrtoint(buf, 0, &val) != 0) + return -EINVAL; + + switch (val) { + case 0: + ioc->enable_sdev_max_qd = 0; + shost_for_each_device(sdev, ioc->shost) { + sas_device_priv_data = sdev->hostdata; + if (!sas_device_priv_data) + continue; + sas_target_priv_data = sas_device_priv_data->sas_target; + if (!sas_target_priv_data) + continue; + + if (sas_target_priv_data->flags & + MPT_TARGET_FLAGS_VOLUME) { + raid_device = + mpt3sas_raid_device_find_by_handle(ioc, + sas_target_priv_data->handle); + + switch (raid_device->volume_type) { + case MPI2_RAID_VOL_TYPE_RAID0: + if (raid_device->device_info & + MPI2_SAS_DEVICE_INFO_SSP_TARGET) + qdepth = + MPT3SAS_SAS_QUEUE_DEPTH; + else + qdepth = + MPT3SAS_SATA_QUEUE_DEPTH; + break; + case MPI2_RAID_VOL_TYPE_RAID1E: + case MPI2_RAID_VOL_TYPE_RAID1: + case MPI2_RAID_VOL_TYPE_RAID10: + case MPI2_RAID_VOL_TYPE_UNKNOWN: + default: + qdepth = MPT3SAS_RAID_QUEUE_DEPTH; + } + } else if (sas_target_priv_data->flags & + MPT_TARGET_FLAGS_PCIE_DEVICE) + qdepth = MPT3SAS_NVME_QUEUE_DEPTH; + else + qdepth = MPT3SAS_SAS_QUEUE_DEPTH; + + mpt3sas_scsih_change_queue_depth(sdev, qdepth); + } + break; + case 1: + ioc->enable_sdev_max_qd = 1; + shost_for_each_device(sdev, ioc->shost) + mpt3sas_scsih_change_queue_depth(sdev, + shost->can_queue); + break; + default: + return -EINVAL; + } + + return strlen(buf); +} +static DEVICE_ATTR_RW(enable_sdev_max_qd); + struct device_attribute *mpt3sas_host_attrs[] = { &dev_attr_version_fw, &dev_attr_version_bios, @@ -3384,14 +3526,16 @@ struct device_attribute *mpt3sas_host_attrs[] = { &dev_attr_diag_trigger_event, &dev_attr_diag_trigger_scsi, &dev_attr_diag_trigger_mpi, + &dev_attr_drv_support_bitmap, &dev_attr_BRM_status, + &dev_attr_enable_sdev_max_qd, NULL, }; /* device attributes */ /** - * _ctl_device_sas_address_show - sas address + * sas_address_show - sas address * @dev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3401,7 +3545,7 @@ struct device_attribute *mpt3sas_host_attrs[] = { * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr, +sas_address_show(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); @@ -3410,10 +3554,10 @@ _ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "0x%016llx\n", (unsigned long long)sas_device_priv_data->sas_target->sas_address); } -static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL); +static DEVICE_ATTR_RO(sas_address); /** - * _ctl_device_handle_show - device handle + * sas_device_handle_show - device handle * @dev: pointer to embedded class device * @attr: ? * @buf: the buffer returned @@ -3423,7 +3567,7 @@ static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL); * A sysfs 'read-only' shost attribute. */ static ssize_t -_ctl_device_handle_show(struct device *dev, struct device_attribute *attr, +sas_device_handle_show(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); @@ -3432,10 +3576,10 @@ _ctl_device_handle_show(struct device *dev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, "0x%04x\n", sas_device_priv_data->sas_target->handle); } -static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL); +static DEVICE_ATTR_RO(sas_device_handle); /** - * _ctl_device_ncq_io_prio_show - send prioritized io commands to device + * sas_ncq_io_prio_show - send prioritized io commands to device * @dev: pointer to embedded device * @attr: ? * @buf: the buffer returned @@ -3443,7 +3587,7 @@ static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL); * A sysfs 'read/write' sdev attribute, only works with SATA */ static ssize_t -_ctl_device_ncq_prio_enable_show(struct device *dev, +sas_ncq_prio_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); @@ -3454,7 +3598,7 @@ _ctl_device_ncq_prio_enable_show(struct device *dev, } static ssize_t -_ctl_device_ncq_prio_enable_store(struct device *dev, +sas_ncq_prio_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -3471,9 +3615,7 @@ _ctl_device_ncq_prio_enable_store(struct device *dev, sas_device_priv_data->ncq_prio_enable = ncq_prio_enable; return strlen(buf); } -static DEVICE_ATTR(sas_ncq_prio_enable, S_IRUGO | S_IWUSR, - _ctl_device_ncq_prio_enable_show, - _ctl_device_ncq_prio_enable_store); +static DEVICE_ATTR_RW(sas_ncq_prio_enable); struct device_attribute *mpt3sas_dev_attrs[] = { &dev_attr_sas_address, diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 1ccfbc7eebe0..c8e512ba6d39 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -51,7 +51,6 @@ #include <linux/workqueue.h> #include <linux/delay.h> #include <linux/pci.h> -#include <linux/pci-aspm.h> #include <linux/interrupt.h> #include <linux/aer.h> #include <linux/raid_class.h> @@ -113,22 +112,22 @@ MODULE_PARM_DESC(logging_level, static ushort max_sectors = 0xFFFF; -module_param(max_sectors, ushort, 0); +module_param(max_sectors, ushort, 0444); MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767 default=32767"); static int missing_delay[2] = {-1, -1}; -module_param_array(missing_delay, int, NULL, 0); +module_param_array(missing_delay, int, NULL, 0444); MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay"); /* scsi-mid layer global parmeter is max_report_luns, which is 511 */ #define MPT3SAS_MAX_LUN (16895) static u64 max_lun = MPT3SAS_MAX_LUN; -module_param(max_lun, ullong, 0); +module_param(max_lun, ullong, 0444); MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); static ushort hbas_to_enumerate; -module_param(hbas_to_enumerate, ushort, 0); +module_param(hbas_to_enumerate, ushort, 0444); MODULE_PARM_DESC(hbas_to_enumerate, " 0 - enumerates both SAS 2.0 & SAS 3.0 generation HBAs\n \ 1 - enumerates only SAS 2.0 generation HBAs\n \ @@ -142,19 +141,23 @@ MODULE_PARM_DESC(hbas_to_enumerate, * Either bit can be set, or both */ static int diag_buffer_enable = -1; -module_param(diag_buffer_enable, int, 0); +module_param(diag_buffer_enable, int, 0444); MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers (TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); static int disable_discovery = -1; -module_param(disable_discovery, int, 0); +module_param(disable_discovery, int, 0444); MODULE_PARM_DESC(disable_discovery, " disable discovery "); /* permit overriding the host protection capabilities mask (EEDP/T10 PI) */ static int prot_mask = -1; -module_param(prot_mask, int, 0); +module_param(prot_mask, int, 0444); MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 "); +static bool enable_sdev_max_qd; +module_param(enable_sdev_max_qd, bool, 0444); +MODULE_PARM_DESC(enable_sdev_max_qd, + "Enable sdev max qd as can_queue, def=disabled(0)"); /* raid transport support */ static struct raid_template *mpt3sas_raid_template; @@ -1152,6 +1155,11 @@ _scsih_pcie_device_add(struct MPT3SAS_ADAPTER *ioc, list_add_tail(&pcie_device->list, &ioc->pcie_device_list); spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + if (pcie_device->access_status == + MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED) { + clear_bit(pcie_device->handle, ioc->pend_os_device_add); + return; + } if (scsi_add_device(ioc->shost, PCIE_CHANNEL, pcie_device->id, 0)) { _scsih_pcie_device_remove(ioc, pcie_device); } else if (!pcie_device->starget) { @@ -1196,7 +1204,9 @@ _scsih_pcie_device_init_add(struct MPT3SAS_ADAPTER *ioc, spin_lock_irqsave(&ioc->pcie_device_lock, flags); pcie_device_get(pcie_device); list_add_tail(&pcie_device->list, &ioc->pcie_device_init_list); - _scsih_determine_boot_device(ioc, pcie_device, PCIE_CHANNEL); + if (pcie_device->access_status != + MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED) + _scsih_determine_boot_device(ioc, pcie_device, PCIE_CHANNEL); spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); } /** @@ -1433,17 +1443,20 @@ _scsih_is_end_device(u32 device_info) } /** - * _scsih_is_nvme_device - determines if device is an nvme device + * _scsih_is_nvme_pciescsi_device - determines if + * device is an pcie nvme/scsi device * @device_info: bitfield providing information about the device. * Context: none * - * Return: 1 if nvme device. + * Returns 1 if device is pcie device type nvme/scsi. */ static int -_scsih_is_nvme_device(u32 device_info) +_scsih_is_nvme_pciescsi_device(u32 device_info) { - if ((device_info & MPI26_PCIE_DEVINFO_MASK_DEVICE_TYPE) - == MPI26_PCIE_DEVINFO_NVME) + if (((device_info & MPI26_PCIE_DEVINFO_MASK_DEVICE_TYPE) + == MPI26_PCIE_DEVINFO_NVME) || + ((device_info & MPI26_PCIE_DEVINFO_MASK_DEVICE_TYPE) + == MPI26_PCIE_DEVINFO_SCSI)) return 1; else return 0; @@ -1509,7 +1522,13 @@ scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) max_depth = shost->can_queue; - /* limit max device queue for SATA to 32 */ + /* + * limit max device queue for SATA to 32 if enable_sdev_max_qd + * is disabled. + */ + if (ioc->enable_sdev_max_qd) + goto not_sata; + sas_device_priv_data = sdev->hostdata; if (!sas_device_priv_data) goto not_sata; @@ -1539,6 +1558,25 @@ scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) } /** + * mpt3sas_scsih_change_queue_depth - setting device queue depth + * @sdev: scsi device struct + * @qdepth: requested queue depth + * + * Returns nothing. + */ +void +mpt3sas_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) +{ + struct Scsi_Host *shost = sdev->host; + struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); + + if (ioc->enable_sdev_max_qd) + qdepth = shost->can_queue; + + scsih_change_queue_depth(sdev, qdepth); +} + +/** * scsih_target_alloc - target add routine * @starget: scsi target struct * @@ -2296,7 +2334,7 @@ scsih_slave_configure(struct scsi_device *sdev) MPT3SAS_RAID_MAX_SECTORS); } - scsih_change_queue_depth(sdev, qdepth); + mpt3sas_scsih_change_queue_depth(sdev, qdepth); /* raid transport support */ if (!ioc->is_warpdrive) @@ -2360,7 +2398,7 @@ scsih_slave_configure(struct scsi_device *sdev) pcie_device_put(pcie_device); spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); - scsih_change_queue_depth(sdev, qdepth); + mpt3sas_scsih_change_queue_depth(sdev, qdepth); /* Enable QUEUE_FLAG_NOMERGES flag, so that IOs won't be ** merged and can eliminate holes created during merging ** operation. @@ -2420,7 +2458,7 @@ scsih_slave_configure(struct scsi_device *sdev) _scsih_display_sata_capabilities(ioc, handle, sdev); - scsih_change_queue_depth(sdev, qdepth); + mpt3sas_scsih_change_queue_depth(sdev, qdepth); if (ssp_target) { sas_read_port_mode_page(sdev); @@ -2685,7 +2723,7 @@ mpt3sas_scsih_issue_tm(struct MPT3SAS_ADAPTER *ioc, u16 handle, u64 lun, int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN); mpt3sas_scsih_set_tm_flag(ioc, handle); init_completion(&ioc->tm_cmds.done); - mpt3sas_base_put_smid_hi_priority(ioc, smid, msix_task); + ioc->put_smid_hi_priority(ioc, smid, msix_task); wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); if (!(ioc->tm_cmds.status & MPT3_CMD_COMPLETE)) { if (mpt3sas_base_check_cmd_timeout(ioc, @@ -2872,7 +2910,8 @@ scsih_abort(struct scsi_cmnd *scmd) handle = sas_device_priv_data->sas_target->handle; pcie_device = mpt3sas_get_pdev_by_handle(ioc, handle); - if (pcie_device && (!ioc->tm_custom_handling)) + if (pcie_device && (!ioc->tm_custom_handling) && + (!(mpt3sas_scsih_is_pcie_scsi_device(pcie_device->device_info)))) timeout = ioc->nvme_abort_timeout; r = mpt3sas_scsih_issue_locked_tm(ioc, handle, scmd->device->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, @@ -2943,11 +2982,13 @@ scsih_dev_reset(struct scsi_cmnd *scmd) pcie_device = mpt3sas_get_pdev_by_handle(ioc, handle); - if (pcie_device && (!ioc->tm_custom_handling)) { + if (pcie_device && (!ioc->tm_custom_handling) && + (!(mpt3sas_scsih_is_pcie_scsi_device(pcie_device->device_info)))) { tr_timeout = pcie_device->reset_timeout; tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE; } else tr_method = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET; + r = mpt3sas_scsih_issue_locked_tm(ioc, handle, scmd->device->lun, MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 0, tr_timeout, tr_method); @@ -3020,7 +3061,8 @@ scsih_target_reset(struct scsi_cmnd *scmd) pcie_device = mpt3sas_get_pdev_by_handle(ioc, handle); - if (pcie_device && (!ioc->tm_custom_handling)) { + if (pcie_device && (!ioc->tm_custom_handling) && + (!(mpt3sas_scsih_is_pcie_scsi_device(pcie_device->device_info)))) { tr_timeout = pcie_device->reset_timeout; tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE; } else @@ -3598,7 +3640,9 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) sas_address = pcie_device->wwid; } spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); - if (pcie_device && (!ioc->tm_custom_handling)) + if (pcie_device && (!ioc->tm_custom_handling) && + (!(mpt3sas_scsih_is_pcie_scsi_device( + pcie_device->device_info)))) tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE; else @@ -3659,7 +3703,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; mpi_request->MsgFlags = tr_method; set_bit(handle, ioc->device_remove_in_progress); - mpt3sas_base_put_smid_hi_priority(ioc, smid, 0); + ioc->put_smid_hi_priority(ioc, smid, 0); mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL); out: @@ -3755,7 +3799,7 @@ _scsih_tm_tr_complete(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; mpi_request->DevHandle = mpi_request_tm->DevHandle; - mpt3sas_base_put_smid_default(ioc, smid_sas_ctrl); + ioc->put_smid_default(ioc, smid_sas_ctrl); return _scsih_check_for_pending_tm(ioc, smid); } @@ -3881,7 +3925,7 @@ _scsih_tm_tr_volume_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; mpi_request->DevHandle = cpu_to_le16(handle); mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; - mpt3sas_base_put_smid_hi_priority(ioc, smid, 0); + ioc->put_smid_hi_priority(ioc, smid, 0); } /** @@ -3970,7 +4014,7 @@ _scsih_issue_delayed_event_ack(struct MPT3SAS_ADAPTER *ioc, u16 smid, U16 event, ack_request->EventContext = event_context; ack_request->VF_ID = 0; /* TODO */ ack_request->VP_ID = 0; - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); } /** @@ -4026,7 +4070,7 @@ _scsih_issue_delayed_sas_io_unit_ctrl(struct MPT3SAS_ADAPTER *ioc, mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; mpi_request->DevHandle = cpu_to_le16(handle); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); } /** @@ -4654,11 +4698,8 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) * since we're lockless at this point */ do { - if (test_bit(0, &sas_device_priv_data->ata_command_pending)) { - scmd->result = SAM_STAT_BUSY; - scmd->scsi_done(scmd); - return 0; - } + if (test_bit(0, &sas_device_priv_data->ata_command_pending)) + return SCSI_MLQUEUE_DEVICE_BUSY; } while (_scsih_set_satl_pending(scmd, true)); if (scmd->sc_data_direction == DMA_FROM_DEVICE) @@ -4734,12 +4775,12 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) { mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len | MPI25_SCSIIO_IOFLAGS_FAST_PATH); - mpt3sas_base_put_smid_fast_path(ioc, smid, handle); + ioc->put_smid_fast_path(ioc, smid, handle); } else ioc->put_smid_scsi_io(ioc, smid, le16_to_cpu(mpi_request->DevHandle)); } else - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); return 0; out: @@ -5210,6 +5251,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) ((ioc_status & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) { st->direct_io = 0; + st->scmd = scmd; memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); mpi_request->DevHandle = cpu_to_le16(sas_device_priv_data->sas_target->handle); @@ -6455,24 +6497,17 @@ _scsih_sas_device_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc, /** * _scsih_sas_device_status_change_event - handle device status change * @ioc: per adapter object - * @fw_event: The fw_event_work object + * @event_data: The fw event * Context: user. */ static void _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) + Mpi2EventDataSasDeviceStatusChange_t *event_data) { struct MPT3SAS_TARGET *target_priv_data; struct _sas_device *sas_device; u64 sas_address; unsigned long flags; - Mpi2EventDataSasDeviceStatusChange_t *event_data = - (Mpi2EventDataSasDeviceStatusChange_t *) - fw_event->event_data; - - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - _scsih_sas_device_status_change_event_debug(ioc, - event_data); /* In MPI Revision K (0xC), the internal device reset complete was * implemented, so avoid setting tm_busy flag for older firmware. @@ -6504,6 +6539,12 @@ _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc, else target_priv_data->tm_busy = 0; + if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + ioc_info(ioc, + "%s tm_busy flag for handle(0x%04x)\n", + (target_priv_data->tm_busy == 1) ? "Enable" : "Disable", + target_priv_data->handle); + out: if (sas_device) sas_device_put(sas_device); @@ -6538,6 +6579,11 @@ _scsih_check_pcie_access_status(struct MPT3SAS_ADAPTER *ioc, u64 wwid, break; case MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED: desc = "PCIe device blocked"; + ioc_info(ioc, + "Device with Access Status (%s): wwid(0x%016llx), " + "handle(0x%04x)\n ll only be added to the internal list", + desc, (u64)wwid, handle); + rc = 0; break; case MPI26_PCIEDEV0_ASTATUS_MEMORY_SPACE_ACCESS_FAILED: desc = "PCIe device mem space access failed"; @@ -6642,7 +6688,8 @@ _scsih_pcie_device_remove_from_sml(struct MPT3SAS_ADAPTER *ioc, pcie_device->enclosure_level, pcie_device->connector_name); - if (pcie_device->starget) + if (pcie_device->starget && (pcie_device->access_status != + MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED)) scsi_remove_target(&pcie_device->starget->dev); dewtprintk(ioc, ioc_info(ioc, "%s: exit: handle(0x%04x), wwid(0x%016llx)\n", @@ -6693,7 +6740,7 @@ _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) /* check if this is end device */ device_info = le32_to_cpu(pcie_device_pg0.DeviceInfo); - if (!(_scsih_is_nvme_device(device_info))) + if (!(_scsih_is_nvme_pciescsi_device(device_info))) return; wwid = le64_to_cpu(pcie_device_pg0.WWID); @@ -6708,6 +6755,7 @@ _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) if (unlikely(pcie_device->handle != handle)) { starget = pcie_device->starget; sas_target_priv_data = starget->hostdata; + pcie_device->access_status = pcie_device_pg0.AccessStatus; starget_printk(KERN_INFO, starget, "handle changed from(0x%04x) to (0x%04x)!!!\n", pcie_device->handle, handle); @@ -6802,7 +6850,8 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) pcie_device_pg0.AccessStatus)) return 0; - if (!(_scsih_is_nvme_device(le32_to_cpu(pcie_device_pg0.DeviceInfo)))) + if (!(_scsih_is_nvme_pciescsi_device(le32_to_cpu + (pcie_device_pg0.DeviceInfo)))) return 0; pcie_device = mpt3sas_get_pdev_by_wwid(ioc, wwid); @@ -6812,6 +6861,31 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) return 0; } + /* PCIe Device Page 2 contains read-only information about a + * specific NVMe device; therefore, this page is only + * valid for NVMe devices and skip for pcie devices of type scsi. + */ + if (!(mpt3sas_scsih_is_pcie_scsi_device( + le32_to_cpu(pcie_device_pg0.DeviceInfo)))) { + if (mpt3sas_config_get_pcie_device_pg2(ioc, &mpi_reply, + &pcie_device_pg2, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, + handle)) { + ioc_err(ioc, + "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + return 0; + } + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + ioc_err(ioc, + "failure at %s:%d/%s()!\n", __FILE__, + __LINE__, __func__); + return 0; + } + } + pcie_device = kzalloc(sizeof(struct _pcie_device), GFP_KERNEL); if (!pcie_device) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -6823,6 +6897,7 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) pcie_device->id = ioc->pcie_target_id++; pcie_device->channel = PCIE_CHANNEL; pcie_device->handle = handle; + pcie_device->access_status = pcie_device_pg0.AccessStatus; pcie_device->device_info = le32_to_cpu(pcie_device_pg0.DeviceInfo); pcie_device->wwid = wwid; pcie_device->port_num = pcie_device_pg0.PortNum; @@ -6854,27 +6929,16 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) le64_to_cpu(enclosure_dev->pg0.EnclosureLogicalID); } /* TODO -- Add device name once FW supports it */ - if (mpt3sas_config_get_pcie_device_pg2(ioc, &mpi_reply, - &pcie_device_pg2, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)) { - ioc_err(ioc, "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - kfree(pcie_device); - return 0; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - ioc_err(ioc, "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - kfree(pcie_device); - return 0; - } - pcie_device->nvme_mdts = - le32_to_cpu(pcie_device_pg2.MaximumDataTransferSize); - if (pcie_device_pg2.ControllerResetTO) - pcie_device->reset_timeout = - pcie_device_pg2.ControllerResetTO; - else + if (!(mpt3sas_scsih_is_pcie_scsi_device( + le32_to_cpu(pcie_device_pg0.DeviceInfo)))) { + pcie_device->nvme_mdts = + le32_to_cpu(pcie_device_pg2.MaximumDataTransferSize); + if (pcie_device_pg2.ControllerResetTO) + pcie_device->reset_timeout = + pcie_device_pg2.ControllerResetTO; + else + pcie_device->reset_timeout = 30; + } else pcie_device->reset_timeout = 30; if (ioc->wait_for_discovery_to_complete) @@ -7601,7 +7665,7 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num) handle, phys_disk_num)); init_completion(&ioc->scsih_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { @@ -8506,6 +8570,8 @@ _scsih_mark_responding_pcie_device(struct MPT3SAS_ADAPTER *ioc, if ((pcie_device->wwid == le64_to_cpu(pcie_device_pg0->WWID)) && (pcie_device->slot == le16_to_cpu( pcie_device_pg0->Slot))) { + pcie_device->access_status = + pcie_device_pg0->AccessStatus; pcie_device->responding = 1; starget = pcie_device->starget; if (starget && starget->hostdata) { @@ -8593,7 +8659,7 @@ _scsih_search_responding_pcie_devices(struct MPT3SAS_ADAPTER *ioc) } handle = le16_to_cpu(pcie_device_pg0.DevHandle); device_info = le32_to_cpu(pcie_device_pg0.DeviceInfo); - if (!(_scsih_is_nvme_device(device_info))) + if (!(_scsih_is_nvme_pciescsi_device(device_info))) continue; _scsih_mark_responding_pcie_device(ioc, &pcie_device_pg0); } @@ -9174,7 +9240,7 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) break; } handle = le16_to_cpu(pcie_device_pg0.DevHandle); - if (!(_scsih_is_nvme_device( + if (!(_scsih_is_nvme_pciescsi_device( le32_to_cpu(pcie_device_pg0.DeviceInfo)))) continue; pcie_device = mpt3sas_get_pdev_by_wwid(ioc, @@ -9307,7 +9373,10 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) _scsih_sas_topology_change_event(ioc, fw_event); break; case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: - _scsih_sas_device_status_change_event(ioc, fw_event); + if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + _scsih_sas_device_status_change_event_debug(ioc, + (Mpi2EventDataSasDeviceStatusChange_t *) + fw_event->event_data); break; case MPI2_EVENT_SAS_DISCOVERY: _scsih_sas_discovery_event(ioc, fw_event); @@ -9480,6 +9549,10 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, break; } case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: + _scsih_sas_device_status_change_event(ioc, + (Mpi2EventDataSasDeviceStatusChange_t *) + mpi_reply->EventData); + break; case MPI2_EVENT_IR_OPERATION_STATUS: case MPI2_EVENT_SAS_DISCOVERY: case MPI2_EVENT_SAS_DEVICE_DISCOVERY_ERROR: @@ -9633,7 +9706,7 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc) if (!ioc->hide_ir_msg) ioc_info(ioc, "IR shutdown (sending)\n"); init_completion(&ioc->scsih_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { @@ -9670,6 +9743,7 @@ static void scsih_remove(struct pci_dev *pdev) struct _pcie_device *pcie_device, *pcienext; struct workqueue_struct *wq; unsigned long flags; + Mpi2ConfigReply_t mpi_reply; ioc->remove_host = 1; @@ -9684,7 +9758,13 @@ static void scsih_remove(struct pci_dev *pdev) spin_unlock_irqrestore(&ioc->fw_event_lock, flags); if (wq) destroy_workqueue(wq); - + /* + * Copy back the unmodified ioc page1. so that on next driver load, + * current modified changes on ioc page1 won't take effect. + */ + if (ioc->is_aero_ioc) + mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, + &ioc->ioc_pg1_copy); /* release all the volumes */ _scsih_ir_shutdown(ioc); sas_remove_host(shost); @@ -9747,6 +9827,7 @@ scsih_shutdown(struct pci_dev *pdev) struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); struct workqueue_struct *wq; unsigned long flags; + Mpi2ConfigReply_t mpi_reply; ioc->remove_host = 1; @@ -9761,6 +9842,13 @@ scsih_shutdown(struct pci_dev *pdev) spin_unlock_irqrestore(&ioc->fw_event_lock, flags); if (wq) destroy_workqueue(wq); + /* + * Copy back the unmodified ioc page1 so that on next driver load, + * current modified changes on ioc page1 won't take effect. + */ + if (ioc->is_aero_ioc) + mpt3sas_config_set_ioc_pg1(ioc, &mpi_reply, + &ioc->ioc_pg1_copy); _scsih_ir_shutdown(ioc); mpt3sas_base_detach(ioc); @@ -10023,6 +10111,12 @@ _scsih_probe_pcie(struct MPT3SAS_ADAPTER *ioc) pcie_device_put(pcie_device); continue; } + if (pcie_device->access_status == + MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED) { + pcie_device_make_active(ioc, pcie_device); + pcie_device_put(pcie_device); + continue; + } rc = scsi_add_device(ioc->shost, PCIE_CHANNEL, pcie_device->id, 0); if (rc) { @@ -10222,6 +10316,7 @@ static struct scsi_host_template mpt3sas_driver_template = { .this_id = -1, .sg_tablesize = MPT3SAS_SG_DEPTH, .max_sectors = 32767, + .max_segment_size = 0xffffffff, .cmd_per_lun = 7, .shost_attrs = mpt3sas_host_attrs, .sdev_attrs = mpt3sas_dev_attrs, @@ -10436,6 +10531,13 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx; ioc->logging_level = logging_level; ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds; + /* + * Enable MEMORY MOVE support flag. + */ + ioc->drv_support_bitmap |= MPT_DRV_SUPPORT_BITMAP_MEMMOVE; + + ioc->enable_sdev_max_qd = enable_sdev_max_qd; + /* misc semaphores and spin locks */ mutex_init(&ioc->reset_in_progress_mutex); /* initializing pci_access_mutex lock */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index 60ae2d0feb2b..5324662751bf 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -367,7 +367,7 @@ _transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc, ioc_info(ioc, "report_manufacture - send to sas_addr(0x%016llx)\n", (u64)sas_address)); init_completion(&ioc->transport_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { @@ -1139,7 +1139,7 @@ _transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc, (u64)phy->identify.sas_address, phy->number)); init_completion(&ioc->transport_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { @@ -1434,7 +1434,7 @@ _transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc, (u64)phy->identify.sas_address, phy->number, phy_operation)); init_completion(&ioc->transport_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { @@ -1911,7 +1911,7 @@ _transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, ioc_info(ioc, "%s: sending smp request\n", __func__)); init_completion(&ioc->transport_cmds.done); - mpt3sas_base_put_smid_default(ioc, smid); + ioc->put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ); if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) { diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 6dcae0e50018..3e0b8ebe257f 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -1193,7 +1193,7 @@ static int mvs_dev_found_notify(struct domain_device *dev, int lock) mvi_device->dev_type = dev->dev_type; mvi_device->mvi_info = mvi; mvi_device->sas_device = dev; - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) { + if (parent_dev && dev_is_expander(parent_dev->dev_type)) { int phy_id; u8 phy_num = parent_dev->ex_dev.num_phys; struct ex_phy *phy; diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h index b7d7ec435487..519edc796691 100644 --- a/drivers/scsi/mvsas/mv_sas.h +++ b/drivers/scsi/mvsas/mv_sas.h @@ -50,9 +50,6 @@ extern struct mvs_info *tgt_mvi; extern const struct mvs_dispatch mvs_64xx_dispatch; extern const struct mvs_dispatch mvs_94xx_dispatch; -#define DEV_IS_EXPANDER(type) \ - ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE)) - #define bit(n) ((u64)1 << n) #define for_each_phy(__lseq_mask, __mc, __lseq) \ diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index 1fb6f6ca627e..8906aceda4c4 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -195,23 +195,22 @@ static int mvumi_make_sgl(struct mvumi_hba *mhba, struct scsi_cmnd *scmd, unsigned int sgnum = scsi_sg_count(scmd); dma_addr_t busaddr; - sg = scsi_sglist(scmd); - *sg_count = dma_map_sg(&mhba->pdev->dev, sg, sgnum, + *sg_count = dma_map_sg(&mhba->pdev->dev, scsi_sglist(scmd), sgnum, scmd->sc_data_direction); if (*sg_count > mhba->max_sge) { dev_err(&mhba->pdev->dev, "sg count[0x%x] is bigger than max sg[0x%x].\n", *sg_count, mhba->max_sge); - dma_unmap_sg(&mhba->pdev->dev, sg, sgnum, + dma_unmap_sg(&mhba->pdev->dev, scsi_sglist(scmd), sgnum, scmd->sc_data_direction); return -1; } - for (i = 0; i < *sg_count; i++) { - busaddr = sg_dma_address(&sg[i]); + scsi_for_each_sg(scmd, sg, *sg_count, i) { + busaddr = sg_dma_address(sg); m_sg->baseaddr_l = cpu_to_le32(lower_32_bits(busaddr)); m_sg->baseaddr_h = cpu_to_le32(upper_32_bits(busaddr)); m_sg->flags = 0; - sgd_setsz(mhba, m_sg, cpu_to_le32(sg_dma_len(&sg[i]))); + sgd_setsz(mhba, m_sg, cpu_to_le32(sg_dma_len(sg))); if ((i + 1) == *sg_count) m_sg->flags |= 1U << mhba->eot_flag; diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index e6a95498ac0d..e0b427fdf818 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -3910,11 +3910,14 @@ static void __init ncr_prepare_setting(struct ncb *np) np->scsi_mode = SMODE_HVD; break; } + /* fall through */ case 3: /* SYMBIOS controllers report HVD through GPIO3 */ if (INB(nc_gpreg) & 0x08) break; + /* fall through */ case 2: /* Set HVD unconditionally */ np->scsi_mode = SMODE_HVD; + /* fall through */ case 1: /* Trust previous settings for HVD */ if (np->sv_stest2 & 0x20) np->scsi_mode = SMODE_HVD; @@ -6714,6 +6717,7 @@ void ncr_int_sir (struct ncb *np) OUTL_DSP (scr_to_cpu(tp->lp[0]->jump_ccb[0])); return; } + /* fall through */ case SIR_RESEL_BAD_TARGET: /* Will send a TARGET RESET message */ case SIR_RESEL_BAD_LUN: /* Will send a TARGET RESET message */ case SIR_RESEL_BAD_I_T_L_Q: /* Will send an ABORT TAG message */ diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c deleted file mode 100644 index 815bb4097c1b..000000000000 --- a/drivers/scsi/osst.c +++ /dev/null @@ -1,6108 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying - file Documentation/scsi/st.txt for more information. - - History: - - OnStream SCSI Tape support (osst) cloned from st.c by - Willem Riede (osst@riede.org) Feb 2000 - Fixes ... Kurt Garloff <garloff@suse.de> Mar 2000 - - Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. - Contribution and ideas from several people including (in alphabetical - order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer, - Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale. - - Copyright 1992 - 2002 Kai Makisara / 2000 - 2006 Willem Riede - email osst@riede.org - - $Header: /cvsroot/osst/Driver/osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $ - - Microscopic alterations - Rik Ling, 2000/12/21 - Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara - Some small formal changes - aeb, 950809 -*/ - -static const char * cvsid = "$Id: osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $"; -static const char * osst_version = "0.99.4"; - -/* The "failure to reconnect" firmware bug */ -#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/ -#define OSST_FW_NEED_POLL_MAX 10704 /*(108D)*/ -#define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7) - -#include <linux/module.h> - -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/sched/signal.h> -#include <linux/proc_fs.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/mtio.h> -#include <linux/ioctl.h> -#include <linux/fcntl.h> -#include <linux/spinlock.h> -#include <linux/vmalloc.h> -#include <linux/blkdev.h> -#include <linux/moduleparam.h> -#include <linux/delay.h> -#include <linux/jiffies.h> -#include <linux/mutex.h> -#include <linux/uaccess.h> -#include <asm/dma.h> - -/* The driver prints some debugging information on the console if DEBUG - is defined and non-zero. */ -#define DEBUG 0 - -/* The message level for the debug messages is currently set to KERN_NOTICE - so that people can easily see the messages. Later when the debugging messages - in the drivers are more widely classified, this may be changed to KERN_DEBUG. */ -#define OSST_DEB_MSG KERN_NOTICE - -#include <scsi/scsi.h> -#include <scsi/scsi_dbg.h> -#include <scsi/scsi_device.h> -#include <scsi/scsi_driver.h> -#include <scsi/scsi_eh.h> -#include <scsi/scsi_host.h> -#include <scsi/scsi_ioctl.h> - -#define ST_KILOBYTE 1024 - -#include "st.h" -#include "osst.h" -#include "osst_options.h" -#include "osst_detect.h" - -static DEFINE_MUTEX(osst_int_mutex); -static int max_dev = 0; -static int write_threshold_kbs = 0; -static int max_sg_segs = 0; - -#ifdef MODULE -MODULE_AUTHOR("Willem Riede"); -MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR); -MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE); - -module_param(max_dev, int, 0444); -MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)"); - -module_param(write_threshold_kbs, int, 0644); -MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)"); - -module_param(max_sg_segs, int, 0644); -MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)"); -#else -static struct osst_dev_parm { - char *name; - int *val; -} parms[] __initdata = { - { "max_dev", &max_dev }, - { "write_threshold_kbs", &write_threshold_kbs }, - { "max_sg_segs", &max_sg_segs } -}; -#endif - -/* Some default definitions have been moved to osst_options.h */ -#define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE) -#define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE) - -/* The buffer size should fit into the 24 bits for length in the - 6-byte SCSI read and write commands. */ -#if OSST_BUFFER_SIZE >= (2 << 24 - 1) -#error "Buffer size should not exceed (2 << 24 - 1) bytes!" -#endif - -#if DEBUG -static int debugging = 1; -/* uncomment define below to test error recovery */ -// #define OSST_INJECT_ERRORS 1 -#endif - -/* Do not retry! The drive firmware already retries when appropriate, - and when it tries to tell us something, we had better listen... */ -#define MAX_RETRIES 0 - -#define NO_TAPE NOT_READY - -#define OSST_WAIT_POSITION_COMPLETE (HZ > 200 ? HZ / 200 : 1) -#define OSST_WAIT_WRITE_COMPLETE (HZ / 12) -#define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2) - -#define OSST_TIMEOUT (200 * HZ) -#define OSST_LONG_TIMEOUT (1800 * HZ) - -#define TAPE_NR(x) (iminor(x) & ((1 << ST_MODE_SHIFT)-1)) -#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT) -#define TAPE_REWIND(x) ((iminor(x) & 0x80) == 0) -#define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1)) - -/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower - 24 bits) */ -#define SET_DENS_AND_BLK 0x10001 - -static int osst_buffer_size = OSST_BUFFER_SIZE; -static int osst_write_threshold = OSST_WRITE_THRESHOLD; -static int osst_max_sg_segs = OSST_MAX_SG; -static int osst_max_dev = OSST_MAX_TAPES; -static int osst_nr_dev; - -static struct osst_tape **os_scsi_tapes = NULL; -static DEFINE_RWLOCK(os_scsi_tapes_lock); - -static int modes_defined = 0; - -static struct osst_buffer *new_tape_buffer(int, int, int); -static int enlarge_buffer(struct osst_buffer *, int); -static void normalize_buffer(struct osst_buffer *); -static int append_to_buffer(const char __user *, struct osst_buffer *, int); -static int from_buffer(struct osst_buffer *, char __user *, int); -static int osst_zero_buffer_tail(struct osst_buffer *); -static int osst_copy_to_buffer(struct osst_buffer *, unsigned char *); -static int osst_copy_from_buffer(struct osst_buffer *, unsigned char *); - -static int osst_probe(struct device *); -static int osst_remove(struct device *); - -static struct scsi_driver osst_template = { - .gendrv = { - .name = "osst", - .owner = THIS_MODULE, - .probe = osst_probe, - .remove = osst_remove, - } -}; - -static int osst_int_ioctl(struct osst_tape *STp, struct osst_request ** aSRpnt, - unsigned int cmd_in, unsigned long arg); - -static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int frame, int skip); - -static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt); - -static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt); - -static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending); - -static inline char *tape_name(struct osst_tape *tape) -{ - return tape->drive->disk_name; -} - -/* Routines that handle the interaction with mid-layer SCSI routines */ - - -/* Normalize Sense */ -static void osst_analyze_sense(struct osst_request *SRpnt, struct st_cmdstatus *s) -{ - const u8 *ucp; - const u8 *sense = SRpnt->sense; - - s->have_sense = scsi_normalize_sense(SRpnt->sense, - SCSI_SENSE_BUFFERSIZE, &s->sense_hdr); - s->flags = 0; - - if (s->have_sense) { - s->deferred = 0; - s->remainder_valid = - scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64); - switch (sense[0] & 0x7f) { - case 0x71: - s->deferred = 1; - /* fall through */ - case 0x70: - s->fixed_format = 1; - s->flags = sense[2] & 0xe0; - break; - case 0x73: - s->deferred = 1; - /* fall through */ - case 0x72: - s->fixed_format = 0; - ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4); - s->flags = ucp ? (ucp[3] & 0xe0) : 0; - break; - } - } -} - -/* Convert the result to success code */ -static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt) -{ - char *name = tape_name(STp); - int result = SRpnt->result; - u8 * sense = SRpnt->sense, scode; -#if DEBUG - const char *stp; -#endif - struct st_cmdstatus *cmdstatp; - - if (!result) - return 0; - - cmdstatp = &STp->buffer->cmdstat; - osst_analyze_sense(SRpnt, cmdstatp); - - if (cmdstatp->have_sense) - scode = STp->buffer->cmdstat.sense_hdr.sense_key; - else - scode = 0; -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x\n", - name, result, - SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2], - SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]); - if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n", - name, scode, sense[12], sense[13]); - if (cmdstatp->have_sense) - __scsi_print_sense(STp->device, name, - SRpnt->sense, SCSI_SENSE_BUFFERSIZE); - } - else -#endif - if (cmdstatp->have_sense && ( - scode != NO_SENSE && - scode != RECOVERED_ERROR && -/* scode != UNIT_ATTENTION && */ - scode != BLANK_CHECK && - scode != VOLUME_OVERFLOW && - SRpnt->cmd[0] != MODE_SENSE && - SRpnt->cmd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ - if (cmdstatp->have_sense) { - printk(KERN_WARNING "%s:W: Command with sense data:\n", name); - __scsi_print_sense(STp->device, name, - SRpnt->sense, SCSI_SENSE_BUFFERSIZE); - } - else { - static int notyetprinted = 1; - - printk(KERN_WARNING - "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n", - name, result, driver_byte(result), - host_byte(result)); - if (notyetprinted) { - notyetprinted = 0; - printk(KERN_INFO - "%s:I: This warning may be caused by your scsi controller,\n", name); - printk(KERN_INFO - "%s:I: it has been reported with some Buslogic cards.\n", name); - } - } - } - STp->pos_unknown |= STp->device->was_reset; - - if (cmdstatp->have_sense && scode == RECOVERED_ERROR) { - STp->recover_count++; - STp->recover_erreg++; -#if DEBUG - if (debugging) { - if (SRpnt->cmd[0] == READ_6) - stp = "read"; - else if (SRpnt->cmd[0] == WRITE_6) - stp = "write"; - else - stp = "ioctl"; - printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp, - STp->recover_count); - } -#endif - if ((sense[2] & 0xe0) == 0) - return 0; - } - return (-EIO); -} - - -/* Wakeup from interrupt */ -static void osst_end_async(struct request *req, blk_status_t status) -{ - struct scsi_request *rq = scsi_req(req); - struct osst_request *SRpnt = req->end_io_data; - struct osst_tape *STp = SRpnt->stp; - struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; - - STp->buffer->cmdstat.midlevel_result = SRpnt->result = rq->result; -#if DEBUG - STp->write_pending = 0; -#endif - if (rq->sense_len) - memcpy(SRpnt->sense, rq->sense, SCSI_SENSE_BUFFERSIZE); - if (SRpnt->waiting) - complete(SRpnt->waiting); - - if (SRpnt->bio) { - kfree(mdata->pages); - blk_rq_unmap_user(SRpnt->bio); - } - - blk_put_request(req); -} - -/* osst_request memory management */ -static struct osst_request *osst_allocate_request(void) -{ - return kzalloc(sizeof(struct osst_request), GFP_KERNEL); -} - -static void osst_release_request(struct osst_request *streq) -{ - kfree(streq); -} - -static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, - int cmd_len, int data_direction, void *buffer, unsigned bufflen, - int use_sg, int timeout, int retries) -{ - struct request *req; - struct scsi_request *rq; - struct page **pages = NULL; - struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; - - int err = 0; - int write = (data_direction == DMA_TO_DEVICE); - - req = blk_get_request(SRpnt->stp->device->request_queue, - write ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); - if (IS_ERR(req)) - return DRIVER_ERROR << 24; - - rq = scsi_req(req); - req->rq_flags |= RQF_QUIET; - - SRpnt->bio = NULL; - - if (use_sg) { - struct scatterlist *sg, *sgl = (struct scatterlist *)buffer; - int i; - - pages = kcalloc(use_sg, sizeof(struct page *), GFP_KERNEL); - if (!pages) - goto free_req; - - for_each_sg(sgl, sg, use_sg, i) - pages[i] = sg_page(sg); - - mdata->null_mapped = 1; - - mdata->page_order = get_order(sgl[0].length); - mdata->nr_entries = - DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order); - mdata->offset = 0; - - err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL); - if (err) { - kfree(pages); - goto free_req; - } - SRpnt->bio = req->bio; - mdata->pages = pages; - - } else if (bufflen) { - err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL); - if (err) - goto free_req; - } - - rq->cmd_len = cmd_len; - memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ - memcpy(rq->cmd, cmd, rq->cmd_len); - req->timeout = timeout; - rq->retries = retries; - req->end_io_data = SRpnt; - - blk_execute_rq_nowait(req->q, NULL, req, 1, osst_end_async); - return 0; -free_req: - blk_put_request(req); - return DRIVER_ERROR << 24; -} - -/* Do the scsi command. Waits until command performed if do_wait is true. - Otherwise osst_write_behind_check() is used to check that the command - has finished. */ -static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct osst_tape *STp, - unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait) -{ - unsigned char *bp; - unsigned short use_sg; -#ifdef OSST_INJECT_ERRORS - static int inject = 0; - static int repeat = 0; -#endif - struct completion *waiting; - - /* if async, make sure there's no command outstanding */ - if (!do_wait && ((STp->buffer)->last_SRpnt)) { - printk(KERN_ERR "%s: Async command already active.\n", - tape_name(STp)); - if (signal_pending(current)) - (STp->buffer)->syscall_result = (-EINTR); - else - (STp->buffer)->syscall_result = (-EBUSY); - return NULL; - } - - if (SRpnt == NULL) { - SRpnt = osst_allocate_request(); - if (SRpnt == NULL) { - printk(KERN_ERR "%s: Can't allocate SCSI request.\n", - tape_name(STp)); - if (signal_pending(current)) - (STp->buffer)->syscall_result = (-EINTR); - else - (STp->buffer)->syscall_result = (-EBUSY); - return NULL; - } - SRpnt->stp = STp; - } - - /* If async IO, set last_SRpnt. This ptr tells write_behind_check - which IO is outstanding. It's nulled out when the IO completes. */ - if (!do_wait) - (STp->buffer)->last_SRpnt = SRpnt; - - waiting = &STp->wait; - init_completion(waiting); - SRpnt->waiting = waiting; - - use_sg = (bytes > STp->buffer->sg[0].length) ? STp->buffer->use_sg : 0; - if (use_sg) { - bp = (char *)&(STp->buffer->sg[0]); - if (STp->buffer->sg_segs < use_sg) - use_sg = STp->buffer->sg_segs; - } - else - bp = (STp->buffer)->b_data; - - memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd)); - STp->buffer->cmdstat.have_sense = 0; - STp->buffer->syscall_result = 0; - - if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes, - use_sg, timeout, retries)) - /* could not allocate the buffer or request was too large */ - (STp->buffer)->syscall_result = (-EBUSY); - else if (do_wait) { - wait_for_completion(waiting); - SRpnt->waiting = NULL; - STp->buffer->syscall_result = osst_chk_result(STp, SRpnt); -#ifdef OSST_INJECT_ERRORS - if (STp->buffer->syscall_result == 0 && - cmd[0] == READ_6 && - cmd[4] && - ( (++ inject % 83) == 29 || - (STp->first_frame_position == 240 - /* or STp->read_error_frame to fail again on the block calculated above */ && - ++repeat < 3))) { - printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp)); - STp->buffer->last_result_fatal = 1; - } -#endif - } - return SRpnt; -} - - -/* Handle the write-behind checking (downs the semaphore) */ -static void osst_write_behind_check(struct osst_tape *STp) -{ - struct osst_buffer * STbuffer; - - STbuffer = STp->buffer; - -#if DEBUG - if (STp->write_pending) - STp->nbr_waits++; - else - STp->nbr_finished++; -#endif - wait_for_completion(&(STp->wait)); - STp->buffer->last_SRpnt->waiting = NULL; - - STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt); - - if (STp->buffer->syscall_result) - STp->buffer->syscall_result = - osst_write_error_recovery(STp, &(STp->buffer->last_SRpnt), 1); - else - STp->first_frame_position++; - - osst_release_request(STp->buffer->last_SRpnt); - - if (STbuffer->writing < STbuffer->buffer_bytes) - printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n"); - - STbuffer->last_SRpnt = NULL; - STbuffer->buffer_bytes -= STbuffer->writing; - STbuffer->writing = 0; - - return; -} - - - -/* Onstream specific Routines */ -/* - * Initialize the OnStream AUX - */ -static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_number, - int logical_blk_num, int blk_sz, int blk_cnt) -{ - os_aux_t *aux = STp->buffer->aux; - os_partition_t *par = &aux->partition; - os_dat_t *dat = &aux->dat; - - if (STp->raw) return; - - memset(aux, 0, sizeof(*aux)); - aux->format_id = htonl(0); - memcpy(aux->application_sig, "LIN4", 4); - aux->hdwr = htonl(0); - aux->frame_type = frame_type; - - switch (frame_type) { - case OS_FRAME_TYPE_HEADER: - aux->update_frame_cntr = htonl(STp->update_frame_cntr); - par->partition_num = OS_CONFIG_PARTITION; - par->par_desc_ver = OS_PARTITION_VERSION; - par->wrt_pass_cntr = htons(0xffff); - /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */ - par->first_frame_ppos = htonl(0); - par->last_frame_ppos = htonl(0xbb7); - aux->frame_seq_num = htonl(0); - aux->logical_blk_num_high = htonl(0); - aux->logical_blk_num = htonl(0); - aux->next_mark_ppos = htonl(STp->first_mark_ppos); - break; - case OS_FRAME_TYPE_DATA: - case OS_FRAME_TYPE_MARKER: - dat->dat_sz = 8; - dat->reserved1 = 0; - dat->entry_cnt = 1; - dat->reserved3 = 0; - dat->dat_list[0].blk_sz = htonl(blk_sz); - dat->dat_list[0].blk_cnt = htons(blk_cnt); - dat->dat_list[0].flags = frame_type==OS_FRAME_TYPE_MARKER? - OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA; - dat->dat_list[0].reserved = 0; - /* fall through */ - case OS_FRAME_TYPE_EOD: - aux->update_frame_cntr = htonl(0); - par->partition_num = OS_DATA_PARTITION; - par->par_desc_ver = OS_PARTITION_VERSION; - par->wrt_pass_cntr = htons(STp->wrt_pass_cntr); - par->first_frame_ppos = htonl(STp->first_data_ppos); - par->last_frame_ppos = htonl(STp->capacity); - aux->frame_seq_num = htonl(frame_seq_number); - aux->logical_blk_num_high = htonl(0); - aux->logical_blk_num = htonl(logical_blk_num); - break; - default: ; /* probably FILL */ - } - aux->filemark_cnt = htonl(STp->filemark_cnt); - aux->phys_fm = htonl(0xffffffff); - aux->last_mark_ppos = htonl(STp->last_mark_ppos); - aux->last_mark_lbn = htonl(STp->last_mark_lbn); -} - -/* - * Verify that we have the correct tape frame - */ -static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int quiet) -{ - char * name = tape_name(STp); - os_aux_t * aux = STp->buffer->aux; - os_partition_t * par = &(aux->partition); - struct st_partstat * STps = &(STp->ps[STp->partition]); - unsigned int blk_cnt, blk_sz, i; - - if (STp->raw) { - if (STp->buffer->syscall_result) { - for (i=0; i < STp->buffer->sg_segs; i++) - memset(page_address(sg_page(&STp->buffer->sg[i])), - 0, STp->buffer->sg[i].length); - strcpy(STp->buffer->b_data, "READ ERROR ON FRAME"); - } else - STp->buffer->buffer_bytes = OS_FRAME_SIZE; - return 1; - } - if (STp->buffer->syscall_result) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name); -#endif - return 0; - } - if (ntohl(aux->format_id) != 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id)); -#endif - goto err_out; - } - if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 && - (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name); -#endif - goto err_out; - } - if (par->partition_num != OS_DATA_PARTITION) { - if (!STp->linux_media || STp->linux_media_version != 2) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n", - name, par->partition_num); -#endif - goto err_out; - } - } - if (par->par_desc_ver != OS_PARTITION_VERSION) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver); -#endif - goto err_out; - } - if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n", - name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr); -#endif - goto err_out; - } - if (aux->frame_type != OS_FRAME_TYPE_DATA && - aux->frame_type != OS_FRAME_TYPE_EOD && - aux->frame_type != OS_FRAME_TYPE_MARKER) { - if (!quiet) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type); -#endif - } - goto err_out; - } - if (aux->frame_type == OS_FRAME_TYPE_EOD && - STp->first_frame_position < STp->eod_frame_ppos) { - printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name, - STp->first_frame_position); - goto err_out; - } - if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) { - if (!quiet) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n", - name, ntohl(aux->frame_seq_num), frame_seq_number); -#endif - } - goto err_out; - } - if (aux->frame_type == OS_FRAME_TYPE_MARKER) { - STps->eof = ST_FM_HIT; - - i = ntohl(aux->filemark_cnt); - if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt || - STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name, - STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected", - i, STp->first_frame_position - 1); -#endif - STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1); - if (i >= STp->filemark_cnt) - STp->filemark_cnt = i+1; - } - } - if (aux->frame_type == OS_FRAME_TYPE_EOD) { - STps->eof = ST_EOD_1; - STp->frame_in_buffer = 1; - } - if (aux->frame_type == OS_FRAME_TYPE_DATA) { - blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt); - blk_sz = ntohl(aux->dat.dat_list[0].blk_sz); - STp->buffer->buffer_bytes = blk_cnt * blk_sz; - STp->buffer->read_pointer = 0; - STp->frame_in_buffer = 1; - - /* See what block size was used to write file */ - if (STp->block_size != blk_sz && blk_sz > 0) { - printk(KERN_INFO - "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n", - name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k', - STp->block_size<1024?STp->block_size:STp->block_size/1024, - STp->block_size<1024?'b':'k'); - STp->block_size = blk_sz; - STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz; - } - STps->eof = ST_NOEOF; - } - STp->frame_seq_number = ntohl(aux->frame_seq_num); - STp->logical_blk_num = ntohl(aux->logical_blk_num); - return 1; - -err_out: - if (STp->read_error_frame == 0) - STp->read_error_frame = STp->first_frame_position - 1; - return 0; -} - -/* - * Wait for the unit to become Ready - */ -static int osst_wait_ready(struct osst_tape * STp, struct osst_request ** aSRpnt, - unsigned timeout, int initial_delay) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - unsigned long startwait = jiffies; -#if DEBUG - int dbg = debugging; - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name); -#endif - - if (initial_delay > 0) - msleep(jiffies_to_msecs(initial_delay)); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) return (-EBUSY); - - while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && - (( SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 && - (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8) ) || - ( SRpnt->sense[2] == 6 && SRpnt->sense[12] == 0x28 && - SRpnt->sense[13] == 0 ) )) { -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name); - printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); - debugging = 0; - } -#endif - msleep(100); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - } - *aSRpnt = SRpnt; -#if DEBUG - debugging = dbg; -#endif - if ( STp->buffer->syscall_result && - osst_write_error_recovery(STp, aSRpnt, 0) ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name); - printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name, - STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2], - SRpnt->sense[12], SRpnt->sense[13]); -#endif - return (-EIO); - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name); -#endif - return 0; -} - -/* - * Wait for a tape to be inserted in the unit - */ -static int osst_wait_for_medium(struct osst_tape * STp, struct osst_request ** aSRpnt, unsigned timeout) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - unsigned long startwait = jiffies; -#if DEBUG - int dbg = debugging; - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name); -#endif - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) return (-EBUSY); - - while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && - SRpnt->sense[2] == 2 && SRpnt->sense[12] == 0x3a && SRpnt->sense[13] == 0 ) { -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name); - printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); - debugging = 0; - } -#endif - msleep(100); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - } - *aSRpnt = SRpnt; -#if DEBUG - debugging = dbg; -#endif - if ( STp->buffer->syscall_result && SRpnt->sense[2] != 2 && - SRpnt->sense[12] != 4 && SRpnt->sense[13] == 1) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name); - printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name, - STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2], - SRpnt->sense[12], SRpnt->sense[13]); -#endif - return 0; - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name); -#endif - return 1; -} - -static int osst_position_tape_and_confirm(struct osst_tape * STp, struct osst_request ** aSRpnt, int frame) -{ - int retval; - - osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */ - retval = osst_set_frame_position(STp, aSRpnt, frame, 0); - if (retval) return (retval); - osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE); - return (osst_get_frame_position(STp, aSRpnt)); -} - -/* - * Wait for write(s) to complete - */ -static int osst_flush_drive_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - int result = 0; - int delay = OSST_WAIT_WRITE_COMPLETE; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name); -#endif - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_FILEMARKS; - cmd[1] = 1; - - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) return (-EBUSY); - if (STp->buffer->syscall_result) { - if ((SRpnt->sense[2] & 0x0f) == 2 && SRpnt->sense[12] == 4) { - if (SRpnt->sense[13] == 8) { - delay = OSST_WAIT_LONG_WRITE_COMPLETE; - } - } else - result = osst_write_error_recovery(STp, aSRpnt, 0); - } - result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay); - STp->ps[STp->partition].rw = OS_WRITING_COMPLETE; - - return (result); -} - -#define OSST_POLL_PER_SEC 10 -static int osst_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int curr, int minlast, int to) -{ - unsigned long startwait = jiffies; - char * name = tape_name(STp); -#if DEBUG - char notyetprinted = 1; -#endif - if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING) - printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name); - - while (time_before (jiffies, startwait + to*HZ)) - { - int result; - result = osst_get_frame_position(STp, aSRpnt); - if (result == -EIO) - if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0) - return 0; /* successful recovery leaves drive ready for frame */ - if (result < 0) break; - if (STp->first_frame_position == curr && - ((minlast < 0 && - (signed)STp->last_frame_position > (signed)curr + minlast) || - (minlast >= 0 && STp->cur_frames > minlast) - ) && result >= 0) - { -#if DEBUG - if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC)) - printk (OSST_DEB_MSG - "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n", - name, curr, curr+minlast, STp->first_frame_position, - STp->last_frame_position, STp->cur_frames, - result, (jiffies-startwait)/HZ, - (((jiffies-startwait)%HZ)*10)/HZ); -#endif - return 0; - } -#if DEBUG - if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted) - { - printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n", - name, curr, curr+minlast, STp->first_frame_position, - STp->last_frame_position, STp->cur_frames, result); - notyetprinted--; - } -#endif - msleep(1000 / OSST_POLL_PER_SEC); - } -#if DEBUG - printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n", - name, curr, curr+minlast, STp->first_frame_position, - STp->last_frame_position, STp->cur_frames, - (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ); -#endif - return -EBUSY; -} - -static int osst_recover_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int writing) -{ - struct osst_request * SRpnt; - unsigned char cmd[MAX_COMMAND_SIZE]; - unsigned long startwait = jiffies; - int retval = 1; - char * name = tape_name(STp); - - if (writing) { - char mybuf[24]; - char * olddata = STp->buffer->b_data; - int oldsize = STp->buffer->buffer_size; - - /* write zero fm then read pos - if shows write error, try to recover - if no progress, wait */ - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_FILEMARKS; - cmd[1] = 1; - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, - MAX_RETRIES, 1); - - while (retval && time_before (jiffies, startwait + 5*60*HZ)) { - - if (STp->buffer->syscall_result && (SRpnt->sense[2] & 0x0f) != 2) { - - /* some failure - not just not-ready */ - retval = osst_write_error_recovery(STp, aSRpnt, 0); - break; - } - schedule_timeout_interruptible(HZ / OSST_POLL_PER_SEC); - - STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = READ_POSITION; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 20, DMA_FROM_DEVICE, STp->timeout, - MAX_RETRIES, 1); - - retval = ( STp->buffer->syscall_result || (STp->buffer)->b_data[15] > 25 ); - STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; - } - if (retval) - printk(KERN_ERR "%s:E: Device did not succeed to write buffered data\n", name); - } else - /* TODO - figure out which error conditions can be handled */ - if (STp->buffer->syscall_result) - printk(KERN_WARNING - "%s:W: Recover_wait_frame(read) cannot handle %02x:%02x:%02x\n", name, - (*aSRpnt)->sense[ 2] & 0x0f, - (*aSRpnt)->sense[12], - (*aSRpnt)->sense[13]); - - return retval; -} - -/* - * Read the next OnStream tape frame at the current location - */ -static int osst_read_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int timeout) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - int retval = 0; -#if DEBUG - os_aux_t * aux = STp->buffer->aux; - char * name = tape_name(STp); -#endif - - if (STp->poll) - if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout)) - retval = osst_recover_wait_frame(STp, aSRpnt, 0); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = READ_6; - cmd[1] = 1; - cmd[4] = 1; - -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name); -#endif - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE, - STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) - return (-EBUSY); - - if ((STp->buffer)->syscall_result) { - retval = 1; - if (STp->read_error_frame == 0) { - STp->read_error_frame = STp->first_frame_position; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame); -#endif - } -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", - name, - SRpnt->sense[0], SRpnt->sense[1], - SRpnt->sense[2], SRpnt->sense[3], - SRpnt->sense[4], SRpnt->sense[5], - SRpnt->sense[6], SRpnt->sense[7]); -#endif - } - else - STp->first_frame_position++; -#if DEBUG - if (debugging) { - char sig[8]; int i; - for (i=0;i<4;i++) - sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i]; - sig[4] = '\0'; - printk(OSST_DEB_MSG - "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig, - ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr), - aux->frame_type==1?"EOD":aux->frame_type==2?"MARK": - aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL", - ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num), - ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) ); - if (aux->frame_type==2) - printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name, - ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn)); - printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval); - } -#endif - return (retval); -} - -static int osst_initiate_read(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - struct osst_request * SRpnt ; - unsigned char cmd[MAX_COMMAND_SIZE]; - int retval = 0; - char * name = tape_name(STp); - - if (STps->rw != ST_READING) { /* Initialize read operation */ - if (STps->rw == ST_WRITING || STp->dirty) { - STp->write_type = OS_WRITE_DATA; - osst_flush_write_buffer(STp, aSRpnt); - osst_flush_drive_buffer(STp, aSRpnt); - } - STps->rw = ST_READING; - STp->frame_in_buffer = 0; - - /* - * Issue a read 0 command to get the OnStream drive - * read frames into its buffer. - */ - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = READ_6; - cmd[1] = 1; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name); -#endif - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if ((retval = STp->buffer->syscall_result)) - printk(KERN_WARNING "%s:W: Error starting read ahead\n", name); - } - - return retval; -} - -static int osst_get_logical_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, - int frame_seq_number, int quiet) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - char * name = tape_name(STp); - int cnt = 0, - bad = 0, - past = 0, - x, - position; - - /* - * If we want just any frame (-1) and there is a frame in the buffer, return it - */ - if (frame_seq_number == -1 && STp->frame_in_buffer) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number); -#endif - return (STps->eof); - } - /* - * Search and wait for the next logical tape frame - */ - while (1) { - if (cnt++ > 400) { - printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n", - name, frame_seq_number); - if (STp->read_error_frame) { - osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n", - name, STp->read_error_frame); -#endif - STp->read_error_frame = 0; - STp->abort_count++; - } - return (-EIO); - } -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n", - name, frame_seq_number, cnt); -#endif - if ( osst_initiate_read(STp, aSRpnt) - || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) { - if (STp->raw) - return (-EIO); - position = osst_get_frame_position(STp, aSRpnt); - if (position >= 0xbae && position < 0xbb8) - position = 0xbb8; - else if (position > STp->eod_frame_ppos || ++bad == 10) { - position = STp->read_error_frame - 1; - bad = 0; - } - else { - position += 29; - cnt += 19; - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n", - name, position); -#endif - osst_set_frame_position(STp, aSRpnt, position, 0); - continue; - } - if (osst_verify_frame(STp, frame_seq_number, quiet)) - break; - if (osst_verify_frame(STp, -1, quiet)) { - x = ntohl(STp->buffer->aux->frame_seq_num); - if (STp->fast_open) { - printk(KERN_WARNING - "%s:W: Found logical frame %d instead of %d after fast open\n", - name, x, frame_seq_number); - STp->header_ok = 0; - STp->read_error_frame = 0; - return (-EIO); - } - if (x > frame_seq_number) { - if (++past > 3) { - /* positioning backwards did not bring us to the desired frame */ - position = STp->read_error_frame - 1; - } - else { - position = osst_get_frame_position(STp, aSRpnt) - + frame_seq_number - x - 1; - - if (STp->first_frame_position >= 3000 && position < 3000) - position -= 10; - } -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Found logical frame %d while looking for %d: back up %d\n", - name, x, frame_seq_number, - STp->first_frame_position - position); -#endif - osst_set_frame_position(STp, aSRpnt, position, 0); - cnt += 10; - } - else - past = 0; - } - if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name); -#endif - osst_set_frame_position(STp, aSRpnt, 0xbb8, 0); - cnt--; - } - STp->frame_in_buffer = 0; - } - if (cnt > 1) { - STp->recover_count++; - STp->recover_erreg++; - printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n", - name, STp->read_error_frame); - } - STp->read_count++; - -#if DEBUG - if (debugging || STps->eof) - printk(OSST_DEB_MSG - "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n", - name, frame_seq_number, STp->frame_seq_number, STps->eof); -#endif - STp->fast_open = 0; - STp->read_error_frame = 0; - return (STps->eof); -} - -static int osst_seek_logical_blk(struct osst_tape * STp, struct osst_request ** aSRpnt, int logical_blk_num) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - char * name = tape_name(STp); - int retries = 0; - int frame_seq_estimate, ppos_estimate, move; - - if (logical_blk_num < 0) logical_blk_num = 0; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n", - name, logical_blk_num, STp->logical_blk_num, - STp->block_size<1024?STp->block_size:STp->block_size/1024, - STp->block_size<1024?'b':'k'); -#endif - /* Do we know where we are? */ - if (STps->drv_block >= 0) { - move = logical_blk_num - STp->logical_blk_num; - if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1; - move /= (OS_DATA_SIZE / STp->block_size); - frame_seq_estimate = STp->frame_seq_number + move; - } else - frame_seq_estimate = logical_blk_num * STp->block_size / OS_DATA_SIZE; - - if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10; - else ppos_estimate = frame_seq_estimate + 20; - while (++retries < 10) { - if (ppos_estimate > STp->eod_frame_ppos-2) { - frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate; - ppos_estimate = STp->eod_frame_ppos - 2; - } - if (frame_seq_estimate < 0) { - frame_seq_estimate = 0; - ppos_estimate = 10; - } - osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0); - if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) { - /* we've located the estimated frame, now does it have our block? */ - if (logical_blk_num < STp->logical_blk_num || - logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) { - if (STps->eof == ST_FM_HIT) - move = logical_blk_num < STp->logical_blk_num? -2 : 1; - else { - move = logical_blk_num - STp->logical_blk_num; - if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1; - move /= (OS_DATA_SIZE / STp->block_size); - } - if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1; -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n", - name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, - STp->logical_blk_num, logical_blk_num, move); -#endif - frame_seq_estimate += move; - ppos_estimate += move; - continue; - } else { - STp->buffer->read_pointer = (logical_blk_num - STp->logical_blk_num) * STp->block_size; - STp->buffer->buffer_bytes -= STp->buffer->read_pointer; - STp->logical_blk_num = logical_blk_num; -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n", - name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer, - STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size, - STp->block_size); -#endif - STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt); - if (STps->eof == ST_FM_HIT) { - STps->drv_file++; - STps->drv_block = 0; - } else { - STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)? - STp->logical_blk_num - - (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0): - -1; - } - STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF; - return 0; - } - } - if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0) - goto error; - /* we are not yet at the estimated frame, adjust our estimate of its physical position */ -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n", - name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, - STp->logical_blk_num, logical_blk_num); -#endif - if (frame_seq_estimate != STp->frame_seq_number) - ppos_estimate += frame_seq_estimate - STp->frame_seq_number; - else - break; - } -error: - printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n", - name, logical_blk_num, STp->logical_blk_num, retries); - return (-EIO); -} - -/* The values below are based on the OnStream frame payload size of 32K == 2**15, - * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block - * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions - * inside each frame. Finally, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1. - */ -#define OSST_FRAME_SHIFT 6 -#define OSST_SECTOR_SHIFT 9 -#define OSST_SECTOR_MASK 0x03F - -static int osst_get_sector(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int sector; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG - "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n", - name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num, - STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block, - STp->ps[STp->partition].rw == ST_WRITING?'w':'r', - STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes: - STp->buffer->read_pointer, STp->ps[STp->partition].eof); -#endif - /* do we know where we are inside a file? */ - if (STp->ps[STp->partition].drv_block >= 0) { - sector = (STp->frame_in_buffer ? STp->first_frame_position-1 : - STp->first_frame_position) << OSST_FRAME_SHIFT; - if (STp->ps[STp->partition].rw == ST_WRITING) - sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK; - else - sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK; - } else { - sector = osst_get_frame_position(STp, aSRpnt); - if (sector > 0) - sector <<= OSST_FRAME_SHIFT; - } - return sector; -} - -static int osst_seek_sector(struct osst_tape * STp, struct osst_request ** aSRpnt, int sector) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - int frame = sector >> OSST_FRAME_SHIFT, - offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT, - r; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n", - name, sector, frame, offset); -#endif - if (frame < 0 || frame >= STp->capacity) return (-ENXIO); - - if (frame <= STp->first_data_ppos) { - STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0; - return (osst_set_frame_position(STp, aSRpnt, frame, 0)); - } - r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0); - if (r < 0) return r; - - r = osst_get_logical_frame(STp, aSRpnt, -1, 1); - if (r < 0) return r; - - if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO); - - if (offset) { - STp->logical_blk_num += offset / STp->block_size; - STp->buffer->read_pointer = offset; - STp->buffer->buffer_bytes -= offset; - } else { - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0; - } - STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt); - if (STps->eof == ST_FM_HIT) { - STps->drv_file++; - STps->drv_block = 0; - } else { - STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)? - STp->logical_blk_num - - (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0): - -1; - } - STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF; -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n", - name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num, - STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof); -#endif - return 0; -} - -/* - * Read back the drive's internal buffer contents, as a part - * of the write error recovery mechanism for old OnStream - * firmware revisions. - * Precondition for this function to work: all frames in the - * drive's buffer must be of one type (DATA, MARK or EOD)! - */ -static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst_request ** aSRpnt, - unsigned int frame, unsigned int skip, int pending) -{ - struct osst_request * SRpnt = * aSRpnt; - unsigned char * buffer, * p; - unsigned char cmd[MAX_COMMAND_SIZE]; - int flag, new_frame, i; - int nframes = STp->cur_frames; - int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num) - - (nframes + pending - 1); - int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num) - - (nframes + pending - 1) * blks_per_frame; - char * name = tape_name(STp); - unsigned long startwait = jiffies; -#if DEBUG - int dbg = debugging; -#endif - - if ((buffer = vmalloc(array_size((nframes + 1), OS_DATA_SIZE))) == NULL) - return (-EIO); - - printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n", - name, nframes, pending?" and one that was pending":""); - - osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE])); -#if DEBUG - if (pending && debugging) - printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n", - name, frame_seq_number + nframes, - logical_blk_num + nframes * blks_per_frame, - p[0], p[1], p[2], p[3]); -#endif - for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = 0x3C; /* Buffer Read */ - cmd[1] = 6; /* Retrieve Faulty Block */ - cmd[7] = 32768 >> 8; - cmd[8] = 32768 & 0xff; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE, - STp->timeout, MAX_RETRIES, 1); - - if ((STp->buffer)->syscall_result || !SRpnt) { - printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name); - vfree(buffer); - *aSRpnt = SRpnt; - return (-EIO); - } - osst_copy_from_buffer(STp->buffer, p); -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n", - name, frame_seq_number + i, p[0], p[1], p[2], p[3]); -#endif - } - *aSRpnt = SRpnt; - osst_get_frame_position(STp, aSRpnt); - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames); -#endif - /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */ - /* In the header we don't actually re-write the frames that fail, just the ones after them */ - - for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) { - - if (flag) { - if (STp->write_type == OS_WRITE_HEADER) { - i += skip; - p += skip * OS_DATA_SIZE; - } - else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990) - new_frame = 3000-i; - else - new_frame += skip; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n", - name, new_frame+i, frame_seq_number+i); -#endif - osst_set_frame_position(STp, aSRpnt, new_frame + i, 0); - osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE); - osst_get_frame_position(STp, aSRpnt); - SRpnt = * aSRpnt; - - if (new_frame > frame + 1000) { - printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name); - vfree(buffer); - return (-EIO); - } - if ( i >= nframes + pending ) break; - flag = 0; - } - osst_copy_to_buffer(STp->buffer, p); - /* - * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type! - */ - osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i, - logical_blk_num + i*blks_per_frame, - ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame); - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = 1; - cmd[4] = 1; - -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG - "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n", - name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame, - p[0], p[1], p[2], p[3]); -#endif - SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, - STp->timeout, MAX_RETRIES, 1); - - if (STp->buffer->syscall_result) - flag = 1; - else { - p += OS_DATA_SIZE; i++; - - /* if we just sent the last frame, wait till all successfully written */ - if ( i == nframes + pending ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name); -#endif - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_FILEMARKS; - cmd[1] = 1; - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, - STp->timeout, MAX_RETRIES, 1); -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name); - printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); - debugging = 0; - } -#endif - flag = STp->buffer->syscall_result; - while ( !flag && time_before(jiffies, startwait + 60*HZ) ) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, - MAX_RETRIES, 1); - - if (SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 && - (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8)) { - /* in the process of becoming ready */ - msleep(100); - continue; - } - if (STp->buffer->syscall_result) - flag = 1; - break; - } -#if DEBUG - debugging = dbg; - printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name); -#endif - } - } - *aSRpnt = SRpnt; - if (flag) { - if ((SRpnt->sense[ 2] & 0x0f) == 13 && - SRpnt->sense[12] == 0 && - SRpnt->sense[13] == 2) { - printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name); - vfree(buffer); - return (-EIO); /* hit end of tape = fail */ - } - i = ((SRpnt->sense[3] << 24) | - (SRpnt->sense[4] << 16) | - (SRpnt->sense[5] << 8) | - SRpnt->sense[6] ) - new_frame; - p = &buffer[i * OS_DATA_SIZE]; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i); -#endif - osst_get_frame_position(STp, aSRpnt); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d, buffer = %d\n", - name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames); -#endif - } - } - if (flag) { - /* error recovery did not successfully complete */ - printk(KERN_ERR "%s:D: Write error recovery failed in %s\n", name, - STp->write_type == OS_WRITE_HEADER?"header":"body"); - } - if (!pending) - osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */ - vfree(buffer); - return 0; -} - -static int osst_reposition_and_retry(struct osst_tape * STp, struct osst_request ** aSRpnt, - unsigned int frame, unsigned int skip, int pending) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - char * name = tape_name(STp); - int expected = 0; - int attempts = 1000 / skip; - int flag = 1; - unsigned long startwait = jiffies; -#if DEBUG - int dbg = debugging; -#endif - - while (attempts && time_before(jiffies, startwait + 60*HZ)) { - if (flag) { -#if DEBUG - debugging = dbg; -#endif - if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990) - frame = 3000-skip; - expected = frame+skip+STp->cur_frames+pending; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n", - name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending); -#endif - osst_set_frame_position(STp, aSRpnt, frame + skip, 1); - flag = 0; - attempts--; - schedule_timeout_interruptible(msecs_to_jiffies(100)); - } - if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */ -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n", - name, STp->first_frame_position, - STp->last_frame_position, STp->cur_frames); -#endif - frame = STp->last_frame_position; - flag = 1; - continue; - } - if (pending && STp->cur_frames < 50) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = 1; - cmd[4] = 1; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n", - name, STp->frame_seq_number-1, STp->first_frame_position); -#endif - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, - STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - - if (STp->buffer->syscall_result) { /* additional write error */ - if ((SRpnt->sense[ 2] & 0x0f) == 13 && - SRpnt->sense[12] == 0 && - SRpnt->sense[13] == 2) { - printk(KERN_ERR - "%s:E: Volume overflow in write error recovery\n", - name); - break; /* hit end of tape = fail */ - } - flag = 1; - } - else - pending = 0; - - continue; - } - if (STp->cur_frames == 0) { -#if DEBUG - debugging = dbg; - printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name); -#endif - if (STp->first_frame_position != expected) { - printk(KERN_ERR "%s:A: Actual position %d - expected %d\n", - name, STp->first_frame_position, expected); - return (-EIO); - } - return 0; - } -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name); - printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); - debugging = 0; - } -#endif - schedule_timeout_interruptible(msecs_to_jiffies(100)); - } - printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name); -#if DEBUG - debugging = dbg; -#endif - return (-EIO); -} - -/* - * Error recovery algorithm for the OnStream tape. - */ - -static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending) -{ - struct osst_request * SRpnt = * aSRpnt; - struct st_partstat * STps = & STp->ps[STp->partition]; - char * name = tape_name(STp); - int retval = 0; - int rw_state; - unsigned int frame, skip; - - rw_state = STps->rw; - - if ((SRpnt->sense[ 2] & 0x0f) != 3 - || SRpnt->sense[12] != 12 - || SRpnt->sense[13] != 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name, - SRpnt->sense[2], SRpnt->sense[12], SRpnt->sense[13]); -#endif - return (-EIO); - } - frame = (SRpnt->sense[3] << 24) | - (SRpnt->sense[4] << 16) | - (SRpnt->sense[5] << 8) | - SRpnt->sense[6]; - skip = SRpnt->sense[9]; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip); -#endif - osst_get_frame_position(STp, aSRpnt); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n", - name, STp->first_frame_position, STp->last_frame_position); -#endif - switch (STp->write_type) { - case OS_WRITE_DATA: - case OS_WRITE_EOD: - case OS_WRITE_NEW_MARK: - printk(KERN_WARNING - "%s:I: Relocating %d buffered logical frames from position %u to %u\n", - name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip); - if (STp->os_fw_rev >= 10600) - retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending); - else - retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending); - printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name, - retval?"E" :"I", - retval?"" :"Don't worry, ", - retval?" not ":" "); - break; - case OS_WRITE_LAST_MARK: - printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name); - osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0); - retval = -EIO; - break; - case OS_WRITE_HEADER: - printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name); - retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending); - break; - default: - printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name); - osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0); - } - osst_get_frame_position(STp, aSRpnt); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n", - name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position); - printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num); -#endif - if (retval == 0) { - STp->recover_count++; - STp->recover_erreg++; - } else - STp->abort_count++; - - STps->rw = rw_state; - return retval; -} - -static int osst_space_over_filemarks_backward(struct osst_tape * STp, struct osst_request ** aSRpnt, - int mt_op, int mt_count) -{ - char * name = tape_name(STp); - int cnt; - int last_mark_ppos = -1; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count); -#endif - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name); -#endif - return -EIO; - } - if (STp->linux_media_version >= 4) { - /* - * direct lookup in header filemark list - */ - cnt = ntohl(STp->buffer->aux->filemark_cnt); - if (STp->header_ok && - STp->header_cache != NULL && - (cnt - mt_count) >= 0 && - (cnt - mt_count) < OS_FM_TAB_MAX && - (cnt - mt_count) < STp->filemark_cnt && - STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos) - - last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]); -#if DEBUG - if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX) - printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name, - STp->header_cache == NULL?"lack of header cache":"count out of range"); - else - printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n", - name, cnt, - ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || - (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == - STp->buffer->aux->last_mark_ppos))?"match":"error", - mt_count, last_mark_ppos); -#endif - if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) { - osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Couldn't get logical blk num in space_filemarks\n", name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", - name, last_mark_ppos); - return (-EIO); - } - goto found; - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name); -#endif - } - cnt = 0; - while (cnt != mt_count) { - last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos); - if (last_mark_ppos == -1) - return (-EIO); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos); -#endif - osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); - cnt++; - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", - name, last_mark_ppos); - return (-EIO); - } - } -found: - if (mt_op == MTBSFM) { - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->buffer->buffer_bytes = 0; - STp->buffer->read_pointer = 0; - STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - } - return 0; -} - -/* - * ADRL 1.1 compatible "slow" space filemarks fwd version - * - * Just scans for the filemark sequentially. - */ -static int osst_space_over_filemarks_forward_slow(struct osst_tape * STp, struct osst_request ** aSRpnt, - int mt_op, int mt_count) -{ - int cnt = 0; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count); -#endif - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name); -#endif - return (-EIO); - } - while (1) { - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER) - cnt++; - if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name); -#endif - if (STp->first_frame_position > STp->eod_frame_ppos+1) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n", - name, STp->eod_frame_ppos, STp->first_frame_position-1); -#endif - STp->eod_frame_ppos = STp->first_frame_position-1; - } - return (-EIO); - } - if (cnt == mt_count) - break; - STp->frame_in_buffer = 0; - } - if (mt_op == MTFSF) { - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->buffer->buffer_bytes = 0; - STp->buffer->read_pointer = 0; - STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - } - return 0; -} - -/* - * Fast linux specific version of OnStream FSF - */ -static int osst_space_over_filemarks_forward_fast(struct osst_tape * STp, struct osst_request ** aSRpnt, - int mt_op, int mt_count) -{ - char * name = tape_name(STp); - int cnt = 0, - next_mark_ppos = -1; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count); -#endif - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name); -#endif - return (-EIO); - } - - if (STp->linux_media_version >= 4) { - /* - * direct lookup in header filemark list - */ - cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1; - if (STp->header_ok && - STp->header_cache != NULL && - (cnt + mt_count) < OS_FM_TAB_MAX && - (cnt + mt_count) < STp->filemark_cnt && - ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || - (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos))) - - next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]); -#if DEBUG - if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX) - printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name, - STp->header_cache == NULL?"lack of header cache":"count out of range"); - else - printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n", - name, cnt, - ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || - (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == - STp->buffer->aux->last_mark_ppos))?"match":"error", - mt_count, next_mark_ppos); -#endif - if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); -#endif - return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); - } else { - osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", - name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", - name, next_mark_ppos); - return (-EIO); - } - if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) { - printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n", - name, cnt+mt_count, next_mark_ppos, - ntohl(STp->buffer->aux->filemark_cnt)); - return (-EIO); - } - } - } else { - /* - * Find nearest (usually previous) marker, then jump from marker to marker - */ - while (1) { - if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER) - break; - if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name); -#endif - return (-EIO); - } - if (ntohl(STp->buffer->aux->filemark_cnt) == 0) { - if (STp->first_mark_ppos == -1) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); -#endif - return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); - } - osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos); - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n", - name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n", - name, STp->first_mark_ppos); - return (-EIO); - } - } else { - if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0) - return (-EIO); - mt_count++; - } - } - cnt++; - while (cnt != mt_count) { - next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos); - if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); -#endif - return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt); - } -#if DEBUG - else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos); -#endif - osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); - cnt++; - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", - name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", - name, next_mark_ppos); - return (-EIO); - } - } - } - if (mt_op == MTFSF) { - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->buffer->buffer_bytes = 0; - STp->buffer->read_pointer = 0; - STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - } - return 0; -} - -/* - * In debug mode, we want to see as many errors as possible - * to test the error recovery mechanism. - */ -#if DEBUG -static void osst_set_retries(struct osst_tape * STp, struct osst_request ** aSRpnt, int retries) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt = * aSRpnt; - char * name = tape_name(STp); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH; - - (STp->buffer)->b_data[0] = cmd[4] - 1; - (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */ - (STp->buffer)->b_data[2] = 0; /* Reserved */ - (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */ - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7); - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries; - - if (debugging) - printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries); - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result) - printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries); -} -#endif - - -static int osst_write_filemark(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int result; - int this_mark_ppos = STp->first_frame_position; - int this_mark_lbn = STp->logical_blk_num; -#if DEBUG - char * name = tape_name(STp); -#endif - - if (STp->raw) return 0; - - STp->write_type = OS_WRITE_NEW_MARK; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n", - name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn); -#endif - STp->dirty = 1; - result = osst_flush_write_buffer(STp, aSRpnt); - result |= osst_flush_drive_buffer(STp, aSRpnt); - STp->last_mark_ppos = this_mark_ppos; - STp->last_mark_lbn = this_mark_lbn; - if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX) - STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos); - if (STp->filemark_cnt++ == 0) - STp->first_mark_ppos = this_mark_ppos; - return result; -} - -static int osst_write_eod(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int result; -#if DEBUG - char * name = tape_name(STp); -#endif - - if (STp->raw) return 0; - - STp->write_type = OS_WRITE_EOD; - STp->eod_frame_ppos = STp->first_frame_position; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name, - STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num); -#endif - STp->dirty = 1; - - result = osst_flush_write_buffer(STp, aSRpnt); - result |= osst_flush_drive_buffer(STp, aSRpnt); - STp->eod_frame_lfa = --(STp->frame_seq_number); - return result; -} - -static int osst_write_filler(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count) -{ - char * name = tape_name(STp); - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where); -#endif - osst_wait_ready(STp, aSRpnt, 60 * 5, 0); - osst_set_frame_position(STp, aSRpnt, where, 0); - STp->write_type = OS_WRITE_FILLER; - while (count--) { - memcpy(STp->buffer->b_data, "Filler", 6); - STp->buffer->buffer_bytes = 6; - STp->dirty = 1; - if (osst_flush_write_buffer(STp, aSRpnt)) { - printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name); - return (-EIO); - } - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name); -#endif - return osst_flush_drive_buffer(STp, aSRpnt); -} - -static int __osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count) -{ - char * name = tape_name(STp); - int result; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where); -#endif - osst_wait_ready(STp, aSRpnt, 60 * 5, 0); - osst_set_frame_position(STp, aSRpnt, where, 0); - STp->write_type = OS_WRITE_HEADER; - while (count--) { - osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache); - STp->buffer->buffer_bytes = sizeof(os_header_t); - STp->dirty = 1; - if (osst_flush_write_buffer(STp, aSRpnt)) { - printk(KERN_INFO "%s:I: Couldn't write header frame\n", name); - return (-EIO); - } - } - result = osst_flush_drive_buffer(STp, aSRpnt); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done"); -#endif - return result; -} - -static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int locate_eod) -{ - os_header_t * header; - int result; - char * name = tape_name(STp); - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name); -#endif - if (STp->raw) return 0; - - if (STp->header_cache == NULL) { - if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) { - printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name); - return (-ENOMEM); - } - memset(STp->header_cache, 0, sizeof(os_header_t)); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name); -#endif - } - if (STp->header_ok) STp->update_frame_cntr++; - else STp->update_frame_cntr = 0; - - header = STp->header_cache; - strcpy(header->ident_str, "ADR_SEQ"); - header->major_rev = 1; - header->minor_rev = 4; - header->ext_trk_tb_off = htons(17192); - header->pt_par_num = 1; - header->partition[0].partition_num = OS_DATA_PARTITION; - header->partition[0].par_desc_ver = OS_PARTITION_VERSION; - header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr); - header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos); - header->partition[0].last_frame_ppos = htonl(STp->capacity); - header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos); - header->cfg_col_width = htonl(20); - header->dat_col_width = htonl(1500); - header->qfa_col_width = htonl(0); - header->ext_track_tb.nr_stream_part = 1; - header->ext_track_tb.et_ent_sz = 32; - header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0; - header->ext_track_tb.dat_ext_trk_ey.fmt = 1; - header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736); - header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0; - header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa); - header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos); - header->dat_fm_tab.fm_part_num = 0; - header->dat_fm_tab.fm_tab_ent_sz = 4; - header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cnt<OS_FM_TAB_MAX? - STp->filemark_cnt:OS_FM_TAB_MAX); - - result = __osst_write_header(STp, aSRpnt, 0xbae, 5); - if (STp->update_frame_cntr == 0) - osst_write_filler(STp, aSRpnt, 0xbb3, 5); - result &= __osst_write_header(STp, aSRpnt, 5, 5); - - if (locate_eod) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos); -#endif - osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0); - } - if (result) - printk(KERN_ERR "%s:E: Write header failed\n", name); - else { - memcpy(STp->application_sig, "LIN4", 4); - STp->linux_media = 1; - STp->linux_media_version = 4; - STp->header_ok = 1; - } - return result; -} - -static int osst_reset_header(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - if (STp->header_cache != NULL) - memset(STp->header_cache, 0, sizeof(os_header_t)); - - STp->logical_blk_num = STp->frame_seq_number = 0; - STp->frame_in_buffer = 0; - STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A; - STp->filemark_cnt = 0; - STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1; - return osst_write_header(STp, aSRpnt, 1); -} - -static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt, int ppos) -{ - char * name = tape_name(STp); - os_header_t * header; - os_aux_t * aux; - char id_string[8]; - int linux_media_version, - update_frame_cntr; - - if (STp->raw) - return 1; - - if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) { - if (osst_set_frame_position(STp, aSRpnt, ppos, 0)) - printk(KERN_WARNING "%s:W: Couldn't position tape\n", name); - osst_wait_ready(STp, aSRpnt, 60 * 15, 0); - if (osst_initiate_read (STp, aSRpnt)) { - printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name); - return 0; - } - } - if (osst_read_frame(STp, aSRpnt, 180)) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name); -#endif - return 0; - } - header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */ - aux = STp->buffer->aux; - if (aux->frame_type != OS_FRAME_TYPE_HEADER) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos); -#endif - return 0; - } - if (ntohl(aux->frame_seq_num) != 0 || - ntohl(aux->logical_blk_num) != 0 || - aux->partition.partition_num != OS_CONFIG_PARTITION || - ntohl(aux->partition.first_frame_ppos) != 0 || - ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name, - ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num), - aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos), - ntohl(aux->partition.last_frame_ppos)); -#endif - return 0; - } - if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 && - strncmp(header->ident_str, "ADR-SEQ", 7) != 0) { - strlcpy(id_string, header->ident_str, 8); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string); -#endif - return 0; - } - update_frame_cntr = ntohl(aux->update_frame_cntr); - if (update_frame_cntr < STp->update_frame_cntr) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n", - name, ppos, update_frame_cntr, STp->update_frame_cntr); -#endif - return 0; - } - if (header->major_rev != 1 || header->minor_rev != 4 ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n", - name, (header->major_rev != 1 || header->minor_rev < 2 || - header->minor_rev > 4 )? "Invalid" : "Warning:", - header->major_rev, header->minor_rev); -#endif - if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4) - return 0; - } -#if DEBUG - if (header->pt_par_num != 1) - printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n", - name, header->pt_par_num); -#endif - memcpy(id_string, aux->application_sig, 4); - id_string[4] = 0; - if (memcmp(id_string, "LIN", 3) == 0) { - STp->linux_media = 1; - linux_media_version = id_string[3] - '0'; - if (linux_media_version != 4) - printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n", - name, linux_media_version); - } else { - printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string); - return 0; - } - if (linux_media_version < STp->linux_media_version) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n", - name, ppos, linux_media_version); -#endif - return 0; - } - if (linux_media_version > STp->linux_media_version) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n", - name, ppos, linux_media_version); -#endif - memcpy(STp->application_sig, id_string, 5); - STp->linux_media_version = linux_media_version; - STp->update_frame_cntr = -1; - } - if (update_frame_cntr > STp->update_frame_cntr) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n", - name, ppos, update_frame_cntr); -#endif - if (STp->header_cache == NULL) { - if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) { - printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name); - return 0; - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name); -#endif - } - osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache); - header = STp->header_cache; /* further accesses from cached (full) copy */ - - STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr); - STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos); - STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos); - STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb); - STp->filemark_cnt = ntohl(aux->filemark_cnt); - STp->first_mark_ppos = ntohl(aux->next_mark_ppos); - STp->last_mark_ppos = ntohl(aux->last_mark_ppos); - STp->last_mark_lbn = ntohl(aux->last_mark_lbn); - STp->update_frame_cntr = update_frame_cntr; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n", - name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt); - printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name, - STp->first_data_ppos, - ntohl(header->partition[0].last_frame_ppos), - ntohl(header->partition[0].eod_frame_ppos)); - printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n", - name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos); -#endif - if (header->minor_rev < 4 && STp->linux_media_version == 4) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name); -#endif - memcpy((void *)header->dat_fm_tab.fm_tab_ent, - (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent)); - memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list)); - } - if (header->minor_rev == 4 && - (header->ext_trk_tb_off != htons(17192) || - header->partition[0].partition_num != OS_DATA_PARTITION || - header->partition[0].par_desc_ver != OS_PARTITION_VERSION || - header->partition[0].last_frame_ppos != htonl(STp->capacity) || - header->cfg_col_width != htonl(20) || - header->dat_col_width != htonl(1500) || - header->qfa_col_width != htonl(0) || - header->ext_track_tb.nr_stream_part != 1 || - header->ext_track_tb.et_ent_sz != 32 || - header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION || - header->ext_track_tb.dat_ext_trk_ey.fmt != 1 || - header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) || - header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 || - header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) || - header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION || - header->dat_fm_tab.fm_tab_ent_sz != 4 || - header->dat_fm_tab.fm_tab_ent_cnt != - htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX))) - printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name); - - } - - return 1; -} - -static int osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int position, ppos; - int first, last; - int valid = 0; - char * name = tape_name(STp); - - position = osst_get_frame_position(STp, aSRpnt); - - if (STp->raw) { - STp->header_ok = STp->linux_media = 1; - STp->linux_media_version = 0; - return 1; - } - STp->header_ok = STp->linux_media = STp->linux_media_version = 0; - STp->wrt_pass_cntr = STp->update_frame_cntr = -1; - STp->eod_frame_ppos = STp->first_data_ppos = -1; - STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reading header\n", name); -#endif - - /* optimization for speed - if we are positioned at ppos 10, read second group first */ - /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */ - - first = position==10?0xbae: 5; - last = position==10?0xbb3:10; - - for (ppos = first; ppos < last; ppos++) - if (__osst_analyze_headers(STp, aSRpnt, ppos)) - valid = 1; - - first = position==10? 5:0xbae; - last = position==10?10:0xbb3; - - for (ppos = first; ppos < last; ppos++) - if (__osst_analyze_headers(STp, aSRpnt, ppos)) - valid = 1; - - if (!valid) { - printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name); - STp->eod_frame_ppos = STp->first_data_ppos = 0; - osst_set_frame_position(STp, aSRpnt, 10, 0); - return 0; - } - if (position <= STp->first_data_ppos) { - position = STp->first_data_ppos; - STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0; - } - osst_set_frame_position(STp, aSRpnt, position, 0); - STp->header_ok = 1; - - return 1; -} - -static int osst_verify_position(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int frame_position = STp->first_frame_position; - int frame_seq_numbr = STp->frame_seq_number; - int logical_blk_num = STp->logical_blk_num; - int halfway_frame = STp->frame_in_buffer; - int read_pointer = STp->buffer->read_pointer; - int prev_mark_ppos = -1; - int actual_mark_ppos, i, n; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name); -#endif - osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0); - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name); -#endif - return (-EIO); - } - if (STp->linux_media_version >= 4) { - for (i=0; i<STp->filemark_cnt; i++) - if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position) - prev_mark_ppos = n; - } else - prev_mark_ppos = frame_position - 1; /* usually - we don't really know */ - actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ? - frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos); - if (frame_position != STp->first_frame_position || - frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) || - prev_mark_ppos != actual_mark_ppos ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name, - STp->first_frame_position, frame_position, - STp->frame_seq_number + (halfway_frame?0:1), - frame_seq_numbr, actual_mark_ppos, prev_mark_ppos); -#endif - return (-EIO); - } - if (halfway_frame) { - /* prepare buffer for append and rewrite on top of original */ - osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0); - STp->buffer->buffer_bytes = read_pointer; - STp->ps[STp->partition].rw = ST_WRITING; - STp->dirty = 1; - } - STp->frame_in_buffer = halfway_frame; - STp->frame_seq_number = frame_seq_numbr; - STp->logical_blk_num = logical_blk_num; - return 0; -} - -/* Acc. to OnStream, the vers. numbering is the following: - * X.XX for released versions (X=digit), - * XXXY for unreleased versions (Y=letter) - * Ordering 1.05 < 106A < 106B < ... < 106a < ... < 1.06 - * This fn makes monoton numbers out of this scheme ... - */ -static unsigned int osst_parse_firmware_rev (const char * str) -{ - if (str[1] == '.') { - return (str[0]-'0')*10000 - +(str[2]-'0')*1000 - +(str[3]-'0')*100; - } else { - return (str[0]-'0')*10000 - +(str[1]-'0')*1000 - +(str[2]-'0')*100 - 100 - +(str[3]-'@'); - } -} - -/* - * Configure the OnStream SCII tape drive for default operation - */ -static int osst_configure_onstream(struct osst_tape *STp, struct osst_request ** aSRpnt) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - char * name = tape_name(STp); - struct osst_request * SRpnt = * aSRpnt; - osst_mode_parameter_header_t * header; - osst_block_size_page_t * bs; - osst_capabilities_page_t * cp; - osst_tape_paramtr_page_t * prm; - int drive_buffer_size; - - if (STp->ready != ST_READY) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Not Ready\n", name); -#endif - return (-EIO); - } - - if (STp->os_fw_rev < 10600) { - printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev); - printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name); - } - - /* - * Configure 32.5KB (data+aux) frame size. - * Get the current frame size from the block size mode page - */ - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - cmd[1] = 8; - cmd[2] = BLOCK_SIZE_PAGE; - cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); - if (SRpnt == NULL) { -#if DEBUG - printk(OSST_DEB_MSG "osst :D: Busy\n"); -#endif - return (-EBUSY); - } - *aSRpnt = SRpnt; - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name); - return (-EIO); - } - - header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; - bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl); - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No"); - printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No"); - printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No"); - printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No"); -#endif - - /* - * Configure default auto columns mode, 32.5KB transfer mode - */ - bs->one = 1; - bs->play32 = 0; - bs->play32_5 = 1; - bs->record32 = 0; - bs->record32_5 = 1; - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name); - return (-EIO); - } - -#if DEBUG - printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name); - /* - * In debug mode, we want to see as many errors as possible - * to test the error recovery mechanism. - */ - osst_set_retries(STp, aSRpnt, 0); - SRpnt = * aSRpnt; -#endif - - /* - * Set vendor name to 'LIN4' for "Linux support version 4". - */ - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH; - - header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1; - header->medium_type = 0; /* Medium Type - ignoring */ - header->dsp = 0; /* Reserved */ - header->bdl = 0; /* Block Descriptor Length */ - - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7); - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L'; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I'; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N'; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4'; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name, - (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2)); - return (-EIO); - } - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - cmd[1] = 8; - cmd[2] = CAPABILITIES_PAGE; - cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Can't get capabilities page\n", name); - return (-EIO); - } - - header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; - cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data + - sizeof(osst_mode_parameter_header_t) + header->bdl); - - drive_buffer_size = ntohs(cp->buffer_size) / 2; - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - cmd[1] = 8; - cmd[2] = TAPE_PARAMTR_PAGE; - cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name); - return (-EIO); - } - - header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; - prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data + - sizeof(osst_mode_parameter_header_t) + header->bdl); - - STp->density = prm->density; - STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n", - name, STp->density, STp->capacity / 32, drive_buffer_size); -#endif - - return 0; - -} - - -/* Step over EOF if it has been inadvertently crossed (ioctl not used because - it messes up the block number). */ -static int cross_eof(struct osst_tape *STp, struct osst_request ** aSRpnt, int forward) -{ - int result; - char * name = tape_name(STp); - -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n", - name, forward ? "forward" : "backward"); -#endif - - if (forward) { - /* assumes that the filemark is already read by the drive, so this is low cost */ - result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1); - } - else - /* assumes this is only called if we just read the filemark! */ - result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1); - - if (result < 0) - printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n", - name, forward ? "forward" : "backward"); - - return result; -} - - -/* Get the tape position. */ - -static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt) -{ - unsigned char scmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - int result = 0; - char * name = tape_name(STp); - - /* KG: We want to be able to use it for checking Write Buffer availability - * and thus don't want to risk to overwrite anything. Exchange buffers ... */ - char mybuf[24]; - char * olddata = STp->buffer->b_data; - int oldsize = STp->buffer->buffer_size; - - if (STp->ready != ST_READY) return (-EIO); - - memset (scmd, 0, MAX_COMMAND_SIZE); - scmd[0] = READ_POSITION; - - STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; - SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, DMA_FROM_DEVICE, - STp->timeout, MAX_RETRIES, 1); - if (!SRpnt) { - STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; - return (-EBUSY); - } - *aSRpnt = SRpnt; - - if (STp->buffer->syscall_result) - result = ((SRpnt->sense[2] & 0x0f) == 3) ? -EIO : -EINVAL; /* 3: Write Error */ - - if (result == -EINVAL) - printk(KERN_ERR "%s:E: Can't read tape position.\n", name); - else { - if (result == -EIO) { /* re-read position - this needs to preserve media errors */ - unsigned char mysense[16]; - memcpy (mysense, SRpnt->sense, 16); - memset (scmd, 0, MAX_COMMAND_SIZE); - scmd[0] = READ_POSITION; - STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; - SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, DMA_FROM_DEVICE, - STp->timeout, MAX_RETRIES, 1); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reread position, reason=[%02x:%02x:%02x], result=[%s%02x:%02x:%02x]\n", - name, mysense[2], mysense[12], mysense[13], STp->buffer->syscall_result?"":"ok:", - SRpnt->sense[2],SRpnt->sense[12],SRpnt->sense[13]); -#endif - if (!STp->buffer->syscall_result) - memcpy (SRpnt->sense, mysense, 16); - else - printk(KERN_WARNING "%s:W: Double error in get position\n", name); - } - STp->first_frame_position = ((STp->buffer)->b_data[4] << 24) - + ((STp->buffer)->b_data[5] << 16) - + ((STp->buffer)->b_data[6] << 8) - + (STp->buffer)->b_data[7]; - STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24) - + ((STp->buffer)->b_data[ 9] << 16) - + ((STp->buffer)->b_data[10] << 8) - + (STp->buffer)->b_data[11]; - STp->cur_frames = (STp->buffer)->b_data[15]; -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name, - STp->first_frame_position, STp->last_frame_position, - ((STp->buffer)->b_data[0]&0x80)?" (BOP)": - ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"", - STp->cur_frames); - } -#endif - if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Correcting read position %d, %d, %d\n", name, - STp->first_frame_position, STp->last_frame_position, STp->cur_frames); -#endif - STp->first_frame_position = STp->last_frame_position; - } - } - STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; - - return (result == 0 ? STp->first_frame_position : result); -} - - -/* Set the tape block */ -static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int ppos, int skip) -{ - unsigned char scmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - struct st_partstat * STps; - int result = 0; - int pp = (ppos == 3000 && !skip)? 0 : ppos; - char * name = tape_name(STp); - - if (STp->ready != ST_READY) return (-EIO); - - STps = &(STp->ps[STp->partition]); - - if (ppos < 0 || ppos > STp->capacity) { - printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos); - pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1); - result = (-EINVAL); - } - - do { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp); -#endif - memset (scmd, 0, MAX_COMMAND_SIZE); - scmd[0] = SEEK_10; - scmd[1] = 1; - scmd[3] = (pp >> 24); - scmd[4] = (pp >> 16); - scmd[5] = (pp >> 8); - scmd[6] = pp; - if (skip) - scmd[9] = 0x80; - - SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, DMA_NONE, STp->long_timeout, - MAX_RETRIES, 1); - if (!SRpnt) - return (-EBUSY); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result != 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n", - name, STp->first_frame_position, pp); -#endif - result = (-EIO); - } - if (pp != ppos) - osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE); - } while ((pp != ppos) && (pp = ppos)); - STp->first_frame_position = STp->last_frame_position = ppos; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->rw = ST_IDLE; - STp->frame_in_buffer = 0; - return result; -} - -static int osst_write_trailer(struct osst_tape *STp, struct osst_request ** aSRpnt, int leave_at_EOT) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - int result = 0; - - if (STp->write_type != OS_WRITE_NEW_MARK) { - /* true unless the user wrote the filemark for us */ - result = osst_flush_drive_buffer(STp, aSRpnt); - if (result < 0) goto out; - result = osst_write_filemark(STp, aSRpnt); - if (result < 0) goto out; - - if (STps->drv_file >= 0) - STps->drv_file++ ; - STps->drv_block = 0; - } - result = osst_write_eod(STp, aSRpnt); - osst_write_header(STp, aSRpnt, leave_at_EOT); - - STps->eof = ST_FM; -out: - return result; -} - -/* osst versions of st functions - augmented and stripped to suit OnStream only */ - -/* Flush the write buffer (never need to write if variable blocksize). */ -static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt) -{ - int offset, transfer, blks = 0; - int result = 0; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt = *aSRpnt; - struct st_partstat * STps; - char * name = tape_name(STp); - - if ((STp->buffer)->writing) { - if (SRpnt == (STp->buffer)->last_SRpnt) -#if DEBUG - { printk(OSST_DEB_MSG - "%s:D: aSRpnt points to osst_request that write_behind_check will release -- cleared\n", name); -#endif - *aSRpnt = SRpnt = NULL; -#if DEBUG - } else if (SRpnt) - printk(OSST_DEB_MSG - "%s:D: aSRpnt does not point to osst_request that write_behind_check will release -- strange\n", name); -#endif - osst_write_behind_check(STp); - if ((STp->buffer)->syscall_result) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n", - name, (STp->buffer)->midlevel_result); -#endif - if ((STp->buffer)->midlevel_result == INT_MAX) - return (-ENOSPC); - return (-EIO); - } - } - - result = 0; - if (STp->dirty == 1) { - - STp->write_count++; - STps = &(STp->ps[STp->partition]); - STps->rw = ST_WRITING; - offset = STp->buffer->buffer_bytes; - blks = (offset + STp->block_size - 1) / STp->block_size; - transfer = OS_FRAME_SIZE; - - if (offset < OS_DATA_SIZE) - osst_zero_buffer_tail(STp->buffer); - - if (STp->poll) - if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120)) - result = osst_recover_wait_frame(STp, aSRpnt, 1); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = 1; - cmd[4] = 1; - - switch (STp->write_type) { - case OS_WRITE_DATA: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", - name, blks, STp->frame_seq_number, - STp->logical_blk_num - blks, STp->logical_blk_num - 1); -#endif - osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++, - STp->logical_blk_num - blks, STp->block_size, blks); - break; - case OS_WRITE_EOD: - osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++, - STp->logical_blk_num, 0, 0); - break; - case OS_WRITE_NEW_MARK: - osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++, - STp->logical_blk_num++, 0, blks=1); - break; - case OS_WRITE_HEADER: - osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0); - break; - default: /* probably FILLER */ - osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0); - } -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transferring %d bytes in %d lblocks.\n", - name, offset, transfer, blks); -#endif - - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, DMA_TO_DEVICE, - STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) - return (-EBUSY); - - if ((STp->buffer)->syscall_result != 0) { -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n", - name, SRpnt->sense[0], SRpnt->sense[2], - SRpnt->sense[12], SRpnt->sense[13]); -#endif - if ((SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */ - (SRpnt->sense[2] & 0x0f) == NO_SENSE) { - STp->dirty = 0; - (STp->buffer)->buffer_bytes = 0; - result = (-ENOSPC); - } - else { - if (osst_write_error_recovery(STp, aSRpnt, 1)) { - printk(KERN_ERR "%s:E: Error on flush write.\n", name); - result = (-EIO); - } - } - STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */ - } - else { - STp->first_frame_position++; - STp->dirty = 0; - (STp->buffer)->buffer_bytes = 0; - } - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result); -#endif - return result; -} - - -/* Flush the tape buffer. The tape will be positioned correctly unless - seek_next is true. */ -static int osst_flush_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt, int seek_next) -{ - struct st_partstat * STps; - int backspace = 0, result = 0; -#if DEBUG - char * name = tape_name(STp); -#endif - - /* - * If there was a bus reset, block further access - * to this device. - */ - if( STp->pos_unknown) - return (-EIO); - - if (STp->ready != ST_READY) - return 0; - - STps = &(STp->ps[STp->partition]); - if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */ - STp->write_type = OS_WRITE_DATA; - return osst_flush_write_buffer(STp, aSRpnt); - } - if (STp->block_size == 0) - return 0; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name); -#endif - - if (!STp->can_bsr) { - backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size - - ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ; - (STp->buffer)->buffer_bytes = 0; - (STp->buffer)->read_pointer = 0; - STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */ - } - - if (!seek_next) { - if (STps->eof == ST_FM_HIT) { - result = cross_eof(STp, aSRpnt, 0); /* Back over the EOF hit */ - if (!result) - STps->eof = ST_NOEOF; - else { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - } - } - if (!result && backspace > 0) /* TODO -- design and run a test case for this */ - result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace); - } - else if (STps->eof == ST_FM_HIT) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_NOEOF; - } - - return result; -} - -static int osst_write_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int synchronous) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - int blks; -#if DEBUG - char * name = tape_name(STp); -#endif - - if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */ -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name); -#endif - if (osst_flush_drive_buffer(STp, aSRpnt) < 0) { - return (-EIO); - } - /* error recovery may have bumped us past the header partition */ - if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name); -#endif - osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8); - } - } - - if (STp->poll) - if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -48, 120)) - if (osst_recover_wait_frame(STp, aSRpnt, 1)) - return (-EIO); - -// osst_build_stats(STp, &SRpnt); - - STp->ps[STp->partition].rw = ST_WRITING; - STp->write_type = OS_WRITE_DATA; - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = 1; - cmd[4] = 1; /* one frame at a time... */ - blks = STp->buffer->buffer_bytes / STp->block_size; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks, - STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1); -#endif - osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++, - STp->logical_blk_num - blks, STp->block_size, blks); - -#if DEBUG - if (!synchronous) - STp->write_pending = 1; -#endif - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, STp->timeout, - MAX_RETRIES, synchronous); - if (!SRpnt) - return (-EBUSY); - *aSRpnt = SRpnt; - - if (synchronous) { - if (STp->buffer->syscall_result != 0) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Error on write:\n", name); -#endif - if ((SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x40)) { - if ((SRpnt->sense[2] & 0x0f) == VOLUME_OVERFLOW) - return (-ENOSPC); - } - else { - if (osst_write_error_recovery(STp, aSRpnt, 1)) - return (-EIO); - } - } - else - STp->first_frame_position++; - } - - STp->write_count++; - - return 0; -} - -/* Lock or unlock the drive door. Don't use when struct osst_request allocated. */ -static int do_door_lock(struct osst_tape * STp, int do_lock) -{ - int retval; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl"); -#endif - - retval = scsi_set_medium_removal(STp->device, - do_lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW); - if (!retval) - STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED; - else - STp->door_locked = ST_LOCK_FAILS; - return retval; -} - -/* Set the internal state after reset */ -static void reset_state(struct osst_tape *STp) -{ - int i; - struct st_partstat *STps; - - STp->pos_unknown = 0; - for (i = 0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = -1; - STps->drv_file = -1; - } -} - - -/* Entry points to osst */ - -/* Write command */ -static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos) -{ - ssize_t total, retval = 0; - ssize_t i, do_count, blks, transfer; - int write_threshold; - int doing_write = 0; - const char __user * b_point; - struct osst_request * SRpnt = NULL; - struct st_modedef * STm; - struct st_partstat * STps; - struct osst_tape * STp = filp->private_data; - char * name = tape_name(STp); - - - if (mutex_lock_interruptible(&STp->lock)) - return (-ERESTARTSYS); - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(STp->device) ) { - retval = (-ENXIO); - goto out; - } - - if (STp->ready != ST_READY) { - if (STp->ready == ST_NO_TAPE) - retval = (-ENOMEDIUM); - else - retval = (-EIO); - goto out; - } - STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) { - retval = (-ENXIO); - goto out; - } - if (count == 0) - goto out; - - /* - * If there was a bus reset, block further access - * to this device. - */ - if (STp->pos_unknown) { - retval = (-EIO); - goto out; - } - -#if DEBUG - if (!STp->in_use) { - printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); - retval = (-EIO); - goto out; - } -#endif - - if (STp->write_prot) { - retval = (-EACCES); - goto out; - } - - /* Write must be integral number of blocks */ - if (STp->block_size != 0 && (count % STp->block_size) != 0) { - printk(KERN_ERR "%s:E: Write (%zd bytes) not multiple of tape block size (%d%c).\n", - name, count, STp->block_size<1024? - STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); - retval = (-EINVAL); - goto out; - } - - if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) { - printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n", - name, STp->first_frame_position); - retval = (-ENOSPC); - goto out; - } - - if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1)) - STp->door_locked = ST_LOCKED_AUTO; - - STps = &(STp->ps[STp->partition]); - - if (STps->rw == ST_READING) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name, - STps->drv_file, STps->drv_block); -#endif - retval = osst_flush_buffer(STp, &SRpnt, 0); - if (retval) - goto out; - STps->rw = ST_IDLE; - } - if (STps->rw != ST_WRITING) { - /* Are we totally rewriting this tape? */ - if (!STp->header_ok || - (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) || - (STps->drv_file == 0 && STps->drv_block == 0)) { - STp->wrt_pass_cntr++; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n", - name, STp->wrt_pass_cntr); -#endif - osst_reset_header(STp, &SRpnt); - STps->drv_file = STps->drv_block = 0; - } - /* Do we know where we'll be writing on the tape? */ - else { - if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) || - STps->drv_file < 0 || STps->drv_block < 0) { - if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */ - STps->drv_file = STp->filemark_cnt; - STps->drv_block = 0; - } - else { - /* We have no idea where the tape is positioned - give up */ -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Cannot write at indeterminate position.\n", name); -#endif - retval = (-EIO); - goto out; - } - } - if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) { - STp->filemark_cnt = STps->drv_file; - STp->last_mark_ppos = - ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]); - printk(KERN_WARNING - "%s:W: Overwriting file %d with old write pass counter %d\n", - name, STps->drv_file, STp->wrt_pass_cntr); - printk(KERN_WARNING - "%s:W: may lead to stale data being accepted on reading back!\n", - name); -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n", - name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn); -#endif - } - } - STp->fast_open = 0; - } - if (!STp->header_ok) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name); -#endif - retval = (-EIO); - goto out; - } - - if ((STp->buffer)->writing) { -if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__); - osst_write_behind_check(STp); - if ((STp->buffer)->syscall_result) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name, - (STp->buffer)->midlevel_result); -#endif - if ((STp->buffer)->midlevel_result == INT_MAX) - STps->eof = ST_EOM_OK; - else - STps->eof = ST_EOM_ERROR; - } - } - if (STps->eof == ST_EOM_OK) { - retval = (-ENOSPC); - goto out; - } - else if (STps->eof == ST_EOM_ERROR) { - retval = (-EIO); - goto out; - } - - /* Check the buffer readability in cases where copy_user might catch - the problems after some tape movement. */ - if ((copy_from_user(&i, buf, 1) != 0 || - copy_from_user(&i, buf + count - 1, 1) != 0)) { - retval = (-EFAULT); - goto out; - } - - if (!STm->do_buffer_writes) { - write_threshold = 1; - } - else - write_threshold = (STp->buffer)->buffer_blocks * STp->block_size; - if (!STm->do_async_writes) - write_threshold--; - - total = count; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n", - name, (int) count, STps->drv_file, STps->drv_block, - STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position); -#endif - b_point = buf; - while ((STp->buffer)->buffer_bytes + count > write_threshold) - { - doing_write = 1; - do_count = (STp->buffer)->buffer_blocks * STp->block_size - - (STp->buffer)->buffer_bytes; - if (do_count > count) - do_count = count; - - i = append_to_buffer(b_point, STp->buffer, do_count); - if (i) { - retval = i; - goto out; - } - - blks = do_count / STp->block_size; - STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */ - - i = osst_write_frame(STp, &SRpnt, 1); - - if (i == (-ENOSPC)) { - transfer = STp->buffer->writing; /* FIXME -- check this logic */ - if (transfer <= do_count) { - *ppos += do_count - transfer; - count -= do_count - transfer; - if (STps->drv_block >= 0) { - STps->drv_block += (do_count - transfer) / STp->block_size; - } - STps->eof = ST_EOM_OK; - retval = (-ENOSPC); /* EOM within current request */ -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n", - name, (int) transfer); -#endif - } - else { - STps->eof = ST_EOM_ERROR; - STps->drv_block = (-1); /* Too cautious? */ - retval = (-EIO); /* EOM for old data */ -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name); -#endif - } - } - else - retval = i; - - if (retval < 0) { - if (SRpnt != NULL) { - osst_release_request(SRpnt); - SRpnt = NULL; - } - STp->buffer->buffer_bytes = 0; - STp->dirty = 0; - if (count < total) - retval = total - count; - goto out; - } - - *ppos += do_count; - b_point += do_count; - count -= do_count; - if (STps->drv_block >= 0) { - STps->drv_block += blks; - } - STp->buffer->buffer_bytes = 0; - STp->dirty = 0; - } /* end while write threshold exceeded */ - - if (count != 0) { - STp->dirty = 1; - i = append_to_buffer(b_point, STp->buffer, count); - if (i) { - retval = i; - goto out; - } - blks = count / STp->block_size; - STp->logical_blk_num += blks; - if (STps->drv_block >= 0) { - STps->drv_block += blks; - } - *ppos += count; - count = 0; - } - - if (doing_write && (STp->buffer)->syscall_result != 0) { - retval = (STp->buffer)->syscall_result; - goto out; - } - - if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) { - /* Schedule an asynchronous write */ - (STp->buffer)->writing = ((STp->buffer)->buffer_bytes / - STp->block_size) * STp->block_size; - STp->dirty = !((STp->buffer)->writing == - (STp->buffer)->buffer_bytes); - - i = osst_write_frame(STp, &SRpnt, 0); - if (i < 0) { - retval = (-EIO); - goto out; - } - SRpnt = NULL; /* Prevent releasing this request! */ - } - STps->at_sm &= (total == 0); - if (total > 0) - STps->eof = ST_NOEOF; - - retval = total; - -out: - if (SRpnt != NULL) osst_release_request(SRpnt); - - mutex_unlock(&STp->lock); - - return retval; -} - - -/* Read command */ -static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos) -{ - ssize_t total, retval = 0; - ssize_t i, transfer; - int special; - struct st_modedef * STm; - struct st_partstat * STps; - struct osst_request * SRpnt = NULL; - struct osst_tape * STp = filp->private_data; - char * name = tape_name(STp); - - - if (mutex_lock_interruptible(&STp->lock)) - return (-ERESTARTSYS); - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(STp->device) ) { - retval = (-ENXIO); - goto out; - } - - if (STp->ready != ST_READY) { - if (STp->ready == ST_NO_TAPE) - retval = (-ENOMEDIUM); - else - retval = (-EIO); - goto out; - } - STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) { - retval = (-ENXIO); - goto out; - } -#if DEBUG - if (!STp->in_use) { - printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); - retval = (-EIO); - goto out; - } -#endif - /* Must have initialized medium */ - if (!STp->header_ok) { - retval = (-EIO); - goto out; - } - - if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1)) - STp->door_locked = ST_LOCKED_AUTO; - - STps = &(STp->ps[STp->partition]); - if (STps->rw == ST_WRITING) { - retval = osst_flush_buffer(STp, &SRpnt, 0); - if (retval) - goto out; - STps->rw = ST_IDLE; - /* FIXME -- this may leave the tape without EOD and up2date headers */ - } - - if ((count % STp->block_size) != 0) { - printk(KERN_WARNING - "%s:W: Read (%zd bytes) not multiple of tape block size (%d%c).\n", name, count, - STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); - } - -#if DEBUG - if (debugging && STps->eof != ST_NOEOF) - printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name, - STps->eof, (STp->buffer)->buffer_bytes); -#endif - if ((STp->buffer)->buffer_bytes == 0 && - STps->eof >= ST_EOD_1) { - if (STps->eof < ST_EOD) { - STps->eof += 1; - retval = 0; - goto out; - } - retval = (-EIO); /* EOM or Blank Check */ - goto out; - } - - /* Check the buffer writability before any tape movement. Don't alter - buffer data. */ - if (copy_from_user(&i, buf, 1) != 0 || - copy_to_user (buf, &i, 1) != 0 || - copy_from_user(&i, buf + count - 1, 1) != 0 || - copy_to_user (buf + count - 1, &i, 1) != 0) { - retval = (-EFAULT); - goto out; - } - - /* Loop until enough data in buffer or a special condition found */ - for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) { - - /* Get new data if the buffer is empty */ - if ((STp->buffer)->buffer_bytes == 0) { - if (STps->eof == ST_FM_HIT) - break; - special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0); - if (special < 0) { /* No need to continue read */ - STp->frame_in_buffer = 0; - retval = special; - goto out; - } - } - - /* Move the data from driver buffer to user buffer */ - if ((STp->buffer)->buffer_bytes > 0) { -#if DEBUG - if (debugging && STps->eof != ST_NOEOF) - printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name, - STps->eof, (STp->buffer)->buffer_bytes, (int) (count - total)); -#endif - /* force multiple of block size, note block_size may have been adjusted */ - transfer = (((STp->buffer)->buffer_bytes < count - total ? - (STp->buffer)->buffer_bytes : count - total)/ - STp->block_size) * STp->block_size; - - if (transfer == 0) { - printk(KERN_WARNING - "%s:W: Nothing can be transferred, requested %zd, tape block size (%d%c).\n", - name, count, STp->block_size < 1024? - STp->block_size:STp->block_size/1024, - STp->block_size<1024?'b':'k'); - break; - } - i = from_buffer(STp->buffer, buf, transfer); - if (i) { - retval = i; - goto out; - } - STp->logical_blk_num += transfer / STp->block_size; - STps->drv_block += transfer / STp->block_size; - *ppos += transfer; - buf += transfer; - total += transfer; - } - - if ((STp->buffer)->buffer_bytes == 0) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n", - name, STp->frame_seq_number); -#endif - STp->frame_in_buffer = 0; - STp->frame_seq_number++; /* frame to look for next time */ - } - } /* for (total = 0, special = 0; total < count && !special; ) */ - - /* Change the eof state if no data from tape or buffer */ - if (total == 0) { - if (STps->eof == ST_FM_HIT) { - STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM; - STps->drv_block = 0; - if (STps->drv_file >= 0) - STps->drv_file++; - } - else if (STps->eof == ST_EOD_1) { - STps->eof = ST_EOD_2; - if (STps->drv_block > 0 && STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - } - else if (STps->eof == ST_EOD_2) - STps->eof = ST_EOD; - } - else if (STps->eof == ST_FM) - STps->eof = ST_NOEOF; - - retval = total; - -out: - if (SRpnt != NULL) osst_release_request(SRpnt); - - mutex_unlock(&STp->lock); - - return retval; -} - - -/* Set the driver options */ -static void osst_log_options(struct osst_tape *STp, struct st_modedef *STm, char *name) -{ - printk(KERN_INFO -"%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", - name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, - STm->do_read_ahead); - printk(KERN_INFO -"%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", - name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); - printk(KERN_INFO -"%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", - name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, - STp->scsi2_logical); - printk(KERN_INFO -"%s:I: sysv: %d\n", name, STm->sysv); -#if DEBUG - printk(KERN_INFO - "%s:D: debugging: %d\n", - name, debugging); -#endif -} - - -static int osst_set_options(struct osst_tape *STp, long options) -{ - int value; - long code; - struct st_modedef * STm; - char * name = tape_name(STp); - - STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) { - memcpy(STm, &(STp->modes[0]), sizeof(*STm)); - modes_defined = 1; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n", - name, STp->current_mode); -#endif - } - - code = options & MT_ST_OPTIONS; - if (code == MT_ST_BOOLEANS) { - STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0; - STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0; - STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0; - STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0; - STp->two_fm = (options & MT_ST_TWO_FM) != 0; - STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0; - STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0; - STp->can_bsr = (options & MT_ST_CAN_BSR) != 0; - STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0; - if ((STp->device)->scsi_level >= SCSI_2) - STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; - STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; - STm->sysv = (options & MT_ST_SYSV) != 0; -#if DEBUG - debugging = (options & MT_ST_DEBUGGING) != 0; -#endif - osst_log_options(STp, STm, name); - } - else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { - value = (code == MT_ST_SETBOOLEANS); - if ((options & MT_ST_BUFFER_WRITES) != 0) - STm->do_buffer_writes = value; - if ((options & MT_ST_ASYNC_WRITES) != 0) - STm->do_async_writes = value; - if ((options & MT_ST_DEF_WRITES) != 0) - STm->defaults_for_writes = value; - if ((options & MT_ST_READ_AHEAD) != 0) - STm->do_read_ahead = value; - if ((options & MT_ST_TWO_FM) != 0) - STp->two_fm = value; - if ((options & MT_ST_FAST_MTEOM) != 0) - STp->fast_mteom = value; - if ((options & MT_ST_AUTO_LOCK) != 0) - STp->do_auto_lock = value; - if ((options & MT_ST_CAN_BSR) != 0) - STp->can_bsr = value; - if ((options & MT_ST_NO_BLKLIMS) != 0) - STp->omit_blklims = value; - if ((STp->device)->scsi_level >= SCSI_2 && - (options & MT_ST_CAN_PARTITIONS) != 0) - STp->can_partitions = value; - if ((options & MT_ST_SCSI2LOGICAL) != 0) - STp->scsi2_logical = value; - if ((options & MT_ST_SYSV) != 0) - STm->sysv = value; -#if DEBUG - if ((options & MT_ST_DEBUGGING) != 0) - debugging = value; -#endif - osst_log_options(STp, STm, name); - } - else if (code == MT_ST_WRITE_THRESHOLD) { - value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE; - if (value < 1 || value > osst_buffer_size) { - printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n", - name, value); - return (-EIO); - } - STp->write_threshold = value; - printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n", - name, value); - } - else if (code == MT_ST_DEF_BLKSIZE) { - value = (options & ~MT_ST_OPTIONS); - if (value == ~MT_ST_OPTIONS) { - STm->default_blksize = (-1); - printk(KERN_INFO "%s:I: Default block size disabled.\n", name); - } - else { - if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) { - printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n", - name, value); - return (-EINVAL); - } - STm->default_blksize = value; - printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n", - name, STm->default_blksize); - } - } - else if (code == MT_ST_TIMEOUTS) { - value = (options & ~MT_ST_OPTIONS); - if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { - STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; - printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name, - (value & ~MT_ST_SET_LONG_TIMEOUT)); - } - else { - STp->timeout = value * HZ; - printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value); - } - } - else if (code == MT_ST_DEF_OPTIONS) { - code = (options & ~MT_ST_CLEAR_DEFAULT); - value = (options & MT_ST_CLEAR_DEFAULT); - if (code == MT_ST_DEF_DENSITY) { - if (value == MT_ST_CLEAR_DEFAULT) { - STm->default_density = (-1); - printk(KERN_INFO "%s:I: Density default disabled.\n", name); - } - else { - STm->default_density = value & 0xff; - printk(KERN_INFO "%s:I: Density default set to %x\n", - name, STm->default_density); - } - } - else if (code == MT_ST_DEF_DRVBUFFER) { - if (value == MT_ST_CLEAR_DEFAULT) { - STp->default_drvbuffer = 0xff; - printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name); - } - else { - STp->default_drvbuffer = value & 7; - printk(KERN_INFO "%s:I: Drive buffer default set to %x\n", - name, STp->default_drvbuffer); - } - } - else if (code == MT_ST_DEF_COMPRESSION) { - if (value == MT_ST_CLEAR_DEFAULT) { - STm->default_compression = ST_DONT_TOUCH; - printk(KERN_INFO "%s:I: Compression default disabled.\n", name); - } - else { - STm->default_compression = (value & 1 ? ST_YES : ST_NO); - printk(KERN_INFO "%s:I: Compression default set to %x\n", - name, (value & 1)); - } - } - } - else - return (-EIO); - - return 0; -} - - -/* Internal ioctl function */ -static int osst_int_ioctl(struct osst_tape * STp, struct osst_request ** aSRpnt, - unsigned int cmd_in, unsigned long arg) -{ - int timeout; - long ltmp; - int i, ioctl_result; - int chg_eof = 1; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt = * aSRpnt; - struct st_partstat * STps; - int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num; - int datalen = 0, direction = DMA_NONE; - char * name = tape_name(STp); - - if (STp->ready != ST_READY && cmd_in != MTLOAD) { - if (STp->ready == ST_NO_TAPE) - return (-ENOMEDIUM); - else - return (-EIO); - } - timeout = STp->long_timeout; - STps = &(STp->ps[STp->partition]); - fileno = STps->drv_file; - blkno = STps->drv_block; - at_sm = STps->at_sm; - frame_seq_numbr = STp->frame_seq_number; - logical_blk_num = STp->logical_blk_num; - - memset(cmd, 0, MAX_COMMAND_SIZE); - switch (cmd_in) { - case MTFSFM: - chg_eof = 0; /* Changed from the FSF after this */ - /* fall through */ - case MTFSF: - if (STp->raw) - return (-EIO); - if (STp->linux_media) - ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg); - else - ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg); - if (fileno >= 0) - fileno += arg; - blkno = 0; - at_sm &= (arg == 0); - goto os_bypass; - - case MTBSF: - chg_eof = 0; /* Changed from the FSF after this */ - /* fall through */ - case MTBSFM: - if (STp->raw) - return (-EIO); - ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg); - if (fileno >= 0) - fileno -= arg; - blkno = (-1); /* We can't know the block number */ - at_sm &= (arg == 0); - goto os_bypass; - - case MTFSR: - case MTBSR: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n", - name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num); -#endif - if (cmd_in == MTFSR) { - logical_blk_num += arg; - if (blkno >= 0) blkno += arg; - } - else { - logical_blk_num -= arg; - if (blkno >= 0) blkno -= arg; - } - ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num); - fileno = STps->drv_file; - blkno = STps->drv_block; - at_sm &= (arg == 0); - goto os_bypass; - - case MTFSS: - cmd[0] = SPACE; - cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */ - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); -#endif - if (arg != 0) { - blkno = fileno = (-1); - at_sm = 1; - } - break; - case MTBSS: - cmd[0] = SPACE; - cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */ - ltmp = (-arg); - cmd[2] = (ltmp >> 16); - cmd[3] = (ltmp >> 8); - cmd[4] = ltmp; -#if DEBUG - if (debugging) { - if (cmd[2] & 0x80) - ltmp = 0xff000000; - ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; - printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n", - name, (-ltmp)); - } -#endif - if (arg != 0) { - blkno = fileno = (-1); - at_sm = 1; - } - break; - case MTWEOF: - if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) { - STp->write_type = OS_WRITE_DATA; - ioctl_result = osst_flush_write_buffer(STp, &SRpnt); - } else - ioctl_result = 0; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg); -#endif - for (i=0; i<arg; i++) - ioctl_result |= osst_write_filemark(STp, &SRpnt); - if (fileno >= 0) fileno += arg; - if (blkno >= 0) blkno = 0; - goto os_bypass; - - case MTWSM: - if (STp->write_prot) - return (-EACCES); - if (!STp->raw) - return 0; - cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */ - if (cmd_in == MTWSM) - cmd[1] = 2; - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; - timeout = STp->timeout; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); -#endif - if (fileno >= 0) - fileno += arg; - blkno = 0; - at_sm = (cmd_in == MTWSM); - break; - case MTOFFL: - case MTLOAD: - case MTUNLOAD: - case MTRETEN: - cmd[0] = START_STOP; - cmd[1] = 1; /* Don't wait for completion */ - if (cmd_in == MTLOAD) { - if (STp->ready == ST_NO_TAPE) - cmd[4] = 4; /* open tray */ - else - cmd[4] = 1; /* load */ - } - if (cmd_in == MTRETEN) - cmd[4] = 3; /* retension then mount */ - if (cmd_in == MTOFFL) - cmd[4] = 4; /* rewind then eject */ - timeout = STp->timeout; -#if DEBUG - if (debugging) { - switch (cmd_in) { - case MTUNLOAD: - printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name); - break; - case MTLOAD: - printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name); - break; - case MTRETEN: - printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name); - break; - case MTOFFL: - printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name); - break; - } - } -#endif - fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ; - break; - case MTNOP: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name); -#endif - return 0; /* Should do something ? */ - break; - case MTEOM: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name); -#endif - if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) || - (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) { - ioctl_result = -EIO; - goto os_bypass; - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name); -#endif - ioctl_result = -EIO; - goto os_bypass; - } - ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0); - fileno = STp->filemark_cnt; - blkno = at_sm = 0; - goto os_bypass; - - case MTERASE: - if (STp->write_prot) - return (-EACCES); - ioctl_result = osst_reset_header(STp, &SRpnt); - i = osst_write_eod(STp, &SRpnt); - if (i < ioctl_result) ioctl_result = i; - i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos); - if (i < ioctl_result) ioctl_result = i; - fileno = blkno = at_sm = 0 ; - goto os_bypass; - - case MTREW: - cmd[0] = REZERO_UNIT; /* rewind */ - cmd[1] = 1; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]); -#endif - fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ; - break; - - case MTSETBLK: /* Set block length */ - if ((STps->drv_block == 0 ) && - !STp->dirty && - ((STp->buffer)->buffer_bytes == 0) && - ((arg & MT_ST_BLKSIZE_MASK) >= 512 ) && - ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) && - !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK)) ) { - /* - * Only allowed to change the block size if you opened the - * device at the beginning of a file before writing anything. - * Note, that when reading, changing block_size is futile, - * as the size used when writing overrides it. - */ - STp->block_size = (arg & MT_ST_BLKSIZE_MASK); - printk(KERN_INFO "%s:I: Block size set to %d bytes.\n", - name, STp->block_size); - return 0; - } - /* fall through */ - case MTSETDENSITY: /* Set tape density */ - case MTSETDRVBUFFER: /* Set drive buffering */ - case SET_DENS_AND_BLK: /* Set density and block size */ - chg_eof = 0; - if (STp->dirty || (STp->buffer)->buffer_bytes != 0) - return (-EIO); /* Not allowed if data in buffer */ - if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) && - (arg & MT_ST_BLKSIZE_MASK) != 0 && - (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) { - printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n", - name, (int)(arg & MT_ST_BLKSIZE_MASK), - (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now"); - return (-EINVAL); - } - return 0; /* FIXME silently ignore if block size didn't change */ - - default: - return (-ENOSYS); - } - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, 1); - - ioctl_result = (STp->buffer)->syscall_result; - - if (!SRpnt) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name); -#endif - return ioctl_result; - } - - if (!ioctl_result) { /* SCSI command successful */ - STp->frame_seq_number = frame_seq_numbr; - STp->logical_blk_num = logical_blk_num; - } - -os_bypass: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result); -#endif - - if (!ioctl_result) { /* success */ - - if (cmd_in == MTFSFM) { - fileno--; - blkno--; - } - if (cmd_in == MTBSFM) { - fileno++; - blkno++; - } - STps->drv_block = blkno; - STps->drv_file = fileno; - STps->at_sm = at_sm; - - if (cmd_in == MTEOM) - STps->eof = ST_EOD; - else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) { - ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1); - STps->drv_block++; - STp->logical_blk_num++; - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->buffer->read_pointer = 0; - } - else if (cmd_in == MTFSF) - STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM; - else if (chg_eof) - STps->eof = ST_NOEOF; - - if (cmd_in == MTOFFL || cmd_in == MTUNLOAD) - STp->rew_at_close = 0; - else if (cmd_in == MTLOAD) { - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STp->ps[i].rw = ST_IDLE; - STp->ps[i].last_block_valid = 0;/* FIXME - where else is this field maintained? */ - } - STp->partition = 0; - } - - if (cmd_in == MTREW) { - ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos); - if (ioctl_result > 0) - ioctl_result = 0; - } - - } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) { - if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0) - STps->drv_file = STps->drv_block = -1; - else - STps->drv_file = STps->drv_block = 0; - STps->eof = ST_NOEOF; - } else if (cmd_in == MTFSF || cmd_in == MTFSFM) { - if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) - STps->drv_file = STps->drv_block = -1; - else { - STps->drv_file = STp->filemark_cnt; - STps->drv_block = 0; - } - STps->eof = ST_EOD; - } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) { - STps->drv_file = STps->drv_block = (-1); - STps->eof = ST_NOEOF; - STp->header_ok = 0; - } else if (cmd_in == MTERASE) { - STp->header_ok = 0; - } else if (SRpnt) { /* SCSI command was not completely successful. */ - if (SRpnt->sense[2] & 0x40) { - STps->eof = ST_EOM_OK; - STps->drv_block = 0; - } - if (chg_eof) - STps->eof = ST_NOEOF; - - if ((SRpnt->sense[2] & 0x0f) == BLANK_CHECK) - STps->eof = ST_EOD; - - if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60)) - ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE); - } - *aSRpnt = SRpnt; - - return ioctl_result; -} - - -/* Open the device */ -static int __os_scsi_tape_open(struct inode * inode, struct file * filp) -{ - unsigned short flags; - int i, b_size, new_session = 0, retval = 0; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt = NULL; - struct osst_tape * STp; - struct st_modedef * STm; - struct st_partstat * STps; - char * name; - int dev = TAPE_NR(inode); - int mode = TAPE_MODE(inode); - - /* - * We really want to do nonseekable_open(inode, filp); here, but some - * versions of tar incorrectly call lseek on tapes and bail out if that - * fails. So we disallow pread() and pwrite(), but permit lseeks. - */ - filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); - - write_lock(&os_scsi_tapes_lock); - if (dev >= osst_max_dev || os_scsi_tapes == NULL || - (STp = os_scsi_tapes[dev]) == NULL || !STp->device) { - write_unlock(&os_scsi_tapes_lock); - return (-ENXIO); - } - - name = tape_name(STp); - - if (STp->in_use) { - write_unlock(&os_scsi_tapes_lock); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name); -#endif - return (-EBUSY); - } - if (scsi_device_get(STp->device)) { - write_unlock(&os_scsi_tapes_lock); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name); -#endif - return (-ENXIO); - } - filp->private_data = STp; - STp->in_use = 1; - write_unlock(&os_scsi_tapes_lock); - STp->rew_at_close = TAPE_REWIND(inode); - - if( !scsi_block_when_processing_errors(STp->device) ) { - return -ENXIO; - } - - if (mode != STp->current_mode) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n", - name, STp->current_mode, mode); -#endif - new_session = 1; - STp->current_mode = mode; - } - STm = &(STp->modes[STp->current_mode]); - - flags = filp->f_flags; - STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY); - - STp->raw = TAPE_IS_RAW(inode); - if (STp->raw) - STp->header_ok = 0; - - /* Allocate data segments for this device's tape buffer */ - if (!enlarge_buffer(STp->buffer, STp->restr_dma)) { - printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name); - retval = (-EOVERFLOW); - goto err_out; - } - if (STp->buffer->buffer_size >= OS_FRAME_SIZE) { - for (i = 0, b_size = 0; - (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE); - b_size += STp->buffer->sg[i++].length); - STp->buffer->aux = (os_aux_t *) (page_address(sg_page(&STp->buffer->sg[i])) + OS_DATA_SIZE - b_size); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name, - STp->buffer->b_data, page_address(STp->buffer->sg[0].page)); - printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name, - STp->buffer->aux, i, page_address(STp->buffer->sg[i].page)); -#endif - } else { - STp->buffer->aux = NULL; /* this had better never happen! */ - printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE); - retval = (-EIO); - goto err_out; - } - STp->buffer->writing = 0; - STp->buffer->syscall_result = 0; - STp->dirty = 0; - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; - } - STp->ready = ST_READY; -#if DEBUG - STp->nbr_waits = STp->nbr_finished = 0; -#endif - - memset (cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - if (!SRpnt) { - retval = (STp->buffer)->syscall_result; /* FIXME - valid? */ - goto err_out; - } - if ((SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x0f) == NOT_READY && - SRpnt->sense[12] == 4 ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sense[13]); -#endif - if (filp->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto err_out; - } - if (SRpnt->sense[13] == 2) { /* initialize command required (LOAD) */ - memset (cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = START_STOP; - cmd[1] = 1; - cmd[4] = 1; - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, - STp->timeout, MAX_RETRIES, 1); - } - osst_wait_ready(STp, &SRpnt, (SRpnt->sense[13]==1?15:3) * 60, 0); - } - if ((SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name); -#endif - STp->header_ok = 0; - - for (i=0; i < 10; i++) { - - memset (cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, - STp->timeout, MAX_RETRIES, 1); - if ((SRpnt->sense[0] & 0x70) != 0x70 || - (SRpnt->sense[2] & 0x0f) != UNIT_ATTENTION) - break; - } - - STp->pos_unknown = 0; - STp->partition = STp->new_partition = 0; - if (STp->can_partitions) - STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */ - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = 0; - STps->drv_file = 0 ; - } - new_session = 1; - STp->recover_count = 0; - STp->abort_count = 0; - } - /* - * if we have valid headers from before, and the drive/tape seem untouched, - * open without reconfiguring and re-reading the headers - */ - if (!STp->buffer->syscall_result && STp->header_ok && - !SRpnt->result && SRpnt->sense[0] == 0) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - cmd[1] = 8; - cmd[2] = VENDOR_IDENT_PAGE; - cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); - - if (STp->buffer->syscall_result || - STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' || - STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' || - STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' || - STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name, - STp->buffer->b_data[MODE_HEADER_LENGTH + 2], - STp->buffer->b_data[MODE_HEADER_LENGTH + 3], - STp->buffer->b_data[MODE_HEADER_LENGTH + 4], - STp->buffer->b_data[MODE_HEADER_LENGTH + 5]); -#endif - STp->header_ok = 0; - } - i = STp->first_frame_position; - if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) { - if (STp->door_locked == ST_UNLOCKED) { - if (do_door_lock(STp, 1)) - printk(KERN_INFO "%s:I: Can't lock drive door\n", name); - else - STp->door_locked = ST_LOCKED_AUTO; - } - if (!STp->frame_in_buffer) { - STp->block_size = (STm->default_blksize > 0) ? - STm->default_blksize : OS_DATA_SIZE; - STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0; - } - STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size; - STp->fast_open = 1; - osst_release_request(SRpnt); - return 0; - } -#if DEBUG - if (i != STp->first_frame_position) - printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n", - name, i, STp->first_frame_position); -#endif - STp->header_ok = 0; - } - STp->fast_open = 0; - - if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */ - (SRpnt->sense[2] != 2 || SRpnt->sense[12] != 0x3A) ) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = 4 + MODE_HEADER_LENGTH; - - (STp->buffer)->b_data[0] = cmd[4] - 1; - (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */ - (STp->buffer)->b_data[2] = 0; /* Reserved */ - (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */ - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name); -#endif - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); - - STp->header_ok = 0; - - for (i=0; i < 10; i++) { - - memset (cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, - STp->timeout, MAX_RETRIES, 1); - if ((SRpnt->sense[0] & 0x70) != 0x70 || - (SRpnt->sense[2] & 0x0f) == NOT_READY) - break; - - if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { - int j; - - STp->pos_unknown = 0; - STp->partition = STp->new_partition = 0; - if (STp->can_partitions) - STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ - for (j = 0; j < ST_NBR_PARTITIONS; j++) { - STps = &(STp->ps[j]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = 0; - STps->drv_file = 0 ; - } - new_session = 1; - } - } - } - - if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */ - printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name); - - if ((STp->buffer)->syscall_result != 0) { - if ((STp->device)->scsi_level >= SCSI_2 && - (SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x0f) == NOT_READY && - SRpnt->sense[12] == 0x3a) { /* Check ASC */ - STp->ready = ST_NO_TAPE; - } else - STp->ready = ST_NOT_READY; - osst_release_request(SRpnt); - SRpnt = NULL; - STp->density = 0; /* Clear the erroneous "residue" */ - STp->write_prot = 0; - STp->block_size = 0; - STp->ps[0].drv_file = STp->ps[0].drv_block = (-1); - STp->partition = STp->new_partition = 0; - STp->door_locked = ST_UNLOCKED; - return 0; - } - - osst_configure_onstream(STp, &SRpnt); - - STp->block_size = STp->raw ? OS_FRAME_SIZE : ( - (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE); - STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size; - STp->buffer->buffer_bytes = - STp->buffer->read_pointer = - STp->frame_in_buffer = 0; - -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n", - name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size, - (STp->buffer)->buffer_blocks); -#endif - - if (STp->drv_write_prot) { - STp->write_prot = 1; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Write protected\n", name); -#endif - if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) { - retval = (-EROFS); - goto err_out; - } - } - - if (new_session) { /* Change the drive parameters for the new mode */ -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: New Session\n", name); -#endif - STp->density_changed = STp->blksize_changed = 0; - STp->compression_changed = 0; - } - - /* - * properly position the tape and check the ADR headers - */ - if (STp->door_locked == ST_UNLOCKED) { - if (do_door_lock(STp, 1)) - printk(KERN_INFO "%s:I: Can't lock drive door\n", name); - else - STp->door_locked = ST_LOCKED_AUTO; - } - - osst_analyze_headers(STp, &SRpnt); - - osst_release_request(SRpnt); - SRpnt = NULL; - - return 0; - -err_out: - if (SRpnt != NULL) - osst_release_request(SRpnt); - normalize_buffer(STp->buffer); - STp->header_ok = 0; - STp->in_use = 0; - scsi_device_put(STp->device); - - return retval; -} - -/* BKL pushdown: spaghetti avoidance wrapper */ -static int os_scsi_tape_open(struct inode * inode, struct file * filp) -{ - int ret; - - mutex_lock(&osst_int_mutex); - ret = __os_scsi_tape_open(inode, filp); - mutex_unlock(&osst_int_mutex); - return ret; -} - - - -/* Flush the tape buffer before close */ -static int os_scsi_tape_flush(struct file * filp, fl_owner_t id) -{ - int result = 0, result2; - struct osst_tape * STp = filp->private_data; - struct st_modedef * STm = &(STp->modes[STp->current_mode]); - struct st_partstat * STps = &(STp->ps[STp->partition]); - struct osst_request * SRpnt = NULL; - char * name = tape_name(STp); - - if (file_count(filp) > 1) - return 0; - - if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) { - STp->write_type = OS_WRITE_DATA; - result = osst_flush_write_buffer(STp, &SRpnt); - if (result != 0 && result != (-ENOSPC)) - goto out; - } - if ( STps->rw >= ST_WRITING && !STp->pos_unknown) { - -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n", - name, (long)(filp->f_pos)); - printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n", - name, STp->nbr_waits, STp->nbr_finished); - } -#endif - result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close)); -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n", - name, 1+STp->two_fm); -#endif - } - else if (!STp->rew_at_close) { - STps = &(STp->ps[STp->partition]); - if (!STm->sysv || STps->rw != ST_READING) { - if (STp->can_bsr) - result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */ - else if (STps->eof == ST_FM_HIT) { - result = cross_eof(STp, &SRpnt, 0); - if (result) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_FM; - } - else - STps->eof = ST_NOEOF; - } - } - else if ((STps->eof == ST_NOEOF && - !(result = cross_eof(STp, &SRpnt, 1))) || - STps->eof == ST_FM_HIT) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_FM; - } - } - -out: - if (STp->rew_at_close) { - result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos); - STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0; - if (result == 0 && result2 < 0) - result = result2; - } - if (SRpnt) osst_release_request(SRpnt); - - if (STp->abort_count || STp->recover_count) { - printk(KERN_INFO "%s:I:", name); - if (STp->abort_count) - printk(" %d unrecovered errors", STp->abort_count); - if (STp->recover_count) - printk(" %d recovered errors", STp->recover_count); - if (STp->write_count) - printk(" in %d frames written", STp->write_count); - if (STp->read_count) - printk(" in %d frames read", STp->read_count); - printk("\n"); - STp->recover_count = 0; - STp->abort_count = 0; - } - STp->write_count = 0; - STp->read_count = 0; - - return result; -} - - -/* Close the device and release it */ -static int os_scsi_tape_close(struct inode * inode, struct file * filp) -{ - int result = 0; - struct osst_tape * STp = filp->private_data; - - if (STp->door_locked == ST_LOCKED_AUTO) - do_door_lock(STp, 0); - - if (STp->raw) - STp->header_ok = 0; - - normalize_buffer(STp->buffer); - write_lock(&os_scsi_tapes_lock); - STp->in_use = 0; - write_unlock(&os_scsi_tapes_lock); - - scsi_device_put(STp->device); - - return result; -} - - -/* The ioctl command */ -static long osst_ioctl(struct file * file, - unsigned int cmd_in, unsigned long arg) -{ - int i, cmd_nr, cmd_type, blk, retval = 0; - struct st_modedef * STm; - struct st_partstat * STps; - struct osst_request * SRpnt = NULL; - struct osst_tape * STp = file->private_data; - char * name = tape_name(STp); - void __user * p = (void __user *)arg; - - mutex_lock(&osst_int_mutex); - if (mutex_lock_interruptible(&STp->lock)) { - mutex_unlock(&osst_int_mutex); - return -ERESTARTSYS; - } - -#if DEBUG - if (debugging && !STp->in_use) { - printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); - retval = (-EIO); - goto out; - } -#endif - STm = &(STp->modes[STp->current_mode]); - STps = &(STp->ps[STp->partition]); - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in, - file->f_flags & O_NDELAY); - if (retval) - goto out; - - cmd_type = _IOC_TYPE(cmd_in); - cmd_nr = _IOC_NR(cmd_in); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name, - cmd_type, cmd_nr, STp->raw?"raw":"normal"); -#endif - if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { - struct mtop mtc; - int auto_weof = 0; - - if (_IOC_SIZE(cmd_in) != sizeof(mtc)) { - retval = (-EINVAL); - goto out; - } - - i = copy_from_user((char *) &mtc, p, sizeof(struct mtop)); - if (i) { - retval = (-EFAULT); - goto out; - } - - if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { - printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name); - retval = (-EPERM); - goto out; - } - - if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) { - retval = (-ENXIO); - goto out; - } - - if (!STp->pos_unknown) { - - if (STps->eof == ST_FM_HIT) { - if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) { - mtc.mt_count -= 1; - if (STps->drv_file >= 0) - STps->drv_file += 1; - } - else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) { - mtc.mt_count += 1; - if (STps->drv_file >= 0) - STps->drv_file += 1; - } - } - - if (mtc.mt_op == MTSEEK) { - /* Old position must be restored if partition will be changed */ - i = !STp->can_partitions || (STp->new_partition != STp->partition); - } - else { - i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || - mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || - mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || - mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || - mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM || - mtc.mt_op == MTCOMPRESSION; - } - i = osst_flush_buffer(STp, &SRpnt, i); - if (i < 0) { - retval = i; - goto out; - } - } - else { - /* - * If there was a bus reset, block further access - * to this device. If the user wants to rewind the tape, - * then reset the flag and allow access again. - */ - if(mtc.mt_op != MTREW && - mtc.mt_op != MTOFFL && - mtc.mt_op != MTRETEN && - mtc.mt_op != MTERASE && - mtc.mt_op != MTSEEK && - mtc.mt_op != MTEOM) { - retval = (-EIO); - goto out; - } - reset_state(STp); - /* remove this when the midlevel properly clears was_reset */ - STp->device->was_reset = 0; - } - - if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK && - mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && - mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER && - mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART && - mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) { - - /* - * The user tells us to move to another position on the tape. - * If we were appending to the tape content, that would leave - * the tape without proper end, in that case write EOD and - * update the header to reflect its position. - */ -#if DEBUG - printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name, - STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle", - STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number, - STp->logical_blk_num, STps->drv_file, STps->drv_block ); -#endif - if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) { - auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) && - !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL)); - i = osst_write_trailer(STp, &SRpnt, - !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL)); -#if DEBUG - printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", - name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos, - STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block ); -#endif - if (i < 0) { - retval = i; - goto out; - } - } - STps->rw = ST_IDLE; - } - - if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED) - do_door_lock(STp, 0); /* Ignore result! */ - - if (mtc.mt_op == MTSETDRVBUFFER && - (mtc.mt_count & MT_ST_OPTIONS) != 0) { - retval = osst_set_options(STp, mtc.mt_count); - goto out; - } - - if (mtc.mt_op == MTSETPART) { - if (mtc.mt_count >= STp->nbr_partitions) - retval = -EINVAL; - else { - STp->new_partition = mtc.mt_count; - retval = 0; - } - goto out; - } - - if (mtc.mt_op == MTMKPART) { - if (!STp->can_partitions) { - retval = (-EINVAL); - goto out; - } - if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*|| - (i = partition_tape(inode, mtc.mt_count)) < 0*/) { - retval = i; - goto out; - } - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STp->ps[i].rw = ST_IDLE; - STp->ps[i].at_sm = 0; - STp->ps[i].last_block_valid = 0; - } - STp->partition = STp->new_partition = 0; - STp->nbr_partitions = 1; /* Bad guess ?-) */ - STps->drv_block = STps->drv_file = 0; - retval = 0; - goto out; - } - - if (mtc.mt_op == MTSEEK) { - if (STp->raw) - i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0); - else - i = osst_seek_sector(STp, &SRpnt, mtc.mt_count); - if (!STp->can_partitions) - STp->ps[0].rw = ST_IDLE; - retval = i; - goto out; - } - - if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) { - retval = do_door_lock(STp, (mtc.mt_op == MTLOCK)); - goto out; - } - - if (auto_weof) - cross_eof(STp, &SRpnt, 0); - - if (mtc.mt_op == MTCOMPRESSION) - retval = -EINVAL; /* OnStream drives don't have compression hardware */ - else - /* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS - * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */ - retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count); - goto out; - } - - if (!STm->defined) { - retval = (-ENXIO); - goto out; - } - - if ((i = osst_flush_buffer(STp, &SRpnt, 0)) < 0) { - retval = i; - goto out; - } - - if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) { - struct mtget mt_status; - - if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) { - retval = (-EINVAL); - goto out; - } - - mt_status.mt_type = MT_ISONSTREAM_SC; - mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT; - mt_status.mt_dsreg = - ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) | - ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK); - mt_status.mt_blkno = STps->drv_block; - mt_status.mt_fileno = STps->drv_file; - if (STp->block_size != 0) { - if (STps->rw == ST_WRITING) - mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size; - else if (STps->rw == ST_READING) - mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes + - STp->block_size - 1) / STp->block_size; - } - - mt_status.mt_gstat = 0; - if (STp->drv_write_prot) - mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff); - if (mt_status.mt_blkno == 0) { - if (mt_status.mt_fileno == 0) - mt_status.mt_gstat |= GMT_BOT(0xffffffff); - else - mt_status.mt_gstat |= GMT_EOF(0xffffffff); - } - mt_status.mt_resid = STp->partition; - if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR) - mt_status.mt_gstat |= GMT_EOT(0xffffffff); - else if (STps->eof >= ST_EOM_OK) - mt_status.mt_gstat |= GMT_EOD(0xffffffff); - if (STp->density == 1) - mt_status.mt_gstat |= GMT_D_800(0xffffffff); - else if (STp->density == 2) - mt_status.mt_gstat |= GMT_D_1600(0xffffffff); - else if (STp->density == 3) - mt_status.mt_gstat |= GMT_D_6250(0xffffffff); - if (STp->ready == ST_READY) - mt_status.mt_gstat |= GMT_ONLINE(0xffffffff); - if (STp->ready == ST_NO_TAPE) - mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff); - if (STps->at_sm) - mt_status.mt_gstat |= GMT_SM(0xffffffff); - if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) || - STp->drv_buffer != 0) - mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff); - - i = copy_to_user(p, &mt_status, sizeof(struct mtget)); - if (i) { - retval = (-EFAULT); - goto out; - } - - STp->recover_erreg = 0; /* Clear after read */ - retval = 0; - goto out; - } /* End of MTIOCGET */ - - if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) { - struct mtpos mt_pos; - - if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) { - retval = (-EINVAL); - goto out; - } - if (STp->raw) - blk = osst_get_frame_position(STp, &SRpnt); - else - blk = osst_get_sector(STp, &SRpnt); - if (blk < 0) { - retval = blk; - goto out; - } - mt_pos.mt_blkno = blk; - i = copy_to_user(p, &mt_pos, sizeof(struct mtpos)); - if (i) - retval = -EFAULT; - goto out; - } - if (SRpnt) osst_release_request(SRpnt); - - mutex_unlock(&STp->lock); - - retval = scsi_ioctl(STp->device, cmd_in, p); - mutex_unlock(&osst_int_mutex); - return retval; - -out: - if (SRpnt) osst_release_request(SRpnt); - - mutex_unlock(&STp->lock); - mutex_unlock(&osst_int_mutex); - - return retval; -} - -#ifdef CONFIG_COMPAT -static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg) -{ - struct osst_tape *STp = file->private_data; - struct scsi_device *sdev = STp->device; - int ret = -ENOIOCTLCMD; - if (sdev->host->hostt->compat_ioctl) { - - ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg); - - } - return ret; -} -#endif - - - -/* Memory handling routines */ - -/* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */ -static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg ) -{ - int i; - gfp_t priority; - struct osst_buffer *tb; - - if (from_initialization) - priority = GFP_ATOMIC; - else - priority = GFP_KERNEL; - - i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist); - tb = kzalloc(i, priority); - if (!tb) { - printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n"); - return NULL; - } - - tb->sg_segs = tb->orig_sg_segs = 0; - tb->use_sg = max_sg; - tb->in_use = 1; - tb->dma = need_dma; - tb->buffer_size = 0; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG - "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n", - i, max_sg, need_dma); -#endif - return tb; -} - -/* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */ -static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma) -{ - int segs, nbr, max_segs, b_size, order, got; - gfp_t priority; - - if (STbuffer->buffer_size >= OS_FRAME_SIZE) - return 1; - - if (STbuffer->sg_segs) { - printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n"); - normalize_buffer(STbuffer); - } - /* See how many segments we can use -- need at least two */ - nbr = max_segs = STbuffer->use_sg; - if (nbr <= 2) - return 0; - - priority = GFP_KERNEL /* | __GFP_NOWARN */; - if (need_dma) - priority |= GFP_DMA; - - /* Try to allocate the first segment up to OS_DATA_SIZE and the others - big enough to reach the goal (code assumes no segments in place) */ - for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) { - struct page *page = alloc_pages(priority, order); - - STbuffer->sg[0].offset = 0; - if (page != NULL) { - sg_set_page(&STbuffer->sg[0], page, b_size, 0); - STbuffer->b_data = page_address(page); - break; - } - } - if (sg_page(&STbuffer->sg[0]) == NULL) { - printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n"); - return 0; - } - /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */ - for (segs=STbuffer->sg_segs=1, got=b_size; - segs < max_segs && got < OS_FRAME_SIZE; ) { - struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order); - STbuffer->sg[segs].offset = 0; - if (page == NULL) { - printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n", - OS_FRAME_SIZE); -#if DEBUG - STbuffer->buffer_size = got; -#endif - normalize_buffer(STbuffer); - return 0; - } - sg_set_page(&STbuffer->sg[segs], page, (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size, 0); - got += STbuffer->sg[segs].length; - STbuffer->buffer_size = got; - STbuffer->sg_segs = ++segs; - } -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG - "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n", - got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data); - printk(OSST_DEB_MSG - "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n", - STbuffer->sg[0].length, page_address(STbuffer->sg[0].page), - STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page)); - } -#endif - - return 1; -} - - -/* Release the segments */ -static void normalize_buffer(struct osst_buffer *STbuffer) -{ - int i, order, b_size; - - for (i=0; i < STbuffer->sg_segs; i++) { - - for (b_size = PAGE_SIZE, order = 0; - b_size < STbuffer->sg[i].length; - b_size *= 2, order++); - - __free_pages(sg_page(&STbuffer->sg[i]), order); - STbuffer->buffer_size -= STbuffer->sg[i].length; - } -#if DEBUG - if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs) - printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n", - STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs); -#endif - STbuffer->sg_segs = STbuffer->orig_sg_segs = 0; -} - - -/* Move data from the user buffer to the tape buffer. Returns zero (success) or - negative error code. */ -static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, int do_count) -{ - int i, cnt, res, offset; - - for (i=0, offset=st_bp->buffer_bytes; - i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) - offset -= st_bp->sg[i].length; - if (i == st_bp->sg_segs) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n"); - return (-EIO); - } - for ( ; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length - offset < do_count ? - st_bp->sg[i].length - offset : do_count; - res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt); - if (res) - return (-EFAULT); - do_count -= cnt; - st_bp->buffer_bytes += cnt; - ubp += cnt; - offset = 0; - } - if (do_count) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n", - do_count); - return (-EIO); - } - return 0; -} - - -/* Move data from the tape buffer to the user buffer. Returns zero (success) or - negative error code. */ -static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count) -{ - int i, cnt, res, offset; - - for (i=0, offset=st_bp->read_pointer; - i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) - offset -= st_bp->sg[i].length; - if (i == st_bp->sg_segs) { /* Should never happen */ - printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n"); - return (-EIO); - } - for ( ; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length - offset < do_count ? - st_bp->sg[i].length - offset : do_count; - res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt); - if (res) - return (-EFAULT); - do_count -= cnt; - st_bp->buffer_bytes -= cnt; - st_bp->read_pointer += cnt; - ubp += cnt; - offset = 0; - } - if (do_count) { /* Should never happen */ - printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count); - return (-EIO); - } - return 0; -} - -/* Sets the tail of the buffer after fill point to zero. - Returns zero (success) or negative error code. */ -static int osst_zero_buffer_tail(struct osst_buffer *st_bp) -{ - int i, offset, do_count, cnt; - - for (i = 0, offset = st_bp->buffer_bytes; - i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) - offset -= st_bp->sg[i].length; - if (i == st_bp->sg_segs) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n"); - return (-EIO); - } - for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes; - i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length - offset < do_count ? - st_bp->sg[i].length - offset : do_count ; - memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt); - do_count -= cnt; - offset = 0; - } - if (do_count) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count); - return (-EIO); - } - return 0; -} - -/* Copy a osst 32K chunk of memory into the buffer. - Returns zero (success) or negative error code. */ -static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr) -{ - int i, cnt, do_count = OS_DATA_SIZE; - - for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length < do_count ? - st_bp->sg[i].length : do_count ; - memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt); - do_count -= cnt; - ptr += cnt; - } - if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n", - do_count, i); - return (-EIO); - } - return 0; -} - -/* Copy a osst 32K chunk of memory from the buffer. - Returns zero (success) or negative error code. */ -static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr) -{ - int i, cnt, do_count = OS_DATA_SIZE; - - for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length < do_count ? - st_bp->sg[i].length : do_count ; - memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt); - do_count -= cnt; - ptr += cnt; - } - if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n", - do_count, i); - return (-EIO); - } - return 0; -} - - -/* Module housekeeping */ - -static void validate_options (void) -{ - if (max_dev > 0) - osst_max_dev = max_dev; - if (write_threshold_kbs > 0) - osst_write_threshold = write_threshold_kbs * ST_KILOBYTE; - if (osst_write_threshold > osst_buffer_size) - osst_write_threshold = osst_buffer_size; - if (max_sg_segs >= OSST_FIRST_SG) - osst_max_sg_segs = max_sg_segs; -#if DEBUG - printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n", - osst_max_dev, osst_write_threshold, osst_max_sg_segs); -#endif -} - -#ifndef MODULE -/* Set the boot options. Syntax: osst=xxx,yyy,... - where xxx is write threshold in 1024 byte blocks, - and yyy is number of s/g segments to use. */ -static int __init osst_setup (char *str) -{ - int i, ints[5]; - char *stp; - - stp = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) { - for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++) - *parms[i].val = ints[i + 1]; - } else { - while (stp != NULL) { - for (i = 0; i < ARRAY_SIZE(parms); i++) { - int len = strlen(parms[i].name); - if (!strncmp(stp, parms[i].name, len) && - (*(stp + len) == ':' || *(stp + len) == '=')) { - *parms[i].val = - simple_strtoul(stp + len + 1, NULL, 0); - break; - } - } - if (i >= ARRAY_SIZE(parms)) - printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n", - stp); - stp = strchr(stp, ','); - if (stp) - stp++; - } - } - - return 1; -} - -__setup("osst=", osst_setup); - -#endif - -static const struct file_operations osst_fops = { - .owner = THIS_MODULE, - .read = osst_read, - .write = osst_write, - .unlocked_ioctl = osst_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = osst_compat_ioctl, -#endif - .open = os_scsi_tape_open, - .flush = os_scsi_tape_flush, - .release = os_scsi_tape_close, - .llseek = noop_llseek, -}; - -static int osst_supports(struct scsi_device * SDp) -{ - struct osst_support_data { - char *vendor; - char *model; - char *rev; - char *driver_hint; /* Name of the correct driver, NULL if unknown */ - }; - -static struct osst_support_data support_list[] = { - /* {"XXX", "Yy-", "", NULL}, example */ - SIGS_FROM_OSST, - {NULL, }}; - - struct osst_support_data *rp; - - /* We are willing to drive OnStream SC-x0 as well as the - * * IDE, ParPort, FireWire, USB variants, if accessible by - * * emulation layer (ide-scsi, usb-storage, ...) */ - - for (rp=&(support_list[0]); rp->vendor != NULL; rp++) - if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) && - !strncmp(rp->model, SDp->model, strlen(rp->model)) && - !strncmp(rp->rev, SDp->rev, strlen(rp->rev))) - return 1; - return 0; -} - -/* - * sysfs support for osst driver parameter information - */ - -static ssize_t version_show(struct device_driver *ddd, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", osst_version); -} - -static DRIVER_ATTR_RO(version); - -static int osst_create_sysfs_files(struct device_driver *sysfs) -{ - return driver_create_file(sysfs, &driver_attr_version); -} - -static void osst_remove_sysfs_files(struct device_driver *sysfs) -{ - driver_remove_file(sysfs, &driver_attr_version); -} - -/* - * sysfs support for accessing ADR header information - */ - -static ssize_t osst_adr_rev_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d.%d\n", STp->header_cache->major_rev, STp->header_cache->minor_rev); - return l; -} - -DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL); - -static ssize_t osst_linux_media_version_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "LIN%d\n", STp->linux_media_version); - return l; -} - -DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL); - -static ssize_t osst_capacity_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d\n", STp->capacity); - return l; -} - -DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL); - -static ssize_t osst_first_data_ppos_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d\n", STp->first_data_ppos); - return l; -} - -DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL); - -static ssize_t osst_eod_frame_ppos_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d\n", STp->eod_frame_ppos); - return l; -} - -DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL); - -static ssize_t osst_filemark_cnt_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d\n", STp->filemark_cnt); - return l; -} - -DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL); - -static struct class *osst_sysfs_class; - -static int osst_sysfs_init(void) -{ - osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape"); - if (IS_ERR(osst_sysfs_class)) { - printk(KERN_ERR "osst :W: Unable to register sysfs class\n"); - return PTR_ERR(osst_sysfs_class); - } - - return 0; -} - -static void osst_sysfs_destroy(dev_t dev) -{ - device_destroy(osst_sysfs_class, dev); -} - -static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name) -{ - struct device *osst_member; - int err; - - osst_member = device_create(osst_sysfs_class, device, dev, STp, - "%s", name); - if (IS_ERR(osst_member)) { - printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name); - return PTR_ERR(osst_member); - } - - err = device_create_file(osst_member, &dev_attr_ADR_rev); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_media_version); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_capacity); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_BOT_frame); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_EOD_frame); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_file_count); - if (err) - goto err_out; - - return 0; - -err_out: - osst_sysfs_destroy(dev); - return err; -} - -static void osst_sysfs_cleanup(void) -{ - class_destroy(osst_sysfs_class); -} - -/* - * osst startup / cleanup code - */ - -static int osst_probe(struct device *dev) -{ - struct scsi_device * SDp = to_scsi_device(dev); - struct osst_tape * tpnt; - struct st_modedef * STm; - struct st_partstat * STps; - struct osst_buffer * buffer; - struct gendisk * drive; - int i, dev_num, err = -ENODEV; - - if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) - return -ENODEV; - - drive = alloc_disk(1); - if (!drive) { - printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n"); - return -ENODEV; - } - - /* if this is the first attach, build the infrastructure */ - write_lock(&os_scsi_tapes_lock); - if (os_scsi_tapes == NULL) { - os_scsi_tapes = kmalloc_array(osst_max_dev, - sizeof(struct osst_tape *), - GFP_ATOMIC); - if (os_scsi_tapes == NULL) { - write_unlock(&os_scsi_tapes_lock); - printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n"); - goto out_put_disk; - } - for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL; - } - - if (osst_nr_dev >= osst_max_dev) { - write_unlock(&os_scsi_tapes_lock); - printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev); - goto out_put_disk; - } - - /* find a free minor number */ - for (i = 0; i < osst_max_dev && os_scsi_tapes[i]; i++) - ; - if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)"); - dev_num = i; - - /* allocate a struct osst_tape for this device */ - tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC); - if (!tpnt) { - write_unlock(&os_scsi_tapes_lock); - printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n"); - goto out_put_disk; - } - - /* allocate a buffer for this device */ - i = SDp->host->sg_tablesize; - if (osst_max_sg_segs < i) - i = osst_max_sg_segs; - buffer = new_tape_buffer(1, SDp->host->unchecked_isa_dma, i); - if (buffer == NULL) { - write_unlock(&os_scsi_tapes_lock); - printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n"); - kfree(tpnt); - goto out_put_disk; - } - os_scsi_tapes[dev_num] = tpnt; - tpnt->buffer = buffer; - tpnt->device = SDp; - drive->private_data = &tpnt->driver; - sprintf(drive->disk_name, "osst%d", dev_num); - tpnt->driver = &osst_template; - tpnt->drive = drive; - tpnt->in_use = 0; - tpnt->capacity = 0xfffff; - tpnt->dirty = 0; - tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ - tpnt->restr_dma = (SDp->host)->unchecked_isa_dma; - tpnt->density = 0; - tpnt->do_auto_lock = OSST_AUTO_LOCK; - tpnt->can_bsr = OSST_IN_FILE_POS; - tpnt->can_partitions = 0; - tpnt->two_fm = OSST_TWO_FM; - tpnt->fast_mteom = OSST_FAST_MTEOM; - tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */ - tpnt->write_threshold = osst_write_threshold; - tpnt->default_drvbuffer = 0xff; /* No forced buffering */ - tpnt->partition = 0; - tpnt->new_partition = 0; - tpnt->nbr_partitions = 0; - tpnt->min_block = 512; - tpnt->max_block = OS_DATA_SIZE; - tpnt->timeout = OSST_TIMEOUT; - tpnt->long_timeout = OSST_LONG_TIMEOUT; - - /* Recognize OnStream tapes */ - /* We don't need to test for OnStream, as this has been done in detect () */ - tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev); - tpnt->omit_blklims = 1; - - tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) || - (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp); - tpnt->frame_in_buffer = 0; - tpnt->header_ok = 0; - tpnt->linux_media = 0; - tpnt->header_cache = NULL; - - for (i=0; i < ST_NBR_MODES; i++) { - STm = &(tpnt->modes[i]); - STm->defined = 0; - STm->sysv = OSST_SYSV; - STm->defaults_for_writes = 0; - STm->do_async_writes = OSST_ASYNC_WRITES; - STm->do_buffer_writes = OSST_BUFFER_WRITES; - STm->do_read_ahead = OSST_READ_AHEAD; - STm->default_compression = ST_DONT_TOUCH; - STm->default_blksize = 512; - STm->default_density = (-1); /* No forced density */ - } - - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STps = &(tpnt->ps[i]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = (-1); - STps->drv_file = (-1); - } - - tpnt->current_mode = 0; - tpnt->modes[0].defined = 1; - tpnt->modes[2].defined = 1; - tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0; - - mutex_init(&tpnt->lock); - osst_nr_dev++; - write_unlock(&os_scsi_tapes_lock); - - { - char name[8]; - - /* Rewind entry */ - err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt)); - if (err) - goto out_free_buffer; - - /* No-rewind entry */ - snprintf(name, 8, "%s%s", "n", tape_name(tpnt)); - err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name); - if (err) - goto out_free_sysfs1; - } - - sdev_printk(KERN_INFO, SDp, - "osst :I: Attached OnStream %.5s tape as %s\n", - SDp->model, tape_name(tpnt)); - - return 0; - -out_free_sysfs1: - osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num)); -out_free_buffer: - kfree(buffer); -out_put_disk: - put_disk(drive); - return err; -}; - -static int osst_remove(struct device *dev) -{ - struct scsi_device * SDp = to_scsi_device(dev); - struct osst_tape * tpnt; - int i; - - if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0)) - return 0; - - write_lock(&os_scsi_tapes_lock); - for(i=0; i < osst_max_dev; i++) { - if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) { - osst_sysfs_destroy(MKDEV(OSST_MAJOR, i)); - osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128)); - tpnt->device = NULL; - put_disk(tpnt->drive); - os_scsi_tapes[i] = NULL; - osst_nr_dev--; - write_unlock(&os_scsi_tapes_lock); - vfree(tpnt->header_cache); - if (tpnt->buffer) { - normalize_buffer(tpnt->buffer); - kfree(tpnt->buffer); - } - kfree(tpnt); - return 0; - } - } - write_unlock(&os_scsi_tapes_lock); - return 0; -} - -static int __init init_osst(void) -{ - int err; - - printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid); - - validate_options(); - - err = osst_sysfs_init(); - if (err) - return err; - - err = register_chrdev(OSST_MAJOR, "osst", &osst_fops); - if (err < 0) { - printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR); - goto err_out; - } - - err = scsi_register_driver(&osst_template.gendrv); - if (err) - goto err_out_chrdev; - - err = osst_create_sysfs_files(&osst_template.gendrv); - if (err) - goto err_out_scsidrv; - - return 0; - -err_out_scsidrv: - scsi_unregister_driver(&osst_template.gendrv); -err_out_chrdev: - unregister_chrdev(OSST_MAJOR, "osst"); -err_out: - osst_sysfs_cleanup(); - return err; -} - -static void __exit exit_osst (void) -{ - int i; - struct osst_tape * STp; - - osst_remove_sysfs_files(&osst_template.gendrv); - scsi_unregister_driver(&osst_template.gendrv); - unregister_chrdev(OSST_MAJOR, "osst"); - osst_sysfs_cleanup(); - - if (os_scsi_tapes) { - for (i=0; i < osst_max_dev; ++i) { - if (!(STp = os_scsi_tapes[i])) continue; - /* This is defensive, supposed to happen during detach */ - vfree(STp->header_cache); - if (STp->buffer) { - normalize_buffer(STp->buffer); - kfree(STp->buffer); - } - put_disk(STp->drive); - kfree(STp); - } - kfree(os_scsi_tapes); - } - printk(KERN_INFO "osst :I: Unloaded.\n"); -} - -module_init(init_osst); -module_exit(exit_osst); diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h deleted file mode 100644 index b90ae280853d..000000000000 --- a/drivers/scsi/osst.h +++ /dev/null @@ -1,651 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * $Header: /cvsroot/osst/Driver/osst.h,v 1.16 2005/01/01 21:13:35 wriede Exp $ - */ - -#include <asm/byteorder.h> -#include <linux/completion.h> -#include <linux/mutex.h> - -/* FIXME - rename and use the following two types or delete them! - * and the types really should go to st.h anyway... - * INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C) - */ -typedef struct { - unsigned device_type :5; /* Peripheral Device Type */ - unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */ - unsigned reserved1_6t0 :7; /* Reserved */ - unsigned rmb :1; /* Removable Medium Bit */ - unsigned ansi_version :3; /* ANSI Version */ - unsigned ecma_version :3; /* ECMA Version */ - unsigned iso_version :2; /* ISO Version */ - unsigned response_format :4; /* Response Data Format */ - unsigned reserved3_45 :2; /* Reserved */ - unsigned reserved3_6 :1; /* TrmIOP - Reserved */ - unsigned reserved3_7 :1; /* AENC - Reserved */ - u8 additional_length; /* Additional Length (total_length-4) */ - u8 rsv5, rsv6, rsv7; /* Reserved */ - u8 vendor_id[8]; /* Vendor Identification */ - u8 product_id[16]; /* Product Identification */ - u8 revision_level[4]; /* Revision Level */ - u8 vendor_specific[20]; /* Vendor Specific - Optional */ - u8 reserved56t95[40]; /* Reserved - Optional */ - /* Additional information may be returned */ -} idetape_inquiry_result_t; - -/* - * READ POSITION packet command - Data Format (From Table 6-57) - */ -typedef struct { - unsigned reserved0_10 :2; /* Reserved */ - unsigned bpu :1; /* Block Position Unknown */ - unsigned reserved0_543 :3; /* Reserved */ - unsigned eop :1; /* End Of Partition */ - unsigned bop :1; /* Beginning Of Partition */ - u8 partition; /* Partition Number */ - u8 reserved2, reserved3; /* Reserved */ - u32 first_block; /* First Block Location */ - u32 last_block; /* Last Block Location (Optional) */ - u8 reserved12; /* Reserved */ - u8 blocks_in_buffer[3]; /* Blocks In Buffer - (Optional) */ - u32 bytes_in_buffer; /* Bytes In Buffer (Optional) */ -} idetape_read_position_result_t; - -/* - * Follows structures which are related to the SELECT SENSE / MODE SENSE - * packet commands. - */ -#define COMPRESSION_PAGE 0x0f -#define COMPRESSION_PAGE_LENGTH 16 - -#define CAPABILITIES_PAGE 0x2a -#define CAPABILITIES_PAGE_LENGTH 20 - -#define TAPE_PARAMTR_PAGE 0x2b -#define TAPE_PARAMTR_PAGE_LENGTH 16 - -#define NUMBER_RETRIES_PAGE 0x2f -#define NUMBER_RETRIES_PAGE_LENGTH 4 - -#define BLOCK_SIZE_PAGE 0x30 -#define BLOCK_SIZE_PAGE_LENGTH 4 - -#define BUFFER_FILLING_PAGE 0x33 -#define BUFFER_FILLING_PAGE_LENGTH 4 - -#define VENDOR_IDENT_PAGE 0x36 -#define VENDOR_IDENT_PAGE_LENGTH 8 - -#define LOCATE_STATUS_PAGE 0x37 -#define LOCATE_STATUS_PAGE_LENGTH 0 - -#define MODE_HEADER_LENGTH 4 - - -/* - * REQUEST SENSE packet command result - Data Format. - */ -typedef struct { - unsigned error_code :7; /* Current of deferred errors */ - unsigned valid :1; /* The information field conforms to QIC-157C */ - u8 reserved1 :8; /* Segment Number - Reserved */ - unsigned sense_key :4; /* Sense Key */ - unsigned reserved2_4 :1; /* Reserved */ - unsigned ili :1; /* Incorrect Length Indicator */ - unsigned eom :1; /* End Of Medium */ - unsigned filemark :1; /* Filemark */ - u32 information __attribute__ ((packed)); - u8 asl; /* Additional sense length (n-7) */ - u32 command_specific; /* Additional command specific information */ - u8 asc; /* Additional Sense Code */ - u8 ascq; /* Additional Sense Code Qualifier */ - u8 replaceable_unit_code; /* Field Replaceable Unit Code */ - unsigned sk_specific1 :7; /* Sense Key Specific */ - unsigned sksv :1; /* Sense Key Specific information is valid */ - u8 sk_specific2; /* Sense Key Specific */ - u8 sk_specific3; /* Sense Key Specific */ - u8 pad[2]; /* Padding to 20 bytes */ -} idetape_request_sense_result_t; - -/* - * Mode Parameter Header for the MODE SENSE packet command - */ -typedef struct { - u8 mode_data_length; /* Length of the following data transfer */ - u8 medium_type; /* Medium Type */ - u8 dsp; /* Device Specific Parameter */ - u8 bdl; /* Block Descriptor Length */ -} osst_mode_parameter_header_t; - -/* - * Mode Parameter Block Descriptor the MODE SENSE packet command - * - * Support for block descriptors is optional. - */ -typedef struct { - u8 density_code; /* Medium density code */ - u8 blocks[3]; /* Number of blocks */ - u8 reserved4; /* Reserved */ - u8 length[3]; /* Block Length */ -} osst_parameter_block_descriptor_t; - -/* - * The Data Compression Page, as returned by the MODE SENSE packet command. - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned ps :1; - unsigned reserved0 :1; /* Reserved */ - unsigned page_code :6; /* Page Code - Should be 0xf */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page Code - Should be 0xf */ - unsigned reserved0 :1; /* Reserved */ - unsigned ps :1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - u8 page_length; /* Page Length - Should be 14 */ -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned dce :1; /* Data Compression Enable */ - unsigned dcc :1; /* Data Compression Capable */ - unsigned reserved2 :6; /* Reserved */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved2 :6; /* Reserved */ - unsigned dcc :1; /* Data Compression Capable */ - unsigned dce :1; /* Data Compression Enable */ -#else -#error "Please fix <asm/byteorder.h>" -#endif -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned dde :1; /* Data Decompression Enable */ - unsigned red :2; /* Report Exception on Decompression */ - unsigned reserved3 :5; /* Reserved */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved3 :5; /* Reserved */ - unsigned red :2; /* Report Exception on Decompression */ - unsigned dde :1; /* Data Decompression Enable */ -#else -#error "Please fix <asm/byteorder.h>" -#endif - u32 ca; /* Compression Algorithm */ - u32 da; /* Decompression Algorithm */ - u8 reserved[4]; /* Reserved */ -} osst_data_compression_page_t; - -/* - * The Medium Partition Page, as returned by the MODE SENSE packet command. - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned ps :1; - unsigned reserved1_6 :1; /* Reserved */ - unsigned page_code :6; /* Page Code - Should be 0x11 */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page Code - Should be 0x11 */ - unsigned reserved1_6 :1; /* Reserved */ - unsigned ps :1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - u8 page_length; /* Page Length - Should be 6 */ - u8 map; /* Maximum Additional Partitions - Should be 0 */ - u8 apd; /* Additional Partitions Defined - Should be 0 */ -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned fdp :1; /* Fixed Data Partitions */ - unsigned sdp :1; /* Should be 0 */ - unsigned idp :1; /* Should be 0 */ - unsigned psum :2; /* Should be 0 */ - unsigned reserved4_012 :3; /* Reserved */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved4_012 :3; /* Reserved */ - unsigned psum :2; /* Should be 0 */ - unsigned idp :1; /* Should be 0 */ - unsigned sdp :1; /* Should be 0 */ - unsigned fdp :1; /* Fixed Data Partitions */ -#else -#error "Please fix <asm/byteorder.h>" -#endif - u8 mfr; /* Medium Format Recognition */ - u8 reserved[2]; /* Reserved */ -} osst_medium_partition_page_t; - -/* - * Capabilities and Mechanical Status Page - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned reserved1_67 :2; - unsigned page_code :6; /* Page code - Should be 0x2a */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page code - Should be 0x2a */ - unsigned reserved1_67 :2; -#else -#error "Please fix <asm/byteorder.h>" -#endif - u8 page_length; /* Page Length - Should be 0x12 */ - u8 reserved2, reserved3; -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned reserved4_67 :2; - unsigned sprev :1; /* Supports SPACE in the reverse direction */ - unsigned reserved4_1234 :4; - unsigned ro :1; /* Read Only Mode */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned ro :1; /* Read Only Mode */ - unsigned reserved4_1234 :4; - unsigned sprev :1; /* Supports SPACE in the reverse direction */ - unsigned reserved4_67 :2; -#else -#error "Please fix <asm/byteorder.h>" -#endif -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned reserved5_67 :2; - unsigned qfa :1; /* Supports the QFA two partition formats */ - unsigned reserved5_4 :1; - unsigned efmt :1; /* Supports ERASE command initiated formatting */ - unsigned reserved5_012 :3; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved5_012 :3; - unsigned efmt :1; /* Supports ERASE command initiated formatting */ - unsigned reserved5_4 :1; - unsigned qfa :1; /* Supports the QFA two partition formats */ - unsigned reserved5_67 :2; -#else -#error "Please fix <asm/byteorder.h>" -#endif -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned cmprs :1; /* Supports data compression */ - unsigned ecc :1; /* Supports error correction */ - unsigned reserved6_45 :2; /* Reserved */ - unsigned eject :1; /* The device can eject the volume */ - unsigned prevent :1; /* The device defaults in the prevent state after power up */ - unsigned locked :1; /* The volume is locked */ - unsigned lock :1; /* Supports locking the volume */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned lock :1; /* Supports locking the volume */ - unsigned locked :1; /* The volume is locked */ - unsigned prevent :1; /* The device defaults in the prevent state after power up */ - unsigned eject :1; /* The device can eject the volume */ - unsigned reserved6_45 :2; /* Reserved */ - unsigned ecc :1; /* Supports error correction */ - unsigned cmprs :1; /* Supports data compression */ -#else -#error "Please fix <asm/byteorder.h>" -#endif -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */ - /* transfers for slow buffer memory ??? */ - /* Also 32768 block size in some cases */ - unsigned reserved7_3_6 :4; - unsigned blk1024 :1; /* Supports 1024 bytes block size */ - unsigned blk512 :1; /* Supports 512 bytes block size */ - unsigned reserved7_0 :1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved7_0 :1; - unsigned blk512 :1; /* Supports 512 bytes block size */ - unsigned blk1024 :1; /* Supports 1024 bytes block size */ - unsigned reserved7_3_6 :4; - unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */ - /* transfers for slow buffer memory ??? */ - /* Also 32768 block size in some cases */ -#else -#error "Please fix <asm/byteorder.h>" -#endif - __be16 max_speed; /* Maximum speed supported in KBps */ - u8 reserved10, reserved11; - __be16 ctl; /* Continuous Transfer Limit in blocks */ - __be16 speed; /* Current Speed, in KBps */ - __be16 buffer_size; /* Buffer Size, in 512 bytes */ - u8 reserved18, reserved19; -} osst_capabilities_page_t; - -/* - * Block Size Page - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned ps :1; - unsigned reserved1_6 :1; - unsigned page_code :6; /* Page code - Should be 0x30 */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page code - Should be 0x30 */ - unsigned reserved1_6 :1; - unsigned ps :1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - u8 page_length; /* Page Length - Should be 2 */ - u8 reserved2; -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned one :1; - unsigned reserved2_6 :1; - unsigned record32_5 :1; - unsigned record32 :1; - unsigned reserved2_23 :2; - unsigned play32_5 :1; - unsigned play32 :1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned play32 :1; - unsigned play32_5 :1; - unsigned reserved2_23 :2; - unsigned record32 :1; - unsigned record32_5 :1; - unsigned reserved2_6 :1; - unsigned one :1; -#else -#error "Please fix <asm/byteorder.h>" -#endif -} osst_block_size_page_t; - -/* - * Tape Parameters Page - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned ps :1; - unsigned reserved1_6 :1; - unsigned page_code :6; /* Page code - Should be 0x2b */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page code - Should be 0x2b */ - unsigned reserved1_6 :1; - unsigned ps :1; -#else -#error "Please fix <asm/byteorder.h>" -#endif - u8 reserved2; - u8 density; - u8 reserved3,reserved4; - __be16 segtrk; - __be16 trks; - u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10; -} osst_tape_paramtr_page_t; - -/* OnStream definitions */ - -#define OS_CONFIG_PARTITION (0xff) -#define OS_DATA_PARTITION (0) -#define OS_PARTITION_VERSION (1) - -/* - * partition - */ -typedef struct os_partition_s { - __u8 partition_num; - __u8 par_desc_ver; - __be16 wrt_pass_cntr; - __be32 first_frame_ppos; - __be32 last_frame_ppos; - __be32 eod_frame_ppos; -} os_partition_t; - -/* - * DAT entry - */ -typedef struct os_dat_entry_s { - __be32 blk_sz; - __be16 blk_cnt; - __u8 flags; - __u8 reserved; -} os_dat_entry_t; - -/* - * DAT - */ -#define OS_DAT_FLAGS_DATA (0xc) -#define OS_DAT_FLAGS_MARK (0x1) - -typedef struct os_dat_s { - __u8 dat_sz; - __u8 reserved1; - __u8 entry_cnt; - __u8 reserved3; - os_dat_entry_t dat_list[16]; -} os_dat_t; - -/* - * Frame types - */ -#define OS_FRAME_TYPE_FILL (0) -#define OS_FRAME_TYPE_EOD (1 << 0) -#define OS_FRAME_TYPE_MARKER (1 << 1) -#define OS_FRAME_TYPE_HEADER (1 << 3) -#define OS_FRAME_TYPE_DATA (1 << 7) - -/* - * AUX - */ -typedef struct os_aux_s { - __be32 format_id; /* hardware compatibility AUX is based on */ - char application_sig[4]; /* driver used to write this media */ - __be32 hdwr; /* reserved */ - __be32 update_frame_cntr; /* for configuration frame */ - __u8 frame_type; - __u8 frame_type_reserved; - __u8 reserved_18_19[2]; - os_partition_t partition; - __u8 reserved_36_43[8]; - __be32 frame_seq_num; - __be32 logical_blk_num_high; - __be32 logical_blk_num; - os_dat_t dat; - __u8 reserved188_191[4]; - __be32 filemark_cnt; - __be32 phys_fm; - __be32 last_mark_ppos; - __u8 reserved204_223[20]; - - /* - * __u8 app_specific[32]; - * - * Linux specific fields: - */ - __be32 next_mark_ppos; /* when known, points to next marker */ - __be32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ - __u8 linux_specific[24]; - - __u8 reserved_256_511[256]; -} os_aux_t; - -#define OS_FM_TAB_MAX 1024 - -typedef struct os_fm_tab_s { - __u8 fm_part_num; - __u8 reserved_1; - __u8 fm_tab_ent_sz; - __u8 reserved_3; - __be16 fm_tab_ent_cnt; - __u8 reserved6_15[10]; - __be32 fm_tab_ent[OS_FM_TAB_MAX]; -} os_fm_tab_t; - -typedef struct os_ext_trk_ey_s { - __u8 et_part_num; - __u8 fmt; - __be16 fm_tab_off; - __u8 reserved4_7[4]; - __be32 last_hlb_hi; - __be32 last_hlb; - __be32 last_pp; - __u8 reserved20_31[12]; -} os_ext_trk_ey_t; - -typedef struct os_ext_trk_tb_s { - __u8 nr_stream_part; - __u8 reserved_1; - __u8 et_ent_sz; - __u8 reserved3_15[13]; - os_ext_trk_ey_t dat_ext_trk_ey; - os_ext_trk_ey_t qfa_ext_trk_ey; -} os_ext_trk_tb_t; - -typedef struct os_header_s { - char ident_str[8]; - __u8 major_rev; - __u8 minor_rev; - __be16 ext_trk_tb_off; - __u8 reserved12_15[4]; - __u8 pt_par_num; - __u8 pt_reserved1_3[3]; - os_partition_t partition[16]; - __be32 cfg_col_width; - __be32 dat_col_width; - __be32 qfa_col_width; - __u8 cartridge[16]; - __u8 reserved304_511[208]; - __be32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */ - os_ext_trk_tb_t ext_track_tb; - __u8 reserved17272_17735[464]; - os_fm_tab_t dat_fm_tab; - os_fm_tab_t qfa_fm_tab; - __u8 reserved25960_32767[6808]; -} os_header_t; - - -/* - * OnStream ADRL frame - */ -#define OS_FRAME_SIZE (32 * 1024 + 512) -#define OS_DATA_SIZE (32 * 1024) -#define OS_AUX_SIZE (512) -//#define OSST_MAX_SG 2 - -/* The OnStream tape buffer descriptor. */ -struct osst_buffer { - unsigned char in_use; - unsigned char dma; /* DMA-able buffer */ - int buffer_size; - int buffer_blocks; - int buffer_bytes; - int read_pointer; - int writing; - int midlevel_result; - int syscall_result; - struct osst_request *last_SRpnt; - struct st_cmdstatus cmdstat; - struct rq_map_data map_data; - unsigned char *b_data; - os_aux_t *aux; /* onstream AUX structure at end of each block */ - unsigned short use_sg; /* zero or number of s/g segments for this adapter */ - unsigned short sg_segs; /* number of segments in s/g list */ - unsigned short orig_sg_segs; /* number of segments allocated at first try */ - struct scatterlist sg[1]; /* MUST BE last item */ -} ; - -/* The OnStream tape drive descriptor */ -struct osst_tape { - struct scsi_driver *driver; - unsigned capacity; - struct scsi_device *device; - struct mutex lock; /* for serialization */ - struct completion wait; /* for SCSI commands */ - struct osst_buffer * buffer; - - /* Drive characteristics */ - unsigned char omit_blklims; - unsigned char do_auto_lock; - unsigned char can_bsr; - unsigned char can_partitions; - unsigned char two_fm; - unsigned char fast_mteom; - unsigned char restr_dma; - unsigned char scsi2_logical; - unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */ - unsigned char pos_unknown; /* after reset position unknown */ - int write_threshold; - int timeout; /* timeout for normal commands */ - int long_timeout; /* timeout for commands known to take long time*/ - - /* Mode characteristics */ - struct st_modedef modes[ST_NBR_MODES]; - int current_mode; - - /* Status variables */ - int partition; - int new_partition; - int nbr_partitions; /* zero until partition support enabled */ - struct st_partstat ps[ST_NBR_PARTITIONS]; - unsigned char dirty; - unsigned char ready; - unsigned char write_prot; - unsigned char drv_write_prot; - unsigned char in_use; - unsigned char blksize_changed; - unsigned char density_changed; - unsigned char compression_changed; - unsigned char drv_buffer; - unsigned char density; - unsigned char door_locked; - unsigned char rew_at_close; - unsigned char inited; - int block_size; - int min_block; - int max_block; - int recover_count; /* from tape opening */ - int abort_count; - int write_count; - int read_count; - int recover_erreg; /* from last status call */ - /* - * OnStream specific data - */ - int os_fw_rev; /* the firmware revision * 10000 */ - unsigned char raw; /* flag OnStream raw access (32.5KB block size) */ - unsigned char poll; /* flag that this drive needs polling (IDE|firmware) */ - unsigned char frame_in_buffer; /* flag that the frame as per frame_seq_number - * has been read into STp->buffer and is valid */ - int frame_seq_number; /* logical frame number */ - int logical_blk_num; /* logical block number */ - unsigned first_frame_position; /* physical frame to be transferred to/from host */ - unsigned last_frame_position; /* physical frame to be transferd to/from tape */ - int cur_frames; /* current number of frames in internal buffer */ - int max_frames; /* max number of frames in internal buffer */ - char application_sig[5]; /* application signature */ - unsigned char fast_open; /* flag that reminds us we didn't check headers at open */ - unsigned short wrt_pass_cntr; /* write pass counter */ - int update_frame_cntr; /* update frame counter */ - int onstream_write_error; /* write error recovery active */ - int header_ok; /* header frame verified ok */ - int linux_media; /* reading linux-specifc media */ - int linux_media_version; - os_header_t * header_cache; /* cache is kept for filemark positions */ - int filemark_cnt; - int first_mark_ppos; - int last_mark_ppos; - int last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ - int first_data_ppos; - int eod_frame_ppos; - int eod_frame_lfa; - int write_type; /* used in write error recovery */ - int read_error_frame; /* used in read error recovery */ - unsigned long cmd_start_time; - unsigned long max_cmd_time; - -#if DEBUG - unsigned char write_pending; - int nbr_finished; - int nbr_waits; - unsigned char last_cmnd[6]; - unsigned char last_sense[16]; -#endif - struct gendisk *drive; -} ; - -/* scsi tape command */ -struct osst_request { - unsigned char cmd[MAX_COMMAND_SIZE]; - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; - int result; - struct osst_tape *stp; - struct completion *waiting; - struct bio *bio; -}; - -/* Values of write_type */ -#define OS_WRITE_DATA 0 -#define OS_WRITE_EOD 1 -#define OS_WRITE_NEW_MARK 2 -#define OS_WRITE_LAST_MARK 3 -#define OS_WRITE_HEADER 4 -#define OS_WRITE_FILLER 5 - -/* Additional rw state */ -#define OS_WRITING_COMPLETE 3 diff --git a/drivers/scsi/osst_detect.h b/drivers/scsi/osst_detect.h deleted file mode 100644 index 83c1d4fb11db..000000000000 --- a/drivers/scsi/osst_detect.h +++ /dev/null @@ -1,7 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#define SIGS_FROM_OSST \ - {"OnStream", "SC-", "", "osst"}, \ - {"OnStream", "DI-", "", "osst"}, \ - {"OnStream", "DP-", "", "osst"}, \ - {"OnStream", "FW-", "", "osst"}, \ - {"OnStream", "USB", "", "osst"} diff --git a/drivers/scsi/osst_options.h b/drivers/scsi/osst_options.h deleted file mode 100644 index a6a389b88876..000000000000 --- a/drivers/scsi/osst_options.h +++ /dev/null @@ -1,107 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - The compile-time configurable defaults for the Linux SCSI tape driver. - - Copyright 1995 Kai Makisara. - - Last modified: Wed Sep 2 21:24:07 1998 by root@home - - Changed (and renamed) for OnStream SCSI drives garloff@suse.de - 2000-06-21 - - $Header: /cvsroot/osst/Driver/osst_options.h,v 1.6 2003/12/23 14:22:12 wriede Exp $ -*/ - -#ifndef _OSST_OPTIONS_H -#define _OSST_OPTIONS_H - -/* The minimum limit for the number of SCSI tape devices is determined by - OSST_MAX_TAPES. If the number of tape devices and the "slack" defined by - OSST_EXTRA_DEVS exceeds OSST_MAX_TAPES, the large number is used. */ -#define OSST_MAX_TAPES 4 - -/* If OSST_IN_FILE_POS is nonzero, the driver positions the tape after the - record been read by the user program even if the tape has moved further - because of buffered reads. Should be set to zero to support also drives - that can't space backwards over records. NOTE: The tape will be - spaced backwards over an "accidentally" crossed filemark in any case. */ -#define OSST_IN_FILE_POS 1 - -/* The tape driver buffer size in kilobytes. */ -/* Don't change, as this is the HW blocksize */ -#define OSST_BUFFER_BLOCKS 32 - -/* The number of kilobytes of data in the buffer that triggers an - asynchronous write in fixed block mode. See also OSST_ASYNC_WRITES - below. */ -#define OSST_WRITE_THRESHOLD_BLOCKS 32 - -/* OSST_EOM_RESERVE defines the number of frames are kept in reserve for - * * write error recovery when writing near end of medium. ENOSPC is returned - * * when write() is called and the tape write position is within this number - * * of blocks from the tape capacity. */ -#define OSST_EOM_RESERVE 300 - -/* The maximum number of tape buffers the driver allocates. The number - is also constrained by the number of drives detected. Determines the - maximum number of concurrently active tape drives. */ -#define OSST_MAX_BUFFERS OSST_MAX_TAPES - -/* Maximum number of scatter/gather segments */ -/* Fit one buffer in pages and add one for the AUX header */ -#define OSST_MAX_SG (((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) + 1) - -/* The number of scatter/gather segments to allocate at first try (must be - smaller or equal to the maximum). */ -#define OSST_FIRST_SG ((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) - -/* The size of the first scatter/gather segments (determines the maximum block - size for SCSI adapters not supporting scatter/gather). The default is set - to try to allocate the buffer as one chunk. */ -#define OSST_FIRST_ORDER (15-PAGE_SHIFT) - - -/* The following lines define defaults for properties that can be set - separately for each drive using the MTSTOPTIONS ioctl. */ - -/* If OSST_TWO_FM is non-zero, the driver writes two filemarks after a - file being written. Some drives can't handle two filemarks at the - end of data. */ -#define OSST_TWO_FM 0 - -/* If OSST_BUFFER_WRITES is non-zero, writes in fixed block mode are - buffered until the driver buffer is full or asynchronous write is - triggered. */ -#define OSST_BUFFER_WRITES 1 - -/* If OSST_ASYNC_WRITES is non-zero, the SCSI write command may be started - without waiting for it to finish. May cause problems in multiple - tape backups. */ -#define OSST_ASYNC_WRITES 1 - -/* If OSST_READ_AHEAD is non-zero, blocks are read ahead in fixed block - mode. */ -#define OSST_READ_AHEAD 1 - -/* If OSST_AUTO_LOCK is non-zero, the drive door is locked at the first - read or write command after the device is opened. The door is opened - when the device is closed. */ -#define OSST_AUTO_LOCK 0 - -/* If OSST_FAST_MTEOM is non-zero, the MTEOM ioctl is done using the - direct SCSI command. The file number status is lost but this method - is fast with some drives. Otherwise MTEOM is done by spacing over - files and the file number status is retained. */ -#define OSST_FAST_MTEOM 0 - -/* If OSST_SCSI2LOGICAL is nonzero, the logical block addresses are used for - MTIOCPOS and MTSEEK by default. Vendor addresses are used if OSST_SCSI2LOGICAL - is zero. */ -#define OSST_SCSI2LOGICAL 0 - -/* If OSST_SYSV is non-zero, the tape behaves according to the SYS V semantics. - The default is BSD semantics. */ -#define OSST_SYSV 0 - - -#endif diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig index c544f48a1d18..2368f34efba3 100644 --- a/drivers/scsi/pcmcia/Kconfig +++ b/drivers/scsi/pcmcia/Kconfig @@ -20,6 +20,16 @@ config PCMCIA_AHA152X To compile this driver as a module, choose M here: the module will be called aha152x_cs. +config PCMCIA_FDOMAIN + tristate "Future Domain PCMCIA support" + select SCSI_FDOMAIN + help + Say Y here if you intend to attach this type of PCMCIA SCSI host + adapter to your computer. + + To compile this driver as a module, choose M here: the + module will be called fdomain_cs. + config PCMCIA_NINJA_SCSI tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support" depends on !64BIT diff --git a/drivers/scsi/pcmcia/Makefile b/drivers/scsi/pcmcia/Makefile index a5a24dd44e7e..02f5b44a2685 100644 --- a/drivers/scsi/pcmcia/Makefile +++ b/drivers/scsi/pcmcia/Makefile @@ -4,6 +4,7 @@ ccflags-y := -I $(srctree)/drivers/scsi # 16-bit client drivers obj-$(CONFIG_PCMCIA_QLOGIC) += qlogic_cs.o +obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o obj-$(CONFIG_PCMCIA_AHA152X) += aha152x_cs.o obj-$(CONFIG_PCMCIA_NINJA_SCSI) += nsp_cs.o obj-$(CONFIG_PCMCIA_SYM53C500) += sym53c500_cs.o diff --git a/drivers/scsi/pcmcia/fdomain_cs.c b/drivers/scsi/pcmcia/fdomain_cs.c new file mode 100644 index 000000000000..e42acf314d06 --- /dev/null +++ b/drivers/scsi/pcmcia/fdomain_cs.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MPL-1.1) +/* + * Driver for Future Domain-compatible PCMCIA SCSI cards + * Copyright 2019 Ondrej Zary + * + * The initial developer of the original code is David A. Hinds + * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <scsi/scsi_host.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/ds.h> +#include "fdomain.h" + +MODULE_AUTHOR("Ondrej Zary, David Hinds"); +MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver"); +MODULE_LICENSE("Dual MPL/GPL"); + +static int fdomain_config_check(struct pcmcia_device *p_dev, void *priv_data) +{ + p_dev->io_lines = 10; + p_dev->resource[0]->end = FDOMAIN_REGION_SIZE; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; + return pcmcia_request_io(p_dev); +} + +static int fdomain_probe(struct pcmcia_device *link) +{ + int ret; + struct Scsi_Host *sh; + + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + link->config_regs = PRESENT_OPTION; + + ret = pcmcia_loop_config(link, fdomain_config_check, NULL); + if (ret) + return ret; + + ret = pcmcia_enable_device(link); + if (ret) + goto fail_disable; + + if (!request_region(link->resource[0]->start, FDOMAIN_REGION_SIZE, + "fdomain_cs")) + goto fail_disable; + + sh = fdomain_create(link->resource[0]->start, link->irq, 7, &link->dev); + if (!sh) { + dev_err(&link->dev, "Controller initialization failed"); + ret = -ENODEV; + goto fail_release; + } + + link->priv = sh; + + return 0; + +fail_release: + release_region(link->resource[0]->start, FDOMAIN_REGION_SIZE); +fail_disable: + pcmcia_disable_device(link); + return ret; +} + +static void fdomain_remove(struct pcmcia_device *link) +{ + fdomain_destroy(link->priv); + release_region(link->resource[0]->start, FDOMAIN_REGION_SIZE); + pcmcia_disable_device(link); +} + +static const struct pcmcia_device_id fdomain_ids[] = { + PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88, + 0x859cad20), + PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e), + PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation", + "SCSI PCMCIA Credit Card Controller", + 0x182bdafe, 0xc80d106f), + PCMCIA_DEVICE_NULL, +}; +MODULE_DEVICE_TABLE(pcmcia, fdomain_ids); + +static struct pcmcia_driver fdomain_cs_driver = { + .owner = THIS_MODULE, + .name = "fdomain_cs", + .probe = fdomain_probe, + .remove = fdomain_remove, + .id_table = fdomain_ids, +}; + +module_pcmcia_driver(fdomain_cs_driver); diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index a81748e6e8fb..97416e1dcc5b 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -789,7 +789,7 @@ static void nsp_pio_read(struct scsi_cmnd *SCpnt) SCpnt->SCp.buffers_residual != 0 ) { //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out); SCpnt->SCp.buffers_residual--; - SCpnt->SCp.buffer++; + SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer); SCpnt->SCp.ptr = BUFFER_ADDR; SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; time_out = 1000; @@ -887,7 +887,7 @@ static void nsp_pio_write(struct scsi_cmnd *SCpnt) SCpnt->SCp.buffers_residual != 0 ) { //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next"); SCpnt->SCp.buffers_residual--; - SCpnt->SCp.buffer++; + SCpnt->SCp.buffer = sg_next(SCpnt->SCp.buffer); SCpnt->SCp.ptr = BUFFER_ADDR; SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; time_out = 1000; diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index d193961ea82f..6b85016b4db3 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -462,6 +462,24 @@ static ssize_t pm8001_ctl_bios_version_show(struct device *cdev, } static DEVICE_ATTR(bios_version, S_IRUGO, pm8001_ctl_bios_version_show, NULL); /** + * event_log_size_show - event log size + * @cdev: pointer to embedded class device + * @buf: the buffer returned + * + * A sysfs read shost attribute. + */ +static ssize_t event_log_size_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); + struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; + + return snprintf(buf, PAGE_SIZE, "%d\n", + pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size); +} +static DEVICE_ATTR_RO(event_log_size); +/** * pm8001_ctl_aap_log_show - IOP event log * @cdev: pointer to embedded class device * @buf: the buffer returned @@ -474,25 +492,26 @@ static ssize_t pm8001_ctl_iop_log_show(struct device *cdev, struct Scsi_Host *shost = class_to_shost(cdev); struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; -#define IOP_MEMMAP(r, c) \ - (*(u32 *)((u8*)pm8001_ha->memoryMap.region[IOP].virt_ptr + (r) * 32 \ - + (c))) - int i; char *str = buf; - int max = 2; - for (i = 0; i < max; i++) { - str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" - "0x%08x 0x%08x\n", - IOP_MEMMAP(i, 0), - IOP_MEMMAP(i, 4), - IOP_MEMMAP(i, 8), - IOP_MEMMAP(i, 12), - IOP_MEMMAP(i, 16), - IOP_MEMMAP(i, 20), - IOP_MEMMAP(i, 24), - IOP_MEMMAP(i, 28)); + u32 read_size = + pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size / 1024; + static u32 start, end, count; + u32 max_read_times = 32; + u32 max_count = (read_size * 1024) / (max_read_times * 4); + u32 *temp = (u32 *)pm8001_ha->memoryMap.region[IOP].virt_ptr; + + if ((count % max_count) == 0) { + start = 0; + end = max_read_times; + count = 0; + } else { + start = end; + end = end + max_read_times; } + for (; start < end; start++) + str += sprintf(str, "%08x ", *(temp+start)); + count++; return str - buf; } static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL); @@ -796,6 +815,7 @@ struct device_attribute *pm8001_host_attrs[] = { &dev_attr_max_sg_list, &dev_attr_sas_spec_support, &dev_attr_logging_level, + &dev_attr_event_log_size, &dev_attr_host_sas_address, &dev_attr_bios_version, &dev_attr_ib_log, diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 109effd3557d..68a8217032d0 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -2356,7 +2356,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && (status != IO_UNDERFLOW)) { if (!((t->dev->parent) && - (DEV_IS_EXPANDER(t->dev->parent->dev_type)))) { + (dev_is_expander(t->dev->parent->dev_type)))) { for (i = 0 , j = 4; j <= 7 && i <= 3; i++ , j++) sata_addr_low[i] = pm8001_ha->sas_addr[j]; for (i = 0 , j = 0; j <= 3 && i <= 3; i++ , j++) @@ -4560,7 +4560,7 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) stp_sspsmp_sata = 0x01; /*ssp or smp*/ } - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + if (parent_dev && dev_is_expander(parent_dev->dev_type)) phy_id = parent_dev->ex_dev.ex_phy->phy_id; else phy_id = pm8001_dev->attached_phy; diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 88eef3b18e41..7e48154e11c3 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -634,7 +634,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev) dev->lldd_dev = pm8001_device; pm8001_device->dev_type = dev->dev_type; pm8001_device->dcompletion = &completion; - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) { + if (parent_dev && dev_is_expander(parent_dev->dev_type)) { int phy_id; struct ex_phy *phy; for (phy_id = 0; phy_id < parent_dev->ex_dev.num_phys; @@ -888,6 +888,8 @@ static void pm8001_dev_gone_notify(struct domain_device *dev) spin_unlock_irqrestore(&pm8001_ha->lock, flags); pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , dev, 1, 0); + while (pm8001_dev->running_req) + msleep(20); spin_lock_irqsave(&pm8001_ha->lock, flags); } PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id); @@ -1181,7 +1183,7 @@ int pm8001_query_task(struct sas_task *task) return rc; } -/* mandatory SAM-3, still need free task/ccb info, abord the specified task */ +/* mandatory SAM-3, still need free task/ccb info, abort the specified task */ int pm8001_abort_task(struct sas_task *task) { unsigned long flags; @@ -1256,8 +1258,10 @@ int pm8001_abort_task(struct sas_task *task) PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Waiting for Port reset\n")); wait_for_completion(&completion_reset); - if (phy->port_reset_status) + if (phy->port_reset_status) { + pm8001_dev_gone_notify(dev); goto out; + } /* * 4. SATA Abort ALL @@ -1304,28 +1308,22 @@ out: int pm8001_abort_task_set(struct domain_device *dev, u8 *lun) { - int rc = TMF_RESP_FUNC_FAILED; struct pm8001_tmf_task tmf_task; tmf_task.tmf = TMF_ABORT_TASK_SET; - rc = pm8001_issue_ssp_tmf(dev, lun, &tmf_task); - return rc; + return pm8001_issue_ssp_tmf(dev, lun, &tmf_task); } int pm8001_clear_aca(struct domain_device *dev, u8 *lun) { - int rc = TMF_RESP_FUNC_FAILED; struct pm8001_tmf_task tmf_task; tmf_task.tmf = TMF_CLEAR_ACA; - rc = pm8001_issue_ssp_tmf(dev, lun, &tmf_task); - - return rc; + return pm8001_issue_ssp_tmf(dev, lun, &tmf_task); } int pm8001_clear_task_set(struct domain_device *dev, u8 *lun) { - int rc = TMF_RESP_FUNC_FAILED; struct pm8001_tmf_task tmf_task; struct pm8001_device *pm8001_dev = dev->lldd_dev; struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev); @@ -1334,7 +1332,6 @@ int pm8001_clear_task_set(struct domain_device *dev, u8 *lun) pm8001_printk("I_T_L_Q clear task set[%x]\n", pm8001_dev->device_id)); tmf_task.tmf = TMF_CLEAR_TASK_SET; - rc = pm8001_issue_ssp_tmf(dev, lun, &tmf_task); - return rc; + return pm8001_issue_ssp_tmf(dev, lun, &tmf_task); } diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index ac6d8e3f22de..ff17c6aff63d 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -103,7 +103,6 @@ do { \ #define PM8001_READ_VPD -#define DEV_IS_EXPANDER(type) ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE)) #define IS_SPCV_12G(dev) ((dev->device == 0X8074) \ || (dev->device == 0X8076) \ || (dev->device == 0X8077) \ diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 301de40eb708..73261902d75d 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -604,7 +604,7 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha) pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer &= 0x0000ffff; pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer |= - 0x140000; + CHIP_8006_PORT_RECOVERY_TIMEOUT; } pm8001_mw32(address, MAIN_PORT_RECOVERY_TIMER, pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer); @@ -2066,7 +2066,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && (status != IO_UNDERFLOW)) { if (!((t->dev->parent) && - (DEV_IS_EXPANDER(t->dev->parent->dev_type)))) { + (dev_is_expander(t->dev->parent->dev_type)))) { for (i = 0 , j = 4; i <= 3 && j <= 7; i++ , j++) sata_addr_low[i] = pm8001_ha->sas_addr[j]; for (i = 0 , j = 0; i <= 3 && j <= 3; i++ , j++) @@ -4561,7 +4561,7 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) stp_sspsmp_sata = 0x01; /*ssp or smp*/ } - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) + if (parent_dev && dev_is_expander(parent_dev->dev_type)) phy_id = parent_dev->ex_dev.ex_phy->phy_id; else phy_id = pm8001_dev->attached_phy; diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index 84d7426441bf..dc9ab7689060 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h @@ -230,6 +230,8 @@ #define SAS_MAX_AIP 0x200000 #define IT_NEXUS_TIMEOUT 0x7D0 #define PORT_RECOVERY_TIMEOUT ((IT_NEXUS_TIMEOUT/100) + 30) +/* Port recovery timeout, 10000 ms for PM8006 controller */ +#define CHIP_8006_PORT_RECOVERY_TIMEOUT 0x640000 #ifdef __LITTLE_ENDIAN_BITFIELD struct sas_identify_frame_local { diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index ca22526aff7f..398d2af60832 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3255,7 +3255,7 @@ static int pmcraid_copy_sglist( int direction ) { - struct scatterlist *scatterlist; + struct scatterlist *sg; void *kaddr; int bsize_elem; int i; @@ -3264,10 +3264,10 @@ static int pmcraid_copy_sglist( /* Determine the actual number of bytes per element */ bsize_elem = PAGE_SIZE * (1 << sglist->order); - scatterlist = sglist->scatterlist; + sg = sglist->scatterlist; - for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); + for (i = 0; i < (len / bsize_elem); i++, sg = sg_next(sg), buffer += bsize_elem) { + struct page *page = sg_page(sg); kaddr = kmap(page); if (direction == DMA_TO_DEVICE) @@ -3282,11 +3282,11 @@ static int pmcraid_copy_sglist( return -EFAULT; } - scatterlist[i].length = bsize_elem; + sg->length = bsize_elem; } if (len % bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); + struct page *page = sg_page(sg); kaddr = kmap(page); @@ -3297,7 +3297,7 @@ static int pmcraid_copy_sglist( kunmap(page); - scatterlist[i].length = len % bsize_elem; + sg->length = len % bsize_elem; } if (rc) { @@ -5841,7 +5841,7 @@ out_disable_device: } /* - * PCI driver structure of pcmraid driver + * PCI driver structure of pmcraid driver */ static struct pci_driver pmcraid_driver = { .name = PMCRAID_DRIVER_NAME, diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 35213082e933..a406cc825426 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -590,7 +590,7 @@ static int ppa_completion(struct scsi_cmnd *cmd) if (cmd->SCp.buffer && !cmd->SCp.this_residual) { /* if scatter/gather, advance to the next segment */ if (cmd->SCp.buffers_residual--) { - cmd->SCp.buffer++; + cmd->SCp.buffer = sg_next(cmd->SCp.buffer); cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); diff --git a/drivers/scsi/qedf/qedf.h b/drivers/scsi/qedf/qedf.h index 5a021217bfc9..f3f399fe10c8 100644 --- a/drivers/scsi/qedf/qedf.h +++ b/drivers/scsi/qedf/qedf.h @@ -49,6 +49,7 @@ #define QEDF_ABORT_TIMEOUT (10 * 1000) #define QEDF_CLEANUP_TIMEOUT 1 #define QEDF_MAX_CDB_LEN 16 +#define QEDF_LL2_BUF_SIZE 2500 /* Buffer size required for LL2 Rx */ #define UPSTREAM_REMOVE 1 #define UPSTREAM_KEEP 1 diff --git a/drivers/scsi/qedf/qedf_debugfs.c b/drivers/scsi/qedf/qedf_debugfs.c index d905a307302d..b88bed9bb133 100644 --- a/drivers/scsi/qedf/qedf_debugfs.c +++ b/drivers/scsi/qedf/qedf_debugfs.c @@ -47,13 +47,13 @@ qedf_dbg_host_init(struct qedf_dbg_ctx *qedf, * @pf: the pf that is stopping **/ void -qedf_dbg_host_exit(struct qedf_dbg_ctx *qedf) +qedf_dbg_host_exit(struct qedf_dbg_ctx *qedf_dbg) { - QEDF_INFO(qedf, QEDF_LOG_DEBUGFS, "Destroying debugfs host " + QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "Destroying debugfs host " "entry\n"); /* remove debugfs entries of this PF */ - debugfs_remove_recursive(qedf->bdf_dentry); - qedf->bdf_dentry = NULL; + debugfs_remove_recursive(qedf_dbg->bdf_dentry); + qedf_dbg->bdf_dentry = NULL; } /** @@ -140,10 +140,10 @@ qedf_dbg_debug_cmd_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos) { int cnt; - struct qedf_dbg_ctx *qedf = + struct qedf_dbg_ctx *qedf_dbg = (struct qedf_dbg_ctx *)filp->private_data; - QEDF_INFO(qedf, QEDF_LOG_DEBUGFS, "entered\n"); + QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "debug mask=0x%x\n", qedf_debug); cnt = sprintf(buffer, "debug mask = 0x%x\n", qedf_debug); cnt = min_t(int, count, cnt - *ppos); @@ -158,7 +158,7 @@ qedf_dbg_debug_cmd_write(struct file *filp, const char __user *buffer, uint32_t val; void *kern_buf; int rval; - struct qedf_dbg_ctx *qedf = + struct qedf_dbg_ctx *qedf_dbg = (struct qedf_dbg_ctx *)filp->private_data; if (!count || *ppos) @@ -178,7 +178,7 @@ qedf_dbg_debug_cmd_write(struct file *filp, const char __user *buffer, else qedf_debug = val; - QEDF_INFO(qedf, QEDF_LOG_DEBUGFS, "Setting debug=0x%x.\n", val); + QEDF_INFO(qedf_dbg, QEDF_LOG_DEBUGFS, "Setting debug=0x%x.\n", val); return count; } diff --git a/drivers/scsi/qedf/qedf_els.c b/drivers/scsi/qedf/qedf_els.c index 5996f68fbf2b..87e169dcebdb 100644 --- a/drivers/scsi/qedf/qedf_els.c +++ b/drivers/scsi/qedf/qedf_els.c @@ -179,8 +179,11 @@ static void qedf_rrq_compl(struct qedf_els_cb_arg *cb_arg) orig_io_req = cb_arg->aborted_io_req; - if (!orig_io_req) + if (!orig_io_req) { + QEDF_ERR(&qedf->dbg_ctx, + "Original io_req is NULL, rrq_req = %p.\n", rrq_req); goto out_free; + } if (rrq_req->event != QEDF_IOREQ_EV_ELS_TMO && rrq_req->event != QEDF_IOREQ_EV_ELS_ERR_DETECT) @@ -350,8 +353,10 @@ void qedf_restart_rport(struct qedf_rport *fcport) u32 port_id; unsigned long flags; - if (!fcport) + if (!fcport) { + QEDF_ERR(NULL, "fcport is NULL.\n"); return; + } spin_lock_irqsave(&fcport->rport_lock, flags); if (test_bit(QEDF_RPORT_IN_RESET, &fcport->flags) || @@ -418,8 +423,11 @@ static void qedf_l2_els_compl(struct qedf_els_cb_arg *cb_arg) * If we are flushing the command just free the cb_arg as none of the * response data will be valid. */ - if (els_req->event == QEDF_IOREQ_EV_ELS_FLUSH) + if (els_req->event == QEDF_IOREQ_EV_ELS_FLUSH) { + QEDF_ERR(NULL, "els_req xid=0x%x event is flush.\n", + els_req->xid); goto free_arg; + } fcport = els_req->fcport; mp_req = &(els_req->mp_req); @@ -532,8 +540,10 @@ static void qedf_srr_compl(struct qedf_els_cb_arg *cb_arg) orig_io_req = cb_arg->aborted_io_req; - if (!orig_io_req) + if (!orig_io_req) { + QEDF_ERR(NULL, "orig_io_req is NULL.\n"); goto out_free; + } clear_bit(QEDF_CMD_SRR_SENT, &orig_io_req->flags); @@ -547,8 +557,11 @@ static void qedf_srr_compl(struct qedf_els_cb_arg *cb_arg) orig_io_req, orig_io_req->xid, srr_req->xid, refcount); /* If a SRR times out, simply free resources */ - if (srr_req->event == QEDF_IOREQ_EV_ELS_TMO) + if (srr_req->event == QEDF_IOREQ_EV_ELS_TMO) { + QEDF_ERR(&qedf->dbg_ctx, + "ELS timeout rec_xid=0x%x.\n", srr_req->xid); goto out_put; + } /* Normalize response data into struct fc_frame */ mp_req = &(srr_req->mp_req); @@ -721,8 +734,11 @@ void qedf_process_seq_cleanup_compl(struct qedf_ctx *qedf, cb_arg = io_req->cb_arg; /* If we timed out just free resources */ - if (io_req->event == QEDF_IOREQ_EV_ELS_TMO || !cqe) + if (io_req->event == QEDF_IOREQ_EV_ELS_TMO || !cqe) { + QEDF_ERR(&qedf->dbg_ctx, + "cqe is NULL or timeout event (0x%x)", io_req->event); goto free; + } /* Kill the timer we put on the request */ cancel_delayed_work_sync(&io_req->timeout_work); @@ -825,8 +841,10 @@ static void qedf_rec_compl(struct qedf_els_cb_arg *cb_arg) orig_io_req = cb_arg->aborted_io_req; - if (!orig_io_req) + if (!orig_io_req) { + QEDF_ERR(NULL, "orig_io_req is NULL.\n"); goto out_free; + } if (rec_req->event != QEDF_IOREQ_EV_ELS_TMO && rec_req->event != QEDF_IOREQ_EV_ELS_ERR_DETECT) @@ -838,8 +856,12 @@ static void qedf_rec_compl(struct qedf_els_cb_arg *cb_arg) orig_io_req, orig_io_req->xid, rec_req->xid, refcount); /* If a REC times out, free resources */ - if (rec_req->event == QEDF_IOREQ_EV_ELS_TMO) + if (rec_req->event == QEDF_IOREQ_EV_ELS_TMO) { + QEDF_ERR(&qedf->dbg_ctx, + "Got TMO event, orig_io_req %p orig_io_xid=0x%x.\n", + orig_io_req, orig_io_req->xid); goto out_put; + } /* Normalize response data into struct fc_frame */ mp_req = &(rec_req->mp_req); diff --git a/drivers/scsi/qedf/qedf_fip.c b/drivers/scsi/qedf/qedf_fip.c index 362d2bed72fb..bb82f0875eca 100644 --- a/drivers/scsi/qedf/qedf_fip.c +++ b/drivers/scsi/qedf/qedf_fip.c @@ -23,8 +23,11 @@ void qedf_fcoe_send_vlan_req(struct qedf_ctx *qedf) int rc = -1; skb = dev_alloc_skb(sizeof(struct fip_vlan)); - if (!skb) + if (!skb) { + QEDF_ERR(&qedf->dbg_ctx, + "Failed to allocate skb.\n"); return; + } eth_fr = (char *)skb->data; vlan = (struct fip_vlan *)eth_fr; @@ -250,18 +253,24 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb) fc_wwpn_valid = true; break; case FIP_DT_VN_ID: + fabric_id_valid = false; vp = (struct fip_vn_desc *)desc; - QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, - "vx_port fd_fc_id=%x fd_mac=%pM.\n", - ntoh24(vp->fd_fc_id), vp->fd_mac); - /* Check vx_port fabric ID */ - if (ntoh24(vp->fd_fc_id) != - qedf->lport->port_id) - fabric_id_valid = false; - /* Check vx_port MAC */ - if (!ether_addr_equal(vp->fd_mac, - qedf->data_src_addr)) - fabric_id_valid = false; + + QEDF_ERR(&qedf->dbg_ctx, + "CVL vx_port fd_fc_id=0x%x fd_mac=%pM fd_wwpn=%016llx.\n", + ntoh24(vp->fd_fc_id), vp->fd_mac, + get_unaligned_be64(&vp->fd_wwpn)); + /* Check for vx_port wwpn OR Check vx_port + * fabric ID OR Check vx_port MAC + */ + if ((get_unaligned_be64(&vp->fd_wwpn) == + qedf->wwpn) || + (ntoh24(vp->fd_fc_id) == + qedf->lport->port_id) || + (ether_addr_equal(vp->fd_mac, + qedf->data_src_addr))) { + fabric_id_valid = true; + } break; default: /* Ignore anything else */ diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index d881e822f92c..e749a2dcaad7 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -104,6 +104,8 @@ static void qedf_cmd_timeout(struct work_struct *work) qedf_process_seq_cleanup_compl(qedf, NULL, io_req); break; default: + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Hit default case, xid=0x%x.\n", io_req->xid); break; } } @@ -122,8 +124,10 @@ void qedf_cmd_mgr_free(struct qedf_cmd_mgr *cmgr) num_ios = max_xid - min_xid + 1; /* Free fcoe_bdt_ctx structures */ - if (!cmgr->io_bdt_pool) + if (!cmgr->io_bdt_pool) { + QEDF_ERR(&qedf->dbg_ctx, "io_bdt_pool is NULL.\n"); goto free_cmd_pool; + } bd_tbl_sz = QEDF_MAX_BDS_PER_CMD * sizeof(struct scsi_sge); for (i = 0; i < num_ios; i++) { @@ -226,8 +230,11 @@ struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf) io_req->sense_buffer = dma_alloc_coherent(&qedf->pdev->dev, QEDF_SCSI_SENSE_BUFFERSIZE, &io_req->sense_buffer_dma, GFP_KERNEL); - if (!io_req->sense_buffer) + if (!io_req->sense_buffer) { + QEDF_ERR(&qedf->dbg_ctx, + "Failed to alloc sense buffer.\n"); goto mem_err; + } /* Allocate task parameters to pass to f/w init funcions */ io_req->task_params = kzalloc(sizeof(*io_req->task_params), @@ -437,8 +444,12 @@ void qedf_release_cmd(struct kref *ref) struct qedf_rport *fcport = io_req->fcport; unsigned long flags; - if (io_req->cmd_type == QEDF_SCSI_CMD) + if (io_req->cmd_type == QEDF_SCSI_CMD) { + QEDF_WARN(&fcport->qedf->dbg_ctx, + "Cmd released called without scsi_done called, io_req %p xid=0x%x.\n", + io_req, io_req->xid); WARN_ON(io_req->sc_cmd); + } if (io_req->cmd_type == QEDF_ELS || io_req->cmd_type == QEDF_TASK_MGMT_CMD) @@ -447,8 +458,10 @@ void qedf_release_cmd(struct kref *ref) atomic_inc(&cmd_mgr->free_list_cnt); atomic_dec(&fcport->num_active_ios); atomic_set(&io_req->state, QEDF_CMD_ST_INACTIVE); - if (atomic_read(&fcport->num_active_ios) < 0) + if (atomic_read(&fcport->num_active_ios) < 0) { QEDF_WARN(&(fcport->qedf->dbg_ctx), "active_ios < 0.\n"); + WARN_ON(1); + } /* Increment task retry identifier now that the request is released */ io_req->task_retry_identifier++; @@ -951,6 +964,9 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) if (test_bit(QEDF_UNLOADING, &qedf->flags) || test_bit(QEDF_DBG_STOP_IO, &qedf->flags)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "Returning DNC as unloading or stop io, flags 0x%lx.\n", + qedf->flags); sc_cmd->result = DID_NO_CONNECT << 16; sc_cmd->scsi_done(sc_cmd); return 0; @@ -967,6 +983,9 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) rval = fc_remote_port_chkready(rport); if (rval) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "fc_remote_port_chkready failed=0x%x for port_id=0x%06x.\n", + rval, rport->port_id); sc_cmd->result = rval; sc_cmd->scsi_done(sc_cmd); return 0; @@ -974,12 +993,14 @@ qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) /* Retry command if we are doing a qed drain operation */ if (test_bit(QEDF_DRAIN_ACTIVE, &qedf->flags)) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Drain active.\n"); rc = SCSI_MLQUEUE_HOST_BUSY; goto exit_qcmd; } if (lport->state != LPORT_ST_READY || atomic_read(&qedf->link_state) != QEDF_LINK_UP) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "Link down.\n"); rc = SCSI_MLQUEUE_HOST_BUSY; goto exit_qcmd; } @@ -1297,8 +1318,10 @@ void qedf_scsi_done(struct qedf_ctx *qedf, struct qedf_ioreq *io_req, struct scsi_cmnd *sc_cmd; int refcount; - if (!io_req) + if (!io_req) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, "io_req is NULL\n"); return; + } if (test_and_set_bit(QEDF_CMD_ERR_SCSI_DONE, &io_req->flags)) { QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, @@ -1414,8 +1437,12 @@ void qedf_process_warning_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, u64 err_warn_bit_map; u8 err_warn = 0xff; - if (!cqe) + if (!cqe) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "cqe is NULL for io_req %p xid=0x%x\n", + io_req, io_req->xid); return; + } QEDF_ERR(&(io_req->fcport->qedf->dbg_ctx), "Warning CQE, " "xid=0x%x\n", io_req->xid); @@ -1477,8 +1504,11 @@ void qedf_process_error_detect(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, { int rval; - if (!cqe) + if (!cqe) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_IO, + "cqe is NULL for io_req %p\n", io_req); return; + } QEDF_ERR(&(io_req->fcport->qedf->dbg_ctx), "Error detection CQE, " "xid=0x%x\n", io_req->xid); @@ -1543,8 +1573,10 @@ void qedf_flush_active_ios(struct qedf_rport *fcport, int lun) int wait_cnt = 100; int refcount = 0; - if (!fcport) + if (!fcport) { + QEDF_ERR(NULL, "fcport is NULL\n"); return; + } /* Check that fcport is still offloaded */ if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { @@ -1976,6 +2008,10 @@ void qedf_process_abts_compl(struct qedf_ctx *qedf, struct fcoe_cqe *cqe, clear_bit(QEDF_CMD_IN_ABORT, &io_req->flags); if (io_req->sc_cmd) { + if (!io_req->return_scsi_cmd_on_abts) + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM, + "Not call scsi_done for xid=0x%x.\n", + io_req->xid); if (io_req->return_scsi_cmd_on_abts) qedf_scsi_done(qedf, io_req, DID_ERROR); } @@ -2201,6 +2237,10 @@ int qedf_initiate_cleanup(struct qedf_ioreq *io_req, } if (io_req->sc_cmd) { + if (!io_req->return_scsi_cmd_on_abts) + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_SCSI_TM, + "Not call scsi_done for xid=0x%x.\n", + io_req->xid); if (io_req->return_scsi_cmd_on_abts) qedf_scsi_done(qedf, io_req, DID_ERROR); } @@ -2241,7 +2281,7 @@ static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd, u16 sqe_idx; if (!sc_cmd) { - QEDF_ERR(&(qedf->dbg_ctx), "invalid arg\n"); + QEDF_ERR(&qedf->dbg_ctx, "sc_cmd is NULL\n"); return FAILED; } @@ -2363,8 +2403,8 @@ int qedf_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) QEDF_ERR(NULL, "tm_flags 0x%x sc_cmd %p op = 0x%02x target_id = 0x%x lun=%d\n", - tm_flags, sc_cmd, sc_cmd->cmnd[0], rport->scsi_target_id, - (int)sc_cmd->device->lun); + tm_flags, sc_cmd, sc_cmd->cmd_len ? sc_cmd->cmnd[0] : 0xff, + rport->scsi_target_id, (int)sc_cmd->device->lun); if (!rdata || !kref_get_unless_zero(&rdata->kref)) { QEDF_ERR(NULL, "stale rport\n"); @@ -2515,6 +2555,11 @@ void qedf_process_unsol_compl(struct qedf_ctx *qedf, uint16_t que_idx, fh = (struct fc_frame_header *)fc_frame_header_get(fp); memcpy(fh, (void *)bdq_addr, pktlen); + QEDF_WARN(&qedf->dbg_ctx, + "Processing Unsolicated frame, src=%06x dest=%06x r_ctl=0x%x type=0x%x cmd=%02x\n", + ntoh24(fh->fh_s_id), ntoh24(fh->fh_d_id), fh->fh_r_ctl, + fh->fh_type, fc_frame_payload_op(fp)); + /* Initialize the frame so libfc sees it as a valid frame */ crc = fcoe_fc_crc(fp); fc_frame_init(fp); diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 6ef0f741bf89..59ca98f12afd 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -27,6 +27,7 @@ const struct qed_fcoe_ops *qed_ops; static int qedf_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void qedf_remove(struct pci_dev *pdev); +static void qedf_shutdown(struct pci_dev *pdev); /* * Driver module parameters. @@ -110,16 +111,18 @@ static struct kmem_cache *qedf_io_work_cache; void qedf_set_vlan_id(struct qedf_ctx *qedf, int vlan_id) { - qedf->vlan_id = vlan_id; - qedf->vlan_id |= qedf->prio << VLAN_PRIO_SHIFT; - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Setting vlan_id=%04x " - "prio=%d.\n", vlan_id, qedf->prio); + int vlan_id_tmp = 0; + + vlan_id_tmp = vlan_id | (qedf->prio << VLAN_PRIO_SHIFT); + qedf->vlan_id = vlan_id_tmp; + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Setting vlan_id=0x%04x prio=%d.\n", + vlan_id_tmp, qedf->prio); } /* Returns true if we have a valid vlan, false otherwise */ static bool qedf_initiate_fipvlan_req(struct qedf_ctx *qedf) { - int rc; while (qedf->fipvlan_retries--) { /* This is to catch if link goes down during fipvlan retries */ @@ -128,20 +131,25 @@ static bool qedf_initiate_fipvlan_req(struct qedf_ctx *qedf) return false; } - if (qedf->vlan_id > 0) + if (test_bit(QEDF_UNLOADING, &qedf->flags)) { + QEDF_ERR(&qedf->dbg_ctx, "Driver unloading.\n"); + return false; + } + + if (qedf->vlan_id > 0) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "vlan = 0x%x already set, calling ctlr_link_up.\n", + qedf->vlan_id); + if (atomic_read(&qedf->link_state) == QEDF_LINK_UP) + fcoe_ctlr_link_up(&qedf->ctlr); return true; + } QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "Retry %d.\n", qedf->fipvlan_retries); init_completion(&qedf->fipvlan_compl); qedf_fcoe_send_vlan_req(qedf); - rc = wait_for_completion_timeout(&qedf->fipvlan_compl, - 1 * HZ); - if (rc > 0 && - (atomic_read(&qedf->link_state) == QEDF_LINK_UP)) { - fcoe_ctlr_link_up(&qedf->ctlr); - return true; - } + wait_for_completion_timeout(&qedf->fipvlan_compl, 1 * HZ); } return false; @@ -162,6 +170,8 @@ static void qedf_handle_link_update(struct work_struct *work) return; if (atomic_read(&qedf->link_state) != QEDF_LINK_UP) { + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Link is down, resetting vlan_id.\n"); qedf->vlan_id = 0; return; } @@ -311,8 +321,10 @@ int qedf_send_flogi(struct qedf_ctx *qedf) lport = qedf->lport; - if (!lport->tt.elsct_send) + if (!lport->tt.elsct_send) { + QEDF_ERR(&qedf->dbg_ctx, "tt.elsct_send not set.\n"); return -EINVAL; + } fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); if (!fp) { @@ -330,11 +342,6 @@ int qedf_send_flogi(struct qedf_ctx *qedf) return 0; } -struct qedf_tmp_rdata_item { - struct fc_rport_priv *rdata; - struct list_head list; -}; - /* * This function is called if link_down_tmo is in use. If we get a link up and * link_down_tmo has not expired then use just FLOGI/ADISC to recover our @@ -344,9 +351,8 @@ static void qedf_link_recovery(struct work_struct *work) { struct qedf_ctx *qedf = container_of(work, struct qedf_ctx, link_recovery.work); - struct qedf_rport *fcport; + struct fc_lport *lport = qedf->lport; struct fc_rport_priv *rdata; - struct qedf_tmp_rdata_item *rdata_item, *tmp_rdata_item; bool rc; int retries = 30; int rval, i; @@ -413,33 +419,14 @@ static void qedf_link_recovery(struct work_struct *work) * Call lport->tt.rport_login which will cause libfc to send an * ADISC since the rport is in state ready. */ - rcu_read_lock(); - list_for_each_entry_rcu(fcport, &qedf->fcports, peers) { - rdata = fcport->rdata; - if (rdata == NULL) - continue; - rdata_item = kzalloc(sizeof(struct qedf_tmp_rdata_item), - GFP_ATOMIC); - if (!rdata_item) - continue; + mutex_lock(&lport->disc.disc_mutex); + list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) { if (kref_get_unless_zero(&rdata->kref)) { - rdata_item->rdata = rdata; - list_add(&rdata_item->list, &rdata_login_list); - } else - kfree(rdata_item); - } - rcu_read_unlock(); - /* - * Do the fc_rport_login outside of the rcu lock so we don't take a - * mutex in an atomic context. - */ - list_for_each_entry_safe(rdata_item, tmp_rdata_item, &rdata_login_list, - list) { - list_del(&rdata_item->list); - fc_rport_login(rdata_item->rdata); - kref_put(&rdata_item->rdata->kref, fc_rport_destroy); - kfree(rdata_item); + fc_rport_login(rdata); + kref_put(&rdata->kref, fc_rport_destroy); + } } + mutex_unlock(&lport->disc.disc_mutex); } static void qedf_update_link_speed(struct qedf_ctx *qedf, @@ -467,6 +454,9 @@ static void qedf_update_link_speed(struct qedf_ctx *qedf, case 100000: lport->link_speed = FC_PORTSPEED_100GBIT; break; + case 20000: + lport->link_speed = FC_PORTSPEED_20GBIT; + break; default: lport->link_speed = FC_PORTSPEED_UNKNOWN; break; @@ -476,16 +466,40 @@ static void qedf_update_link_speed(struct qedf_ctx *qedf, * Set supported link speed by querying the supported * capabilities of the link. */ - if (link->supported_caps & SUPPORTED_10000baseKR_Full) + if ((link->supported_caps & QED_LM_10000baseT_Full_BIT) || + (link->supported_caps & QED_LM_10000baseKX4_Full_BIT) || + (link->supported_caps & QED_LM_10000baseR_FEC_BIT) || + (link->supported_caps & QED_LM_10000baseCR_Full_BIT) || + (link->supported_caps & QED_LM_10000baseSR_Full_BIT) || + (link->supported_caps & QED_LM_10000baseLR_Full_BIT) || + (link->supported_caps & QED_LM_10000baseLRM_Full_BIT) || + (link->supported_caps & QED_LM_10000baseKR_Full_BIT)) { lport->link_supported_speeds |= FC_PORTSPEED_10GBIT; - if (link->supported_caps & SUPPORTED_25000baseKR_Full) + } + if ((link->supported_caps & QED_LM_25000baseKR_Full_BIT) || + (link->supported_caps & QED_LM_25000baseCR_Full_BIT) || + (link->supported_caps & QED_LM_25000baseSR_Full_BIT)) { lport->link_supported_speeds |= FC_PORTSPEED_25GBIT; - if (link->supported_caps & SUPPORTED_40000baseLR4_Full) + } + if ((link->supported_caps & QED_LM_40000baseLR4_Full_BIT) || + (link->supported_caps & QED_LM_40000baseKR4_Full_BIT) || + (link->supported_caps & QED_LM_40000baseCR4_Full_BIT) || + (link->supported_caps & QED_LM_40000baseSR4_Full_BIT)) { lport->link_supported_speeds |= FC_PORTSPEED_40GBIT; - if (link->supported_caps & SUPPORTED_50000baseKR2_Full) + } + if ((link->supported_caps & QED_LM_50000baseKR2_Full_BIT) || + (link->supported_caps & QED_LM_50000baseCR2_Full_BIT) || + (link->supported_caps & QED_LM_50000baseSR2_Full_BIT)) { lport->link_supported_speeds |= FC_PORTSPEED_50GBIT; - if (link->supported_caps & SUPPORTED_100000baseKR4_Full) + } + if ((link->supported_caps & QED_LM_100000baseKR4_Full_BIT) || + (link->supported_caps & QED_LM_100000baseSR4_Full_BIT) || + (link->supported_caps & QED_LM_100000baseCR4_Full_BIT) || + (link->supported_caps & QED_LM_100000baseLR4_ER4_Full_BIT)) { lport->link_supported_speeds |= FC_PORTSPEED_100GBIT; + } + if (link->supported_caps & QED_LM_20000baseKR2_Full_BIT) + lport->link_supported_speeds |= FC_PORTSPEED_20GBIT; fc_host_supported_speeds(lport->host) = lport->link_supported_speeds; } @@ -493,6 +507,16 @@ static void qedf_link_update(void *dev, struct qed_link_output *link) { struct qedf_ctx *qedf = (struct qedf_ctx *)dev; + /* + * Prevent race where we're removing the module and we get link update + * for qed. + */ + if (test_bit(QEDF_UNLOADING, &qedf->flags)) { + QEDF_ERR(&qedf->dbg_ctx, + "Ignore link update, driver getting unload.\n"); + return; + } + if (link->link_up) { if (atomic_read(&qedf->link_state) == QEDF_LINK_UP) { QEDF_INFO((&qedf->dbg_ctx), QEDF_LOG_DISC, @@ -572,7 +596,7 @@ static void qedf_dcbx_handler(void *dev, struct qed_dcbx_get *get, u32 mib_type) tmp_prio = get->operational.app_prio.fcoe; if (qedf_default_prio > -1) qedf->prio = qedf_default_prio; - else if (tmp_prio < 0 || tmp_prio > 7) { + else if (tmp_prio > 7) { QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "FIP/FCoE prio %d out of range, setting to %d.\n", tmp_prio, QEDF_DEFAULT_PRIO); @@ -1077,7 +1101,7 @@ static int qedf_xmit(struct fc_lport *lport, struct fc_frame *fp) return -ENOMEM; } frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; - cp = kmap_atomic(skb_frag_page(frag)) + frag->page_offset; + cp = kmap_atomic(skb_frag_page(frag)) + skb_frag_off(frag); } else { cp = skb_put(skb, tlen); } @@ -2215,16 +2239,21 @@ static void qedf_simd_int_handler(void *cookie) static void qedf_sync_free_irqs(struct qedf_ctx *qedf) { int i; + u16 vector_idx = 0; + u32 vector; if (qedf->int_info.msix_cnt) { for (i = 0; i < qedf->int_info.used_cnt; i++) { - synchronize_irq(qedf->int_info.msix[i].vector); - irq_set_affinity_hint(qedf->int_info.msix[i].vector, - NULL); - irq_set_affinity_notifier(qedf->int_info.msix[i].vector, - NULL); - free_irq(qedf->int_info.msix[i].vector, - &qedf->fp_array[i]); + vector_idx = i * qedf->dev_info.common.num_hwfns + + qed_ops->common->get_affin_hwfn_idx(qedf->cdev); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Freeing IRQ #%d vector_idx=%d.\n", + i, vector_idx); + vector = qedf->int_info.msix[vector_idx].vector; + synchronize_irq(vector); + irq_set_affinity_hint(vector, NULL); + irq_set_affinity_notifier(vector, NULL); + free_irq(vector, &qedf->fp_array[i]); } } else qed_ops->common->simd_handler_clean(qedf->cdev, @@ -2237,11 +2266,19 @@ static void qedf_sync_free_irqs(struct qedf_ctx *qedf) static int qedf_request_msix_irq(struct qedf_ctx *qedf) { int i, rc, cpu; + u16 vector_idx = 0; + u32 vector; cpu = cpumask_first(cpu_online_mask); for (i = 0; i < qedf->num_queues; i++) { - rc = request_irq(qedf->int_info.msix[i].vector, - qedf_msix_handler, 0, "qedf", &qedf->fp_array[i]); + vector_idx = i * qedf->dev_info.common.num_hwfns + + qed_ops->common->get_affin_hwfn_idx(qedf->cdev); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "Requesting IRQ #%d vector_idx=%d.\n", + i, vector_idx); + vector = qedf->int_info.msix[vector_idx].vector; + rc = request_irq(vector, qedf_msix_handler, 0, "qedf", + &qedf->fp_array[i]); if (rc) { QEDF_WARN(&(qedf->dbg_ctx), "request_irq failed.\n"); @@ -2250,8 +2287,7 @@ static int qedf_request_msix_irq(struct qedf_ctx *qedf) } qedf->int_info.used_cnt++; - rc = irq_set_affinity_hint(qedf->int_info.msix[i].vector, - get_cpu_mask(cpu)); + rc = irq_set_affinity_hint(vector, get_cpu_mask(cpu)); cpu = cpumask_next(cpu, cpu_online_mask); } @@ -2328,12 +2364,14 @@ static void qedf_recv_frame(struct qedf_ctx *qedf, fr_dev(fp) = lport; fr_sof(fp) = hp->fcoe_sof; if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) { + QEDF_INFO(NULL, QEDF_LOG_LL2, "skb_copy_bits failed.\n"); kfree_skb(skb); return; } fr_eof(fp) = crc_eof.fcoe_eof; fr_crc(fp) = crc_eof.fcoe_crc32; if (pskb_trim(skb, fr_len)) { + QEDF_INFO(NULL, QEDF_LOG_LL2, "pskb_trim failed.\n"); kfree_skb(skb); return; } @@ -2394,9 +2432,9 @@ static void qedf_recv_frame(struct qedf_ctx *qedf, * empty then this is not addressed to our port so simply drop it. */ if (lport->port_id != ntoh24(fh->fh_d_id) && !vn_port) { - QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, - "Dropping frame due to destination mismatch: lport->port_id=%x fh->d_id=%x.\n", - lport->port_id, ntoh24(fh->fh_d_id)); + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2, + "Dropping frame due to destination mismatch: lport->port_id=0x%x fh->d_id=0x%x.\n", + lport->port_id, ntoh24(fh->fh_d_id)); kfree_skb(skb); return; } @@ -2405,6 +2443,8 @@ static void qedf_recv_frame(struct qedf_ctx *qedf, if ((fh->fh_type == FC_TYPE_BLS) && (f_ctl & FC_FC_SEQ_CTX) && (f_ctl & FC_FC_EX_CTX)) { /* Drop incoming ABTS response that has both SEQ/EX CTX set */ + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2, + "Dropping ABTS response as both SEQ/EX CTX set.\n"); kfree_skb(skb); return; } @@ -2548,8 +2588,9 @@ static int qedf_alloc_and_init_sb(struct qedf_ctx *qedf, sizeof(struct status_block_e4), &sb_phys, GFP_KERNEL); if (!sb_virt) { - QEDF_ERR(&(qedf->dbg_ctx), "Status block allocation failed " - "for id = %d.\n", sb_id); + QEDF_ERR(&qedf->dbg_ctx, + "Status block allocation failed for id = %d.\n", + sb_id); return -ENOMEM; } @@ -2557,8 +2598,9 @@ static int qedf_alloc_and_init_sb(struct qedf_ctx *qedf, sb_id, QED_SB_TYPE_STORAGE); if (ret) { - QEDF_ERR(&(qedf->dbg_ctx), "Status block initialization " - "failed for id = %d.\n", sb_id); + QEDF_ERR(&qedf->dbg_ctx, + "Status block initialization failed (0x%x) for id = %d.\n", + ret, sb_id); return ret; } @@ -2642,13 +2684,18 @@ void qedf_process_cqe(struct qedf_ctx *qedf, struct fcoe_cqe *cqe) io_req = &qedf->cmd_mgr->cmds[xid]; /* Completion not for a valid I/O anymore so just return */ - if (!io_req) + if (!io_req) { + QEDF_ERR(&qedf->dbg_ctx, + "io_req is NULL for xid=0x%x.\n", xid); return; + } fcport = io_req->fcport; if (fcport == NULL) { - QEDF_ERR(&(qedf->dbg_ctx), "fcport is NULL.\n"); + QEDF_ERR(&qedf->dbg_ctx, + "fcport is NULL for xid=0x%x io_req=%p.\n", + xid, io_req); return; } @@ -2657,7 +2704,8 @@ void qedf_process_cqe(struct qedf_ctx *qedf, struct fcoe_cqe *cqe) * isn't valid and shouldn't be taken. We should just return. */ if (!test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) { - QEDF_ERR(&(qedf->dbg_ctx), "Session not offloaded yet.\n"); + QEDF_ERR(&qedf->dbg_ctx, + "Session not offloaded yet, fcport = %p.\n", fcport); return; } @@ -2869,6 +2917,7 @@ static int qedf_alloc_global_queues(struct qedf_ctx *qedf) */ if (!qedf->p_cpuq) { status = 1; + QEDF_ERR(&qedf->dbg_ctx, "p_cpuq is NULL.\n"); goto mem_alloc_failure; } @@ -2884,8 +2933,10 @@ static int qedf_alloc_global_queues(struct qedf_ctx *qedf) /* Allocate DMA coherent buffers for BDQ */ rc = qedf_alloc_bdq(qedf); - if (rc) + if (rc) { + QEDF_ERR(&qedf->dbg_ctx, "Unable to allocate bdq.\n"); goto mem_alloc_failure; + } /* Allocate a CQ and an associated PBL for each MSI-X vector */ for (i = 0; i < qedf->num_queues; i++) { @@ -3095,6 +3146,7 @@ static struct pci_driver qedf_pci_driver = { .id_table = qedf_pci_tbl, .probe = qedf_probe, .remove = qedf_remove, + .shutdown = qedf_shutdown, }; static int __qedf_probe(struct pci_dev *pdev, int mode) @@ -3197,6 +3249,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) qed_params.is_vf = is_vf; qedf->cdev = qed_ops->common->probe(pdev, &qed_params); if (!qedf->cdev) { + QEDF_ERR(&qedf->dbg_ctx, "common probe failed.\n"); rc = -ENODEV; goto err1; } @@ -3208,6 +3261,11 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) goto err1; } + QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, + "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n", + qedf->dev_info.common.num_hwfns, + qed_ops->common->get_affin_hwfn_idx(qedf->cdev)); + /* queue allocation code should come here * order should be * slowpath_start @@ -3260,8 +3318,10 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) /* Setup interrupts */ rc = qedf_setup_int(qedf); - if (rc) + if (rc) { + QEDF_ERR(&qedf->dbg_ctx, "Setup interrupts failed.\n"); goto err3; + } rc = qed_ops->start(qedf->cdev, &qedf->tasks); if (rc) { @@ -3343,7 +3403,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) } memset(¶ms, 0, sizeof(params)); - params.mtu = 9000; + params.mtu = QEDF_LL2_BUF_SIZE; ether_addr_copy(params.ll2_mac_address, qedf->mac); /* Start LL2 processing thread */ @@ -3702,6 +3762,11 @@ void qedf_get_protocol_tlv_data(void *dev, void *data) fcoe->scsi_tsk_full = qedf->task_set_fulls; } +static void qedf_shutdown(struct pci_dev *pdev) +{ + __qedf_remove(pdev, QEDF_MODE_NORMAL); +} + /* Generic TLV data callback */ void qedf_get_generic_tlv_data(void *dev, struct qed_generic_tlvs *data) { @@ -3828,7 +3893,7 @@ static void __exit qedf_cleanup(void) } MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("QLogic QEDF 25/40/50/100Gb FCoE Driver"); +MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx FCoE Module"); MODULE_AUTHOR("QLogic Corporation"); MODULE_VERSION(QEDF_VERSION); module_init(qedf_init); diff --git a/drivers/scsi/qedf/qedf_version.h b/drivers/scsi/qedf/qedf_version.h index e57533de7e96..b0e37afe5bbb 100644 --- a/drivers/scsi/qedf/qedf_version.h +++ b/drivers/scsi/qedf/qedf_version.h @@ -4,9 +4,9 @@ * Copyright (c) 2016-2018 Cavium Inc. */ -#define QEDF_VERSION "8.37.25.20" +#define QEDF_VERSION "8.42.3.0" #define QEDF_DRIVER_MAJOR_VER 8 -#define QEDF_DRIVER_MINOR_VER 37 -#define QEDF_DRIVER_REV_VER 25 -#define QEDF_DRIVER_ENG_VER 20 +#define QEDF_DRIVER_MINOR_VER 42 +#define QEDF_DRIVER_REV_VER 3 +#define QEDF_DRIVER_ENG_VER 0 diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c index f210a3e0c9b1..acb930b8c6a6 100644 --- a/drivers/scsi/qedi/qedi_main.c +++ b/drivers/scsi/qedi/qedi_main.c @@ -1313,13 +1313,20 @@ static void qedi_simd_int_handler(void *cookie) static void qedi_sync_free_irqs(struct qedi_ctx *qedi) { int i; + u16 idx; if (qedi->int_info.msix_cnt) { for (i = 0; i < qedi->int_info.used_cnt; i++) { - synchronize_irq(qedi->int_info.msix[i].vector); - irq_set_affinity_hint(qedi->int_info.msix[i].vector, + idx = i * qedi->dev_info.common.num_hwfns + + qedi_ops->common->get_affin_hwfn_idx(qedi->cdev); + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "Freeing IRQ #%d vector_idx=%d.\n", i, idx); + + synchronize_irq(qedi->int_info.msix[idx].vector); + irq_set_affinity_hint(qedi->int_info.msix[idx].vector, NULL); - free_irq(qedi->int_info.msix[i].vector, + free_irq(qedi->int_info.msix[idx].vector, &qedi->fp_array[i]); } } else { @@ -1334,20 +1341,28 @@ static void qedi_sync_free_irqs(struct qedi_ctx *qedi) static int qedi_request_msix_irq(struct qedi_ctx *qedi) { int i, rc, cpu; + u16 idx; cpu = cpumask_first(cpu_online_mask); - for (i = 0; i < qedi->int_info.msix_cnt; i++) { - rc = request_irq(qedi->int_info.msix[i].vector, + for (i = 0; i < MIN_NUM_CPUS_MSIX(qedi); i++) { + idx = i * qedi->dev_info.common.num_hwfns + + qedi_ops->common->get_affin_hwfn_idx(qedi->cdev); + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n", + qedi->dev_info.common.num_hwfns, + qedi_ops->common->get_affin_hwfn_idx(qedi->cdev)); + + rc = request_irq(qedi->int_info.msix[idx].vector, qedi_msix_handler, 0, "qedi", &qedi->fp_array[i]); - if (rc) { QEDI_WARN(&qedi->dbg_ctx, "request_irq failed.\n"); qedi_sync_free_irqs(qedi); return rc; } qedi->int_info.used_cnt++; - rc = irq_set_affinity_hint(qedi->int_info.msix[i].vector, + rc = irq_set_affinity_hint(qedi->int_info.msix[idx].vector, get_cpu_mask(cpu)); cpu = cpumask_next(cpu, cpu_online_mask); } @@ -2415,6 +2430,11 @@ static int __qedi_probe(struct pci_dev *pdev, int mode) if (rc) goto free_host; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "dev_info: num_hwfns=%d affin_hwfn_idx=%d.\n", + qedi->dev_info.common.num_hwfns, + qedi_ops->common->get_affin_hwfn_idx(qedi->cdev)); + if (mode != QEDI_MODE_RECOVERY) { rc = qedi_set_iscsi_pf_param(qedi); if (rc) { diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index e5760c4a27f0..832af4213046 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -357,10 +357,6 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) -#include <asm/sn/io.h> -#endif - /* * Compile time Options: @@ -380,11 +376,6 @@ #define NVRAM_DELAY() udelay(500) /* 2 microseconds */ -#if defined(__ia64__) && !defined(ia64_platform_is) -#define ia64_platform_is(foo) (!strcmp(x, platform_name)) -#endif - - #define IS_ISP1040(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020) #define IS_ISP1x40(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020 || \ ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1240) @@ -1427,15 +1418,6 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha) ha->flags.reset_active = 0; ha->flags.abort_isp_active = 0; -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) - if (ia64_platform_is("sn2")) { - printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA " - "dual channel lockup workaround\n", ha->host_no); - ha->flags.use_pci_vchannel = 1; - driver_setup.no_nvram = 1; - } -#endif - /* TODO: implement support for the 1040 nvram format */ if (IS_ISP1040(ha)) driver_setup.no_nvram = 1; @@ -2251,13 +2233,6 @@ qla1280_nvram_config(struct scsi_qla_host *ha) mb[1] = nv->firmware_feature.f.enable_fast_posting; mb[1] |= nv->firmware_feature.f.report_lvd_bus_transition << 1; mb[1] |= nv->firmware_feature.f.disable_synchronous_backoff << 5; -#if defined(CONFIG_IA64_GENERIC) || defined (CONFIG_IA64_SGI_SN2) - if (ia64_platform_is("sn2")) { - printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA " - "workaround\n", ha->host_no); - mb[1] |= nv->firmware_feature.f.unused_9 << 9; /* XXX */ - } -#endif status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); /* Retry count and delay. */ @@ -2888,12 +2863,6 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) break; dma_handle = sg_dma_address(s); -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) - if (ha->flags.use_pci_vchannel) - sn_pci_set_vchan(ha->pdev, - (unsigned long *)&dma_handle, - SCSI_BUS_32(cmd)); -#endif *dword_ptr++ = cpu_to_le32(lower_32_bits(dma_handle)); *dword_ptr++ = @@ -2950,12 +2919,6 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) if (cnt == 5) break; dma_handle = sg_dma_address(s); -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) - if (ha->flags.use_pci_vchannel) - sn_pci_set_vchan(ha->pdev, - (unsigned long *)&dma_handle, - SCSI_BUS_32(cmd)); -#endif *dword_ptr++ = cpu_to_le32(lower_32_bits(dma_handle)); *dword_ptr++ = diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index b496206362a9..a1a8aefc7cc3 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -1055,9 +1055,6 @@ struct scsi_qla_host { uint32_t reset_active:1; /* 3 */ uint32_t abort_isp_active:1; /* 4 */ uint32_t disable_risc_code_load:1; /* 5 */ -#ifdef __ia64__ - uint32_t use_pci_vchannel:1; -#endif } flags; struct nvram nvram; diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 8d560c562e9c..7259bce85e0e 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -382,7 +382,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, ha->optrom_region_size = size; ha->optrom_state = QLA_SREADING; - ha->optrom_buffer = vmalloc(ha->optrom_region_size); + ha->optrom_buffer = vzalloc(ha->optrom_region_size); if (ha->optrom_buffer == NULL) { ql_log(ql_log_warn, vha, 0x7062, "Unable to allocate memory for optrom retrieval " @@ -404,7 +404,6 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, "Reading flash region -- 0x%x/0x%x.\n", ha->optrom_region_start, ha->optrom_region_size); - memset(ha->optrom_buffer, 0, ha->optrom_region_size); ha->isp_ops->read_optrom(vha, ha->optrom_buffer, ha->optrom_region_start, ha->optrom_region_size); break; @@ -441,9 +440,6 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, valid = 0; if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0) valid = 1; - else if (start == (ha->flt_region_boot * 4) || - start == (ha->flt_region_fw * 4)) - valid = 1; else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) valid = 1; if (!valid) { @@ -457,7 +453,7 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, ha->optrom_region_size = size; ha->optrom_state = QLA_SWRITING; - ha->optrom_buffer = vmalloc(ha->optrom_region_size); + ha->optrom_buffer = vzalloc(ha->optrom_region_size); if (ha->optrom_buffer == NULL) { ql_log(ql_log_warn, vha, 0x7066, "Unable to allocate memory for optrom update " @@ -472,7 +468,6 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, "Staging flash region write -- 0x%x/0x%x.\n", ha->optrom_region_start, ha->optrom_region_size); - memset(ha->optrom_buffer, 0, ha->optrom_region_size); break; case 3: if (ha->optrom_state != QLA_SWRITING) { @@ -491,8 +486,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, "Writing flash region -- 0x%x/0x%x.\n", ha->optrom_region_start, ha->optrom_region_size); - ha->isp_ops->write_optrom(vha, ha->optrom_buffer, + rval = ha->isp_ops->write_optrom(vha, ha->optrom_buffer, ha->optrom_region_start, ha->optrom_region_size); + if (rval) + rval = -EIO; break; default: rval = -EINVAL; @@ -726,7 +723,8 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj, break; } else { /* Make sure FC side is not in reset */ - qla2x00_wait_for_hba_online(vha); + WARN_ON_ONCE(qla2x00_wait_for_hba_online(vha) != + QLA_SUCCESS); /* Issue MPI reset */ scsi_block_requests(vha->host); @@ -1126,7 +1124,8 @@ qla2x00_pci_info_show(struct device *dev, struct device_attribute *attr, char pci_info[30]; return scnprintf(buf, PAGE_SIZE, "%s\n", - vha->hw->isp_ops->pci_info_str(vha, pci_info)); + vha->hw->isp_ops->pci_info_str(vha, pci_info, + sizeof(pci_info))); } static ssize_t @@ -2920,6 +2919,8 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) struct qla_hw_data *ha = vha->hw; uint16_t id = vha->vp_idx; + set_bit(VPORT_DELETE, &vha->dpc_flags); + while (test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags) || test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags)) msleep(1000); @@ -2956,6 +2957,8 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) dma_free_coherent(&ha->pdev->dev, vha->gnl.size, vha->gnl.l, vha->gnl.ldma); + vha->gnl.l = NULL; + vfree(vha->scan.l); if (vha->qpair && vha->qpair->vp_idx == vha->vp_idx) { diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 5441557b424b..99f0a1a08143 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -12,10 +12,8 @@ #include <linux/bsg-lib.h> /* BSG support for ELS/CT pass through */ -void -qla2x00_bsg_job_done(void *ptr, int res) +void qla2x00_bsg_job_done(srb_t *sp, int res) { - srb_t *sp = ptr; struct bsg_job *bsg_job = sp->u.bsg_job; struct fc_bsg_reply *bsg_reply = bsg_job->reply; @@ -25,10 +23,8 @@ qla2x00_bsg_job_done(void *ptr, int res) sp->free(sp); } -void -qla2x00_bsg_sp_free(void *ptr) +void qla2x00_bsg_sp_free(srb_t *sp) { - srb_t *sp = ptr; struct qla_hw_data *ha = sp->vha->hw; struct bsg_job *bsg_job = sp->u.bsg_job; struct fc_bsg_request *bsg_request = bsg_job->request; @@ -257,7 +253,7 @@ qla2x00_process_els(struct bsg_job *bsg_job) srb_t *sp; const char *type; int req_sg_cnt, rsp_sg_cnt; - int rval = (DRIVER_ERROR << 16); + int rval = (DID_ERROR << 16); uint16_t nextlid = 0; if (bsg_request->msgcode == FC_BSG_RPT_ELS) { @@ -341,6 +337,8 @@ qla2x00_process_els(struct bsg_job *bsg_job) dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); if (!req_sg_cnt) { + dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); rval = -ENOMEM; goto done_free_fcport; } @@ -348,6 +346,8 @@ qla2x00_process_els(struct bsg_job *bsg_job) rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); if (!rsp_sg_cnt) { + dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); rval = -ENOMEM; goto done_free_fcport; } @@ -432,7 +432,7 @@ qla2x00_process_ct(struct bsg_job *bsg_job) struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; - int rval = (DRIVER_ERROR << 16); + int rval = (DID_ERROR << 16); int req_sg_cnt, rsp_sg_cnt; uint16_t loop_id; struct fc_port *fcport; @@ -1778,8 +1778,8 @@ qla24xx_process_bidir_cmd(struct bsg_job *bsg_job) uint16_t nextlid = 0; uint32_t tot_dsds; srb_t *sp = NULL; - uint32_t req_data_len = 0; - uint32_t rsp_data_len = 0; + uint32_t req_data_len; + uint32_t rsp_data_len; /* Check the type of the adapter */ if (!IS_BIDI_CAPABLE(ha)) { @@ -1884,6 +1884,9 @@ qla24xx_process_bidir_cmd(struct bsg_job *bsg_job) goto done_unmap_sg; } + req_data_len = bsg_job->request_payload.payload_len; + rsp_data_len = bsg_job->reply_payload.payload_len; + if (req_data_len != rsp_data_len) { rval = EXT_STATUS_BUSY; ql_log(ql_log_warn, vha, 0x70aa, @@ -1891,10 +1894,6 @@ qla24xx_process_bidir_cmd(struct bsg_job *bsg_job) goto done_unmap_sg; } - req_data_len = bsg_job->request_payload.payload_len; - rsp_data_len = bsg_job->reply_payload.payload_len; - - /* Alloc SRB structure */ sp = qla2x00_get_sp(vha, &(vha->bidir_fcport), GFP_KERNEL); if (!sp) { @@ -1951,7 +1950,7 @@ qlafx00_mgmt_cmd(struct bsg_job *bsg_job) struct Scsi_Host *host = fc_bsg_to_shost(bsg_job); scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; - int rval = (DRIVER_ERROR << 16); + int rval = (DID_ERROR << 16); struct qla_mt_iocb_rqst_fx00 *piocb_rqst; srb_t *sp; int req_sg_cnt = 0, rsp_sg_cnt = 0; diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 9e80646722e2..30afc59c1870 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -2743,7 +2743,8 @@ ql_dump_regs(uint level, scsi_qla_host_t *vha, uint id) void -ql_dump_buffer(uint level, scsi_qla_host_t *vha, uint id, void *buf, uint size) +ql_dump_buffer(uint level, scsi_qla_host_t *vha, uint id, const void *buf, + uint size) { uint cnt; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 1a4095c56eee..6ffa9877c28b 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -34,6 +34,20 @@ #include <scsi/scsi_transport_fc.h> #include <scsi/scsi_bsg_fc.h> +/* Big endian Fibre Channel S_ID (source ID) or D_ID (destination ID). */ +typedef struct { + uint8_t domain; + uint8_t area; + uint8_t al_pa; +} be_id_t; + +/* Little endian Fibre Channel S_ID (source ID) or D_ID (destination ID). */ +typedef struct { + uint8_t al_pa; + uint8_t area; + uint8_t domain; +} le_id_t; + #include "qla_bsg.h" #include "qla_dsd.h" #include "qla_nx.h" @@ -117,9 +131,9 @@ #define RD_REG_BYTE_RELAXED(addr) readb_relaxed(addr) #define RD_REG_WORD_RELAXED(addr) readw_relaxed(addr) #define RD_REG_DWORD_RELAXED(addr) readl_relaxed(addr) -#define WRT_REG_BYTE(addr, data) writeb(data,addr) -#define WRT_REG_WORD(addr, data) writew(data,addr) -#define WRT_REG_DWORD(addr, data) writel(data,addr) +#define WRT_REG_BYTE(addr, data) writeb(data, addr) +#define WRT_REG_WORD(addr, data) writew(data, addr) +#define WRT_REG_DWORD(addr, data) writel(data, addr) /* * ISP83XX specific remote register addresses @@ -207,7 +221,7 @@ * 133Mhz slot. */ #define RD_REG_WORD_PIO(addr) (inw((unsigned long)addr)) -#define WRT_REG_WORD_PIO(addr, data) (outw(data,(unsigned long)addr)) +#define WRT_REG_WORD_PIO(addr, data) (outw(data, (unsigned long)addr)) /* * Fibre Channel device definitions. @@ -303,7 +317,8 @@ struct srb_cmd { uint32_t request_sense_length; uint32_t fw_sense_length; uint8_t *request_sense_ptr; - void *ctx; + struct ct6_dsd *ct6_ctx; + struct crc_context *crc_ctx; }; /* @@ -343,6 +358,51 @@ typedef union { } port_id_t; #define INVALID_PORT_ID 0xFFFFFF +static inline le_id_t be_id_to_le(be_id_t id) +{ + le_id_t res; + + res.domain = id.domain; + res.area = id.area; + res.al_pa = id.al_pa; + + return res; +} + +static inline be_id_t le_id_to_be(le_id_t id) +{ + be_id_t res; + + res.domain = id.domain; + res.area = id.area; + res.al_pa = id.al_pa; + + return res; +} + +static inline port_id_t be_to_port_id(be_id_t id) +{ + port_id_t res; + + res.b.domain = id.domain; + res.b.area = id.area; + res.b.al_pa = id.al_pa; + res.b.rsvd_1 = 0; + + return res; +} + +static inline be_id_t port_id_to_be_id(port_id_t port_id) +{ + be_id_t res; + + res.domain = port_id.b.domain; + res.area = port_id.b.area; + res.al_pa = port_id.b.al_pa; + + return res; +} + struct els_logo_payload { uint8_t opcode; uint8_t rsvd[3]; @@ -395,7 +455,7 @@ struct srb_iocb { struct els_logo_payload *els_logo_pyld; dma_addr_t els_logo_pyld_dma; } els_logo; - struct { + struct els_plogi { #define ELS_DCMD_PLOGI 0x3 uint32_t flags; uint32_t els_cmd; @@ -532,9 +592,12 @@ typedef struct srb { uint8_t cmd_type; uint8_t pad[3]; atomic_t ref_count; + struct kref cmd_kref; /* need to migrate ref_count over to this */ + void *priv; wait_queue_head_t nvme_ls_waitq; struct fc_port *fcport; struct scsi_qla_host *vha; + unsigned int start_timer:1; uint32_t handle; uint16_t flags; uint16_t type; @@ -552,13 +615,22 @@ typedef struct srb { struct bsg_job *bsg_job; struct srb_cmd scmd; } u; - void (*done)(void *, int); - void (*free)(void *); + /* + * Report completion status @res and call sp_put(@sp). @res is + * an NVMe status code, a SCSI result (e.g. DID_OK << 16) or a + * QLA_* status value. + */ + void (*done)(struct srb *sp, int res); + /* Stop the timer and free @sp. Only used by the FCP code. */ + void (*free)(struct srb *sp); + /* + * Call nvme_private->fd->done() and free @sp. Only used by the NVMe + * code. + */ + void (*put_fn)(struct kref *kref); } srb_t; #define GET_CMD_SP(sp) (sp->u.scmd.cmd) -#define SET_CMD_SP(sp, cmd) (sp->u.scmd.cmd = cmd) -#define GET_CMD_CTX_SP(sp) (sp->u.scmd.ctx) #define GET_CMD_SENSE_LEN(sp) \ (sp->u.scmd.request_sense_length) @@ -918,6 +990,11 @@ struct mbx_cmd_32 { #define MBS_LINK_DOWN_ERROR 0x400B #define MBS_DIAG_ECHO_TEST_ERROR 0x400C +static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) +{ + return MBS_COMMAND_COMPLETE <= mbs && mbs <= MBS_DIAG_ECHO_TEST_ERROR; +} + /* * ISP mailbox asynchronous event status codes */ @@ -1848,7 +1925,7 @@ struct crc_context { uint16_t reserved_2; uint16_t reserved_3; uint32_t reserved_4; - struct dsd64 data_dsd; + struct dsd64 data_dsd[1]; uint32_t reserved_5[2]; uint32_t reserved_6; } nobundling; @@ -1858,7 +1935,7 @@ struct crc_context { uint16_t reserved_1; __le16 dseg_count; /* Data segment count */ uint32_t reserved_2; - struct dsd64 data_dsd; + struct dsd64 data_dsd[1]; struct dsd64 dif_dsd; } bundling; } u; @@ -2286,22 +2363,6 @@ enum login_state { /* FW control Target side */ DSC_LS_LOGO_PEND, }; -enum fcport_mgt_event { - FCME_RELOGIN = 1, - FCME_RSCN, - FCME_PLOGI_DONE, /* Initiator side sent LLIOCB */ - FCME_PRLI_DONE, - FCME_GNL_DONE, - FCME_GPSC_DONE, - FCME_GPDB_DONE, - FCME_GPNID_DONE, - FCME_GFFID_DONE, - FCME_ADISC_DONE, - FCME_GNNID_DONE, - FCME_GFPNID_DONE, - FCME_ELS_PLOGI_DONE, -}; - enum rscn_addr_format { RSCN_PORT_ADDR, RSCN_AREA_ADDR, @@ -2335,8 +2396,8 @@ typedef struct fc_port { unsigned int query:1; unsigned int id_changed:1; unsigned int scan_needed:1; + unsigned int n2n_flag:1; - struct work_struct nvme_del_work; struct completion nvme_del_done; uint32_t nvme_prli_service_param; #define NVME_PRLI_SP_CONF BIT_7 @@ -2386,7 +2447,6 @@ typedef struct fc_port { uint8_t fc4_type; uint8_t fc4f_nvme; uint8_t scan_state; - uint8_t n2n_flag; unsigned long last_queue_full; unsigned long last_ramp_up; @@ -2420,7 +2480,6 @@ typedef struct fc_port { #define QLA_FCPORT_FOUND 2 struct event_arg { - enum fcport_mgt_event event; fc_port_t *fcport; srb_t *sp; port_id_t id; @@ -2743,7 +2802,7 @@ struct ct_sns_req { /* GA_NXT, GPN_ID, GNN_ID, GFT_ID, GFPN_ID */ struct { uint8_t reserved; - uint8_t port_id[3]; + be_id_t port_id; } port_id; struct { @@ -2762,13 +2821,13 @@ struct ct_sns_req { struct { uint8_t reserved; - uint8_t port_id[3]; + be_id_t port_id; uint8_t fc4_types[32]; } rft_id; struct { uint8_t reserved; - uint8_t port_id[3]; + be_id_t port_id; uint16_t reserved2; uint8_t fc4_feature; uint8_t fc4_type; @@ -2776,7 +2835,7 @@ struct ct_sns_req { struct { uint8_t reserved; - uint8_t port_id[3]; + be_id_t port_id; uint8_t node_name[8]; } rnn_id; @@ -2863,7 +2922,7 @@ struct ct_rsp_hdr { struct ct_sns_gid_pt_data { uint8_t control_byte; - uint8_t port_id[3]; + be_id_t port_id; }; /* It's the same for both GPN_FT and GNN_FT */ @@ -2893,7 +2952,7 @@ struct ct_sns_rsp { union { struct { uint8_t port_type; - uint8_t port_id[3]; + be_id_t port_id; uint8_t port_name[8]; uint8_t sym_port_name_len; uint8_t sym_port_name[255]; @@ -2977,6 +3036,7 @@ enum scan_flags_t { enum fc4type_t { FS_FC4TYPE_FCP = BIT_0, FS_FC4TYPE_NVME = BIT_1, + FS_FCP_IS_N2N = BIT_7, }; struct fab_scan_rp { @@ -3109,7 +3169,7 @@ struct isp_operations { void (*update_fw_options) (struct scsi_qla_host *); int (*load_risc) (struct scsi_qla_host *, uint32_t *); - char * (*pci_info_str) (struct scsi_qla_host *, char *); + char * (*pci_info_str)(struct scsi_qla_host *, char *, size_t); char * (*fw_version_str)(struct scsi_qla_host *, char *, size_t); irq_handler_t intr_handler; @@ -3848,7 +3908,7 @@ struct qla_hw_data { /* NVRAM configuration data */ #define MAX_NVRAM_SIZE 4096 -#define VPD_OFFSET MAX_NVRAM_SIZE / 2 +#define VPD_OFFSET (MAX_NVRAM_SIZE / 2) uint16_t nvram_size; uint16_t nvram_base; void *nvram; @@ -4335,6 +4395,7 @@ typedef struct scsi_qla_host { #define IOCB_WORK_ACTIVE 31 #define SET_ZIO_THRESHOLD_NEEDED 32 #define ISP_ABORT_TO_ROM 33 +#define VPORT_DELETE 34 unsigned long pci_flags; #define PFLG_DISCONNECTED 0 /* PCI device removed */ @@ -4376,7 +4437,6 @@ typedef struct scsi_qla_host { struct nvme_fc_local_port *nvme_local_port; struct completion nvme_del_done; - struct list_head nvme_rport_list; uint16_t fcoe_vlan_id; uint16_t fcoe_fcf_idx; @@ -4627,6 +4687,7 @@ struct secure_flash_update_block_pk { #define QLA_SUSPENDED 0x106 #define QLA_BUSY 0x107 #define QLA_ALREADY_REGISTERED 0x109 +#define QLA_OS_TIMER_EXPIRED 0x10a #define NVRAM_DELAY() udelay(10) diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index a432caebefec..0a6fb359f4d5 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -57,10 +57,9 @@ qla2x00_dfs_tgt_port_database_show(struct seq_file *s, void *unused) { scsi_qla_host_t *vha = s->private; struct qla_hw_data *ha = vha->hw; - struct gid_list_info *gid_list; + struct gid_list_info *gid_list, *gid; dma_addr_t gid_list_dma; fc_port_t fc_port; - char *id_iter; int rc, i; uint16_t entries, loop_id; struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; @@ -82,13 +81,11 @@ qla2x00_dfs_tgt_port_database_show(struct seq_file *s, void *unused) if (rc != QLA_SUCCESS) goto out_free_id_list; - id_iter = (char *)gid_list; + gid = gid_list; seq_puts(s, "Port Name Port ID Loop ID\n"); for (i = 0; i < entries; i++) { - struct gid_list_info *gid = - (struct gid_list_info *)id_iter; loop_id = le16_to_cpu(gid->loop_id); memset(&fc_port, 0, sizeof(fc_port_t)); @@ -99,7 +96,7 @@ qla2x00_dfs_tgt_port_database_show(struct seq_file *s, void *unused) fc_port.port_name, fc_port.d_id.b.domain, fc_port.d_id.b.area, fc_port.d_id.b.al_pa, fc_port.loop_id); - id_iter += ha->gid_list_info_size; + gid = (void *)gid + ha->gid_list_info_size; } out_free_id_list: dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), diff --git a/drivers/scsi/qla2xxx/qla_dsd.h b/drivers/scsi/qla2xxx/qla_dsd.h index 7479924ba422..20788054b91b 100644 --- a/drivers/scsi/qla2xxx/qla_dsd.h +++ b/drivers/scsi/qla2xxx/qla_dsd.h @@ -1,6 +1,8 @@ #ifndef _QLA_DSD_H_ #define _QLA_DSD_H_ +#include <asm/unaligned.h> + /* 32-bit data segment descriptor (8 bytes) */ struct dsd32 { __le32 address; diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index df079a8c2b33..732bb871c433 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -761,13 +761,13 @@ struct els_entry_24xx { #define ECF_CLR_PASSTHRU_PEND BIT_12 #define ECF_INCL_FRAME_HDR BIT_11 - uint32_t rx_byte_count; - uint32_t tx_byte_count; + __le32 rx_byte_count; + __le32 tx_byte_count; __le64 tx_address __packed; /* Data segment 0 address. */ - uint32_t tx_len; /* Data segment 0 length. */ + __le32 tx_len; /* Data segment 0 length. */ __le64 rx_address __packed; /* Data segment 1 address. */ - uint32_t rx_len; /* Data segment 1 length. */ + __le32 rx_len; /* Data segment 1 length. */ }; struct els_sts_entry_24xx { diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index bbe69ab5cf3f..d11416dcee4e 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -45,6 +45,8 @@ extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *); extern int qla24xx_els_dcmd_iocb(scsi_qla_host_t *, int, port_id_t); extern int qla24xx_els_dcmd2_iocb(scsi_qla_host_t *, int, fc_port_t *, bool); +extern void qla2x00_els_dcmd2_free(scsi_qla_host_t *vha, + struct els_plogi *els_plogi); extern void qla2x00_update_fcports(scsi_qla_host_t *); @@ -96,7 +98,11 @@ extern int qla2x00_init_rings(scsi_qla_host_t *); extern struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *, int, int, bool); extern int qla2xxx_delete_qpair(struct scsi_qla_host *, struct qla_qpair *); -void qla2x00_fcport_event_handler(scsi_qla_host_t *, struct event_arg *); +void qla2x00_handle_rscn(scsi_qla_host_t *vha, struct event_arg *ea); +void qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, + struct event_arg *ea); +void qla24xx_handle_relogin_event(scsi_qla_host_t *vha, + struct event_arg *ea); int qla24xx_async_gpdb(struct scsi_qla_host *, fc_port_t *, u8); int qla24xx_async_prli(struct scsi_qla_host *, fc_port_t *); int qla24xx_async_notify_ack(scsi_qla_host_t *, fc_port_t *, @@ -213,9 +219,9 @@ extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32); extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32); extern void qla2x00_disable_board_on_pci_error(struct work_struct *); -extern void qla2x00_sp_compl(void *, int); -extern void qla2xxx_qpair_sp_free_dma(void *); -extern void qla2xxx_qpair_sp_compl(void *, int); +extern void qla2x00_sp_compl(srb_t *sp, int); +extern void qla2xxx_qpair_sp_free_dma(srb_t *sp); +extern void qla2xxx_qpair_sp_compl(srb_t *sp, int); extern void qla24xx_sched_upd_fcport(fc_port_t *); void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *, uint16_t *); @@ -244,7 +250,7 @@ extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *); extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *); extern scsi_qla_host_t *qla24xx_create_vhost(struct fc_vport *); -extern void qla2x00_sp_free_dma(void *); +extern void qla2x00_sp_free_dma(srb_t *sp); extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *); extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int); @@ -272,6 +278,7 @@ extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t); extern void qla2x00_build_scsi_iocbs_64(srb_t *, cmd_entry_t *, uint16_t); extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t, struct req_que *); +extern uint32_t qla2xxx_get_next_handle(struct req_que *req); extern int qla2x00_start_scsi(srb_t *sp); extern int qla24xx_start_scsi(srb_t *sp); int qla2x00_marker(struct scsi_qla_host *, struct qla_qpair *, @@ -554,7 +561,7 @@ fc_port_t *qla2x00_find_fcport_by_nportid(scsi_qla_host_t *, port_id_t *, u8); * Global Function Prototypes in qla_sup.c source file. */ extern void qla2x00_release_nvram_protection(scsi_qla_host_t *); -extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *, +extern int qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *, uint32_t, uint32_t); extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, void *, uint32_t, uint32_t); @@ -630,7 +637,7 @@ extern ulong qla27xx_fwdt_template_size(void *); extern void qla2xxx_dump_post_process(scsi_qla_host_t *, int); extern void ql_dump_regs(uint, scsi_qla_host_t *, uint); -extern void ql_dump_buffer(uint, scsi_qla_host_t *, uint, void *, uint); +extern void ql_dump_buffer(uint, scsi_qla_host_t *, uint, const void *, uint); /* * Global Function Prototypes in qla_gs.c source file. */ @@ -732,7 +739,7 @@ extern int qlafx00_initialize_adapter(struct scsi_qla_host *); extern int qlafx00_soft_reset(scsi_qla_host_t *); extern int qlafx00_chip_diag(scsi_qla_host_t *); extern void qlafx00_config_rings(struct scsi_qla_host *); -extern char *qlafx00_pci_info_str(struct scsi_qla_host *, char *); +extern char *qlafx00_pci_info_str(struct scsi_qla_host *, char *, size_t); extern char *qlafx00_fw_version_str(struct scsi_qla_host *, char *, size_t); extern irqreturn_t qlafx00_intr_handler(int, void *); extern void qlafx00_enable_intrs(struct qla_hw_data *); @@ -790,10 +797,10 @@ extern int qla82xx_restart_isp(scsi_qla_host_t *); /* IOCB related functions */ extern int qla82xx_start_scsi(srb_t *); -extern void qla2x00_sp_free(void *); +extern void qla2x00_sp_free(srb_t *sp); extern void qla2x00_sp_timeout(struct timer_list *); -extern void qla2x00_bsg_job_done(void *, int); -extern void qla2x00_bsg_sp_free(void *); +extern void qla2x00_bsg_job_done(srb_t *sp, int); +extern void qla2x00_bsg_sp_free(srb_t *sp); extern void qla2x00_start_iocbs(struct scsi_qla_host *, struct req_que *); /* Interrupt related */ @@ -822,8 +829,8 @@ extern int qla82xx_device_state_handler(scsi_qla_host_t *); extern void qla8xxx_dev_failed_handler(scsi_qla_host_t *); extern void qla82xx_clear_qsnt_ready(scsi_qla_host_t *); -extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *, - size_t, char *); +extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *, size_t, + const char *); extern int qla82xx_mbx_intr_enable(scsi_qla_host_t *); extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *); extern void qla82xx_start_iocbs(scsi_qla_host_t *); @@ -908,4 +915,6 @@ void qlt_clr_qp_table(struct scsi_qla_host *vha); void qlt_set_mode(struct scsi_qla_host *); int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode); +/* nvme.c */ +void qla_nvme_unregister_remote_port(struct fc_port *fcport); #endif /* _QLA_GBL_H */ diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 9f58e591666d..5298ed10059f 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -226,9 +226,7 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport) ct_rsp = &ha->ct_sns->p.rsp; /* Prepare CT arguments -- port_id */ - ct_req->req.port_id.port_id[0] = fcport->d_id.b.domain; - ct_req->req.port_id.port_id[1] = fcport->d_id.b.area; - ct_req->req.port_id.port_id[2] = fcport->d_id.b.al_pa; + ct_req->req.port_id.port_id = port_id_to_be_id(fcport->d_id); /* Execute MS IOCB */ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, @@ -242,9 +240,7 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport) rval = QLA_FUNCTION_FAILED; } else { /* Populate fc_port_t entry. */ - fcport->d_id.b.domain = ct_rsp->rsp.ga_nxt.port_id[0]; - fcport->d_id.b.area = ct_rsp->rsp.ga_nxt.port_id[1]; - fcport->d_id.b.al_pa = ct_rsp->rsp.ga_nxt.port_id[2]; + fcport->d_id = be_to_port_id(ct_rsp->rsp.ga_nxt.port_id); memcpy(fcport->node_name, ct_rsp->rsp.ga_nxt.node_name, WWN_SIZE); @@ -337,9 +333,7 @@ qla2x00_gid_pt(scsi_qla_host_t *vha, sw_info_t *list) /* Set port IDs in switch info list. */ for (i = 0; i < ha->max_fibre_devices; i++) { gid_data = &ct_rsp->rsp.gid_pt.entries[i]; - list[i].d_id.b.domain = gid_data->port_id[0]; - list[i].d_id.b.area = gid_data->port_id[1]; - list[i].d_id.b.al_pa = gid_data->port_id[2]; + list[i].d_id = be_to_port_id(gid_data->port_id); memset(list[i].fabric_port_name, 0, WWN_SIZE); list[i].fp_speed = PORT_SPEED_UNKNOWN; @@ -403,9 +397,7 @@ qla2x00_gpn_id(scsi_qla_host_t *vha, sw_info_t *list) ct_rsp = &ha->ct_sns->p.rsp; /* Prepare CT arguments -- port_id */ - ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; - ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; - ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; + ct_req->req.port_id.port_id = port_id_to_be_id(list[i].d_id); /* Execute MS IOCB */ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, @@ -472,9 +464,7 @@ qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list) ct_rsp = &ha->ct_sns->p.rsp; /* Prepare CT arguments -- port_id */ - ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; - ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; - ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; + ct_req->req.port_id.port_id = port_id_to_be_id(list[i].d_id); /* Execute MS IOCB */ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, @@ -509,9 +499,8 @@ qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list) return (rval); } -static void qla2x00_async_sns_sp_done(void *s, int rc) +static void qla2x00_async_sns_sp_done(srb_t *sp, int rc) { - struct srb *sp = s; struct scsi_qla_host *vha = sp->vha; struct ct_sns_pkt *ct_sns; struct qla_work_evt *e; @@ -639,9 +628,7 @@ static int qla_async_rftid(scsi_qla_host_t *vha, port_id_t *d_id) ct_req = qla2x00_prep_ct_req(ct_sns, RFT_ID_CMD, RFT_ID_RSP_SIZE); /* Prepare CT arguments -- port_id, FC-4 types */ - ct_req->req.rft_id.port_id[0] = vha->d_id.b.domain; - ct_req->req.rft_id.port_id[1] = vha->d_id.b.area; - ct_req->req.rft_id.port_id[2] = vha->d_id.b.al_pa; + ct_req->req.rft_id.port_id = port_id_to_be_id(vha->d_id); ct_req->req.rft_id.fc4_types[2] = 0x01; /* FCP-3 */ if (vha->flags.nvme_enabled) @@ -737,9 +724,7 @@ static int qla_async_rffid(scsi_qla_host_t *vha, port_id_t *d_id, ct_req = qla2x00_prep_ct_req(ct_sns, RFF_ID_CMD, RFF_ID_RSP_SIZE); /* Prepare CT arguments -- port_id, FC-4 feature, FC-4 type */ - ct_req->req.rff_id.port_id[0] = d_id->b.domain; - ct_req->req.rff_id.port_id[1] = d_id->b.area; - ct_req->req.rff_id.port_id[2] = d_id->b.al_pa; + ct_req->req.rff_id.port_id = port_id_to_be_id(*d_id); ct_req->req.rff_id.fc4_feature = fc4feature; ct_req->req.rff_id.fc4_type = fc4type; /* SCSI - FCP */ @@ -830,9 +815,7 @@ static int qla_async_rnnid(scsi_qla_host_t *vha, port_id_t *d_id, ct_req = qla2x00_prep_ct_req(ct_sns, RNN_ID_CMD, RNN_ID_RSP_SIZE); /* Prepare CT arguments -- port_id, node_name */ - ct_req->req.rnn_id.port_id[0] = vha->d_id.b.domain; - ct_req->req.rnn_id.port_id[1] = vha->d_id.b.area; - ct_req->req.rnn_id.port_id[2] = vha->d_id.b.al_pa; + ct_req->req.rnn_id.port_id = port_id_to_be_id(vha->d_id); memcpy(ct_req->req.rnn_id.node_name, vha->node_name, WWN_SIZE); sp->u.iocb_cmd.u.ctarg.req_size = RNN_ID_REQ_SIZE; @@ -1479,7 +1462,7 @@ qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size, return ct_pkt; } -static inline ms_iocb_entry_t * +static void qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size) { struct qla_hw_data *ha = vha->hw; @@ -1493,8 +1476,6 @@ qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size) ms_pkt->req_bytecount = cpu_to_le32(req_size); ms_pkt->req_dsd.length = ms_pkt->req_bytecount; } - - return ms_pkt; } /** @@ -1557,7 +1538,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) /* Attributes */ ct_req->req.rhba.attrs.count = cpu_to_be32(FDMI_HBA_ATTR_COUNT); - entries = ct_req->req.rhba.hba_identifier; + entries = &ct_req->req; /* Nodename. */ eiter = entries + size; @@ -1766,7 +1747,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha) /* Attributes */ ct_req->req.rpa.attrs.count = cpu_to_be32(FDMI_PORT_ATTR_COUNT); - entries = ct_req->req.rpa.port_name; + entries = &ct_req->req; /* FC4 types. */ eiter = entries + size; @@ -1979,7 +1960,7 @@ qla2x00_fdmiv2_rhba(scsi_qla_host_t *vha) /* Attributes */ ct_req->req.rhba2.attrs.count = cpu_to_be32(FDMIV2_HBA_ATTR_COUNT); - entries = ct_req->req.rhba2.hba_identifier; + entries = &ct_req->req; /* Nodename. */ eiter = entries + size; @@ -2338,7 +2319,7 @@ qla2x00_fdmiv2_rpa(scsi_qla_host_t *vha) /* Attributes */ ct_req->req.rpa2.attrs.count = cpu_to_be32(FDMIV2_PORT_ATTR_COUNT); - entries = ct_req->req.rpa2.port_name; + entries = &ct_req->req; /* FC4 types. */ eiter = entries + size; @@ -2730,9 +2711,7 @@ qla2x00_gfpn_id(scsi_qla_host_t *vha, sw_info_t *list) ct_rsp = &ha->ct_sns->p.rsp; /* Prepare CT arguments -- port_id */ - ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; - ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; - ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; + ct_req->req.port_id.port_id = port_id_to_be_id(list[i].d_id); /* Execute MS IOCB */ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, @@ -2936,9 +2915,7 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list) ct_rsp = &ha->ct_sns->p.rsp; /* Prepare CT arguments -- port_id */ - ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; - ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; - ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; + ct_req->req.port_id.port_id = port_id_to_be_id(list[i].d_id); /* Execute MS IOCB */ rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, @@ -3011,9 +2988,8 @@ void qla24xx_handle_gpsc_event(scsi_qla_host_t *vha, struct event_arg *ea) qla_post_iidma_work(vha, fcport); } -static void qla24xx_async_gpsc_sp_done(void *s, int res) +static void qla24xx_async_gpsc_sp_done(srb_t *sp, int res) { - struct srb *sp = s; struct scsi_qla_host *vha = sp->vha; struct qla_hw_data *ha = vha->hw; fc_port_t *fcport = sp->fcport; @@ -3055,11 +3031,10 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res) be16_to_cpu(ct_rsp->rsp.gpsc.speed)); } memset(&ea, 0, sizeof(ea)); - ea.event = FCME_GPSC_DONE; ea.rc = res; ea.fcport = fcport; ea.sp = sp; - qla2x00_fcport_event_handler(vha, &ea); + qla24xx_handle_gpsc_event(vha, &ea); done: sp->free(sp); @@ -3127,7 +3102,8 @@ int qla24xx_post_gpnid_work(struct scsi_qla_host *vha, port_id_t *id) { struct qla_work_evt *e; - if (test_bit(UNLOADING, &vha->dpc_flags)) + if (test_bit(UNLOADING, &vha->dpc_flags) || + (vha->vp_idx && test_bit(VPORT_DELETE, &vha->dpc_flags))) return 0; e = qla2x00_alloc_work(vha, QLA_EVT_GPNID); @@ -3144,17 +3120,7 @@ void qla24xx_sp_unmap(scsi_qla_host_t *vha, srb_t *sp) switch (sp->type) { case SRB_ELS_DCMD: - if (c->u.els_plogi.els_plogi_pyld) - dma_free_coherent(&vha->hw->pdev->dev, - c->u.els_plogi.tx_size, - c->u.els_plogi.els_plogi_pyld, - c->u.els_plogi.els_plogi_pyld_dma); - - if (c->u.els_plogi.els_resp_pyld) - dma_free_coherent(&vha->hw->pdev->dev, - c->u.els_plogi.rx_size, - c->u.els_plogi.els_resp_pyld, - c->u.els_plogi.els_resp_pyld_dma); + qla2x00_els_dcmd2_free(vha, &c->u.els_plogi); break; case SRB_CT_PTHRU_CMD: default: @@ -3280,9 +3246,8 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) } } -static void qla2x00_async_gpnid_sp_done(void *s, int res) +static void qla2x00_async_gpnid_sp_done(srb_t *sp, int res) { - struct srb *sp = s; struct scsi_qla_host *vha = sp->vha; struct ct_sns_req *ct_req = (struct ct_sns_req *)sp->u.iocb_cmd.u.ctarg.req; @@ -3295,22 +3260,19 @@ static void qla2x00_async_gpnid_sp_done(void *s, int res) if (res) ql_dbg(ql_dbg_disc, vha, 0x2066, "Async done-%s fail res %x rscn gen %d ID %3phC. %8phC\n", - sp->name, res, sp->gen1, ct_req->req.port_id.port_id, + sp->name, res, sp->gen1, &ct_req->req.port_id.port_id, ct_rsp->rsp.gpn_id.port_name); else ql_dbg(ql_dbg_disc, vha, 0x2066, "Async done-%s good rscn gen %d ID %3phC. %8phC\n", - sp->name, sp->gen1, ct_req->req.port_id.port_id, + sp->name, sp->gen1, &ct_req->req.port_id.port_id, ct_rsp->rsp.gpn_id.port_name); memset(&ea, 0, sizeof(ea)); memcpy(ea.port_name, ct_rsp->rsp.gpn_id.port_name, WWN_SIZE); ea.sp = sp; - ea.id.b.domain = ct_req->req.port_id.port_id[0]; - ea.id.b.area = ct_req->req.port_id.port_id[1]; - ea.id.b.al_pa = ct_req->req.port_id.port_id[2]; + ea.id = be_to_port_id(ct_req->req.port_id.port_id); ea.rc = res; - ea.event = FCME_GPNID_DONE; spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); list_del(&sp->elem); @@ -3329,25 +3291,22 @@ static void qla2x00_async_gpnid_sp_done(void *s, int res) return; } - qla2x00_fcport_event_handler(vha, &ea); + qla24xx_handle_gpnid_event(vha, &ea); e = qla2x00_alloc_work(vha, QLA_EVT_UNMAP); if (!e) { /* please ignore kernel warning. otherwise, we have mem leak. */ - if (sp->u.iocb_cmd.u.ctarg.req) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.req_allocated_size, - sp->u.iocb_cmd.u.ctarg.req, - sp->u.iocb_cmd.u.ctarg.req_dma); - sp->u.iocb_cmd.u.ctarg.req = NULL; - } - if (sp->u.iocb_cmd.u.ctarg.rsp) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, - sp->u.iocb_cmd.u.ctarg.rsp, - sp->u.iocb_cmd.u.ctarg.rsp_dma); - sp->u.iocb_cmd.u.ctarg.rsp = NULL; - } + dma_free_coherent(&vha->hw->pdev->dev, + sp->u.iocb_cmd.u.ctarg.req_allocated_size, + sp->u.iocb_cmd.u.ctarg.req, + sp->u.iocb_cmd.u.ctarg.req_dma); + sp->u.iocb_cmd.u.ctarg.req = NULL; + + dma_free_coherent(&vha->hw->pdev->dev, + sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, + sp->u.iocb_cmd.u.ctarg.rsp, + sp->u.iocb_cmd.u.ctarg.rsp_dma); + sp->u.iocb_cmd.u.ctarg.rsp = NULL; sp->free(sp); return; @@ -3419,9 +3378,7 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id) ct_req = qla2x00_prep_ct_req(ct_sns, GPN_ID_CMD, GPN_ID_RSP_SIZE); /* GPN_ID req */ - ct_req->req.port_id.port_id[0] = id->b.domain; - ct_req->req.port_id.port_id[1] = id->b.area; - ct_req->req.port_id.port_id[2] = id->b.al_pa; + ct_req->req.port_id.port_id = port_id_to_be_id(*id); sp->u.iocb_cmd.u.ctarg.req_size = GPN_ID_REQ_SIZE; sp->u.iocb_cmd.u.ctarg.rsp_size = GPN_ID_RSP_SIZE; @@ -3432,7 +3389,7 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id) ql_dbg(ql_dbg_disc, vha, 0x2067, "Async-%s hdl=%x ID %3phC.\n", sp->name, - sp->handle, ct_req->req.port_id.port_id); + sp->handle, &ct_req->req.port_id.port_id); rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) @@ -3467,54 +3424,52 @@ done: void qla24xx_handle_gffid_event(scsi_qla_host_t *vha, struct event_arg *ea) { - fc_port_t *fcport = ea->fcport; + fc_port_t *fcport = ea->fcport; - qla24xx_post_gnl_work(vha, fcport); + qla24xx_post_gnl_work(vha, fcport); } -void qla24xx_async_gffid_sp_done(void *s, int res) +void qla24xx_async_gffid_sp_done(srb_t *sp, int res) { - struct srb *sp = s; - struct scsi_qla_host *vha = sp->vha; - fc_port_t *fcport = sp->fcport; - struct ct_sns_rsp *ct_rsp; - struct event_arg ea; - - ql_dbg(ql_dbg_disc, vha, 0x2133, - "Async done-%s res %x ID %x. %8phC\n", - sp->name, res, fcport->d_id.b24, fcport->port_name); - - fcport->flags &= ~FCF_ASYNC_SENT; - ct_rsp = &fcport->ct_desc.ct_sns->p.rsp; - /* - * FC-GS-7, 5.2.3.12 FC-4 Features - format - * The format of the FC-4 Features object, as defined by the FC-4, - * Shall be an array of 4-bit values, one for each type code value - */ - if (!res) { - if (ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET] & 0xf) { - /* w1 b00:03 */ - fcport->fc4_type = - ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET]; - fcport->fc4_type &= 0xf; - } + struct scsi_qla_host *vha = sp->vha; + fc_port_t *fcport = sp->fcport; + struct ct_sns_rsp *ct_rsp; + struct event_arg ea; - if (ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET] & 0xf) { - /* w5 [00:03]/28h */ - fcport->fc4f_nvme = - ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET]; - fcport->fc4f_nvme &= 0xf; + ql_dbg(ql_dbg_disc, vha, 0x2133, + "Async done-%s res %x ID %x. %8phC\n", + sp->name, res, fcport->d_id.b24, fcport->port_name); + + fcport->flags &= ~FCF_ASYNC_SENT; + ct_rsp = &fcport->ct_desc.ct_sns->p.rsp; + /* + * FC-GS-7, 5.2.3.12 FC-4 Features - format + * The format of the FC-4 Features object, as defined by the FC-4, + * Shall be an array of 4-bit values, one for each type code value + */ + if (!res) { + if (ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET] & 0xf) { + /* w1 b00:03 */ + fcport->fc4_type = + ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET]; + fcport->fc4_type &= 0xf; } - } - memset(&ea, 0, sizeof(ea)); - ea.sp = sp; - ea.fcport = sp->fcport; - ea.rc = res; - ea.event = FCME_GFFID_DONE; + if (ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET] & 0xf) { + /* w5 [00:03]/28h */ + fcport->fc4f_nvme = + ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET]; + fcport->fc4f_nvme &= 0xf; + } + } + + memset(&ea, 0, sizeof(ea)); + ea.sp = sp; + ea.fcport = sp->fcport; + ea.rc = res; - qla2x00_fcport_event_handler(vha, &ea); - sp->free(sp); + qla24xx_handle_gffid_event(vha, &ea); + sp->free(sp); } /* Get FC4 Feature with Nport ID. */ @@ -3674,7 +3629,6 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) list_for_each_entry(fcport, &vha->vp_fcports, list) { if (memcmp(rp->port_name, fcport->port_name, WWN_SIZE)) continue; - fcport->scan_needed = 0; fcport->scan_state = QLA_FCPORT_FOUND; found = true; /* @@ -3683,10 +3637,12 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) { qla2x00_clear_loop_id(fcport); fcport->flags |= FCF_FABRIC_DEVICE; - } else if (fcport->d_id.b24 != rp->id.b24) { + } else if (fcport->d_id.b24 != rp->id.b24 || + fcport->scan_needed) { qlt_schedule_sess_for_deletion(fcport); } fcport->d_id.b24 = rp->id.b24; + fcport->scan_needed = 0; break; } @@ -3898,9 +3854,8 @@ static void qla2x00_find_free_fcp_nvme_slot(struct scsi_qla_host *vha, } } -static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) +static void qla2x00_async_gpnft_gnnft_sp_done(srb_t *sp, int res) { - struct srb *sp = s; struct scsi_qla_host *vha = sp->vha; struct ct_sns_req *ct_req = (struct ct_sns_req *)sp->u.iocb_cmd.u.ctarg.req; @@ -4053,9 +4008,6 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp, rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { - spin_lock_irqsave(&vha->work_lock, flags); - vha->scan.scan_flags &= ~SF_SCANNING; - spin_unlock_irqrestore(&vha->work_lock, flags); goto done_free_sp; } @@ -4079,6 +4031,17 @@ done_free_sp: sp->free(sp); + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_flags &= ~SF_SCANNING; + if (vha->scan.scan_flags == 0) { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s: schedule\n", __func__); + vha->scan.scan_flags |= SF_QUEUED; + schedule_delayed_work(&vha->scan.scan_work, 5); + } + spin_unlock_irqrestore(&vha->work_lock, flags); + + return rval; } /* GNNFT */ @@ -4152,7 +4115,7 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) rspsz, &sp->u.iocb_cmd.u.ctarg.rsp_dma, GFP_KERNEL); - sp->u.iocb_cmd.u.ctarg.rsp_allocated_size = sizeof(struct ct_sns_pkt); + sp->u.iocb_cmd.u.ctarg.rsp_allocated_size = rspsz; if (!sp->u.iocb_cmd.u.ctarg.rsp) { ql_log(ql_log_warn, vha, 0xffff, "Failed to allocate ct_sns request.\n"); @@ -4208,9 +4171,6 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { - spin_lock_irqsave(&vha->work_lock, flags); - vha->scan.scan_flags &= ~SF_SCANNING; - spin_unlock_irqrestore(&vha->work_lock, flags); goto done_free_sp; } @@ -4234,6 +4194,17 @@ done_free_sp: sp->free(sp); + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_flags &= ~SF_SCANNING; + if (vha->scan.scan_flags == 0) { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s: schedule\n", __func__); + vha->scan.scan_flags |= SF_QUEUED; + schedule_delayed_work(&vha->scan.scan_work, 5); + } + spin_unlock_irqrestore(&vha->work_lock, flags); + + return rval; } @@ -4261,9 +4232,8 @@ void qla24xx_handle_gnnid_event(scsi_qla_host_t *vha, struct event_arg *ea) qla24xx_post_gnl_work(vha, ea->fcport); } -static void qla2x00_async_gnnid_sp_done(void *s, int res) +static void qla2x00_async_gnnid_sp_done(srb_t *sp, int res) { - struct srb *sp = s; struct scsi_qla_host *vha = sp->vha; fc_port_t *fcport = sp->fcport; u8 *node_name = fcport->ct_desc.ct_sns->p.rsp.rsp.gnn_id.node_name; @@ -4279,13 +4249,12 @@ static void qla2x00_async_gnnid_sp_done(void *s, int res) ea.fcport = fcport; ea.sp = sp; ea.rc = res; - ea.event = FCME_GNNID_DONE; ql_dbg(ql_dbg_disc, vha, 0x204f, "Async done-%s res %x, WWPN %8phC %8phC\n", sp->name, res, fcport->port_name, fcport->node_name); - qla2x00_fcport_event_handler(vha, &ea); + qla24xx_handle_gnnid_event(vha, &ea); sp->free(sp); } @@ -4318,9 +4287,7 @@ int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port_t *fcport) GNN_ID_RSP_SIZE); /* GNN_ID req */ - ct_req->req.port_id.port_id[0] = fcport->d_id.b.domain; - ct_req->req.port_id.port_id[1] = fcport->d_id.b.area; - ct_req->req.port_id.port_id[2] = fcport->d_id.b.al_pa; + ct_req->req.port_id.port_id = port_id_to_be_id(fcport->d_id); /* req & rsp use the same buffer */ @@ -4396,9 +4363,8 @@ void qla24xx_handle_gfpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) qla24xx_post_gpsc_work(vha, fcport); } -static void qla2x00_async_gfpnid_sp_done(void *s, int res) +static void qla2x00_async_gfpnid_sp_done(srb_t *sp, int res) { - struct srb *sp = s; struct scsi_qla_host *vha = sp->vha; fc_port_t *fcport = sp->fcport; u8 *fpn = fcport->ct_desc.ct_sns->p.rsp.rsp.gfpn_id.port_name; @@ -4413,13 +4379,12 @@ static void qla2x00_async_gfpnid_sp_done(void *s, int res) ea.fcport = fcport; ea.sp = sp; ea.rc = res; - ea.event = FCME_GFPNID_DONE; ql_dbg(ql_dbg_disc, vha, 0x204f, "Async done-%s res %x, WWPN %8phC %8phC\n", sp->name, res, fcport->port_name, fcport->fabric_port_name); - qla2x00_fcport_event_handler(vha, &ea); + qla24xx_handle_gfpnid_event(vha, &ea); sp->free(sp); } @@ -4450,9 +4415,7 @@ int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_port_t *fcport) GFPN_ID_RSP_SIZE); /* GFPN_ID req */ - ct_req->req.port_id.port_id[0] = fcport->d_id.b.domain; - ct_req->req.port_id.port_id[1] = fcport->d_id.b.area; - ct_req->req.port_id.port_id[2] = fcport->d_id.b.al_pa; + ct_req->req.port_id.port_id = port_id_to_be_id(fcport->d_id); /* req & rsp use the same buffer */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 54772d4c377f..1d041313ec52 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -37,8 +37,8 @@ static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *); static int qla84xx_init_chip(scsi_qla_host_t *); static int qla25xx_init_queues(struct qla_hw_data *); static int qla24xx_post_prli_work(struct scsi_qla_host*, fc_port_t *); -static void qla24xx_handle_plogi_done_event(struct scsi_qla_host *, - struct event_arg *); +static void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, + struct event_arg *ea); static void qla24xx_handle_prli_done_event(struct scsi_qla_host *, struct event_arg *); static void __qla24xx_handle_gpdb_event(scsi_qla_host_t *, struct event_arg *); @@ -63,10 +63,8 @@ qla2x00_sp_timeout(struct timer_list *t) iocb->timeout(sp); } -void -qla2x00_sp_free(void *ptr) +void qla2x00_sp_free(srb_t *sp) { - srb_t *sp = ptr; struct srb_iocb *iocb = &sp->u.iocb_cmd; del_timer(&iocb->timer); @@ -99,22 +97,33 @@ static void qla24xx_abort_iocb_timeout(void *data) { srb_t *sp = data; struct srb_iocb *abt = &sp->u.iocb_cmd; + struct qla_qpair *qpair = sp->qpair; + u32 handle; + unsigned long flags; + + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + for (handle = 1; handle < qpair->req->num_outstanding_cmds; handle++) { + /* removing the abort */ + if (qpair->req->outstanding_cmds[handle] == sp) { + qpair->req->outstanding_cmds[handle] = NULL; + break; + } + } + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); abt->u.abt.comp_status = CS_TIMEOUT; - sp->done(sp, QLA_FUNCTION_TIMEOUT); + sp->done(sp, QLA_OS_TIMER_EXPIRED); } -static void qla24xx_abort_sp_done(void *ptr, int res) +static void qla24xx_abort_sp_done(srb_t *sp, int res) { - srb_t *sp = ptr; struct srb_iocb *abt = &sp->u.iocb_cmd; - if (del_timer(&sp->u.iocb_cmd.timer)) { - if (sp->flags & SRB_WAKEUP_ON_COMP) - complete(&abt->u.abt.comp); - else - sp->free(sp); - } + del_timer(&sp->u.iocb_cmd.timer); + if (sp->flags & SRB_WAKEUP_ON_COMP) + complete(&abt->u.abt.comp); + else + sp->free(sp); } static int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) @@ -127,7 +136,7 @@ static int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) sp = qla2xxx_get_qpair_sp(cmd_sp->vha, cmd_sp->qpair, cmd_sp->fcport, GFP_ATOMIC); if (!sp) - goto done; + return rval; abt_iocb = &sp->u.iocb_cmd; sp->type = SRB_ABT_CMD; @@ -151,20 +160,18 @@ static int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) cmd_sp->type); rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; + if (rval != QLA_SUCCESS) { + sp->free(sp); + return rval; + } if (wait) { wait_for_completion(&abt_iocb->u.abt.comp); rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ? QLA_SUCCESS : QLA_FUNCTION_FAILED; - } else { - goto done; + sp->free(sp); } -done_free_sp: - sp->free(sp); -done: return rval; } @@ -234,13 +241,15 @@ qla2x00_async_iocb_timeout(void *data) sp->done(sp, QLA_FUNCTION_TIMEOUT); } break; + default: + WARN_ON_ONCE(true); + sp->done(sp, QLA_FUNCTION_TIMEOUT); + break; } } -static void -qla2x00_async_login_sp_done(void *ptr, int res) +static void qla2x00_async_login_sp_done(srb_t *sp, int res) { - srb_t *sp = ptr; struct scsi_qla_host *vha = sp->vha; struct srb_iocb *lio = &sp->u.iocb_cmd; struct event_arg ea; @@ -252,14 +261,13 @@ qla2x00_async_login_sp_done(void *ptr, int res) if (!test_bit(UNLOADING, &vha->dpc_flags)) { memset(&ea, 0, sizeof(ea)); - ea.event = FCME_PLOGI_DONE; ea.fcport = sp->fcport; ea.data[0] = lio->u.logio.data[0]; ea.data[1] = lio->u.logio.data[1]; ea.iop[0] = lio->u.logio.iop[0]; ea.iop[1] = lio->u.logio.iop[1]; ea.sp = sp; - qla2x00_fcport_event_handler(vha, &ea); + qla24xx_handle_plogi_done_event(vha, &ea); } sp->free(sp); @@ -289,8 +297,13 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, struct srb_iocb *lio; int rval = QLA_FUNCTION_FAILED; - if (!vha->flags.online) - goto done; + if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT) || + fcport->loop_id == FC_NO_LOOP_ID) { + ql_log(ql_log_warn, vha, 0xffff, + "%s: %8phC - not sending command.\n", + __func__, fcport->port_name); + return rval; + } sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) @@ -341,11 +354,8 @@ done: return rval; } -static void -qla2x00_async_logout_sp_done(void *ptr, int res) +static void qla2x00_async_logout_sp_done(srb_t *sp, int res) { - srb_t *sp = ptr; - sp->fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); sp->fcport->login_gen++; qlt_logo_completion_handler(sp->fcport, res); @@ -359,9 +369,6 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) struct srb_iocb *lio; int rval = QLA_FUNCTION_FAILED; - if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) - return rval; - fcport->flags |= FCF_ASYNC_SENT; sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) @@ -405,10 +412,8 @@ qla2x00_async_prlo_done(struct scsi_qla_host *vha, fc_port_t *fcport, qlt_logo_completion_handler(fcport, data[0]); } -static void -qla2x00_async_prlo_sp_done(void *s, int res) +static void qla2x00_async_prlo_sp_done(srb_t *sp, int res) { - srb_t *sp = (srb_t *)s; struct srb_iocb *lio = &sp->u.iocb_cmd; struct scsi_qla_host *vha = sp->vha; @@ -469,6 +474,9 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) fcport->fw_login_state, ea->rc, fcport->login_gen, ea->sp->gen2, fcport->rscn_gen, ea->sp->gen1, fcport->loop_id); + WARN_ONCE(!qla2xxx_is_valid_mbs(ea->data[0]), "mbs: %#x\n", + ea->data[0]); + if (ea->data[0] != MBS_COMMAND_COMPLETE) { ql_dbg(ql_dbg_disc, vha, 0x2066, "%s %8phC: adisc fail: post delete\n", @@ -511,10 +519,8 @@ static int qla_post_els_plogi_work(struct scsi_qla_host *vha, fc_port_t *fcport) return qla2x00_post_work(vha, e); } -static void -qla2x00_async_adisc_sp_done(void *ptr, int res) +static void qla2x00_async_adisc_sp_done(srb_t *sp, int res) { - srb_t *sp = ptr; struct scsi_qla_host *vha = sp->vha; struct event_arg ea; struct srb_iocb *lio = &sp->u.iocb_cmd; @@ -526,7 +532,6 @@ qla2x00_async_adisc_sp_done(void *ptr, int res) sp->fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); memset(&ea, 0, sizeof(ea)); - ea.event = FCME_ADISC_DONE; ea.rc = res; ea.data[0] = lio->u.logio.data[0]; ea.data[1] = lio->u.logio.data[1]; @@ -535,7 +540,7 @@ qla2x00_async_adisc_sp_done(void *ptr, int res) ea.fcport = sp->fcport; ea.sp = sp; - qla2x00_fcport_event_handler(vha, &ea); + qla24xx_handle_adisc_event(vha, &ea); sp->free(sp); } @@ -741,12 +746,15 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, break; default: if ((id.b24 != fcport->d_id.b24 && - fcport->d_id.b24) || + fcport->d_id.b24 && + fcport->loop_id != FC_NO_LOOP_ID) || (fcport->loop_id != FC_NO_LOOP_ID && fcport->loop_id != loop_id)) { ql_dbg(ql_dbg_disc, vha, 0x20e3, "%s %d %8phC post del sess\n", __func__, __LINE__, fcport->port_name); + if (fcport->n2n_flag) + fcport->d_id.b24 = 0; qlt_schedule_sess_for_deletion(fcport); return; } @@ -754,6 +762,8 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, } fcport->loop_id = loop_id; + if (fcport->n2n_flag) + fcport->d_id.b24 = id.b24; wwn = wwn_to_u64(fcport->port_name); qlt_find_sess_invalidate_other(vha, wwn, @@ -803,6 +813,15 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, fcport->fw_login_state = current_login_state; fcport->d_id = id; switch (current_login_state) { + case DSC_LS_PRLI_PEND: + /* + * In the middle of PRLI. Let it finish. + * Allow relogin code to recheck state again + * with GNL. Push disc_state back to DELETED + * so GNL can go out again + */ + fcport->disc_state = DSC_DELETED; + break; case DSC_LS_PRLI_COMP: if ((e->prli_svc_param_word_3[0] & BIT_4) == 0) fcport->port_type = FCT_INITIATOR; @@ -917,10 +936,8 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, } } /* gnl_event */ -static void -qla24xx_async_gnl_sp_done(void *s, int res) +static void qla24xx_async_gnl_sp_done(srb_t *sp, int res) { - struct srb *sp = s; struct scsi_qla_host *vha = sp->vha; unsigned long flags; struct fc_port *fcport = NULL, *tf; @@ -943,7 +960,6 @@ qla24xx_async_gnl_sp_done(void *s, int res) memset(&ea, 0, sizeof(ea)); ea.sp = sp; ea.rc = res; - ea.event = FCME_GNL_DONE; if (sp->u.iocb_cmd.u.mbx.in_mb[1] >= sizeof(struct get_name_list_extended)) { @@ -961,7 +977,7 @@ qla24xx_async_gnl_sp_done(void *s, int res) wwn = wwn_to_u64(e->port_name); ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x20e8, - "%s %8phC %02x:%02x:%02x state %d/%d lid %x \n", + "%s %8phC %02x:%02x:%02x CLS %x/%x lid %x \n", __func__, (void *)&wwn, e->port_id[2], e->port_id[1], e->port_id[0], e->current_login_state, e->last_login_state, (loop_id & 0x7fff)); @@ -982,7 +998,7 @@ qla24xx_async_gnl_sp_done(void *s, int res) spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); ea.fcport = fcport; - qla2x00_fcport_event_handler(vha, &ea); + qla24xx_handle_gnl_done_event(vha, &ea); } /* create new fcport if fw has knowledge of new sessions */ @@ -1107,10 +1123,8 @@ int qla24xx_post_gnl_work(struct scsi_qla_host *vha, fc_port_t *fcport) return qla2x00_post_work(vha, e); } -static -void qla24xx_async_gpdb_sp_done(void *s, int res) +static void qla24xx_async_gpdb_sp_done(srb_t *sp, int res) { - struct srb *sp = s; struct scsi_qla_host *vha = sp->vha; struct qla_hw_data *ha = vha->hw; fc_port_t *fcport = sp->fcport; @@ -1129,11 +1143,10 @@ void qla24xx_async_gpdb_sp_done(void *s, int res) fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); memset(&ea, 0, sizeof(ea)); - ea.event = FCME_GPDB_DONE; ea.fcport = fcport; ea.sp = sp; - qla2x00_fcport_event_handler(vha, &ea); + qla24xx_handle_gpdb_event(vha, &ea); dma_pool_free(ha->s_dma_pool, sp->u.iocb_cmd.u.mbx.in, sp->u.iocb_cmd.u.mbx.in_dma); @@ -1154,10 +1167,8 @@ static int qla24xx_post_prli_work(struct scsi_qla_host *vha, fc_port_t *fcport) return qla2x00_post_work(vha, e); } -static void -qla2x00_async_prli_sp_done(void *ptr, int res) +static void qla2x00_async_prli_sp_done(srb_t *sp, int res) { - srb_t *sp = ptr; struct scsi_qla_host *vha = sp->vha; struct srb_iocb *lio = &sp->u.iocb_cmd; struct event_arg ea; @@ -1170,7 +1181,6 @@ qla2x00_async_prli_sp_done(void *ptr, int res) if (!test_bit(UNLOADING, &vha->dpc_flags)) { memset(&ea, 0, sizeof(ea)); - ea.event = FCME_PRLI_DONE; ea.fcport = sp->fcport; ea.data[0] = lio->u.logio.data[0]; ea.data[1] = lio->u.logio.data[1]; @@ -1178,7 +1188,7 @@ qla2x00_async_prli_sp_done(void *ptr, int res) ea.iop[1] = lio->u.logio.iop[1]; ea.sp = sp; - qla2x00_fcport_event_handler(vha, &ea); + qla24xx_handle_prli_done_event(vha, &ea); } sp->free(sp); @@ -1262,8 +1272,13 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt) struct port_database_24xx *pd; struct qla_hw_data *ha = vha->hw; - if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) + if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT) || + fcport->loop_id == FC_NO_LOOP_ID) { + ql_log(ql_log_warn, vha, 0xffff, + "%s: %8phC - not sending command.\n", + __func__, fcport->port_name); return rval; + } fcport->disc_state = DSC_GPDB; @@ -1473,7 +1488,7 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) u64 wwn; u16 sec; - ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x20d8, + ql_dbg(ql_dbg_disc, vha, 0x20d8, "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d lid %d scan %d\n", __func__, fcport->port_name, fcport->disc_state, fcport->fw_login_state, fcport->login_pause, fcport->flags, @@ -1484,11 +1499,13 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) return 0; if ((fcport->loop_id != FC_NO_LOOP_ID) && + qla_dual_mode_enabled(vha) && ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || (fcport->fw_login_state == DSC_LS_PRLI_PEND))) return 0; - if (fcport->fw_login_state == DSC_LS_PLOGI_COMP) { + if (fcport->fw_login_state == DSC_LS_PLOGI_COMP && + !N2N_TOPO(vha->hw)) { if (time_before_eq(jiffies, fcport->plogi_nack_done_deadline)) { set_bit(RELOGIN_NEEDED, &vha->dpc_flags); return 0; @@ -1559,8 +1576,9 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) qla24xx_post_gpdb_work(vha, fcport, 0); } else { ql_dbg(ql_dbg_disc, vha, 0x2118, - "%s %d %8phC post NVMe PRLI\n", - __func__, __LINE__, fcport->port_name); + "%s %d %8phC post %s PRLI\n", + __func__, __LINE__, fcport->port_name, + fcport->fc4f_nvme ? "NVME" : "FC"); qla24xx_post_prli_work(vha, fcport); } break; @@ -1636,12 +1654,34 @@ int qla24xx_post_newsess_work(struct scsi_qla_host *vha, port_id_t *id, return qla2x00_post_work(vha, e); } -static +void qla2x00_handle_rscn(scsi_qla_host_t *vha, struct event_arg *ea) +{ + fc_port_t *fcport; + unsigned long flags; + + fcport = qla2x00_find_fcport_by_nportid(vha, &ea->id, 1); + if (fcport) { + fcport->scan_needed = 1; + fcport->rscn_gen++; + } + + spin_lock_irqsave(&vha->work_lock, flags); + if (vha->scan.scan_flags == 0) { + ql_dbg(ql_dbg_disc, vha, 0xffff, "%s: schedule\n", __func__); + vha->scan.scan_flags |= SF_QUEUED; + schedule_delayed_work(&vha->scan.scan_work, 5); + } + spin_unlock_irqrestore(&vha->work_lock, flags); +} + void qla24xx_handle_relogin_event(scsi_qla_host_t *vha, struct event_arg *ea) { fc_port_t *fcport = ea->fcport; + if (test_bit(UNLOADING, &vha->dpc_flags)) + return; + ql_dbg(ql_dbg_disc, vha, 0x2102, "%s %8phC DS %d LS %d P %d del %d cnfl %p rscn %d|%d login %d|%d fl %x\n", __func__, fcport->port_name, fcport->disc_state, @@ -1651,110 +1691,16 @@ void qla24xx_handle_relogin_event(scsi_qla_host_t *vha, fcport->last_login_gen, fcport->login_gen, fcport->flags); - if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || - (fcport->fw_login_state == DSC_LS_PRLI_PEND)) - return; - - if (fcport->fw_login_state == DSC_LS_PLOGI_COMP) { - if (time_before_eq(jiffies, fcport->plogi_nack_done_deadline)) { - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - return; - } - } - if (fcport->last_rscn_gen != fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0x20e9, "%s %d %8phC post gidpn\n", + ql_dbg(ql_dbg_disc, vha, 0x20e9, "%s %d %8phC post gnl\n", __func__, __LINE__, fcport->port_name); - + qla24xx_post_gnl_work(vha, fcport); return; } qla24xx_fcport_handle_login(vha, fcport); } - -static void qla_handle_els_plogi_done(scsi_qla_host_t *vha, - struct event_arg *ea) -{ - ql_dbg(ql_dbg_disc, vha, 0x2118, - "%s %d %8phC post PRLI\n", - __func__, __LINE__, ea->fcport->port_name); - qla24xx_post_prli_work(vha, ea->fcport); -} - -void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) -{ - fc_port_t *fcport; - - switch (ea->event) { - case FCME_RELOGIN: - if (test_bit(UNLOADING, &vha->dpc_flags)) - return; - - qla24xx_handle_relogin_event(vha, ea); - break; - case FCME_RSCN: - if (test_bit(UNLOADING, &vha->dpc_flags)) - return; - { - unsigned long flags; - - fcport = qla2x00_find_fcport_by_nportid - (vha, &ea->id, 1); - if (fcport) { - fcport->scan_needed = 1; - fcport->rscn_gen++; - } - - spin_lock_irqsave(&vha->work_lock, flags); - if (vha->scan.scan_flags == 0) { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s: schedule\n", __func__); - vha->scan.scan_flags |= SF_QUEUED; - schedule_delayed_work(&vha->scan.scan_work, 5); - } - spin_unlock_irqrestore(&vha->work_lock, flags); - } - break; - case FCME_GNL_DONE: - qla24xx_handle_gnl_done_event(vha, ea); - break; - case FCME_GPSC_DONE: - qla24xx_handle_gpsc_event(vha, ea); - break; - case FCME_PLOGI_DONE: /* Initiator side sent LLIOCB */ - qla24xx_handle_plogi_done_event(vha, ea); - break; - case FCME_PRLI_DONE: - qla24xx_handle_prli_done_event(vha, ea); - break; - case FCME_GPDB_DONE: - qla24xx_handle_gpdb_event(vha, ea); - break; - case FCME_GPNID_DONE: - qla24xx_handle_gpnid_event(vha, ea); - break; - case FCME_GFFID_DONE: - qla24xx_handle_gffid_event(vha, ea); - break; - case FCME_ADISC_DONE: - qla24xx_handle_adisc_event(vha, ea); - break; - case FCME_GNNID_DONE: - qla24xx_handle_gnnid_event(vha, ea); - break; - case FCME_GFPNID_DONE: - qla24xx_handle_gfpnid_event(vha, ea); - break; - case FCME_ELS_PLOGI_DONE: - qla_handle_els_plogi_done(vha, ea); - break; - default: - BUG_ON(1); - break; - } -} - /* * RSCN(s) came in for this fcport, but the RSCN(s) was not able * to be consumed by the fcport @@ -1772,10 +1718,9 @@ void qla_rscn_replay(fc_port_t *fcport) if (fcport->scan_needed) { memset(&ea, 0, sizeof(ea)); - ea.event = FCME_RSCN; ea.id = fcport->d_id; ea.id.b.rsvd_1 = RSCN_PORT_ADDR; - qla2x00_fcport_event_handler(fcport->vha, &ea); + qla2x00_handle_rscn(fcport->vha, &ea); } } @@ -1789,10 +1734,8 @@ qla2x00_tmf_iocb_timeout(void *data) complete(&tmf->u.tmf.comp); } -static void -qla2x00_tmf_sp_done(void *ptr, int res) +static void qla2x00_tmf_sp_done(srb_t *sp, int res) { - srb_t *sp = ptr; struct srb_iocb *tmf = &sp->u.iocb_cmd; complete(&tmf->u.tmf.comp); @@ -1890,6 +1833,9 @@ qla24xx_async_abort_command(srb_t *sp) static void qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea) { + WARN_ONCE(!qla2xxx_is_valid_mbs(ea->data[0]), "mbs: %#x\n", + ea->data[0]); + switch (ea->data[0]) { case MBS_COMMAND_COMPLETE: ql_dbg(ql_dbg_disc, vha, 0x2118, @@ -1914,22 +1860,43 @@ qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea) break; } - if (ea->fcport->n2n_flag) { + if (ea->fcport->fc4f_nvme) { ql_dbg(ql_dbg_disc, vha, 0x2118, "%s %d %8phC post fc4 prli\n", __func__, __LINE__, ea->fcport->port_name); ea->fcport->fc4f_nvme = 0; - ea->fcport->n2n_flag = 0; qla24xx_post_prli_work(vha, ea->fcport); + return; + } + + /* at this point both PRLI NVME & PRLI FCP failed */ + if (N2N_TOPO(vha->hw)) { + if (ea->fcport->n2n_link_reset_cnt < 3) { + ea->fcport->n2n_link_reset_cnt++; + /* + * remote port is not sending Plogi. Reset + * link to kick start his state machine + */ + set_bit(N2N_LINK_RESET, &vha->dpc_flags); + } else { + ql_log(ql_log_warn, vha, 0x2119, + "%s %d %8phC Unable to reconnect\n", + __func__, __LINE__, ea->fcport->port_name); + } + } else { + /* + * switch connect. login failed. Take connection + * down and allow relogin to retrigger + */ + ea->fcport->flags &= ~FCF_ASYNC_SENT; + ea->fcport->keep_nport_handle = 0; + qlt_schedule_sess_for_deletion(ea->fcport); } - ql_dbg(ql_dbg_disc, vha, 0x2119, - "%s %d %8phC unhandle event of %x\n", - __func__, __LINE__, ea->fcport->port_name, ea->data[0]); break; } } -static void +void qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) { port_id_t cid; /* conflict Nport id */ @@ -1953,8 +1920,11 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) return; } - if (fcport->disc_state == DSC_DELETE_PEND) + if ((fcport->disc_state == DSC_DELETE_PEND) || + (fcport->disc_state == DSC_DELETED)) { + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); return; + } if (ea->sp->gen2 != fcport->login_gen) { /* target side must have changed it. */ @@ -1972,6 +1942,9 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) return; } + WARN_ONCE(!qla2xxx_is_valid_mbs(ea->data[0]), "mbs: %#x\n", + ea->data[0]); + switch (ea->data[0]) { case MBS_COMMAND_COMPLETE: /* @@ -2266,6 +2239,10 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) if (qla_ini_mode_enabled(vha) || qla_dual_mode_enabled(vha)) rval = qla2x00_init_rings(vha); + /* No point in continuing if firmware initialization failed. */ + if (rval != QLA_SUCCESS) + return rval; + ha->flags.chip_reset_done = 1; if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) { @@ -3082,103 +3059,113 @@ qla24xx_chip_diag(scsi_qla_host_t *vha) } static void -qla2x00_alloc_offload_mem(scsi_qla_host_t *vha) +qla2x00_init_fce_trace(scsi_qla_host_t *vha) { int rval; dma_addr_t tc_dma; void *tc; struct qla_hw_data *ha = vha->hw; - if (ha->eft) { + if (!IS_FWI2_CAPABLE(ha)) + return; + + if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) && + !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) + return; + + if (ha->fce) { ql_dbg(ql_dbg_init, vha, 0x00bd, - "%s: Offload Mem is already allocated.\n", - __func__); + "%s: FCE Mem is already allocated.\n", + __func__); return; } - if (IS_FWI2_CAPABLE(ha)) { - /* Allocate memory for Fibre Channel Event Buffer. */ - if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) && - !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) - goto try_eft; + /* Allocate memory for Fibre Channel Event Buffer. */ + tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma, + GFP_KERNEL); + if (!tc) { + ql_log(ql_log_warn, vha, 0x00be, + "Unable to allocate (%d KB) for FCE.\n", + FCE_SIZE / 1024); + return; + } - if (ha->fce) - dma_free_coherent(&ha->pdev->dev, - FCE_SIZE, ha->fce, ha->fce_dma); + rval = qla2x00_enable_fce_trace(vha, tc_dma, FCE_NUM_BUFFERS, + ha->fce_mb, &ha->fce_bufs); + if (rval) { + ql_log(ql_log_warn, vha, 0x00bf, + "Unable to initialize FCE (%d).\n", rval); + dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc, tc_dma); + return; + } - /* Allocate memory for Fibre Channel Event Buffer. */ - tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma, - GFP_KERNEL); - if (!tc) { - ql_log(ql_log_warn, vha, 0x00be, - "Unable to allocate (%d KB) for FCE.\n", - FCE_SIZE / 1024); - goto try_eft; - } - - rval = qla2x00_enable_fce_trace(vha, tc_dma, FCE_NUM_BUFFERS, - ha->fce_mb, &ha->fce_bufs); - if (rval) { - ql_log(ql_log_warn, vha, 0x00bf, - "Unable to initialize FCE (%d).\n", rval); - dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc, - tc_dma); - ha->flags.fce_enabled = 0; - goto try_eft; - } - ql_dbg(ql_dbg_init, vha, 0x00c0, - "Allocate (%d KB) for FCE...\n", FCE_SIZE / 1024); - - ha->flags.fce_enabled = 1; - ha->fce_dma = tc_dma; - ha->fce = tc; - -try_eft: - if (ha->eft) - dma_free_coherent(&ha->pdev->dev, - EFT_SIZE, ha->eft, ha->eft_dma); + ql_dbg(ql_dbg_init, vha, 0x00c0, + "Allocated (%d KB) for FCE...\n", FCE_SIZE / 1024); - /* Allocate memory for Extended Trace Buffer. */ - tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, - GFP_KERNEL); - if (!tc) { - ql_log(ql_log_warn, vha, 0x00c1, - "Unable to allocate (%d KB) for EFT.\n", - EFT_SIZE / 1024); - goto eft_err; - } + ha->flags.fce_enabled = 1; + ha->fce_dma = tc_dma; + ha->fce = tc; +} - rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS); - if (rval) { - ql_log(ql_log_warn, vha, 0x00c2, - "Unable to initialize EFT (%d).\n", rval); - dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc, - tc_dma); - goto eft_err; - } - ql_dbg(ql_dbg_init, vha, 0x00c3, - "Allocated (%d KB) EFT ...\n", EFT_SIZE / 1024); +static void +qla2x00_init_eft_trace(scsi_qla_host_t *vha) +{ + int rval; + dma_addr_t tc_dma; + void *tc; + struct qla_hw_data *ha = vha->hw; + + if (!IS_FWI2_CAPABLE(ha)) + return; + + if (ha->eft) { + ql_dbg(ql_dbg_init, vha, 0x00bd, + "%s: EFT Mem is already allocated.\n", + __func__); + return; + } - ha->eft_dma = tc_dma; - ha->eft = tc; + /* Allocate memory for Extended Trace Buffer. */ + tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, + GFP_KERNEL); + if (!tc) { + ql_log(ql_log_warn, vha, 0x00c1, + "Unable to allocate (%d KB) for EFT.\n", + EFT_SIZE / 1024); + return; } -eft_err: - return; + rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS); + if (rval) { + ql_log(ql_log_warn, vha, 0x00c2, + "Unable to initialize EFT (%d).\n", rval); + dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc, tc_dma); + return; + } + + ql_dbg(ql_dbg_init, vha, 0x00c3, + "Allocated (%d KB) EFT ...\n", EFT_SIZE / 1024); + + ha->eft_dma = tc_dma; + ha->eft = tc; +} + +static void +qla2x00_alloc_offload_mem(scsi_qla_host_t *vha) +{ + qla2x00_init_fce_trace(vha); + qla2x00_init_eft_trace(vha); } void qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) { - int rval; uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size, eft_size, fce_size, mq_size; struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; struct rsp_que *rsp = ha->rsp_q_map[0]; struct qla2xxx_fw_dump *fw_dump; - dma_addr_t tc_dma; - void *tc; dump_size = fixed_size = mem_size = eft_size = fce_size = mq_size = 0; req_q_size = rsp_q_size = 0; @@ -3216,37 +3203,13 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) } if (ha->tgt.atio_ring) mq_size += ha->tgt.atio_q_length * sizeof(request_t); - /* Allocate memory for Fibre Channel Event Buffer. */ - if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) && - !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) - goto try_eft; - fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE; -try_eft: + qla2x00_init_fce_trace(vha); + if (ha->fce) + fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE; + qla2x00_init_eft_trace(vha); if (ha->eft) - dma_free_coherent(&ha->pdev->dev, - EFT_SIZE, ha->eft, ha->eft_dma); - - /* Allocate memory for Extended Trace Buffer. */ - tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, - GFP_KERNEL); - if (!tc) { - ql_log(ql_log_warn, vha, 0x00c1, - "Unable to allocate (%d KB) for EFT.\n", - EFT_SIZE / 1024); - goto allocate; - } - - rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS); - if (rval) { - ql_log(ql_log_warn, vha, 0x00c2, - "Unable to initialize EFT (%d).\n", rval); - dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc, - tc_dma); - } - ql_dbg(ql_dbg_init, vha, 0x00c3, - "Allocated (%d KB) EFT ...\n", EFT_SIZE / 1024); - eft_size = EFT_SIZE; + eft_size = EFT_SIZE; } if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { @@ -3255,7 +3218,7 @@ try_eft: for (j = 0; j < 2; j++, fwdt++) { if (!fwdt->template) { - ql_log(ql_log_warn, vha, 0x00ba, + ql_dbg(ql_dbg_init, vha, 0x00ba, "-> fwdt%u no template\n", j); continue; } @@ -3268,24 +3231,22 @@ try_eft: j, fwdt->dump_size); dump_size += fwdt->dump_size; } - goto allocate; + } else { + req_q_size = req->length * sizeof(request_t); + rsp_q_size = rsp->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->chain_offset = dump_size; + dump_size += mq_size + fce_size; + if (ha->exchoffld_buf) + dump_size += sizeof(struct qla2xxx_offld_chain) + + ha->exchoffld_size; + if (ha->exlogin_buf) + dump_size += sizeof(struct qla2xxx_offld_chain) + + ha->exlogin_size; } - req_q_size = req->length * sizeof(request_t); - rsp_q_size = rsp->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->chain_offset = dump_size; - dump_size += mq_size + fce_size; - - if (ha->exchoffld_buf) - dump_size += sizeof(struct qla2xxx_offld_chain) + - ha->exchoffld_size; - if (ha->exlogin_buf) - dump_size += sizeof(struct qla2xxx_offld_chain) + - ha->exlogin_size; - -allocate: if (!ha->fw_dump_len || dump_size > ha->fw_dump_alloc_len) { ql_dbg(ql_dbg_init, vha, 0x00c5, @@ -4400,7 +4361,7 @@ qla2x00_configure_hba(scsi_qla_host_t *vha) inline void qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, - char *def) + const char *def) { char *st, *en; uint16_t index; @@ -4412,7 +4373,7 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, if (len > sizeof(zero)) len = sizeof(zero); if (memcmp(model, &zero, len) != 0) { - strncpy(ha->model_number, model, len); + memcpy(ha->model_number, model, len); st = en = ha->model_number; en += len - 1; while (en > st) { @@ -4425,21 +4386,23 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, if (use_tbl && ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && index < QLA_MODEL_NAMES) - strncpy(ha->model_desc, + strlcpy(ha->model_desc, qla2x00_model_name[index * 2 + 1], - sizeof(ha->model_desc) - 1); + sizeof(ha->model_desc)); } else { index = (ha->pdev->subsystem_device & 0xff); if (use_tbl && ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && index < QLA_MODEL_NAMES) { - strcpy(ha->model_number, - qla2x00_model_name[index * 2]); - strncpy(ha->model_desc, + strlcpy(ha->model_number, + qla2x00_model_name[index * 2], + sizeof(ha->model_number)); + strlcpy(ha->model_desc, qla2x00_model_name[index * 2 + 1], - sizeof(ha->model_desc) - 1); + sizeof(ha->model_desc)); } else { - strcpy(ha->model_number, def); + strlcpy(ha->model_number, def, + sizeof(ha->model_number)); } } if (IS_FWI2_CAPABLE(ha)) @@ -4575,20 +4538,6 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) rval = 1; } -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) - /* - * The SN2 does not provide BIOS emulation which means you can't change - * potentially bogus BIOS settings. Force the use of default settings - * for link rate and frame size. Hope that the rest of the settings - * are valid. - */ - if (ia64_platform_is("sn2")) { - nv->frame_payload_size = 2048; - if (IS_QLA23XX(ha)) - nv->special_options[1] = BIT_7; - } -#endif - /* Reset Initialization control block */ memset(icb, 0, ha->init_cb_size); @@ -4877,7 +4826,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) ql_log(ql_log_warn, vha, 0xd049, "Failed to allocate ct_sns request.\n"); kfree(fcport); - fcport = NULL; + return NULL; } INIT_WORK(&fcport->del_work, qla24xx_delete_sess_fn); @@ -5058,35 +5007,54 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) uint16_t index; uint16_t entries; - char *id_iter; + struct gid_list_info *gid; uint16_t loop_id; uint8_t domain, area, al_pa; struct qla_hw_data *ha = vha->hw; unsigned long flags; /* Inititae N2N login. */ - if (test_and_clear_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags)) { - /* borrowing */ - u32 *bp, i, sz; - - memset(ha->init_cb, 0, ha->init_cb_size); - sz = min_t(int, sizeof(struct els_plogi_payload), - ha->init_cb_size); - rval = qla24xx_get_port_login_templ(vha, ha->init_cb_dma, - (void *)ha->init_cb, sz); - if (rval == QLA_SUCCESS) { - bp = (uint32_t *)ha->init_cb; - for (i = 0; i < sz/4 ; i++, bp++) - *bp = cpu_to_be32(*bp); + if (N2N_TOPO(ha)) { + if (test_and_clear_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags)) { + /* borrowing */ + u32 *bp, i, sz; + + memset(ha->init_cb, 0, ha->init_cb_size); + sz = min_t(int, sizeof(struct els_plogi_payload), + ha->init_cb_size); + rval = qla24xx_get_port_login_templ(vha, + ha->init_cb_dma, (void *)ha->init_cb, sz); + if (rval == QLA_SUCCESS) { + bp = (uint32_t *)ha->init_cb; + for (i = 0; i < sz/4 ; i++, bp++) + *bp = cpu_to_be32(*bp); - memcpy(&ha->plogi_els_payld.data, (void *)ha->init_cb, - sizeof(ha->plogi_els_payld.data)); - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - } else { - ql_dbg(ql_dbg_init, vha, 0x00d1, - "PLOGI ELS param read fail.\n"); + memcpy(&ha->plogi_els_payld.data, + (void *)ha->init_cb, + sizeof(ha->plogi_els_payld.data)); + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + } else { + ql_dbg(ql_dbg_init, vha, 0x00d1, + "PLOGI ELS param read fail.\n"); + goto skip_login; + } + } + + list_for_each_entry(fcport, &vha->vp_fcports, list) { + if (fcport->n2n_flag) { + qla24xx_fcport_handle_login(vha, fcport); + return QLA_SUCCESS; + } + } +skip_login: + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_retry++; + spin_unlock_irqrestore(&vha->work_lock, flags); + + if (vha->scan.scan_retry < MAX_SCAN_RETRIES) { + set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); } - return QLA_SUCCESS; } found_devs = 0; @@ -5133,18 +5101,16 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) new_fcport->flags &= ~FCF_FABRIC_DEVICE; /* Add devices to port list. */ - id_iter = (char *)ha->gid_list; + gid = ha->gid_list; for (index = 0; index < entries; index++) { - domain = ((struct gid_list_info *)id_iter)->domain; - area = ((struct gid_list_info *)id_iter)->area; - al_pa = ((struct gid_list_info *)id_iter)->al_pa; + domain = gid->domain; + area = gid->area; + al_pa = gid->al_pa; if (IS_QLA2100(ha) || IS_QLA2200(ha)) - loop_id = (uint16_t) - ((struct gid_list_info *)id_iter)->loop_id_2100; + loop_id = gid->loop_id_2100; else - loop_id = le16_to_cpu( - ((struct gid_list_info *)id_iter)->loop_id); - id_iter += ha->gid_list_info_size; + loop_id = le16_to_cpu(gid->loop_id); + gid = (void *)gid + ha->gid_list_info_size; /* Bypass reserved domain fields. */ if ((domain & 0xf0) == 0xf0) @@ -5369,7 +5335,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) "%s %8phN. rport %p is %s mode\n", __func__, fcport->port_name, rport, (fcport->port_type == FCT_TARGET) ? "tgt" : - ((fcport->port_type & FCT_NVME) ? "nvme" :"ini")); + ((fcport->port_type & FCT_NVME) ? "nvme" : "ini")); fc_remote_port_rolechg(rport, rport_ids.roles); } @@ -5403,7 +5369,6 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); fcport->deleted = 0; fcport->logout_on_delete = 1; - fcport->login_retry = vha->hw->login_retry_count; fcport->n2n_chip_reset = fcport->n2n_link_reset_cnt = 0; switch (vha->hw->current_topology) { @@ -6611,7 +6576,8 @@ qla2x00_quiesce_io(scsi_qla_host_t *vha) LOOP_DOWN_TIME); } /* Wait for pending cmds to complete */ - qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST); + WARN_ON_ONCE(qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) + != QLA_SUCCESS); } void @@ -6699,8 +6665,10 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) } /* Clear all async request states across all VPs. */ - list_for_each_entry(fcport, &vha->vp_fcports, list) + list_for_each_entry(fcport, &vha->vp_fcports, list) { fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); + fcport->scan_state = 0; + } spin_lock_irqsave(&ha->vport_slock, flags); list_for_each_entry(vp, &ha->vp_list, list) { atomic_inc(&vp->vref_count); @@ -7534,8 +7502,12 @@ qla27xx_get_active_image(struct scsi_qla_host *vha, goto check_sec_image; } - qla24xx_read_flash_data(vha, (void *)(&pri_image_status), - ha->flt_region_img_status_pri, sizeof(pri_image_status) >> 2); + if (qla24xx_read_flash_data(vha, (void *)(&pri_image_status), + ha->flt_region_img_status_pri, sizeof(pri_image_status) >> 2) != + QLA_SUCCESS) { + WARN_ON_ONCE(true); + goto check_sec_image; + } qla27xx_print_image(vha, "Primary image", &pri_image_status); if (qla27xx_check_image_status_signature(&pri_image_status)) { @@ -8289,7 +8261,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ? "primary" : "secondary"); } - qla24xx_read_flash_data(vha, ha->vpd, faddr, ha->vpd_size >> 2); + ha->isp_ops->read_optrom(vha, ha->vpd, faddr << 2, ha->vpd_size); /* Get NVRAM data into cache and calculate checksum. */ faddr = ha->flt_region_nvram; @@ -8301,7 +8273,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) "Loading %s nvram image.\n", active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ? "primary" : "secondary"); - qla24xx_read_flash_data(vha, ha->nvram, faddr, ha->nvram_size >> 2); + ha->isp_ops->read_optrom(vha, ha->nvram, faddr << 2, ha->nvram_size); dptr = (uint32_t *)nv; for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++, dptr++) diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index bf063c664352..0c3d907af769 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -152,6 +152,18 @@ qla2x00_chip_is_down(scsi_qla_host_t *vha) return (qla2x00_reset_active(vha) || !vha->hw->flags.fw_started); } +static void qla2xxx_init_sp(srb_t *sp, scsi_qla_host_t *vha, + struct qla_qpair *qpair, fc_port_t *fcport) +{ + memset(sp, 0, sizeof(*sp)); + sp->fcport = fcport; + sp->iocbs = 1; + sp->vha = vha; + sp->qpair = qpair; + sp->cmd_type = TYPE_SRB; + INIT_LIST_HEAD(&sp->elem); +} + static inline srb_t * qla2xxx_get_qpair_sp(scsi_qla_host_t *vha, struct qla_qpair *qpair, fc_port_t *fcport, gfp_t flag) @@ -164,19 +176,9 @@ qla2xxx_get_qpair_sp(scsi_qla_host_t *vha, struct qla_qpair *qpair, return NULL; sp = mempool_alloc(qpair->srb_mempool, flag); - if (!sp) - goto done; - - memset(sp, 0, sizeof(*sp)); - sp->fcport = fcport; - sp->iocbs = 1; - sp->vha = vha; - sp->qpair = qpair; - sp->cmd_type = TYPE_SRB; - INIT_LIST_HEAD(&sp->elem); - -done: - if (!sp) + if (sp) + qla2xxx_init_sp(sp, vha, qpair, fcport); + else QLA_QPAIR_MARK_NOT_BUSY(qpair); return sp; } diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 9312b19ed708..518eb954cf42 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -292,6 +292,26 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, } } +/* + * Find the first handle that is not in use, starting from + * req->current_outstanding_cmd + 1. The caller must hold the lock that is + * associated with @req. + */ +uint32_t qla2xxx_get_next_handle(struct req_que *req) +{ + uint32_t index, handle = req->current_outstanding_cmd; + + for (index = 1; index < req->num_outstanding_cmds; index++) { + handle++; + if (handle == req->num_outstanding_cmds) + handle = 1; + if (!req->outstanding_cmds[handle]) + return handle; + } + + return 0; +} + /** * qla2x00_start_scsi() - Send a SCSI command to the ISP * @sp: command to send to the ISP @@ -306,7 +326,6 @@ qla2x00_start_scsi(srb_t *sp) scsi_qla_host_t *vha; struct scsi_cmnd *cmd; uint32_t *clr_ptr; - uint32_t index; uint32_t handle; cmd_entry_t *cmd_pkt; uint16_t cnt; @@ -339,16 +358,8 @@ qla2x00_start_scsi(srb_t *sp) /* Acquire ring specific lock */ spin_lock_irqsave(&ha->hardware_lock, flags); - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < req->num_outstanding_cmds; index++) { - handle++; - if (handle == req->num_outstanding_cmds) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - if (index == req->num_outstanding_cmds) + handle = qla2xxx_get_next_handle(req); + if (handle == 0) goto queuing_error; /* Map the sg table so we have an accurate count of sg entries needed */ @@ -610,7 +621,7 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, } cur_seg = scsi_sglist(cmd); - ctx = GET_CMD_CTX_SP(sp); + ctx = sp->u.scmd.ct6_ctx; while (tot_dsds) { avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ? @@ -943,8 +954,7 @@ alloc_and_fill: if (sp) { list_add_tail(&dsd_ptr->list, - &((struct crc_context *) - sp->u.scmd.ctx)->dsd_list); + &sp->u.scmd.crc_ctx->dsd_list); sp->flags |= SRB_CRC_CTX_DSD_VALID; } else { @@ -1041,8 +1051,7 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, if (sp) { list_add_tail(&dsd_ptr->list, - &((struct crc_context *) - sp->u.scmd.ctx)->dsd_list); + &sp->u.scmd.crc_ctx->dsd_list); sp->flags |= SRB_CRC_CTX_DSD_VALID; } else { @@ -1088,7 +1097,7 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, sgl = scsi_prot_sglist(cmd); vha = sp->vha; - difctx = sp->u.scmd.ctx; + difctx = sp->u.scmd.crc_ctx; direction_to_device = cmd->sc_data_direction == DMA_TO_DEVICE; ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe021, "%s: scsi_cmnd: %p, crc_ctx: %p, sp: %p\n", @@ -1364,6 +1373,7 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, cur_dsd++; return 0; } + /** * qla24xx_build_scsi_crc_2_iocbs() - Build IOCB command utilizing Command * Type 6 IOCB types. @@ -1427,7 +1437,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, bundling = 0; /* Allocate CRC context from global pool */ - crc_ctx_pkt = sp->u.scmd.ctx = + crc_ctx_pkt = sp->u.scmd.crc_ctx = dma_pool_zalloc(ha->dl_dma_pool, GFP_ATOMIC, &crc_ctx_dma); if (!crc_ctx_pkt) @@ -1515,7 +1525,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, } if (!bundling) { - cur_dsd = &crc_ctx_pkt->u.nobundling.data_dsd; + cur_dsd = &crc_ctx_pkt->u.nobundling.data_dsd[0]; } else { /* * Configure Bundling if we need to fetch interlaving @@ -1525,7 +1535,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes); crc_ctx_pkt->u.bundling.dseg_count = cpu_to_le16(tot_dsds - tot_prot_dsds); - cur_dsd = &crc_ctx_pkt->u.bundling.data_dsd; + cur_dsd = &crc_ctx_pkt->u.bundling.data_dsd[0]; } /* Finish the common fields of CRC pkt */ @@ -1583,7 +1593,6 @@ qla24xx_start_scsi(srb_t *sp) int nseg; unsigned long flags; uint32_t *clr_ptr; - uint32_t index; uint32_t handle; struct cmd_type_7 *cmd_pkt; uint16_t cnt; @@ -1611,16 +1620,8 @@ qla24xx_start_scsi(srb_t *sp) /* Acquire ring specific lock */ spin_lock_irqsave(&ha->hardware_lock, flags); - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < req->num_outstanding_cmds; index++) { - handle++; - if (handle == req->num_outstanding_cmds) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - if (index == req->num_outstanding_cmds) + handle = qla2xxx_get_next_handle(req); + if (handle == 0) goto queuing_error; /* Map the sg table so we have an accurate count of sg entries needed */ @@ -1723,7 +1724,6 @@ qla24xx_dif_start_scsi(srb_t *sp) int nseg; unsigned long flags; uint32_t *clr_ptr; - uint32_t index; uint32_t handle; uint16_t cnt; uint16_t req_cnt = 0; @@ -1764,17 +1764,8 @@ qla24xx_dif_start_scsi(srb_t *sp) /* Acquire ring specific lock */ spin_lock_irqsave(&ha->hardware_lock, flags); - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < req->num_outstanding_cmds; index++) { - handle++; - if (handle == req->num_outstanding_cmds) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - - if (index == req->num_outstanding_cmds) + handle = qla2xxx_get_next_handle(req); + if (handle == 0) goto queuing_error; /* Compute number of required data segments */ @@ -1919,7 +1910,6 @@ qla2xxx_start_scsi_mq(srb_t *sp) int nseg; unsigned long flags; uint32_t *clr_ptr; - uint32_t index; uint32_t handle; struct cmd_type_7 *cmd_pkt; uint16_t cnt; @@ -1950,16 +1940,8 @@ qla2xxx_start_scsi_mq(srb_t *sp) vha->marker_needed = 0; } - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < req->num_outstanding_cmds; index++) { - handle++; - if (handle == req->num_outstanding_cmds) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - if (index == req->num_outstanding_cmds) + handle = qla2xxx_get_next_handle(req); + if (handle == 0) goto queuing_error; /* Map the sg table so we have an accurate count of sg entries needed */ @@ -2063,7 +2045,6 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp) int nseg; unsigned long flags; uint32_t *clr_ptr; - uint32_t index; uint32_t handle; uint16_t cnt; uint16_t req_cnt = 0; @@ -2118,17 +2099,8 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp) vha->marker_needed = 0; } - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < req->num_outstanding_cmds; index++) { - handle++; - if (handle == req->num_outstanding_cmds) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - - if (index == req->num_outstanding_cmds) + handle = qla2xxx_get_next_handle(req); + if (handle == 0) goto queuing_error; /* Compute number of required data segments */ @@ -2275,7 +2247,7 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp) struct qla_hw_data *ha = vha->hw; struct req_que *req = qpair->req; device_reg_t *reg = ISP_QUE_REG(ha, req->id); - uint32_t index, handle; + uint32_t handle; request_t *pkt; uint16_t cnt, req_cnt; @@ -2315,16 +2287,8 @@ __qla2x00_alloc_iocbs(struct qla_qpair *qpair, srb_t *sp) goto queuing_error; if (sp) { - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < req->num_outstanding_cmds; index++) { - handle++; - if (handle == req->num_outstanding_cmds) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - if (index == req->num_outstanding_cmds) { + handle = qla2xxx_get_next_handle(req); + if (handle == 0) { ql_log(ql_log_warn, vha, 0x700b, "No room on outstanding cmd array.\n"); goto queuing_error; @@ -2540,13 +2504,11 @@ void qla2x00_init_timer(srb_t *sp, unsigned long tmo) sp->free = qla2x00_sp_free; if (IS_QLAFX00(sp->vha->hw) && sp->type == SRB_FXIOCB_DCMD) init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp); - add_timer(&sp->u.iocb_cmd.timer); + sp->start_timer = 1; } -static void -qla2x00_els_dcmd_sp_free(void *data) +static void qla2x00_els_dcmd_sp_free(srb_t *sp) { - srb_t *sp = data; struct srb_iocb *elsio = &sp->u.iocb_cmd; kfree(sp->fcport); @@ -2576,10 +2538,8 @@ qla2x00_els_dcmd_iocb_timeout(void *data) complete(&lio->u.els_logo.comp); } -static void -qla2x00_els_dcmd_sp_done(void *ptr, int res) +static void qla2x00_els_dcmd_sp_done(srb_t *sp, int res) { - srb_t *sp = ptr; fc_port_t *fcport = sp->fcport; struct srb_iocb *lio = &sp->u.iocb_cmd; struct scsi_qla_host *vha = sp->vha; @@ -2696,19 +2656,20 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; els_iocb->port_id[1] = sp->fcport->d_id.b.area; els_iocb->port_id[2] = sp->fcport->d_id.b.domain; - els_iocb->s_id[0] = vha->d_id.b.al_pa; - els_iocb->s_id[1] = vha->d_id.b.area; - els_iocb->s_id[2] = vha->d_id.b.domain; - els_iocb->control_flags = 0; + /* For SID the byte order is different than DID */ + els_iocb->s_id[1] = vha->d_id.b.al_pa; + els_iocb->s_id[2] = vha->d_id.b.area; + els_iocb->s_id[0] = vha->d_id.b.domain; if (elsio->u.els_logo.els_cmd == ELS_DCMD_PLOGI) { + els_iocb->control_flags = 0; els_iocb->tx_byte_count = els_iocb->tx_len = - sizeof(struct els_plogi_payload); + cpu_to_le32(sizeof(struct els_plogi_payload)); put_unaligned_le64(elsio->u.els_plogi.els_plogi_pyld_dma, &els_iocb->tx_address); els_iocb->rx_dsd_count = 1; els_iocb->rx_byte_count = els_iocb->rx_len = - sizeof(struct els_plogi_payload); + cpu_to_le32(sizeof(struct els_plogi_payload)); put_unaligned_le64(elsio->u.els_plogi.els_resp_pyld_dma, &els_iocb->rx_address); @@ -2717,7 +2678,9 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) ql_dump_buffer(ql_log_info, vha, 0x0109, (uint8_t *)els_iocb, 0x70); } else { - els_iocb->tx_byte_count = sizeof(struct els_logo_payload); + els_iocb->control_flags = 1 << 13; + els_iocb->tx_byte_count = + cpu_to_le32(sizeof(struct els_logo_payload)); put_unaligned_le64(elsio->u.els_logo.els_logo_pyld_dma, &els_iocb->tx_address); els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload)); @@ -2755,10 +2718,23 @@ qla2x00_els_dcmd2_iocb_timeout(void *data) sp->done(sp, QLA_FUNCTION_TIMEOUT); } -static void -qla2x00_els_dcmd2_sp_done(void *ptr, int res) +void qla2x00_els_dcmd2_free(scsi_qla_host_t *vha, struct els_plogi *els_plogi) +{ + if (els_plogi->els_plogi_pyld) + dma_free_coherent(&vha->hw->pdev->dev, + els_plogi->tx_size, + els_plogi->els_plogi_pyld, + els_plogi->els_plogi_pyld_dma); + + if (els_plogi->els_resp_pyld) + dma_free_coherent(&vha->hw->pdev->dev, + els_plogi->rx_size, + els_plogi->els_resp_pyld, + els_plogi->els_resp_pyld_dma); +} + +static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) { - srb_t *sp = ptr; fc_port_t *fcport = sp->fcport; struct srb_iocb *lio = &sp->u.iocb_cmd; struct scsi_qla_host *vha = sp->vha; @@ -2780,26 +2756,16 @@ qla2x00_els_dcmd2_sp_done(void *ptr, int res) } else { memset(&ea, 0, sizeof(ea)); ea.fcport = fcport; - ea.rc = res; - ea.event = FCME_ELS_PLOGI_DONE; - qla2x00_fcport_event_handler(vha, &ea); + ea.data[0] = MBS_COMMAND_COMPLETE; + ea.sp = sp; + qla24xx_handle_plogi_done_event(vha, &ea); } e = qla2x00_alloc_work(vha, QLA_EVT_UNMAP); if (!e) { struct srb_iocb *elsio = &sp->u.iocb_cmd; - if (elsio->u.els_plogi.els_plogi_pyld) - dma_free_coherent(&sp->vha->hw->pdev->dev, - elsio->u.els_plogi.tx_size, - elsio->u.els_plogi.els_plogi_pyld, - elsio->u.els_plogi.els_plogi_pyld_dma); - - if (elsio->u.els_plogi.els_resp_pyld) - dma_free_coherent(&sp->vha->hw->pdev->dev, - elsio->u.els_plogi.rx_size, - elsio->u.els_plogi.els_resp_pyld, - elsio->u.els_plogi.els_resp_pyld_dma); + qla2x00_els_dcmd2_free(vha, &elsio->u.els_plogi); sp->free(sp); return; } @@ -2899,18 +2865,7 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, out: fcport->flags &= ~(FCF_ASYNC_SENT); - if (elsio->u.els_plogi.els_plogi_pyld) - dma_free_coherent(&sp->vha->hw->pdev->dev, - elsio->u.els_plogi.tx_size, - elsio->u.els_plogi.els_plogi_pyld, - elsio->u.els_plogi.els_plogi_pyld_dma); - - if (elsio->u.els_plogi.els_resp_pyld) - dma_free_coherent(&sp->vha->hw->pdev->dev, - elsio->u.els_plogi.rx_size, - elsio->u.els_plogi.els_resp_pyld, - elsio->u.els_plogi.els_resp_pyld_dma); - + qla2x00_els_dcmd2_free(vha, &elsio->u.els_plogi); sp->free(sp); done: return rval; @@ -3115,7 +3070,6 @@ qla82xx_start_scsi(srb_t *sp) unsigned long flags; struct scsi_cmnd *cmd; uint32_t *clr_ptr; - uint32_t index; uint32_t handle; uint16_t cnt; uint16_t req_cnt; @@ -3155,16 +3109,8 @@ qla82xx_start_scsi(srb_t *sp) /* Acquire ring specific lock */ spin_lock_irqsave(&ha->hardware_lock, flags); - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < req->num_outstanding_cmds; index++) { - handle++; - if (handle == req->num_outstanding_cmds) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - if (index == req->num_outstanding_cmds) + handle = qla2xxx_get_next_handle(req); + if (handle == 0) goto queuing_error; /* Map the sg table so we have an accurate count of sg entries needed */ @@ -3235,7 +3181,7 @@ sufficient_dsds: goto queuing_error; } - ctx = sp->u.scmd.ctx = + ctx = sp->u.scmd.ct6_ctx = mempool_alloc(ha->ctx_mempool, GFP_ATOMIC); if (!ctx) { ql_log(ql_log_fatal, vha, 0x3010, @@ -3431,9 +3377,9 @@ queuing_error: if (tot_dsds) scsi_dma_unmap(cmd); - if (sp->u.scmd.ctx) { - mempool_free(sp->u.scmd.ctx, ha->ctx_mempool); - sp->u.scmd.ctx = NULL; + if (sp->u.scmd.crc_ctx) { + mempool_free(sp->u.scmd.crc_ctx, ha->ctx_mempool); + sp->u.scmd.crc_ctx = NULL; } spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -3668,6 +3614,9 @@ qla2x00_start_sp(srb_t *sp) break; } + if (sp->start_timer) + add_timer(&sp->u.iocb_cmd.timer); + wmb(); qla2x00_start_iocbs(vha, qp->req); done: @@ -3769,7 +3718,6 @@ qla2x00_start_bidir(srb_t *sp, struct scsi_qla_host *vha, uint32_t tot_dsds) struct qla_hw_data *ha = vha->hw; unsigned long flags; uint32_t handle; - uint32_t index; uint16_t req_cnt; uint16_t cnt; uint32_t *clr_ptr; @@ -3794,17 +3742,8 @@ qla2x00_start_bidir(srb_t *sp, struct scsi_qla_host *vha, uint32_t tot_dsds) /* Acquire ring specific lock */ spin_lock_irqsave(&ha->hardware_lock, flags); - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < req->num_outstanding_cmds; index++) { - handle++; - if (handle == req->num_outstanding_cmds) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - - if (index == req->num_outstanding_cmds) { + handle = qla2xxx_get_next_handle(req); + if (handle == 0) { rval = EXT_STATUS_BUSY; goto queuing_error; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 78aec50abe0f..009fd5a33fcd 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -776,7 +776,6 @@ skip_rio: case MBA_LOOP_INIT_ERR: ql_log(ql_log_warn, vha, 0x5090, "LOOP INIT ERROR (%x).\n", mb[1]); - ha->isp_ops->fw_dump(vha, 1); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); break; @@ -1119,10 +1118,9 @@ global_port_update: struct event_arg ea; memset(&ea, 0, sizeof(ea)); - ea.event = FCME_RSCN; ea.id.b24 = rscn_entry; ea.id.b.rsvd_1 = rscn_entry >> 24; - qla2x00_fcport_event_handler(vha, &ea); + qla2x00_handle_rscn(vha, &ea); qla2x00_post_aen_work(vha, FCH_EVT_RSCN, rscn_entry); } break; @@ -1514,7 +1512,7 @@ qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req, if (comp_status == CS_DATA_UNDERRUN) { res = DID_OK << 16; bsg_reply->reply_payload_rcv_len = - le16_to_cpu(((sts_entry_t *)pkt)->rsp_info_len); + le16_to_cpu(pkt->rsp_info_len); ql_log(ql_log_warn, vha, 0x5048, "CT pass-through-%s error comp_status=0x%x total_byte=0x%x.\n", @@ -2257,11 +2255,8 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt, struct bsg_job *bsg_job = NULL; struct fc_bsg_request *bsg_request; struct fc_bsg_reply *bsg_reply; - sts_entry_t *sts; - struct sts_entry_24xx *sts24; - - sts = (sts_entry_t *) pkt; - sts24 = (struct sts_entry_24xx *) pkt; + sts_entry_t *sts = pkt; + struct sts_entry_24xx *sts24 = pkt; /* Validate handle. */ if (index >= req->num_outstanding_cmds) { @@ -2407,8 +2402,8 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) srb_t *sp; fc_port_t *fcport; struct scsi_cmnd *cp; - sts_entry_t *sts; - struct sts_entry_24xx *sts24; + sts_entry_t *sts = pkt; + struct sts_entry_24xx *sts24 = pkt; uint16_t comp_status; uint16_t scsi_status; uint16_t ox_id; @@ -2426,8 +2421,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) uint16_t state_flags = 0; uint16_t retry_delay = 0; - sts = (sts_entry_t *) pkt; - sts24 = (struct sts_entry_24xx *) pkt; if (IS_FWI2_CAPABLE(ha)) { comp_status = le16_to_cpu(sts24->comp_status); scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK; @@ -2727,7 +2720,7 @@ check_scsi_status: "Port to be marked lost on fcport=%02x%02x%02x, current " "port state= %s comp_status %x.\n", fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, - port_state_str[atomic_read(&fcport->state)], + port_state_str[FCS_ONLINE], comp_status); qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1); @@ -3471,10 +3464,8 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) ha->msix_count, ret); goto msix_out; } else if (ret < ha->msix_count) { - ql_log(ql_log_warn, vha, 0x00c6, - "MSI-X: Failed to enable support " - "with %d vectors, using %d vectors.\n", - ha->msix_count, ret); + ql_log(ql_log_info, vha, 0x00c6, + "MSI-X: Using %d vectors\n", ret); ha->msix_count = ret; /* Recalculate queue values */ if (ha->mqiobase && (ql2xmqsupport || ql2xnvmeenable)) { diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 133f5f6270ff..4a1f21c11758 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -253,21 +253,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) { set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); - if (IS_P3P_TYPE(ha)) { - if (RD_REG_DWORD(®->isp82.hint) & - HINT_MBX_INT_PENDING) { - ha->flags.mbox_busy = 0; - spin_unlock_irqrestore(&ha->hardware_lock, - flags); - - atomic_dec(&ha->num_pend_mbx_stage2); - ql_dbg(ql_dbg_mbx, vha, 0x1010, - "Pending mailbox timeout, exiting.\n"); - rval = QLA_FUNCTION_TIMEOUT; - goto premature_exit; - } + if (IS_P3P_TYPE(ha)) WRT_REG_DWORD(®->isp82.hint, HINT_MBX_INT_PENDING); - } else if (IS_FWI2_CAPABLE(ha)) + else if (IS_FWI2_CAPABLE(ha)) WRT_REG_DWORD(®->isp24.hccr, HCCRX_SET_HOST_INT); else WRT_REG_WORD(®->isp.hccr, HCCR_SET_HOST_INT); @@ -394,8 +382,12 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) goto premature_exit; } - if (ha->mailbox_out[0] != MBS_COMMAND_COMPLETE) + if (ha->mailbox_out[0] != MBS_COMMAND_COMPLETE) { + ql_dbg(ql_dbg_mbx, vha, 0x11ff, + "mb_out[0] = %#x <> %#x\n", ha->mailbox_out[0], + MBS_COMMAND_COMPLETE); rval = QLA_FUNCTION_FAILED; + } /* Load return mailbox registers. */ iptr2 = mcp->mb; @@ -710,6 +702,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) mcp->mb[2] = LSW(risc_addr); mcp->mb[3] = 0; mcp->mb[4] = 0; + mcp->mb[11] = 0; ha->flags.using_lr_setting = 0; if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { @@ -754,7 +747,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) if (ha->flags.exchoffld_enabled) mcp->mb[4] |= ENABLE_EXCHANGE_OFFLD; - mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1; + mcp->out_mb |= MBX_4 | MBX_3 | MBX_2 | MBX_1 | MBX_11; mcp->in_mb |= MBX_3 | MBX_2 | MBX_1; } else { mcp->mb[1] = LSW(risc_addr); @@ -2257,7 +2250,7 @@ qla2x00_lip_reset(scsi_qla_host_t *vha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x105a, + ql_dbg(ql_dbg_disc, vha, 0x105a, "Entered %s.\n", __func__); if (IS_CNA_CAPABLE(vha->hw)) { @@ -3891,14 +3884,24 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, case TOPO_N2N: ha->current_topology = ISP_CFG_N; spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); + list_for_each_entry(fcport, &vha->vp_fcports, list) { + fcport->scan_state = QLA_FCPORT_SCAN; + fcport->n2n_flag = 0; + } + fcport = qla2x00_find_fcport_by_wwpn(vha, rptid_entry->u.f1.port_name, 1); spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); if (fcport) { fcport->plogi_nack_done_deadline = jiffies + HZ; - fcport->dm_login_expire = jiffies + 3*HZ; + fcport->dm_login_expire = jiffies + 2*HZ; fcport->scan_state = QLA_FCPORT_FOUND; + fcport->n2n_flag = 1; + fcport->keep_nport_handle = 1; + if (vha->flags.nvme_enabled) + fcport->fc4f_nvme = 1; + switch (fcport->disc_state) { case DSC_DELETED: set_bit(RELOGIN_NEEDED, @@ -3932,7 +3935,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, rptid_entry->u.f1.port_name, rptid_entry->u.f1.node_name, NULL, - FC4_TYPE_UNKNOWN); + FS_FCP_IS_N2N); } /* if our portname is higher then initiate N2N login */ @@ -4031,6 +4034,7 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, list_for_each_entry(fcport, &vha->vp_fcports, list) { fcport->scan_state = QLA_FCPORT_SCAN; + fcport->n2n_flag = 0; } fcport = qla2x00_find_fcport_by_wwpn(vha, @@ -4040,6 +4044,14 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, fcport->login_retry = vha->hw->login_retry_count; fcport->plogi_nack_done_deadline = jiffies + HZ; fcport->scan_state = QLA_FCPORT_FOUND; + fcport->keep_nport_handle = 1; + fcport->n2n_flag = 1; + fcport->d_id.b.domain = + rptid_entry->u.f2.remote_nport_id[2]; + fcport->d_id.b.area = + rptid_entry->u.f2.remote_nport_id[1]; + fcport->d_id.b.al_pa = + rptid_entry->u.f2.remote_nport_id[0]; } } } @@ -6213,10 +6225,8 @@ qla26xx_dport_diagnostics(scsi_qla_host_t *vha, return rval; } -static void qla2x00_async_mb_sp_done(void *s, int res) +static void qla2x00_async_mb_sp_done(srb_t *sp, int res) { - struct srb *sp = s; - sp->u.iocb_cmd.u.mbx.rc = res; complete(&sp->u.iocb_cmd.u.mbx.comp); diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index b2977e49356b..238240984bc1 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -66,6 +66,7 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha) uint16_t vp_id; struct qla_hw_data *ha = vha->hw; unsigned long flags = 0; + u8 i; mutex_lock(&ha->vport_lock); /* @@ -75,8 +76,11 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha) * ensures no active vp_list traversal while the vport is removed * from the queue) */ - wait_event_timeout(vha->vref_waitq, !atomic_read(&vha->vref_count), - 10*HZ); + for (i = 0; i < 10; i++) { + if (wait_event_timeout(vha->vref_waitq, + !atomic_read(&vha->vref_count), HZ) > 0) + break; + } spin_lock_irqsave(&ha->vport_slock, flags); if (atomic_read(&vha->vref_count)) { @@ -262,6 +266,9 @@ qla2x00_alert_all_vps(struct rsp_que *rsp, uint16_t *mb) spin_lock_irqsave(&ha->vport_slock, flags); list_for_each_entry(vha, &ha->vp_list, list) { if (vha->vp_idx) { + if (test_bit(VPORT_DELETE, &vha->dpc_flags)) + continue; + atomic_inc(&vha->vref_count); spin_unlock_irqrestore(&ha->vport_slock, flags); @@ -300,6 +307,20 @@ qla2x00_alert_all_vps(struct rsp_que *rsp, uint16_t *mb) int qla2x00_vp_abort_isp(scsi_qla_host_t *vha) { + fc_port_t *fcport; + + /* + * To exclusively reset vport, we need to log it out first. + * Note: This control_vp can fail if ISP reset is already + * issued, this is expected, as the vp would be already + * logged out due to ISP reset. + */ + if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) { + qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL); + list_for_each_entry(fcport, &vha->vp_fcports, list) + fcport->logout_on_delete = 0; + } + /* * Physical port will do most of the abort and recovery work. We can * just treat it as a loop down @@ -312,16 +333,9 @@ qla2x00_vp_abort_isp(scsi_qla_host_t *vha) atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); } - /* - * To exclusively reset vport, we need to log it out first. Note: this - * control_vp can fail if ISP reset is already issued, this is - * expected, as the vp would be already logged out due to ISP reset. - */ - if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) - qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL); - ql_dbg(ql_dbg_taskm, vha, 0x801d, "Scheduling enable of Vport %d.\n", vha->vp_idx); + return qla24xx_enable_vp(vha); } @@ -901,10 +915,8 @@ failed: return 0; } -static void qla_ctrlvp_sp_done(void *s, int res) +static void qla_ctrlvp_sp_done(srb_t *sp, int res) { - struct srb *sp = s; - if (sp->comp) complete(sp->comp); /* don't free sp here. Let the caller do the free */ diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c index 942ee13b96a4..605b59c76c90 100644 --- a/drivers/scsi/qla2xxx/qla_mr.c +++ b/drivers/scsi/qla2xxx/qla_mr.c @@ -10,7 +10,6 @@ #include <linux/pci.h> #include <linux/ratelimit.h> #include <linux/vmalloc.h> -#include <linux/bsg-lib.h> #include <scsi/scsi_tcq.h> #include <linux/utsname.h> @@ -149,7 +148,8 @@ qlafx00_mailbox_command(scsi_qla_host_t *vha, struct mbx_cmd_32 *mcp) QLAFX00_SET_HST_INTR(ha, ha->mbx_intr_code); spin_unlock_irqrestore(&ha->hardware_lock, flags); - wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ); + WARN_ON_ONCE(wait_for_completion_timeout(&ha->mbx_intr_comp, + mcp->tov * HZ) != 0); } else { ql_dbg(ql_dbg_mbx, vha, 0x112c, "Cmd=%x Polling Mode.\n", command); @@ -688,14 +688,12 @@ qlafx00_config_rings(struct scsi_qla_host *vha) } char * -qlafx00_pci_info_str(struct scsi_qla_host *vha, char *str) +qlafx00_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len) { struct qla_hw_data *ha = vha->hw; - if (pci_is_pcie(ha->pdev)) { - strcpy(str, "PCIe iSA"); - return str; - } + if (pci_is_pcie(ha->pdev)) + strlcpy(str, "PCIe iSA", str_len); return str; } @@ -1799,10 +1797,8 @@ qla2x00_fxdisc_iocb_timeout(void *data) complete(&lio->u.fxiocb.fxiocb_comp); } -static void -qla2x00_fxdisc_sp_done(void *ptr, int res) +static void qla2x00_fxdisc_sp_done(srb_t *sp, int res) { - srb_t *sp = ptr; struct srb_iocb *lio = &sp->u.iocb_cmd; complete(&lio->u.fxiocb.fxiocb_comp); @@ -1881,22 +1877,22 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type) phost_info = &preg_hsi->hsi; memset(preg_hsi, 0, sizeof(struct register_host_info)); phost_info->os_type = OS_TYPE_LINUX; - strncpy(phost_info->sysname, - p_sysid->sysname, SYSNAME_LENGTH); - strncpy(phost_info->nodename, - p_sysid->nodename, NODENAME_LENGTH); + strlcpy(phost_info->sysname, p_sysid->sysname, + sizeof(phost_info->sysname)); + strlcpy(phost_info->nodename, p_sysid->nodename, + sizeof(phost_info->nodename)); if (!strcmp(phost_info->nodename, "(none)")) ha->mr.host_info_resend = true; - strncpy(phost_info->release, - p_sysid->release, RELEASE_LENGTH); - strncpy(phost_info->version, - p_sysid->version, VERSION_LENGTH); - strncpy(phost_info->machine, - p_sysid->machine, MACHINE_LENGTH); - strncpy(phost_info->domainname, - p_sysid->domainname, DOMNAME_LENGTH); - strncpy(phost_info->hostdriver, - QLA2XXX_VERSION, VERSION_LENGTH); + strlcpy(phost_info->release, p_sysid->release, + sizeof(phost_info->release)); + strlcpy(phost_info->version, p_sysid->version, + sizeof(phost_info->version)); + strlcpy(phost_info->machine, p_sysid->machine, + sizeof(phost_info->machine)); + strlcpy(phost_info->domainname, p_sysid->domainname, + sizeof(phost_info->domainname)); + strlcpy(phost_info->hostdriver, QLA2XXX_VERSION, + sizeof(phost_info->hostdriver)); preg_hsi->utc = (uint64_t)ktime_get_real_seconds(); ql_dbg(ql_dbg_init, vha, 0x0149, "ISP%04X: Host registration with firmware\n", @@ -1941,8 +1937,10 @@ qlafx00_fx_disc(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t fx_type) if (fx_type == FXDISC_GET_CONFIG_INFO) { struct config_info_data *pinfo = (struct config_info_data *) fdisc->u.fxiocb.rsp_addr; - strcpy(vha->hw->model_number, pinfo->model_num); - strcpy(vha->hw->model_desc, pinfo->model_description); + strlcpy(vha->hw->model_number, pinfo->model_num, + ARRAY_SIZE(vha->hw->model_number)); + strlcpy(vha->hw->model_desc, pinfo->model_description, + ARRAY_SIZE(vha->hw->model_desc)); memcpy(&vha->hw->mr.symbolic_name, pinfo->symbolic_name, sizeof(vha->hw->mr.symbolic_name)); memcpy(&vha->hw->mr.serial_num, pinfo->serial_num, @@ -2541,6 +2539,8 @@ check_scsi_status: if (rsp->status_srb == NULL) sp->done(sp, res); + else + WARN_ON_ONCE(true); } /** @@ -2618,6 +2618,8 @@ qlafx00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt) if (sense_len == 0) { rsp->status_srb = NULL; sp->done(sp, cp->result); + } else { + WARN_ON_ONCE(true); } } @@ -3073,7 +3075,6 @@ qlafx00_start_scsi(srb_t *sp) { int nseg; unsigned long flags; - uint32_t index; uint32_t handle; uint16_t cnt; uint16_t req_cnt; @@ -3097,16 +3098,8 @@ qlafx00_start_scsi(srb_t *sp) /* Acquire ring specific lock */ spin_lock_irqsave(&ha->hardware_lock, flags); - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < req->num_outstanding_cmds; index++) { - handle++; - if (handle == req->num_outstanding_cmds) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - if (index == req->num_outstanding_cmds) + handle = qla2xxx_get_next_handle(req); + if (handle == 0) goto queuing_error; /* Map the sg table so we have an accurate count of sg entries needed */ diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 22e3fba28e51..6cc19e060afc 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -12,8 +12,6 @@ static struct nvme_fc_port_template qla_nvme_fc_transport; -static void qla_nvme_unregister_remote_port(struct work_struct *); - int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) { struct qla_nvme_rport *rport; @@ -38,7 +36,6 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) (fcport->nvme_flag & NVME_FLAG_REGISTERED)) return 0; - INIT_WORK(&fcport->nvme_del_work, qla_nvme_unregister_remote_port); fcport->nvme_flag &= ~NVME_FLAG_RESETTING; memset(&req, 0, sizeof(struct nvme_fc_port_info)); @@ -74,7 +71,6 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) rport = fcport->nvme_remote_port->private; rport->fcport = fcport; - list_add_tail(&rport->list, &vha->nvme_rport_list); fcport->nvme_flag |= NVME_FLAG_REGISTERED; return 0; @@ -124,53 +120,88 @@ static int qla_nvme_alloc_queue(struct nvme_fc_local_port *lport, return 0; } -static void qla_nvme_sp_ls_done(void *ptr, int res) +static void qla_nvme_release_fcp_cmd_kref(struct kref *kref) { - srb_t *sp = ptr; + struct srb *sp = container_of(kref, struct srb, cmd_kref); + struct nvme_private *priv = (struct nvme_private *)sp->priv; + struct nvmefc_fcp_req *fd; struct srb_iocb *nvme; - struct nvmefc_ls_req *fd; - struct nvme_private *priv; - - if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0)) - return; - - atomic_dec(&sp->ref_count); - - if (res) - res = -EINVAL; - - nvme = &sp->u.iocb_cmd; - fd = nvme->u.nvme.desc; - priv = fd->private; - priv->comp_status = res; - schedule_work(&priv->ls_work); - /* work schedule doesn't need the sp */ - qla2x00_rel_sp(sp); -} + unsigned long flags; -static void qla_nvme_sp_done(void *ptr, int res) -{ - srb_t *sp = ptr; - struct srb_iocb *nvme; - struct nvmefc_fcp_req *fd; + if (!priv) + goto out; nvme = &sp->u.iocb_cmd; fd = nvme->u.nvme.desc; - if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0)) - return; - - atomic_dec(&sp->ref_count); - - if (res == QLA_SUCCESS) { + spin_lock_irqsave(&priv->cmd_lock, flags); + priv->sp = NULL; + sp->priv = NULL; + if (priv->comp_status == QLA_SUCCESS) { fd->rcv_rsplen = nvme->u.nvme.rsp_pyld_len; } else { fd->rcv_rsplen = 0; fd->transferred_length = 0; } fd->status = 0; + spin_unlock_irqrestore(&priv->cmd_lock, flags); + fd->done(fd); +out: qla2xxx_rel_qpair_sp(sp->qpair, sp); +} + +static void qla_nvme_release_ls_cmd_kref(struct kref *kref) +{ + struct srb *sp = container_of(kref, struct srb, cmd_kref); + struct nvme_private *priv = (struct nvme_private *)sp->priv; + struct nvmefc_ls_req *fd; + unsigned long flags; + + if (!priv) + goto out; + + spin_lock_irqsave(&priv->cmd_lock, flags); + priv->sp = NULL; + sp->priv = NULL; + spin_unlock_irqrestore(&priv->cmd_lock, flags); + + fd = priv->fd; + fd->done(fd, priv->comp_status); +out: + qla2x00_rel_sp(sp); +} + +static void qla_nvme_ls_complete(struct work_struct *work) +{ + struct nvme_private *priv = + container_of(work, struct nvme_private, ls_work); + + kref_put(&priv->sp->cmd_kref, qla_nvme_release_ls_cmd_kref); +} + +static void qla_nvme_sp_ls_done(srb_t *sp, int res) +{ + struct nvme_private *priv = sp->priv; + + if (WARN_ON_ONCE(kref_read(&sp->cmd_kref) == 0)) + return; + + if (res) + res = -EINVAL; + + priv->comp_status = res; + INIT_WORK(&priv->ls_work, qla_nvme_ls_complete); + schedule_work(&priv->ls_work); +} + +/* it assumed that QPair lock is held. */ +static void qla_nvme_sp_done(srb_t *sp, int res) +{ + struct nvme_private *priv = sp->priv; + + priv->comp_status = res; + kref_put(&sp->cmd_kref, qla_nvme_release_fcp_cmd_kref); return; } @@ -188,44 +219,49 @@ static void qla_nvme_abort_work(struct work_struct *work) "%s called for sp=%p, hndl=%x on fcport=%p deleted=%d\n", __func__, sp, sp->handle, fcport, fcport->deleted); - if (!ha->flags.fw_started && (fcport && fcport->deleted)) - return; + if (!ha->flags.fw_started && fcport->deleted) + goto out; if (ha->flags.host_shutting_down) { ql_log(ql_log_info, sp->fcport->vha, 0xffff, "%s Calling done on sp: %p, type: 0x%x, sp->ref_count: 0x%x\n", __func__, sp, sp->type, atomic_read(&sp->ref_count)); sp->done(sp, 0); - return; + goto out; } - if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0)) - return; - rval = ha->isp_ops->abort_command(sp); ql_dbg(ql_dbg_io, fcport->vha, 0x212b, "%s: %s command for sp=%p, handle=%x on fcport=%p rval=%x\n", __func__, (rval != QLA_SUCCESS) ? "Failed to abort" : "Aborted", sp, sp->handle, fcport, rval); + +out: + /* kref_get was done before work was schedule. */ + kref_put(&sp->cmd_kref, sp->put_fn); } static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport, struct nvme_fc_remote_port *rport, struct nvmefc_ls_req *fd) { struct nvme_private *priv = fd->private; + unsigned long flags; - INIT_WORK(&priv->abort_work, qla_nvme_abort_work); - schedule_work(&priv->abort_work); -} + spin_lock_irqsave(&priv->cmd_lock, flags); + if (!priv->sp) { + spin_unlock_irqrestore(&priv->cmd_lock, flags); + return; + } -static void qla_nvme_ls_complete(struct work_struct *work) -{ - struct nvme_private *priv = - container_of(work, struct nvme_private, ls_work); - struct nvmefc_ls_req *fd = priv->fd; + if (!kref_get_unless_zero(&priv->sp->cmd_kref)) { + spin_unlock_irqrestore(&priv->cmd_lock, flags); + return; + } + spin_unlock_irqrestore(&priv->cmd_lock, flags); - fd->done(fd, priv->comp_status); + INIT_WORK(&priv->abort_work, qla_nvme_abort_work); + schedule_work(&priv->abort_work); } static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, @@ -240,8 +276,16 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, struct qla_hw_data *ha; srb_t *sp; + + if (!fcport || (fcport && fcport->deleted)) + return rval; + vha = fcport->vha; ha = vha->hw; + + if (!ha->flags.fw_started) + return rval; + /* Alloc SRB structure */ sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC); if (!sp) @@ -250,11 +294,13 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, sp->type = SRB_NVME_LS; sp->name = "nvme_ls"; sp->done = qla_nvme_sp_ls_done; - atomic_set(&sp->ref_count, 1); - nvme = &sp->u.iocb_cmd; + sp->put_fn = qla_nvme_release_ls_cmd_kref; + sp->priv = (void *)priv; priv->sp = sp; + kref_init(&sp->cmd_kref); + spin_lock_init(&priv->cmd_lock); + nvme = &sp->u.iocb_cmd; priv->fd = fd; - INIT_WORK(&priv->ls_work, qla_nvme_ls_complete); nvme->u.nvme.desc = fd; nvme->u.nvme.dir = 0; nvme->u.nvme.dl = 0; @@ -271,8 +317,10 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x700e, "qla2x00_start_sp failed = %d\n", rval); - atomic_dec(&sp->ref_count); wake_up(&sp->nvme_ls_waitq); + sp->priv = NULL; + priv->sp = NULL; + qla2x00_rel_sp(sp); return rval; } @@ -284,6 +332,18 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport, struct nvmefc_fcp_req *fd) { struct nvme_private *priv = fd->private; + unsigned long flags; + + spin_lock_irqsave(&priv->cmd_lock, flags); + if (!priv->sp) { + spin_unlock_irqrestore(&priv->cmd_lock, flags); + return; + } + if (!kref_get_unless_zero(&priv->sp->cmd_kref)) { + spin_unlock_irqrestore(&priv->cmd_lock, flags); + return; + } + spin_unlock_irqrestore(&priv->cmd_lock, flags); INIT_WORK(&priv->abort_work, qla_nvme_abort_work); schedule_work(&priv->abort_work); @@ -293,7 +353,6 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) { unsigned long flags; uint32_t *clr_ptr; - uint32_t index; uint32_t handle; struct cmd_nvme *cmd_pkt; uint16_t cnt, i; @@ -317,17 +376,8 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) /* Acquire qpair specific lock */ spin_lock_irqsave(&qpair->qp_lock, flags); - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < req->num_outstanding_cmds; index++) { - handle++; - if (handle == req->num_outstanding_cmds) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - - if (index == req->num_outstanding_cmds) { + handle = qla2xxx_get_next_handle(req); + if (handle == 0) { rval = -EBUSY; goto queuing_error; } @@ -487,11 +537,11 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, fcport = qla_rport->fcport; - vha = fcport->vha; - - if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) + if (!qpair || !fcport || (qpair && !qpair->fw_started) || + (fcport && fcport->deleted)) return rval; + vha = fcport->vha; /* * If we know the dev is going away while the transport is still sending * IO's return busy back to stall the IO Q. This happens when the @@ -507,12 +557,15 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, if (!sp) return -EBUSY; - atomic_set(&sp->ref_count, 1); init_waitqueue_head(&sp->nvme_ls_waitq); + kref_init(&sp->cmd_kref); + spin_lock_init(&priv->cmd_lock); + sp->priv = (void *)priv; priv->sp = sp; sp->type = SRB_NVME_CMD; sp->name = "nvme_cmd"; sp->done = qla_nvme_sp_done; + sp->put_fn = qla_nvme_release_fcp_cmd_kref; sp->qpair = qpair; sp->vha = vha; nvme = &sp->u.iocb_cmd; @@ -522,8 +575,10 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x212d, "qla2x00_start_nvme_mq failed = %d\n", rval); - atomic_dec(&sp->ref_count); wake_up(&sp->nvme_ls_waitq); + sp->priv = NULL; + priv->sp = NULL; + qla2xxx_rel_qpair_sp(sp->qpair, sp); } return rval; @@ -542,29 +597,16 @@ static void qla_nvme_localport_delete(struct nvme_fc_local_port *lport) static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport) { fc_port_t *fcport; - struct qla_nvme_rport *qla_rport = rport->private, *trport; + struct qla_nvme_rport *qla_rport = rport->private; fcport = qla_rport->fcport; fcport->nvme_remote_port = NULL; fcport->nvme_flag &= ~NVME_FLAG_REGISTERED; - - list_for_each_entry_safe(qla_rport, trport, - &fcport->vha->nvme_rport_list, list) { - if (qla_rport->fcport == fcport) { - list_del(&qla_rport->list); - break; - } - } - complete(&fcport->nvme_del_done); - - if (!test_bit(UNLOADING, &fcport->vha->dpc_flags)) { - INIT_WORK(&fcport->free_work, qlt_free_session_done); - schedule_work(&fcport->free_work); - } - fcport->nvme_flag &= ~NVME_FLAG_DELETING; ql_log(ql_log_info, fcport->vha, 0x2110, - "remoteport_delete of %p completed.\n", fcport); + "remoteport_delete of %p %8phN completed.\n", + fcport, fcport->port_name); + complete(&fcport->nvme_del_done); } static struct nvme_fc_port_template qla_nvme_fc_transport = { @@ -586,35 +628,27 @@ static struct nvme_fc_port_template qla_nvme_fc_transport = { .fcprqst_priv_sz = sizeof(struct nvme_private), }; -static void qla_nvme_unregister_remote_port(struct work_struct *work) +void qla_nvme_unregister_remote_port(struct fc_port *fcport) { - struct fc_port *fcport = container_of(work, struct fc_port, - nvme_del_work); - struct qla_nvme_rport *qla_rport, *trport; + int ret; if (!IS_ENABLED(CONFIG_NVME_FC)) return; ql_log(ql_log_warn, NULL, 0x2112, - "%s: unregister remoteport on %p\n",__func__, fcport); - - list_for_each_entry_safe(qla_rport, trport, - &fcport->vha->nvme_rport_list, list) { - if (qla_rport->fcport == fcport) { - ql_log(ql_log_info, fcport->vha, 0x2113, - "%s: fcport=%p\n", __func__, fcport); - nvme_fc_set_remoteport_devloss - (fcport->nvme_remote_port, 0); - init_completion(&fcport->nvme_del_done); - if (nvme_fc_unregister_remoteport - (fcport->nvme_remote_port)) - ql_log(ql_log_info, fcport->vha, 0x2114, - "%s: Failed to unregister nvme_remote_port\n", - __func__); - wait_for_completion(&fcport->nvme_del_done); - break; - } - } + "%s: unregister remoteport on %p %8phN\n", + __func__, fcport, fcport->port_name); + + if (test_bit(PFLG_DRIVER_REMOVING, &fcport->vha->pci_flags)) + nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0); + + init_completion(&fcport->nvme_del_done); + ret = nvme_fc_unregister_remoteport(fcport->nvme_remote_port); + if (ret) + ql_log(ql_log_info, fcport->vha, 0x2114, + "%s: Failed to unregister nvme_remote_port (%d)\n", + __func__, ret); + wait_for_completion(&fcport->nvme_del_done); } void qla_nvme_delete(struct scsi_qla_host *vha) diff --git a/drivers/scsi/qla2xxx/qla_nvme.h b/drivers/scsi/qla2xxx/qla_nvme.h index d3b8a6440113..ef912902d4e5 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.h +++ b/drivers/scsi/qla2xxx/qla_nvme.h @@ -7,7 +7,6 @@ #ifndef __QLA_NVME_H #define __QLA_NVME_H -#include <linux/blk-mq.h> #include <uapi/scsi/fc/fc_fs.h> #include <uapi/scsi/fc/fc_els.h> #include <linux/nvme-fc-driver.h> @@ -34,10 +33,10 @@ struct nvme_private { struct work_struct ls_work; struct work_struct abort_work; int comp_status; + spinlock_t cmd_lock; }; struct qla_nvme_rport { - struct list_head list; struct fc_port *fcport; }; @@ -119,7 +118,7 @@ struct pt_ls4_rx_unsol { uint32_t exchange_address; uint8_t d_id[3]; uint8_t r_ctl; - uint8_t s_id[3]; + be_id_t s_id; uint8_t cs_ctl; uint8_t f_ctl[3]; uint8_t type; @@ -144,5 +143,5 @@ int qla_nvme_register_remote(struct scsi_qla_host *, struct fc_port *); void qla_nvme_delete(struct scsi_qla_host *); void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *, struct pt_ls4_request *, struct req_que *); -void qla24xx_async_gffid_sp_done(void *, int); +void qla24xx_async_gffid_sp_done(struct srb *sp, int); #endif diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index c760ae354174..2b2028f2383e 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1977,7 +1977,7 @@ qla82xx_check_rcvpeg_state(struct qla_hw_data *ha) } while (--retries); ql_log(ql_log_fatal, vha, 0x00ac, - "Rcv Peg initializatin failed: 0x%x.\n", val); + "Rcv Peg initialization failed: 0x%x.\n", val); read_lock(&ha->hw_lock); qla82xx_wr_32(ha, CRB_RCVPEG_STATE, PHAN_INITIALIZE_FAILED); read_unlock(&ha->hw_lock); @@ -1985,7 +1985,7 @@ qla82xx_check_rcvpeg_state(struct qla_hw_data *ha) } /* ISR related functions */ -static struct qla82xx_legacy_intr_set legacy_intr[] = \ +static struct qla82xx_legacy_intr_set legacy_intr[] = QLA82XX_LEGACY_INTR_CONFIG; /* @@ -2287,7 +2287,9 @@ qla82xx_disable_intrs(struct qla_hw_data *ha) { scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - qla82xx_mbx_intr_disable(vha); + if (ha->interrupts_on) + qla82xx_mbx_intr_disable(vha); + spin_lock_irq(&ha->hardware_lock); if (IS_QLA8044(ha)) qla8044_wr_reg(ha, LEG_INTR_MASK_OFFSET, 1); @@ -3286,7 +3288,7 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) case QLA8XXX_DEV_NEED_QUIESCENT: qla82xx_need_qsnt_handler(vha); /* Reset timeout value after quiescence handler */ - dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout\ + dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout * HZ); break; case QLA8XXX_DEV_QUIESCENT: @@ -3301,7 +3303,7 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) qla82xx_idc_lock(ha); /* Reset timeout value after quiescence handler */ - dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout\ + dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout * HZ); break; case QLA8XXX_DEV_FAILED: @@ -3686,7 +3688,7 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha) for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) { sp = req->outstanding_cmds[cnt]; if (sp) { - if ((!sp->u.scmd.ctx || + if ((!sp->u.scmd.crc_ctx || (sp->flags & SRB_FCP_CMND_DMA_VALID)) && !ha->flags.isp82xx_fw_hung) { @@ -3710,10 +3712,12 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha) /* Wait for pending cmds (physical and virtual) to complete */ if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, - WAIT_HOST)) { + WAIT_HOST) == QLA_SUCCESS) { ql_dbg(ql_dbg_init, vha, 0x00b3, "Done wait for " "pending commands.\n"); + } else { + WARN_ON_ONCE(true); } } } @@ -4232,7 +4236,7 @@ qla82xx_md_collect(scsi_qla_host_t *vha) goto md_failed; } - entry_hdr = (qla82xx_md_entry_hdr_t *) \ + entry_hdr = (qla82xx_md_entry_hdr_t *) (((uint8_t *)ha->md_tmplt_hdr) + tmplt_hdr->first_entry_offset); /* Walk through the entry headers */ @@ -4339,7 +4343,7 @@ qla82xx_md_collect(scsi_qla_host_t *vha) data_collected = (uint8_t *)data_ptr - (uint8_t *)ha->md_dump; skip_nxt_entry: - entry_hdr = (qla82xx_md_entry_hdr_t *) \ + entry_hdr = (qla82xx_md_entry_hdr_t *) (((uint8_t *)entry_hdr) + entry_hdr->entry_size); } diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index 3c7beef92c35..230abee10598 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -486,13 +486,13 @@ #define QLA82XX_ADDR_QDR_NET (0x0000000300000000ULL) #define QLA82XX_P3_ADDR_QDR_NET_MAX (0x0000000303ffffffULL) -#define QLA82XX_PCI_CRBSPACE (unsigned long)0x06000000 -#define QLA82XX_PCI_DIRECT_CRB (unsigned long)0x04400000 -#define QLA82XX_PCI_CAMQM (unsigned long)0x04800000 -#define QLA82XX_PCI_CAMQM_MAX (unsigned long)0x04ffffff -#define QLA82XX_PCI_DDR_NET (unsigned long)0x00000000 -#define QLA82XX_PCI_QDR_NET (unsigned long)0x04000000 -#define QLA82XX_PCI_QDR_NET_MAX (unsigned long)0x043fffff +#define QLA82XX_PCI_CRBSPACE 0x06000000UL +#define QLA82XX_PCI_DIRECT_CRB 0x04400000UL +#define QLA82XX_PCI_CAMQM 0x04800000UL +#define QLA82XX_PCI_CAMQM_MAX 0x04ffffffUL +#define QLA82XX_PCI_DDR_NET 0x00000000UL +#define QLA82XX_PCI_QDR_NET 0x04000000UL +#define QLA82XX_PCI_QDR_NET_MAX 0x043fffffUL /* * Register offsets for MN diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c index 369ac04d0454..c056f466f1f4 100644 --- a/drivers/scsi/qla2xxx/qla_nx2.c +++ b/drivers/scsi/qla2xxx/qla_nx2.c @@ -2810,7 +2810,7 @@ error: #define ISP8044_PEX_DMA_ENGINE_INDEX 8 #define ISP8044_PEX_DMA_BASE_ADDRESS 0x77320000 -#define ISP8044_PEX_DMA_NUM_OFFSET 0x10000 +#define ISP8044_PEX_DMA_NUM_OFFSET 0x10000UL #define ISP8044_PEX_DMA_CMD_ADDR_LOW 0x0 #define ISP8044_PEX_DMA_CMD_ADDR_HIGH 0x04 #define ISP8044_PEX_DMA_CMD_STS_AND_CNTRL 0x08 diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index d056f5e7cf93..726ad4cbf4a6 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -69,7 +69,7 @@ MODULE_PARM_DESC(ql2xplogiabsentdevice, "a Fabric scan. This is needed for several broken switches. " "Default is 0 - no PLOGI. 1 - perform PLOGI."); -int ql2xloginretrycount = 0; +int ql2xloginretrycount; module_param(ql2xloginretrycount, int, S_IRUGO); MODULE_PARM_DESC(ql2xloginretrycount, "Specify an alternate value for the NVRAM login retry count."); @@ -234,7 +234,7 @@ MODULE_PARM_DESC(ql2xmdenable, "0 - MiniDump disabled. " "1 (Default) - MiniDump enabled."); -int ql2xexlogins = 0; +int ql2xexlogins; module_param(ql2xexlogins, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xexlogins, "Number of extended Logins. " @@ -250,7 +250,7 @@ module_param(ql2xiniexchg, uint, 0644); MODULE_PARM_DESC(ql2xiniexchg, "Number of initiator exchanges."); -int ql2xfwholdabts = 0; +int ql2xfwholdabts; module_param(ql2xfwholdabts, int, S_IRUGO); MODULE_PARM_DESC(ql2xfwholdabts, "Allow FW to hold status IOCB until ABTS rsp received. " @@ -536,80 +536,70 @@ static void qla2x00_free_queues(struct qla_hw_data *ha) } static char * -qla2x00_pci_info_str(struct scsi_qla_host *vha, char *str) +qla2x00_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len) { struct qla_hw_data *ha = vha->hw; - static char *pci_bus_modes[] = { + static const char *const pci_bus_modes[] = { "33", "66", "100", "133", }; uint16_t pci_bus; - strcpy(str, "PCI"); pci_bus = (ha->pci_attr & (BIT_9 | BIT_10)) >> 9; if (pci_bus) { - strcat(str, "-X ("); - strcat(str, pci_bus_modes[pci_bus]); + snprintf(str, str_len, "PCI-X (%s MHz)", + pci_bus_modes[pci_bus]); } else { pci_bus = (ha->pci_attr & BIT_8) >> 8; - strcat(str, " ("); - strcat(str, pci_bus_modes[pci_bus]); + snprintf(str, str_len, "PCI (%s MHz)", pci_bus_modes[pci_bus]); } - strcat(str, " MHz)"); - return (str); + return str; } static char * -qla24xx_pci_info_str(struct scsi_qla_host *vha, char *str) +qla24xx_pci_info_str(struct scsi_qla_host *vha, char *str, size_t str_len) { - static char *pci_bus_modes[] = { "33", "66", "100", "133", }; + static const char *const pci_bus_modes[] = { + "33", "66", "100", "133", + }; struct qla_hw_data *ha = vha->hw; uint32_t pci_bus; if (pci_is_pcie(ha->pdev)) { - char lwstr[6]; uint32_t lstat, lspeed, lwidth; + const char *speed_str; pcie_capability_read_dword(ha->pdev, PCI_EXP_LNKCAP, &lstat); lspeed = lstat & PCI_EXP_LNKCAP_SLS; lwidth = (lstat & PCI_EXP_LNKCAP_MLW) >> 4; - strcpy(str, "PCIe ("); switch (lspeed) { case 1: - strcat(str, "2.5GT/s "); + speed_str = "2.5GT/s"; break; case 2: - strcat(str, "5.0GT/s "); + speed_str = "5.0GT/s"; break; case 3: - strcat(str, "8.0GT/s "); + speed_str = "8.0GT/s"; break; default: - strcat(str, "<unknown> "); + speed_str = "<unknown>"; break; } - snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth); - strcat(str, lwstr); + snprintf(str, str_len, "PCIe (%s x%d)", speed_str, lwidth); return str; } - strcpy(str, "PCI"); pci_bus = (ha->pci_attr & CSRX_PCIX_BUS_MODE_MASK) >> 8; - if (pci_bus == 0 || pci_bus == 8) { - strcat(str, " ("); - strcat(str, pci_bus_modes[pci_bus >> 3]); - } else { - strcat(str, "-X "); - if (pci_bus & BIT_2) - strcat(str, "Mode 2"); - else - strcat(str, "Mode 1"); - strcat(str, " ("); - strcat(str, pci_bus_modes[pci_bus & ~BIT_2]); - } - strcat(str, " MHz)"); + if (pci_bus == 0 || pci_bus == 8) + snprintf(str, str_len, "PCI (%s MHz)", + pci_bus_modes[pci_bus >> 3]); + else + snprintf(str, str_len, "PCI-X Mode %d (%s MHz)", + pci_bus & 4 ? 2 : 1, + pci_bus_modes[pci_bus & 3]); return str; } @@ -662,13 +652,10 @@ qla24xx_fw_version_str(struct scsi_qla_host *vha, char *str, size_t size) return str; } -void -qla2x00_sp_free_dma(void *ptr) +void qla2x00_sp_free_dma(srb_t *sp) { - srb_t *sp = ptr; struct qla_hw_data *ha = sp->vha->hw; struct scsi_cmnd *cmd = GET_CMD_SP(sp); - void *ctx = GET_CMD_CTX_SP(sp); if (sp->flags & SRB_DMA_VALID) { scsi_dma_unmap(cmd); @@ -681,24 +668,21 @@ qla2x00_sp_free_dma(void *ptr) sp->flags &= ~SRB_CRC_PROT_DMA_VALID; } - if (!ctx) - return; - if (sp->flags & SRB_CRC_CTX_DSD_VALID) { /* List assured to be having elements */ - qla2x00_clean_dsd_pool(ha, ctx); + qla2x00_clean_dsd_pool(ha, sp->u.scmd.crc_ctx); sp->flags &= ~SRB_CRC_CTX_DSD_VALID; } if (sp->flags & SRB_CRC_CTX_DMA_VALID) { - struct crc_context *ctx0 = ctx; + struct crc_context *ctx0 = sp->u.scmd.crc_ctx; dma_pool_free(ha->dl_dma_pool, ctx0, ctx0->crc_ctx_dma); sp->flags &= ~SRB_CRC_CTX_DMA_VALID; } if (sp->flags & SRB_FCP_CMND_DMA_VALID) { - struct ct6_dsd *ctx1 = ctx; + struct ct6_dsd *ctx1 = sp->u.scmd.ct6_ctx; dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd, ctx1->fcp_cmnd_dma); @@ -709,10 +693,8 @@ qla2x00_sp_free_dma(void *ptr) } } -void -qla2x00_sp_compl(void *ptr, int res) +void qla2x00_sp_compl(srb_t *sp, int res) { - srb_t *sp = ptr; struct scsi_cmnd *cmd = GET_CMD_SP(sp); struct completion *comp = sp->comp; @@ -727,16 +709,12 @@ qla2x00_sp_compl(void *ptr, int res) cmd->scsi_done(cmd); if (comp) complete(comp); - qla2x00_rel_sp(sp); } -void -qla2xxx_qpair_sp_free_dma(void *ptr) +void qla2xxx_qpair_sp_free_dma(srb_t *sp) { - srb_t *sp = (srb_t *)ptr; struct scsi_cmnd *cmd = GET_CMD_SP(sp); struct qla_hw_data *ha = sp->fcport->vha->hw; - void *ctx = GET_CMD_CTX_SP(sp); if (sp->flags & SRB_DMA_VALID) { scsi_dma_unmap(cmd); @@ -749,17 +727,14 @@ qla2xxx_qpair_sp_free_dma(void *ptr) sp->flags &= ~SRB_CRC_PROT_DMA_VALID; } - if (!ctx) - return; - if (sp->flags & SRB_CRC_CTX_DSD_VALID) { /* List assured to be having elements */ - qla2x00_clean_dsd_pool(ha, ctx); + qla2x00_clean_dsd_pool(ha, sp->u.scmd.crc_ctx); sp->flags &= ~SRB_CRC_CTX_DSD_VALID; } if (sp->flags & SRB_DIF_BUNDL_DMA_VALID) { - struct crc_context *difctx = ctx; + struct crc_context *difctx = sp->u.scmd.crc_ctx; struct dsd_dma *dif_dsd, *nxt_dsd; list_for_each_entry_safe(dif_dsd, nxt_dsd, @@ -795,7 +770,7 @@ qla2xxx_qpair_sp_free_dma(void *ptr) } if (sp->flags & SRB_FCP_CMND_DMA_VALID) { - struct ct6_dsd *ctx1 = ctx; + struct ct6_dsd *ctx1 = sp->u.scmd.ct6_ctx; dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd, ctx1->fcp_cmnd_dma); @@ -807,17 +782,15 @@ qla2xxx_qpair_sp_free_dma(void *ptr) } if (sp->flags & SRB_CRC_CTX_DMA_VALID) { - struct crc_context *ctx0 = ctx; + struct crc_context *ctx0 = sp->u.scmd.crc_ctx; - dma_pool_free(ha->dl_dma_pool, ctx, ctx0->crc_ctx_dma); + dma_pool_free(ha->dl_dma_pool, ctx0, ctx0->crc_ctx_dma); sp->flags &= ~SRB_CRC_CTX_DMA_VALID; } } -void -qla2xxx_qpair_sp_compl(void *ptr, int res) +void qla2xxx_qpair_sp_compl(srb_t *sp, int res) { - srb_t *sp = ptr; struct scsi_cmnd *cmd = GET_CMD_SP(sp); struct completion *comp = sp->comp; @@ -832,7 +805,6 @@ qla2xxx_qpair_sp_compl(void *ptr, int res) cmd->scsi_done(cmd); if (comp) complete(comp); - qla2xxx_rel_qpair_sp(sp->qpair, sp); } static int @@ -845,9 +817,6 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); srb_t *sp; int rval; - struct qla_qpair *qpair = NULL; - uint32_t tag; - uint16_t hwq; if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags)) || WARN_ON_ONCE(!rport)) { @@ -856,6 +825,10 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) } if (ha->mqenable) { + uint32_t tag; + uint16_t hwq; + struct qla_qpair *qpair = NULL; + tag = blk_mq_unique_tag(cmd->request); hwq = blk_mq_unique_tag_to_hwq(tag); qpair = ha->queue_pair_map[hwq]; @@ -925,9 +898,8 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) else goto qc24_target_busy; - sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC); - if (!sp) - goto qc24_host_busy; + sp = scsi_cmd_priv(cmd); + qla2xxx_init_sp(sp, vha, vha->hw->base_qpair, fcport); sp->u.scmd.cmd = cmd; sp->type = SRB_SCSI_CMD; @@ -948,9 +920,6 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) qc24_host_busy_free_sp: sp->free(sp); -qc24_host_busy: - return SCSI_MLQUEUE_HOST_BUSY; - qc24_target_busy: return SCSI_MLQUEUE_TARGET_BUSY; @@ -1011,9 +980,8 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, else goto qc24_target_busy; - sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, GFP_ATOMIC); - if (!sp) - goto qc24_host_busy; + sp = scsi_cmd_priv(cmd); + qla2xxx_init_sp(sp, vha, qpair, fcport); sp->u.scmd.cmd = cmd; sp->type = SRB_SCSI_CMD; @@ -1037,9 +1005,6 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, qc24_host_busy_free_sp: sp->free(sp); -qc24_host_busy: - return SCSI_MLQUEUE_HOST_BUSY; - qc24_target_busy: return SCSI_MLQUEUE_TARGET_BUSY; @@ -1058,8 +1023,8 @@ qc24_fail_command: * cmd = Scsi Command to wait on. * * Return: - * Not Found : 0 - * Found : 1 + * Completed in time : QLA_SUCCESS + * Did not complete in time : QLA_FUNCTION_FAILED */ static int qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd) @@ -1150,9 +1115,17 @@ static inline int test_fcport_count(scsi_qla_host_t *vha) void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *vha) { + u8 i; + qla2x00_mark_all_devices_lost(vha, 0); - wait_event_timeout(vha->fcport_waitQ, test_fcport_count(vha), 10*HZ); + for (i = 0; i < 10; i++) { + if (wait_event_timeout(vha->fcport_waitQ, + test_fcport_count(vha), HZ) > 0) + break; + } + + flush_workqueue(vha->hw->wq); } /* @@ -1269,14 +1242,13 @@ static int qla2xxx_eh_abort(struct scsi_cmnd *cmd) { scsi_qla_host_t *vha = shost_priv(cmd->device->host); + DECLARE_COMPLETION_ONSTACK(comp); srb_t *sp; int ret; unsigned int id; uint64_t lun; - unsigned long flags; int rval; struct qla_hw_data *ha = vha->hw; - struct qla_qpair *qpair; if (qla2x00_isp_reg_stat(ha)) { ql_log(ql_log_info, vha, 0x8042, @@ -1288,28 +1260,14 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) if (ret != 0) return ret; - sp = (srb_t *) CMD_SP(cmd); - if (!sp) - return SUCCESS; + sp = scsi_cmd_priv(cmd); - qpair = sp->qpair; - if (!qpair) + if (sp->fcport && sp->fcport->deleted) return SUCCESS; - spin_lock_irqsave(qpair->qp_lock_ptr, flags); - if (sp->type != SRB_SCSI_CMD || GET_CMD_SP(sp) != cmd) { - /* there's a chance an interrupt could clear - the ptr as part of done & free */ - spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + /* Return if the command has already finished. */ + if (sp_get(sp)) return SUCCESS; - } - - if (sp_get(sp)){ - /* ref_count is already 0 */ - spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); - return SUCCESS; - } - spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); id = cmd->device->id; lun = cmd->device->lun; @@ -1331,6 +1289,23 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) sp->done(sp, DID_ABORT << 16); ret = SUCCESS; break; + case QLA_FUNCTION_PARAMETER_ERROR: { + /* Wait for the command completion. */ + uint32_t ratov = ha->r_a_tov/10; + uint32_t ratov_j = msecs_to_jiffies(4 * ratov * 1000); + + WARN_ON_ONCE(sp->comp); + sp->comp = ∁ + if (!wait_for_completion_timeout(&comp, ratov_j)) { + ql_dbg(ql_dbg_taskm, vha, 0xffff, + "%s: Abort wait timer (4 * R_A_TOV[%d]) expired\n", + __func__, ha->r_a_tov); + ret = FAILED; + } else { + ret = SUCCESS; + } + break; + } default: /* * Either abort failed or abort and completion raced. Let @@ -1340,6 +1315,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) break; } + sp->comp = NULL; + atomic_dec(&sp->ref_count); ql_log(ql_log_info, vha, 0x801c, "Abort command issued nexus=%ld:%d:%llu -- %x.\n", vha->host_no, id, lun, ret); @@ -1347,6 +1324,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) return ret; } +/* + * Returns: QLA_SUCCESS or QLA_FUNCTION_FAILED. + */ int qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t, uint64_t l, enum nexus_wait_type type) @@ -1420,6 +1400,9 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, if (err != 0) return err; + if (fcport->deleted) + return SUCCESS; + ql_log(ql_log_info, vha, 0x8009, "%s RESET ISSUED nexus=%ld:%d:%llu cmd=%p.\n", name, vha->host_no, cmd->device->id, cmd->device->lun, cmd); @@ -1534,6 +1517,9 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) return ret; ret = FAILED; + if (qla2x00_chip_is_down(vha)) + return ret; + ql_log(ql_log_info, vha, 0x8012, "BUS RESET ISSUED nexus=%ld:%d:%llu.\n", vha->host_no, id, lun); @@ -1746,6 +1732,8 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, spin_lock_irqsave(qp->qp_lock_ptr, *flags); sp->comp = NULL; } + + atomic_dec(&sp->ref_count); } static void @@ -1800,8 +1788,13 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) int que; struct qla_hw_data *ha = vha->hw; + /* Continue only if initialization complete. */ + if (!ha->base_qpair) + return; __qla2x00_abort_all_cmds(ha->base_qpair, res); + if (!ha->queue_pair_map) + return; for (que = 0; que < ha->max_qpairs; que++) { if (!ha->queue_pair_map[que]) continue; @@ -2477,7 +2470,7 @@ static struct isp_operations qla27xx_isp_ops = { .config_rings = qla24xx_config_rings, .reset_adapter = qla24xx_reset_adapter, .nvram_config = qla81xx_nvram_config, - .update_fw_options = qla81xx_update_fw_options, + .update_fw_options = qla24xx_update_fw_options, .load_risc = qla81xx_load_risc, .pci_info_str = qla24xx_pci_info_str, .fw_version_str = qla24xx_fw_version_str, @@ -3154,6 +3147,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ql_log(ql_log_fatal, base_vha, 0x003d, "Failed to allocate memory for queue pointers..." "aborting.\n"); + ret = -ENODEV; goto probe_failed; } @@ -3232,6 +3226,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) req->req_q_in, req->req_q_out, rsp->rsp_q_in, rsp->rsp_q_out); ha->wq = alloc_workqueue("qla2xxx_wq", 0, 0); + if (unlikely(!ha->wq)) { + ret = -ENOMEM; + goto probe_failed; + } if (ha->isp_ops->initialize_adapter(base_vha)) { ql_log(ql_log_fatal, base_vha, 0x00d6, @@ -3418,7 +3416,8 @@ skip_dpc: "QLogic %s - %s.\n", ha->model_number, ha->model_desc); ql_log(ql_log_info, base_vha, 0x00fc, "ISP%04X: %s @ %s hdma%c host#=%ld fw=%s.\n", - pdev->device, ha->isp_ops->pci_info_str(base_vha, pci_info), + pdev->device, ha->isp_ops->pci_info_str(base_vha, pci_info, + sizeof(pci_info)), pci_name(pdev), ha->flags.enable_64bit_addressing ? '+' : '-', base_vha->host_no, ha->isp_ops->fw_version_str(base_vha, fw_str, sizeof(fw_str))); @@ -3440,6 +3439,12 @@ skip_dpc: return 0; probe_failed: + if (base_vha->gnl.l) { + dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size, + base_vha->gnl.l, base_vha->gnl.ldma); + base_vha->gnl.l = NULL; + } + if (base_vha->timer_active) qla2x00_stop_timer(base_vha); base_vha->flags.online = 0; @@ -3532,6 +3537,10 @@ qla2x00_shutdown(struct pci_dev *pdev) qla2x00_try_to_stop_firmware(vha); } + /* Disable timer */ + if (vha->timer_active) + qla2x00_stop_timer(vha); + /* Turn adapter off line */ vha->flags.online = 0; @@ -3673,7 +3682,7 @@ qla2x00_remove_one(struct pci_dev *pdev) if (!atomic_read(&pdev->enable_cnt)) { dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size, base_vha->gnl.l, base_vha->gnl.ldma); - + base_vha->gnl.l = NULL; scsi_host_put(base_vha->host); kfree(ha); pci_set_drvdata(pdev, NULL); @@ -3713,6 +3722,8 @@ qla2x00_remove_one(struct pci_dev *pdev) dma_free_coherent(&ha->pdev->dev, base_vha->gnl.size, base_vha->gnl.l, base_vha->gnl.ldma); + base_vha->gnl.l = NULL; + vfree(base_vha->scan.l); if (IS_QLAFX00(ha)) @@ -4590,6 +4601,7 @@ qla2x00_free_fw_dump(struct qla_hw_data *ha) ha->fce = NULL; ha->fce_dma = 0; + ha->flags.fce_enabled = 0; ha->eft = NULL; ha->eft_dma = 0; ha->fw_dumped = 0; @@ -4708,7 +4720,7 @@ qla2x00_mem_free(struct qla_hw_data *ha) mempool_destroy(ha->ctx_mempool); ha->ctx_mempool = NULL; - if (ql2xenabledif) { + if (ql2xenabledif && ha->dif_bundl_pool) { struct dsd_dma *dsd, *nxt; list_for_each_entry_safe(dsd, nxt, &ha->pool.unusable.head, @@ -4731,8 +4743,7 @@ qla2x00_mem_free(struct qla_hw_data *ha) } } - if (ha->dif_bundl_pool) - dma_pool_destroy(ha->dif_bundl_pool); + dma_pool_destroy(ha->dif_bundl_pool); ha->dif_bundl_pool = NULL; qlt_mem_free(ha); @@ -4789,7 +4800,6 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, INIT_LIST_HEAD(&vha->plogi_ack_list); INIT_LIST_HEAD(&vha->qp_list); INIT_LIST_HEAD(&vha->gnl.fcports); - INIT_LIST_HEAD(&vha->nvme_rport_list); INIT_LIST_HEAD(&vha->gpnid_list); INIT_WORK(&vha->iocb_work, qla2x00_iocb_work_fn); @@ -4805,7 +4815,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, if (!vha->gnl.l) { ql_log(ql_log_fatal, vha, 0xd04a, "Alloc failed for name list.\n"); - scsi_remove_host(vha->host); + scsi_host_put(vha->host); return NULL; } @@ -4817,7 +4827,8 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, "Alloc failed for scan database.\n"); dma_free_coherent(&ha->pdev->dev, vha->gnl.size, vha->gnl.l, vha->gnl.ldma); - scsi_remove_host(vha->host); + vha->gnl.l = NULL; + scsi_host_put(vha->host); return NULL; } INIT_DELAYED_WORK(&vha->scan.scan_work, qla_scan_work_fn); @@ -5041,13 +5052,19 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) memcpy(fcport->port_name, e->u.new_sess.port_name, WWN_SIZE); + + if (e->u.new_sess.fc4_type & FS_FCP_IS_N2N) + fcport->n2n_flag = 1; + } else { ql_dbg(ql_dbg_disc, vha, 0xffff, "%s %8phC mem alloc fail.\n", __func__, e->u.new_sess.port_name); - if (pla) + if (pla) { + list_del(&pla->list); kmem_cache_free(qla_tgt_plogi_cachep, pla); + } return; } @@ -5078,6 +5095,7 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) if (fcport) { fcport->id_changed = 1; fcport->scan_state = QLA_FCPORT_FOUND; + fcport->chip_reset = vha->hw->base_qpair->chip_reset; memcpy(fcport->node_name, e->u.new_sess.node_name, WWN_SIZE); if (pla) { @@ -5136,11 +5154,9 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) if (dfcp) qlt_schedule_sess_for_deletion(tfcp); - - if (N2N_TOPO(vha->hw)) - fcport->flags &= ~FCF_FABRIC_DEVICE; - if (N2N_TOPO(vha->hw)) { + fcport->flags &= ~FCF_FABRIC_DEVICE; + fcport->keep_nport_handle = 1; if (vha->flags.nvme_enabled) { fcport->fc4f_nvme = 1; fcport->n2n_flag = 1; @@ -5157,8 +5173,10 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) if (free_fcport) { qla2x00_free_fcport(fcport); - if (pla) + if (pla) { + list_del(&pla->list); kmem_cache_free(qla_tgt_plogi_cachep, pla); + } } } @@ -5338,9 +5356,8 @@ void qla2x00_relogin(struct scsi_qla_host *vha) } else { if (vha->hw->current_topology != ISP_CFG_NL) { memset(&ea, 0, sizeof(ea)); - ea.event = FCME_RELOGIN; ea.fcport = fcport; - qla2x00_fcport_event_handler(vha, &ea); + qla24xx_handle_relogin_event(vha, &ea); } else if (vha->hw->current_topology == ISP_CFG_NL) { fcport->login_retry--; @@ -5678,7 +5695,6 @@ exit: void qla83xx_idc_lock(scsi_qla_host_t *base_vha, uint16_t requester_id) { - uint16_t options = (requester_id << 15) | BIT_6; uint32_t data; uint32_t lock_owner; struct qla_hw_data *ha = base_vha->hw; @@ -5711,22 +5727,6 @@ retry_lock: } return; - - /* XXX: IDC-lock implementation using access-control mbx */ -retry_lock2: - if (qla83xx_access_control(base_vha, options, 0, 0, NULL)) { - ql_dbg(ql_dbg_p3p, base_vha, 0xb072, - "Failed to acquire IDC lock. retrying...\n"); - /* Retry/Perform IDC-Lock recovery */ - if (qla83xx_idc_lock_recovery(base_vha) == QLA_SUCCESS) { - qla83xx_wait_logic(); - goto retry_lock2; - } else - ql_log(ql_log_warn, base_vha, 0xb076, - "IDC Lock recovery FAILED.\n"); - } - - return; } void @@ -7148,6 +7148,7 @@ struct scsi_host_template qla2xxx_driver_template = { .supported_mode = MODE_INITIATOR, .track_queue_depth = 1, + .cmd_size = sizeof(srb_t), }; static const struct pci_error_handlers qla2xxx_err_handler = { diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 1eb82384d933..f2d5115b2d8d 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -473,22 +473,24 @@ qla24xx_read_flash_dword(struct qla_hw_data *ha, uint32_t addr, uint32_t *data) return QLA_FUNCTION_TIMEOUT; } -uint32_t * +int qla24xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, uint32_t dwords) { ulong i; + int ret = QLA_SUCCESS; struct qla_hw_data *ha = vha->hw; /* Dword reads to flash. */ faddr = flash_data_addr(ha, faddr); for (i = 0; i < dwords; i++, faddr++, dwptr++) { - if (qla24xx_read_flash_dword(ha, faddr, dwptr)) + ret = qla24xx_read_flash_dword(ha, faddr, dwptr); + if (ret != QLA_SUCCESS) break; cpu_to_le32s(dwptr); } - return dwptr; + return ret; } static int @@ -680,8 +682,8 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) ha->flt_region_flt = flt_addr; wptr = (uint16_t *)ha->flt; - qla24xx_read_flash_data(vha, (void *)flt, flt_addr, - (sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE) >> 2); + ha->isp_ops->read_optrom(vha, (void *)flt, flt_addr << 2, + (sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE)); if (le16_to_cpu(*wptr) == 0xffff) goto no_flash_data; @@ -948,11 +950,11 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha) struct req_que *req = ha->req_q_map[0]; uint16_t cnt, chksum; uint16_t *wptr = (void *)req->ring; - struct qla_fdt_layout *fdt = (void *)req->ring; + struct qla_fdt_layout *fdt = (struct qla_fdt_layout *)req->ring; uint8_t man_id, flash_id; uint16_t mid = 0, fid = 0; - qla24xx_read_flash_data(vha, (void *)fdt, ha->flt_region_fdt, + ha->isp_ops->read_optrom(vha, fdt, ha->flt_region_fdt << 2, OPTROM_BURST_DWORDS); if (le16_to_cpu(*wptr) == 0xffff) goto no_flash_data; diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 2fd5c09b42d4..a06e56224a55 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -188,18 +188,17 @@ static inline int qlt_issue_marker(struct scsi_qla_host *vha, int vha_locked) static inline struct scsi_qla_host *qlt_find_host_by_d_id(struct scsi_qla_host *vha, - uint8_t *d_id) + be_id_t d_id) { struct scsi_qla_host *host; - uint32_t key = 0; + uint32_t key; - if ((vha->d_id.b.area == d_id[1]) && (vha->d_id.b.domain == d_id[0]) && - (vha->d_id.b.al_pa == d_id[2])) + if (vha->d_id.b.area == d_id.area && + vha->d_id.b.domain == d_id.domain && + vha->d_id.b.al_pa == d_id.al_pa) return vha; - key = (uint32_t)d_id[0] << 16; - key |= (uint32_t)d_id[1] << 8; - key |= (uint32_t)d_id[2]; + key = be_to_port_id(d_id).b24; host = btree_lookup32(&vha->hw->tgt.host_map, key); if (!host) @@ -357,9 +356,9 @@ static bool qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt, vha, 0xe03e, "qla_target(%d): Received ATIO_TYPE7 " "with unknown d_id %x:%x:%x\n", vha->vp_idx, - atio->u.isp24.fcp_hdr.d_id[0], - atio->u.isp24.fcp_hdr.d_id[1], - atio->u.isp24.fcp_hdr.d_id[2]); + atio->u.isp24.fcp_hdr.d_id.domain, + atio->u.isp24.fcp_hdr.d_id.area, + atio->u.isp24.fcp_hdr.d_id.al_pa); qlt_queue_unknown_atio(vha, atio, ha_locked); @@ -560,10 +559,8 @@ static int qla24xx_post_nack_work(struct scsi_qla_host *vha, fc_port_t *fcport, return qla2x00_post_work(vha, e); } -static -void qla2x00_async_nack_sp_done(void *s, int res) +static void qla2x00_async_nack_sp_done(srb_t *sp, int res) { - struct srb *sp = (struct srb *)s; struct scsi_qla_host *vha = sp->vha; unsigned long flags; @@ -789,6 +786,8 @@ qlt_plogi_ack_find_add(struct scsi_qla_host *vha, port_id_t *id, { struct qlt_plogi_ack_t *pla; + lockdep_assert_held(&vha->hw->hardware_lock); + list_for_each_entry(pla, &vha->plogi_ack_list, list) { if (pla->id.b24 == id->b24) { ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x210d, @@ -954,7 +953,7 @@ void qlt_free_session_done(struct work_struct *work) struct qla_hw_data *ha = vha->hw; unsigned long flags; bool logout_started = false; - scsi_qla_host_t *base_vha; + scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); struct qlt_plogi_ack_t *own = sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN]; @@ -1004,6 +1003,12 @@ void qlt_free_session_done(struct work_struct *work) else logout_started = true; } + } /* if sess->logout_on_delete */ + + if (sess->nvme_flag & NVME_FLAG_REGISTERED && + !(sess->nvme_flag & NVME_FLAG_DELETING)) { + sess->nvme_flag |= NVME_FLAG_DELETING; + qla_nvme_unregister_remote_port(sess); } } @@ -1015,6 +1020,7 @@ void qlt_free_session_done(struct work_struct *work) if (logout_started) { bool traced = false; + u16 cnt = 0; while (!READ_ONCE(sess->logout_completed)) { if (!traced) { @@ -1024,6 +1030,9 @@ void qlt_free_session_done(struct work_struct *work) traced = true; } msleep(100); + cnt++; + if (cnt > 200) + break; } ql_dbg(ql_dbg_disc, vha, 0xf087, @@ -1096,6 +1105,7 @@ void qlt_free_session_done(struct work_struct *work) } spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); + sess->free_pending = 0; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf001, "Unregistration of sess %p %8phC finished fcp_cnt %d\n", @@ -1104,17 +1114,9 @@ void qlt_free_session_done(struct work_struct *work) if (tgt && (tgt->sess_count == 0)) wake_up_all(&tgt->waitQ); - if (vha->fcport_count == 0) - wake_up_all(&vha->fcport_waitQ); - - base_vha = pci_get_drvdata(ha->pdev); - - sess->free_pending = 0; - - if (test_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags)) - return; - - if ((!tgt || !tgt->tgt_stop) && !LOOP_TRANSITION(vha)) { + if (!test_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags) && + !(vha->vp_idx && test_bit(VPORT_DELETE, &vha->dpc_flags)) && + (!tgt || !tgt->tgt_stop) && !LOOP_TRANSITION(vha)) { switch (vha->host->active_mode) { case MODE_INITIATOR: case MODE_DUAL: @@ -1127,6 +1129,9 @@ void qlt_free_session_done(struct work_struct *work) break; } } + + if (vha->fcport_count == 0) + wake_up_all(&vha->fcport_waitQ); } /* ha->tgt.sess_lock supposed to be held on entry */ @@ -1155,14 +1160,8 @@ void qlt_unreg_sess(struct fc_port *sess) sess->last_rscn_gen = sess->rscn_gen; sess->last_login_gen = sess->login_gen; - if (sess->nvme_flag & NVME_FLAG_REGISTERED && - !(sess->nvme_flag & NVME_FLAG_DELETING)) { - sess->nvme_flag |= NVME_FLAG_DELETING; - schedule_work(&sess->nvme_del_work); - } else { - INIT_WORK(&sess->free_work, qlt_free_session_done); - schedule_work(&sess->free_work); - } + INIT_WORK(&sess->free_work, qlt_free_session_done); + queue_work(sess->vha->hw->wq, &sess->free_work); } EXPORT_SYMBOL(qlt_unreg_sess); @@ -1209,7 +1208,6 @@ static void qla24xx_chk_fcp_state(struct fc_port *sess) sess->logout_on_delete = 0; sess->logo_ack_needed = 0; sess->fw_login_state = DSC_LS_PORT_UNAVAIL; - sess->scan_state = 0; } } @@ -1284,13 +1282,12 @@ static void qlt_clear_tgt_db(struct qla_tgt *tgt) /* At this point tgt could be already dead */ } -static int qla24xx_get_loop_id(struct scsi_qla_host *vha, const uint8_t *s_id, +static int qla24xx_get_loop_id(struct scsi_qla_host *vha, be_id_t s_id, uint16_t *loop_id) { struct qla_hw_data *ha = vha->hw; dma_addr_t gid_list_dma; - struct gid_list_info *gid_list; - char *id_iter; + struct gid_list_info *gid_list, *gid; int res, rc, i; uint16_t entries; @@ -1313,19 +1310,17 @@ static int qla24xx_get_loop_id(struct scsi_qla_host *vha, const uint8_t *s_id, goto out_free_id_list; } - id_iter = (char *)gid_list; + gid = gid_list; res = -ENOENT; for (i = 0; i < entries; i++) { - struct gid_list_info *gid = (struct gid_list_info *)id_iter; - - if ((gid->al_pa == s_id[2]) && - (gid->area == s_id[1]) && - (gid->domain == s_id[0])) { + if (gid->al_pa == s_id.al_pa && + gid->area == s_id.area && + gid->domain == s_id.domain) { *loop_id = le16_to_cpu(gid->loop_id); res = 0; break; } - id_iter += ha->gid_list_info_size; + gid = (void *)gid + ha->gid_list_info_size; } out_free_id_list: @@ -1582,11 +1577,10 @@ static void qlt_release(struct qla_tgt *tgt) struct qla_qpair_hint *h; struct qla_hw_data *ha = vha->hw; - if ((vha->vha_tgt.qla_tgt != NULL) && !tgt->tgt_stop && - !tgt->tgt_stopped) + if (!tgt->tgt_stop && !tgt->tgt_stopped) qlt_stop_phase1(tgt); - if ((vha->vha_tgt.qla_tgt != NULL) && !tgt->tgt_stopped) + if (!tgt->tgt_stopped) qlt_stop_phase2(tgt); for (i = 0; i < vha->hw->max_qpairs + 1; i++) { @@ -1772,12 +1766,8 @@ static int qlt_build_abts_resp_iocb(struct qla_tgt_mgmt_cmd *mcmd) resp->fcp_hdr_le.f_ctl[1] = *p++; resp->fcp_hdr_le.f_ctl[2] = *p; - resp->fcp_hdr_le.d_id[0] = abts->fcp_hdr_le.s_id[0]; - resp->fcp_hdr_le.d_id[1] = abts->fcp_hdr_le.s_id[1]; - resp->fcp_hdr_le.d_id[2] = abts->fcp_hdr_le.s_id[2]; - resp->fcp_hdr_le.s_id[0] = abts->fcp_hdr_le.d_id[0]; - resp->fcp_hdr_le.s_id[1] = abts->fcp_hdr_le.d_id[1]; - resp->fcp_hdr_le.s_id[2] = abts->fcp_hdr_le.d_id[2]; + resp->fcp_hdr_le.d_id = abts->fcp_hdr_le.s_id; + resp->fcp_hdr_le.s_id = abts->fcp_hdr_le.d_id; resp->exchange_addr_to_abort = abts->exchange_addr_to_abort; if (mcmd->fc_tm_rsp == FCP_TMF_CMPL) { @@ -1848,19 +1838,11 @@ static void qlt_24xx_send_abts_resp(struct qla_qpair *qpair, resp->fcp_hdr_le.f_ctl[1] = *p++; resp->fcp_hdr_le.f_ctl[2] = *p; if (ids_reversed) { - resp->fcp_hdr_le.d_id[0] = abts->fcp_hdr_le.d_id[0]; - resp->fcp_hdr_le.d_id[1] = abts->fcp_hdr_le.d_id[1]; - resp->fcp_hdr_le.d_id[2] = abts->fcp_hdr_le.d_id[2]; - resp->fcp_hdr_le.s_id[0] = abts->fcp_hdr_le.s_id[0]; - resp->fcp_hdr_le.s_id[1] = abts->fcp_hdr_le.s_id[1]; - resp->fcp_hdr_le.s_id[2] = abts->fcp_hdr_le.s_id[2]; + resp->fcp_hdr_le.d_id = abts->fcp_hdr_le.d_id; + resp->fcp_hdr_le.s_id = abts->fcp_hdr_le.s_id; } else { - resp->fcp_hdr_le.d_id[0] = abts->fcp_hdr_le.s_id[0]; - resp->fcp_hdr_le.d_id[1] = abts->fcp_hdr_le.s_id[1]; - resp->fcp_hdr_le.d_id[2] = abts->fcp_hdr_le.s_id[2]; - resp->fcp_hdr_le.s_id[0] = abts->fcp_hdr_le.d_id[0]; - resp->fcp_hdr_le.s_id[1] = abts->fcp_hdr_le.d_id[1]; - resp->fcp_hdr_le.s_id[2] = abts->fcp_hdr_le.d_id[2]; + resp->fcp_hdr_le.d_id = abts->fcp_hdr_le.s_id; + resp->fcp_hdr_le.s_id = abts->fcp_hdr_le.d_id; } resp->exchange_addr_to_abort = abts->exchange_addr_to_abort; if (status == FCP_TMF_CMPL) { @@ -1927,18 +1909,14 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, tmp = (CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_TERMINATE); if (mcmd) { - ctio->initiator_id[0] = entry->fcp_hdr_le.s_id[0]; - ctio->initiator_id[1] = entry->fcp_hdr_le.s_id[1]; - ctio->initiator_id[2] = entry->fcp_hdr_le.s_id[2]; + ctio->initiator_id = entry->fcp_hdr_le.s_id; if (mcmd->flags & QLA24XX_MGMT_ABORT_IO_ATTR_VALID) tmp |= (mcmd->abort_io_attr << 9); else if (qpair->retry_term_cnt & 1) tmp |= (0x4 << 9); } else { - ctio->initiator_id[0] = entry->fcp_hdr_le.d_id[0]; - ctio->initiator_id[1] = entry->fcp_hdr_le.d_id[1]; - ctio->initiator_id[2] = entry->fcp_hdr_le.d_id[2]; + ctio->initiator_id = entry->fcp_hdr_le.d_id; if (qpair->retry_term_cnt & 1) tmp |= (0x4 << 9); @@ -1972,8 +1950,7 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, * XXX does not go through the list of other port (which may have cmds * for the same lun) */ -static void abort_cmds_for_lun(struct scsi_qla_host *vha, - u64 lun, uint8_t *s_id) +static void abort_cmds_for_lun(struct scsi_qla_host *vha, u64 lun, be_id_t s_id) { struct qla_tgt_sess_op *op; struct qla_tgt_cmd *cmd; @@ -2149,7 +2126,7 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha, struct qla_hw_data *ha = vha->hw; struct fc_port *sess; uint32_t tag = abts->exchange_addr_to_abort; - uint8_t s_id[3]; + be_id_t s_id; int rc; unsigned long flags; @@ -2173,13 +2150,11 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha, ql_dbg(ql_dbg_tgt_mgt, vha, 0xf011, "qla_target(%d): task abort (s_id=%x:%x:%x, " - "tag=%d, param=%x)\n", vha->vp_idx, abts->fcp_hdr_le.s_id[2], - abts->fcp_hdr_le.s_id[1], abts->fcp_hdr_le.s_id[0], tag, + "tag=%d, param=%x)\n", vha->vp_idx, abts->fcp_hdr_le.s_id.domain, + abts->fcp_hdr_le.s_id.area, abts->fcp_hdr_le.s_id.al_pa, tag, le32_to_cpu(abts->fcp_hdr_le.parameter)); - s_id[0] = abts->fcp_hdr_le.s_id[2]; - s_id[1] = abts->fcp_hdr_le.s_id[1]; - s_id[2] = abts->fcp_hdr_le.s_id[0]; + s_id = le_id_to_be(abts->fcp_hdr_le.s_id); spin_lock_irqsave(&ha->tgt.sess_lock, flags); sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id); @@ -2243,9 +2218,7 @@ static void qlt_24xx_send_task_mgmt_ctio(struct qla_qpair *qpair, ctio->nport_handle = mcmd->sess->loop_id; ctio->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); ctio->vp_index = ha->vp_idx; - ctio->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; - ctio->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; - ctio->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; + ctio->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); ctio->exchange_addr = atio->u.isp24.exchange_addr; temp = (atio->u.isp24.attr << 9)| CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS; @@ -2302,9 +2275,7 @@ void qlt_send_resp_ctio(struct qla_qpair *qpair, struct qla_tgt_cmd *cmd, ctio->nport_handle = cmd->sess->loop_id; ctio->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); ctio->vp_index = vha->vp_idx; - ctio->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; - ctio->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; - ctio->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; + ctio->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); ctio->exchange_addr = atio->u.isp24.exchange_addr; temp = (atio->u.isp24.attr << 9) | CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS; @@ -2605,9 +2576,7 @@ static int qlt_24xx_build_ctio_pkt(struct qla_qpair *qpair, pkt->handle |= CTIO_COMPLETION_HANDLE_MARK; pkt->nport_handle = cpu_to_le16(prm->cmd->loop_id); pkt->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); - pkt->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; - pkt->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; - pkt->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; + pkt->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); pkt->exchange_addr = atio->u.isp24.exchange_addr; temp = atio->u.isp24.attr << 9; pkt->u.status0.flags |= cpu_to_le16(temp); @@ -3120,9 +3089,7 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) pkt->handle |= CTIO_COMPLETION_HANDLE_MARK; pkt->nport_handle = cpu_to_le16(prm->cmd->loop_id); pkt->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); - pkt->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; - pkt->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; - pkt->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; + pkt->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); pkt->exchange_addr = atio->u.isp24.exchange_addr; /* silence compile warning */ @@ -3164,7 +3131,7 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) pkt->crc_context_len = CRC_CONTEXT_LEN_FW; if (!bundling) { - cur_dsd = &crc_ctx_pkt->u.nobundling.data_dsd; + cur_dsd = &crc_ctx_pkt->u.nobundling.data_dsd[0]; } else { /* * Configure Bundling if we need to fetch interlaving @@ -3174,7 +3141,7 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes); crc_ctx_pkt->u.bundling.dseg_count = cpu_to_le16(prm->tot_dsds - prm->prot_seg_cnt); - cur_dsd = &crc_ctx_pkt->u.bundling.data_dsd; + cur_dsd = &crc_ctx_pkt->u.bundling.data_dsd[0]; } /* Finish the common fields of CRC pkt */ @@ -3239,7 +3206,8 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) || (cmd->sess && cmd->sess->deleted)) { cmd->state = QLA_TGT_STATE_PROCESSED; - return 0; + res = 0; + goto free; } ql_dbg_qp(ql_dbg_tgt, qpair, 0xe018, @@ -3250,9 +3218,8 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, res = qlt_pre_xmit_response(cmd, &prm, xmit_type, scsi_status, &full_req_cnt); - if (unlikely(res != 0)) { - return res; - } + if (unlikely(res != 0)) + goto free; spin_lock_irqsave(qpair->qp_lock_ptr, flags); @@ -3272,7 +3239,8 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, vha->flags.online, qla2x00_reset_active(vha), cmd->reset_count, qpair->chip_reset); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); - return 0; + res = 0; + goto free; } /* Does F/W have an IOCBs for this request */ @@ -3375,6 +3343,8 @@ out_unmap_unlock: qlt_unmap_sg(vha, cmd); spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); +free: + vha->hw->tgt.tgt_ops->free_cmd(cmd); return res; } EXPORT_SYMBOL(qlt_xmit_response); @@ -3672,9 +3642,7 @@ static int __qlt_send_term_exchange(struct qla_qpair *qpair, ctio24->nport_handle = CTIO7_NHANDLE_UNRECOGNIZED; ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); ctio24->vp_index = vha->vp_idx; - ctio24->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; - ctio24->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; - ctio24->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; + ctio24->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); ctio24->exchange_addr = atio->u.isp24.exchange_addr; temp = (atio->u.isp24.attr << 9) | CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_TERMINATE; @@ -4107,8 +4075,6 @@ static inline int qlt_get_fcp_task_attr(struct scsi_qla_host *vha, return fcp_task_attr; } -static struct fc_port *qlt_make_local_sess(struct scsi_qla_host *, - uint8_t *); /* * Process context for I/O path into tcm_qla2xxx code */ @@ -4352,9 +4318,7 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, return -ENODEV; } - id.b.al_pa = atio->u.isp24.fcp_hdr.s_id[2]; - id.b.area = atio->u.isp24.fcp_hdr.s_id[1]; - id.b.domain = atio->u.isp24.fcp_hdr.s_id[0]; + id = be_to_port_id(atio->u.isp24.fcp_hdr.s_id); if (IS_SW_RESV_ADDR(id)) return -EBUSY; @@ -4716,6 +4680,8 @@ static int qlt_handle_login(struct scsi_qla_host *vha, struct qlt_plogi_ack_t *pla; unsigned long flags; + lockdep_assert_held(&vha->hw->hardware_lock); + wwn = wwn_to_u64(iocb->u.isp24.port_name); port_id.b.domain = iocb->u.isp24.port_id[2]; @@ -4799,8 +4765,10 @@ static int qlt_handle_login(struct scsi_qla_host *vha, __func__, sess->port_name, sec); } - if (!conflict_sess) + if (!conflict_sess) { + list_del(&pla->list); kmem_cache_free(qla_tgt_plogi_cachep, pla); + } qlt_send_term_imm_notif(vha, iocb, 1); goto out; @@ -4889,6 +4857,8 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, int res = 0; unsigned long flags; + lockdep_assert_held(&ha->hardware_lock); + wwn = wwn_to_u64(iocb->u.isp24.port_name); port_id.b.domain = iocb->u.isp24.port_id[2]; @@ -5165,6 +5135,8 @@ static void qlt_handle_imm_notify(struct scsi_qla_host *vha, int send_notify_ack = 1; uint16_t status; + lockdep_assert_held(&ha->hardware_lock); + status = le16_to_cpu(iocb->u.isp2x.status); switch (status) { case IMM_NTFY_LIP_RESET: @@ -5302,10 +5274,7 @@ static int __qlt_send_busy(struct qla_qpair *qpair, u16 temp; port_id_t id; - id.b.al_pa = atio->u.isp24.fcp_hdr.s_id[2]; - id.b.area = atio->u.isp24.fcp_hdr.s_id[1]; - id.b.domain = atio->u.isp24.fcp_hdr.s_id[0]; - id.b.rsvd_1 = 0; + id = be_to_port_id(atio->u.isp24.fcp_hdr.s_id); spin_lock_irqsave(&ha->tgt.sess_lock, flags); sess = qla2x00_find_fcport_by_nportid(vha, &id, 1); @@ -5333,9 +5302,7 @@ static int __qlt_send_busy(struct qla_qpair *qpair, ctio24->nport_handle = sess->loop_id; ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); ctio24->vp_index = vha->vp_idx; - ctio24->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; - ctio24->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; - ctio24->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; + ctio24->initiator_id = be_id_to_le(atio->u.isp24.fcp_hdr.s_id); ctio24->exchange_addr = atio->u.isp24.exchange_addr; temp = (atio->u.isp24.attr << 9) | CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS | @@ -5767,7 +5734,7 @@ static void qlt_handle_abts_completion(struct scsi_qla_host *vha, entry->error_subcode2); ha->tgt.tgt_ops->free_mcmd(mcmd); } - } else { + } else if (mcmd) { ha->tgt.tgt_ops->free_mcmd(mcmd); } } @@ -6121,21 +6088,21 @@ static fc_port_t *qlt_get_port_database(struct scsi_qla_host *vha, /* Must be called under tgt_mutex */ static struct fc_port *qlt_make_local_sess(struct scsi_qla_host *vha, - uint8_t *s_id) + be_id_t s_id) { struct fc_port *sess = NULL; fc_port_t *fcport = NULL; int rc, global_resets; uint16_t loop_id = 0; - if ((s_id[0] == 0xFF) && (s_id[1] == 0xFC)) { + if (s_id.domain == 0xFF && s_id.area == 0xFC) { /* * This is Domain Controller, so it should be * OK to drop SCSI commands from it. */ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf042, "Unable to find initiator with S_ID %x:%x:%x", - s_id[0], s_id[1], s_id[2]); + s_id.domain, s_id.area, s_id.al_pa); return NULL; } @@ -6152,13 +6119,12 @@ retry: ql_log(ql_log_info, vha, 0xf071, "qla_target(%d): Unable to find " "initiator with S_ID %x:%x:%x", - vha->vp_idx, s_id[0], s_id[1], - s_id[2]); + vha->vp_idx, s_id.domain, s_id.area, s_id.al_pa); if (rc == -ENOENT) { qlt_port_logo_t logo; - sid_to_portid(s_id, &logo.id); + logo.id = be_to_port_id(s_id); logo.cmd_count = 1; qlt_send_first_logo(vha, &logo); } @@ -6197,8 +6163,7 @@ static void qlt_abort_work(struct qla_tgt *tgt, struct qla_hw_data *ha = vha->hw; struct fc_port *sess = NULL; unsigned long flags = 0, flags2 = 0; - uint32_t be_s_id; - uint8_t s_id[3]; + be_id_t s_id; int rc; spin_lock_irqsave(&ha->tgt.sess_lock, flags2); @@ -6206,12 +6171,9 @@ static void qlt_abort_work(struct qla_tgt *tgt, if (tgt->tgt_stop) goto out_term2; - s_id[0] = prm->abts.fcp_hdr_le.s_id[2]; - s_id[1] = prm->abts.fcp_hdr_le.s_id[1]; - s_id[2] = prm->abts.fcp_hdr_le.s_id[0]; + s_id = le_id_to_be(prm->abts.fcp_hdr_le.s_id); - sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, - (unsigned char *)&be_s_id); + sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, s_id); if (!sess) { spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2); @@ -6248,9 +6210,6 @@ static void qlt_abort_work(struct qla_tgt *tgt, out_term2: spin_unlock_irqrestore(&ha->tgt.sess_lock, flags2); - if (sess) - ha->tgt.tgt_ops->put_sess(sess); - out_term: spin_lock_irqsave(&ha->hardware_lock, flags); qlt_24xx_send_abts_resp(ha->base_qpair, &prm->abts, @@ -6266,7 +6225,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt, struct qla_hw_data *ha = vha->hw; struct fc_port *sess; unsigned long flags; - uint8_t *s_id = NULL; /* to hide compiler warnings */ + be_id_t s_id; int rc; u64 unpacked_lun; int fn; @@ -6495,22 +6454,10 @@ void qlt_remove_target_resources(struct qla_hw_data *ha) static void qlt_lport_dump(struct scsi_qla_host *vha, u64 wwpn, unsigned char *b) { - int i; - - pr_debug("qla2xxx HW vha->node_name: "); - for (i = 0; i < WWN_SIZE; i++) - pr_debug("%02x ", vha->node_name[i]); - pr_debug("\n"); - pr_debug("qla2xxx HW vha->port_name: "); - for (i = 0; i < WWN_SIZE; i++) - pr_debug("%02x ", vha->port_name[i]); - pr_debug("\n"); - - pr_debug("qla2xxx passed configfs WWPN: "); + pr_debug("qla2xxx HW vha->node_name: %8phC\n", vha->node_name); + pr_debug("qla2xxx HW vha->port_name: %8phC\n", vha->port_name); put_unaligned_be64(wwpn, b); - for (i = 0; i < WWN_SIZE; i++) - pr_debug("%02x ", b[i]); - pr_debug("\n"); + pr_debug("qla2xxx passed configfs WWPN: %8phC\n", b); } /** @@ -6671,6 +6618,8 @@ qlt_enable_vha(struct scsi_qla_host *vha) if (vha->qlini_mode == QLA2XXX_INI_MODE_ENABLED) return; + if (ha->tgt.num_act_qpairs > ha->max_qpairs) + ha->tgt.num_act_qpairs = ha->max_qpairs; spin_lock_irqsave(&ha->hardware_lock, flags); tgt->tgt_stopped = 0; qlt_set_mode(vha); @@ -6685,7 +6634,8 @@ qlt_enable_vha(struct scsi_qla_host *vha) } else { set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); qla2xxx_wake_dpc(base_vha); - qla2x00_wait_for_hba_online(base_vha); + WARN_ON_ONCE(qla2x00_wait_for_hba_online(base_vha) != + QLA_SUCCESS); } mutex_unlock(&ha->optrom_mutex); } @@ -6716,7 +6666,9 @@ static void qlt_disable_vha(struct scsi_qla_host *vha) set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); - qla2x00_wait_for_hba_online(vha); + if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) + ql_dbg(ql_dbg_tgt, vha, 0xe081, + "qla2x00_wait_for_hba_online() failed\n"); } /* @@ -6815,7 +6767,7 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked) */ ql_log(ql_log_warn, vha, 0xd03c, "corrupted fcp frame SID[%3phN] OXID[%04x] EXCG[%x] %64phN\n", - pkt->u.isp24.fcp_hdr.s_id, + &pkt->u.isp24.fcp_hdr.s_id, be16_to_cpu(pkt->u.isp24.fcp_hdr.ox_id), le32_to_cpu(pkt->u.isp24.exchange_addr), pkt); diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index b8d244f1e189..d006f0a97b8c 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -247,9 +247,9 @@ struct ctio_to_2xxx { struct fcp_hdr { uint8_t r_ctl; - uint8_t d_id[3]; + be_id_t d_id; uint8_t cs_ctl; - uint8_t s_id[3]; + be_id_t s_id; uint8_t type; uint8_t f_ctl[3]; uint8_t seq_id; @@ -261,9 +261,9 @@ struct fcp_hdr { } __packed; struct fcp_hdr_le { - uint8_t d_id[3]; + le_id_t d_id; uint8_t r_ctl; - uint8_t s_id[3]; + le_id_t s_id; uint8_t cs_ctl; uint8_t f_ctl[3]; uint8_t type; @@ -402,7 +402,7 @@ struct ctio7_to_24xx { uint16_t dseg_count; /* Data segment count. */ uint8_t vp_index; uint8_t add_flags; - uint8_t initiator_id[3]; + le_id_t initiator_id; uint8_t reserved; uint32_t exchange_addr; union { @@ -498,7 +498,7 @@ struct ctio_crc2_to_fw { uint8_t add_flags; /* additional flags */ #define CTIO_CRC2_AF_DIF_DSD_ENA BIT_3 - uint8_t initiator_id[3]; /* initiator ID */ + le_id_t initiator_id; /* initiator ID */ uint8_t reserved1; uint32_t exchange_addr; /* rcv exchange address */ uint16_t reserved2; @@ -682,7 +682,7 @@ struct qla_tgt_func_tmpl { struct fc_port *(*find_sess_by_loop_id)(struct scsi_qla_host *, const uint16_t); struct fc_port *(*find_sess_by_s_id)(struct scsi_qla_host *, - const uint8_t *); + const be_id_t); void (*clear_nacl_from_fcport_map)(struct fc_port *); void (*put_sess)(struct fc_port *); void (*shutdown_sess)(struct fc_port *); @@ -912,7 +912,7 @@ struct qla_tgt_cmd { uint8_t scsi_status, sense_key, asc, ascq; struct crc_context *ctx; - uint8_t *cdb; + const uint8_t *cdb; uint64_t lba; uint16_t a_guard, e_guard, a_app_tag, e_app_tag; uint32_t a_ref_tag, e_ref_tag; @@ -1030,22 +1030,11 @@ static inline bool qla_dual_mode_enabled(struct scsi_qla_host *ha) return (ha->host->active_mode == MODE_DUAL); } -static inline uint32_t sid_to_key(const uint8_t *s_id) +static inline uint32_t sid_to_key(const be_id_t s_id) { - uint32_t key; - - key = (((unsigned long)s_id[0] << 16) | - ((unsigned long)s_id[1] << 8) | - (unsigned long)s_id[2]); - return key; -} - -static inline void sid_to_portid(const uint8_t *s_id, port_id_t *p) -{ - memset(p, 0, sizeof(*p)); - p->b.domain = s_id[0]; - p->b.area = s_id[1]; - p->b.al_pa = s_id[2]; + return s_id.domain << 16 | + s_id.area << 8 | + s_id.al_pa; } /* diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index de696a07532e..294d77c02cdf 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -429,7 +429,7 @@ qla27xx_fwdt_entry_t266(struct scsi_qla_host *vha, ql_dbg(ql_dbg_misc, vha, 0xd20a, "%s: reset risc [%lx]\n", __func__, *len); if (buf) - qla24xx_soft_reset(vha->hw); + WARN_ON_ONCE(qla24xx_soft_reset(vha->hw) != QLA_SUCCESS); return qla27xx_next_entry(ent); } @@ -860,8 +860,9 @@ qla27xx_driver_info(struct qla27xx_fwdt_template *tmp) { uint8_t v[] = { 0, 0, 0, 0, 0, 0 }; - sscanf(qla2x00_version_str, "%hhu.%hhu.%hhu.%hhu.%hhu.%hhu", - v+0, v+1, v+2, v+3, v+4, v+5); + WARN_ON_ONCE(sscanf(qla2x00_version_str, + "%hhu.%hhu.%hhu.%hhu.%hhu.%hhu", + v+0, v+1, v+2, v+3, v+4, v+5) != 6); tmp->driver_info[0] = v[3] << 24 | v[2] << 16 | v[1] << 8 | v[0]; tmp->driver_info[1] = v[5] << 8 | v[4]; diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index cd6bdf71e533..a8f2a953ceff 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.01.00.16-k" +#define QLA2XXX_VERSION "10.01.00.19-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 1 diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index d15412d3d9bd..042a24314edc 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -620,6 +620,7 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd) { struct qla_tgt_cmd *cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); + struct scsi_qla_host *vha = cmd->vha; if (cmd->aborted) { /* Cmd can loop during Q-full. tcm_qla2xxx_aborted_task @@ -632,6 +633,7 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd) cmd->se_cmd.transport_state, cmd->se_cmd.t_state, cmd->se_cmd.se_cmd_flags); + vha->hw->tgt.tgt_ops->free_cmd(cmd); return 0; } @@ -659,6 +661,7 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd) { struct qla_tgt_cmd *cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); + struct scsi_qla_host *vha = cmd->vha; int xmit_type = QLA_TGT_XMIT_STATUS; if (cmd->aborted) { @@ -672,6 +675,7 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd) cmd, kref_read(&cmd->se_cmd.cmd_kref), cmd->se_cmd.transport_state, cmd->se_cmd.t_state, cmd->se_cmd.se_cmd_flags); + vha->hw->tgt.tgt_ops->free_cmd(cmd); return 0; } cmd->bufflen = se_cmd->data_length; @@ -1136,9 +1140,8 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(struct se_wwn *wwn, /* * Expected to be called with struct qla_hw_data->tgt.sess_lock held */ -static struct fc_port *tcm_qla2xxx_find_sess_by_s_id( - scsi_qla_host_t *vha, - const uint8_t *s_id) +static struct fc_port *tcm_qla2xxx_find_sess_by_s_id(scsi_qla_host_t *vha, + const be_id_t s_id) { struct tcm_qla2xxx_lport *lport; struct se_node_acl *se_nacl; @@ -1181,7 +1184,7 @@ static void tcm_qla2xxx_set_sess_by_s_id( struct tcm_qla2xxx_nacl *nacl, struct se_session *se_sess, struct fc_port *fc_port, - uint8_t *s_id) + be_id_t s_id) { u32 key; void *slot; @@ -1348,14 +1351,9 @@ static void tcm_qla2xxx_clear_sess_lookup(struct tcm_qla2xxx_lport *lport, struct tcm_qla2xxx_nacl *nacl, struct fc_port *sess) { struct se_session *se_sess = sess->se_sess; - unsigned char be_sid[3]; - - be_sid[0] = sess->d_id.b.domain; - be_sid[1] = sess->d_id.b.area; - be_sid[2] = sess->d_id.b.al_pa; tcm_qla2xxx_set_sess_by_s_id(lport, NULL, nacl, se_sess, - sess, be_sid); + sess, port_id_to_be_id(sess->d_id)); tcm_qla2xxx_set_sess_by_loop_id(lport, NULL, nacl, se_sess, sess, sess->loop_id); } @@ -1401,19 +1399,14 @@ static int tcm_qla2xxx_session_cb(struct se_portal_group *se_tpg, struct fc_port *qlat_sess = p; uint16_t loop_id = qlat_sess->loop_id; unsigned long flags; - unsigned char be_sid[3]; - - be_sid[0] = qlat_sess->d_id.b.domain; - be_sid[1] = qlat_sess->d_id.b.area; - be_sid[2] = qlat_sess->d_id.b.al_pa; /* * And now setup se_nacl and session pointers into HW lport internal * mappings for fabric S_ID and LOOP_ID. */ spin_lock_irqsave(&ha->tgt.sess_lock, flags); - tcm_qla2xxx_set_sess_by_s_id(lport, se_nacl, nacl, - se_sess, qlat_sess, be_sid); + tcm_qla2xxx_set_sess_by_s_id(lport, se_nacl, nacl, se_sess, qlat_sess, + port_id_to_be_id(qlat_sess->d_id)); tcm_qla2xxx_set_sess_by_loop_id(lport, se_nacl, nacl, se_sess, qlat_sess, loop_id); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 9335849f6bea..d539beef3ce8 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -200,10 +200,15 @@ static int qlogicpti_mbox_command(struct qlogicpti *qpti, u_short param[], int f /* Write mailbox command registers. */ switch (mbox_param[param[0]] >> 4) { case 6: sbus_writew(param[5], qpti->qregs + MBOX5); + /* Fall through */ case 5: sbus_writew(param[4], qpti->qregs + MBOX4); + /* Fall through */ case 4: sbus_writew(param[3], qpti->qregs + MBOX3); + /* Fall through */ case 3: sbus_writew(param[2], qpti->qregs + MBOX2); + /* Fall through */ case 2: sbus_writew(param[1], qpti->qregs + MBOX1); + /* Fall through */ case 1: sbus_writew(param[0], qpti->qregs + MBOX0); } @@ -254,10 +259,15 @@ static int qlogicpti_mbox_command(struct qlogicpti *qpti, u_short param[], int f /* Read back output parameters. */ switch (mbox_param[param[0]] & 0xf) { case 6: param[5] = sbus_readw(qpti->qregs + MBOX5); + /* Fall through */ case 5: param[4] = sbus_readw(qpti->qregs + MBOX4); + /* Fall through */ case 4: param[3] = sbus_readw(qpti->qregs + MBOX3); + /* Fall through */ case 3: param[2] = sbus_readw(qpti->qregs + MBOX2); + /* Fall through */ case 2: param[1] = sbus_readw(qpti->qregs + MBOX1); + /* Fall through */ case 1: param[0] = sbus_readw(qpti->qregs + MBOX0); } diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 653d5ea6c5d9..1f5b5c8a7f72 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -86,15 +86,10 @@ unsigned int scsi_logging_level; EXPORT_SYMBOL(scsi_logging_level); #endif -/* sd, scsi core and power management need to coordinate flushing async actions */ -ASYNC_DOMAIN(scsi_sd_probe_domain); -EXPORT_SYMBOL(scsi_sd_probe_domain); - /* - * Separate domain (from scsi_sd_probe_domain) to maximize the benefit of - * asynchronous system resume operations. It is marked 'exclusive' to avoid - * being included in the async_synchronize_full() that is invoked by - * dpm_resume() + * Domain for asynchronous system resume operations. It is marked 'exclusive' + * to avoid being included in the async_synchronize_full() that is invoked by + * dpm_resume(). */ ASYNC_DOMAIN_EXCLUSIVE(scsi_sd_pm_domain); EXPORT_SYMBOL(scsi_sd_pm_domain); @@ -821,7 +816,6 @@ static void __exit exit_scsi(void) scsi_exit_devinfo(); scsi_exit_procfs(); scsi_exit_queue(); - async_unregister_domain(&scsi_sd_probe_domain); } subsys_initcall(init_scsi); diff --git a/drivers/scsi/scsi_debugfs.c b/drivers/scsi/scsi_debugfs.c index c5a8756384bc..c19ea7ab54cb 100644 --- a/drivers/scsi/scsi_debugfs.c +++ b/drivers/scsi/scsi_debugfs.c @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#include <linux/bitops.h> #include <linux/seq_file.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_dbg.h> @@ -18,9 +19,7 @@ static int scsi_flags_show(struct seq_file *m, const unsigned long flags, bool sep = false; int i; - for (i = 0; i < sizeof(flags) * BITS_PER_BYTE; i++) { - if (!(flags & BIT(i))) - continue; + for_each_set_bit(i, &flags, BITS_PER_LONG) { if (sep) seq_puts(m, "|"); sep = true; diff --git a/drivers/scsi/scsi_debugfs.h b/drivers/scsi/scsi_debugfs.h index 951b043e82d0..d125d1bd4184 100644 --- a/drivers/scsi/scsi_debugfs.h +++ b/drivers/scsi/scsi_debugfs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ struct request; struct seq_file; diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index a08ff3bd6310..df14597752ec 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -239,6 +239,8 @@ static struct { {"LSI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, {"ENGENIO", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, {"LENOVO", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, + {"SanDisk", "Cruzer Blade", NULL, BLIST_TRY_VPD_PAGES | + BLIST_INQUIRY_36}, {"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36}, {"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN}, {"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */ diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index bfa569facd5b..ae2fa170f6ad 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -967,6 +967,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, ses->data_direction = scmd->sc_data_direction; ses->sdb = scmd->sdb; ses->result = scmd->result; + ses->resid_len = scmd->req.resid_len; ses->underflow = scmd->underflow; ses->prot_op = scmd->prot_op; ses->eh_eflags = scmd->eh_eflags; @@ -977,6 +978,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, memset(scmd->cmnd, 0, BLK_MAX_CDB); memset(&scmd->sdb, 0, sizeof(scmd->sdb)); scmd->result = 0; + scmd->req.resid_len = 0; if (sense_bytes) { scmd->sdb.length = min_t(unsigned, SCSI_SENSE_BUFFERSIZE, @@ -1029,6 +1031,7 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) scmd->sc_data_direction = ses->data_direction; scmd->sdb = ses->sdb; scmd->result = ses->result; + scmd->req.resid_len = ses->resid_len; scmd->underflow = ses->underflow; scmd->prot_op = ses->prot_op; scmd->eh_eflags = ses->eh_eflags; @@ -1055,7 +1058,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, struct scsi_device *sdev = scmd->device; struct Scsi_Host *shost = sdev->host; DECLARE_COMPLETION_ONSTACK(done); - unsigned long timeleft = timeout; + unsigned long timeleft = timeout, delay; struct scsi_eh_save ses; const unsigned long stall_for = msecs_to_jiffies(100); int rtn; @@ -1066,7 +1069,29 @@ retry: scsi_log_send(scmd); scmd->scsi_done = scsi_eh_done; - rtn = shost->hostt->queuecommand(shost, scmd); + + /* + * Lock sdev->state_mutex to avoid that scsi_device_quiesce() can + * change the SCSI device state after we have examined it and before + * .queuecommand() is called. + */ + mutex_lock(&sdev->state_mutex); + while (sdev->sdev_state == SDEV_BLOCK && timeleft > 0) { + mutex_unlock(&sdev->state_mutex); + SCSI_LOG_ERROR_RECOVERY(5, sdev_printk(KERN_DEBUG, sdev, + "%s: state %d <> %d\n", __func__, sdev->sdev_state, + SDEV_BLOCK)); + delay = min(timeleft, stall_for); + timeleft -= delay; + msleep(jiffies_to_msecs(delay)); + mutex_lock(&sdev->state_mutex); + } + if (sdev->sdev_state != SDEV_BLOCK) + rtn = shost->hostt->queuecommand(shost, scmd); + else + rtn = SCSI_MLQUEUE_DEVICE_BUSY; + mutex_unlock(&sdev->state_mutex); + if (rtn) { if (timeleft > stall_for) { scsi_eh_restore_cmnd(scmd, &ses); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 65d0a10c76ad..91c007d26c1e 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -40,6 +40,18 @@ #include "scsi_priv.h" #include "scsi_logging.h" +/* + * Size of integrity metadata is usually small, 1 inline sg should + * cover normal cases. + */ +#ifdef CONFIG_ARCH_NO_SG_CHAIN +#define SCSI_INLINE_PROT_SG_CNT 0 +#define SCSI_INLINE_SG_CNT 0 +#else +#define SCSI_INLINE_PROT_SG_CNT 1 +#define SCSI_INLINE_SG_CNT 2 +#endif + static struct kmem_cache *scsi_sdb_cache; static struct kmem_cache *scsi_sense_cache; static struct kmem_cache *scsi_sense_isadma_cache; @@ -72,11 +84,11 @@ int scsi_init_sense_cache(struct Scsi_Host *shost) struct kmem_cache *cache; int ret = 0; + mutex_lock(&scsi_sense_cache_mutex); cache = scsi_select_sense_cache(shost->unchecked_isa_dma); if (cache) - return 0; + goto exit; - mutex_lock(&scsi_sense_cache_mutex); if (shost->unchecked_isa_dma) { scsi_sense_isadma_cache = kmem_cache_create("scsi_sense_cache(DMA)", @@ -92,7 +104,7 @@ int scsi_init_sense_cache(struct Scsi_Host *shost) if (!scsi_sense_cache) ret = -ENOMEM; } - + exit: mutex_unlock(&scsi_sense_cache_mutex); return ret; } @@ -542,9 +554,11 @@ static void scsi_uninit_cmd(struct scsi_cmnd *cmd) static void scsi_mq_free_sgtables(struct scsi_cmnd *cmd) { if (cmd->sdb.table.nents) - sg_free_table_chained(&cmd->sdb.table, true); + sg_free_table_chained(&cmd->sdb.table, + SCSI_INLINE_SG_CNT); if (scsi_prot_sg_count(cmd)) - sg_free_table_chained(&cmd->prot_sdb->table, true); + sg_free_table_chained(&cmd->prot_sdb->table, + SCSI_INLINE_PROT_SG_CNT); } static void scsi_mq_uninit_cmd(struct scsi_cmnd *cmd) @@ -977,7 +991,8 @@ static blk_status_t scsi_init_sgtable(struct request *req, * If sg table allocation fails, requeue request later. */ if (unlikely(sg_alloc_table_chained(&sdb->table, - blk_rq_nr_phys_segments(req), sdb->table.sgl))) + blk_rq_nr_phys_segments(req), sdb->table.sgl, + SCSI_INLINE_SG_CNT))) return BLK_STS_RESOURCE; /* @@ -1031,7 +1046,8 @@ blk_status_t scsi_init_io(struct scsi_cmnd *cmd) ivecs = blk_rq_count_integrity_sg(rq->q, rq->bio); if (sg_alloc_table_chained(&prot_sdb->table, ivecs, - prot_sdb->table.sgl)) { + prot_sdb->table.sgl, + SCSI_INLINE_PROT_SG_CNT)) { ret = BLK_STS_RESOURCE; goto out_free_sgtables; } @@ -1073,6 +1089,18 @@ static void scsi_initialize_rq(struct request *rq) cmd->retries = 0; } +/* + * Only called when the request isn't completed by SCSI, and not freed by + * SCSI + */ +static void scsi_cleanup_rq(struct request *rq) +{ + if (rq->rq_flags & RQF_DONTPREP) { + scsi_mq_uninit_cmd(blk_mq_rq_to_pdu(rq)); + rq->rq_flags &= ~RQF_DONTPREP; + } +} + /* Add a command to the list used by the aacraid and dpt_i2o drivers */ void scsi_add_cmd_to_list(struct scsi_cmnd *cmd) { @@ -1436,7 +1464,7 @@ static void scsi_softirq_done(struct request *rq) disposition = scsi_decide_disposition(cmd); if (disposition != SUCCESS && time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { - sdev_printk(KERN_ERR, cmd->device, + scmd_printk(KERN_ERR, cmd, "timing out command, waited %lus\n", wait_for/HZ); disposition = SUCCESS; @@ -1542,9 +1570,9 @@ static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) } /* Size in bytes of the sg-list stored in the scsi-mq command-private data. */ -static unsigned int scsi_mq_sgl_size(struct Scsi_Host *shost) +static unsigned int scsi_mq_inline_sgl_size(struct Scsi_Host *shost) { - return min_t(unsigned int, shost->sg_tablesize, SG_CHUNK_SIZE) * + return min_t(unsigned int, shost->sg_tablesize, SCSI_INLINE_SG_CNT) * sizeof(struct scatterlist); } @@ -1650,10 +1678,11 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, blk_mq_start_request(req); } + cmd->flags &= SCMD_PRESERVED_FLAGS; if (sdev->simple_tags) cmd->flags |= SCMD_TAGGED; - else - cmd->flags &= ~SCMD_TAGGED; + if (bd->last) + cmd->flags |= SCMD_LAST; scsi_init_cmd_errh(cmd); cmd->scsi_done = scsi_mq_done; @@ -1726,7 +1755,7 @@ static int scsi_mq_init_request(struct blk_mq_tag_set *set, struct request *rq, if (scsi_host_get_prot(shost)) { sg = (void *)cmd + sizeof(struct scsi_cmnd) + shost->hostt->cmd_size; - cmd->prot_sdb = (void *)sg + scsi_mq_sgl_size(shost); + cmd->prot_sdb = (void *)sg + scsi_mq_inline_sgl_size(shost); } return 0; @@ -1768,6 +1797,10 @@ void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) blk_queue_max_integrity_segments(q, shost->sg_prot_tablesize); } + if (dev->dma_mask) { + shost->max_sectors = min_t(unsigned int, shost->max_sectors, + dma_max_mapping_size(dev) >> SECTOR_SHIFT); + } blk_queue_max_hw_sectors(q, shost->max_sectors); if (shost->unchecked_isa_dma) blk_queue_bounce_limit(q, BLK_BOUNCE_ISA); @@ -1775,7 +1808,8 @@ void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) dma_set_seg_boundary(dev, shost->dma_boundary); blk_queue_max_segment_size(q, shost->max_segment_size); - dma_set_max_seg_size(dev, shost->max_segment_size); + blk_queue_virt_boundary(q, shost->virt_boundary_mask); + dma_set_max_seg_size(dev, queue_max_segment_size(q)); /* * Set a reasonable default alignment: The larger of 32-byte (dword), @@ -1788,10 +1822,38 @@ void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) } EXPORT_SYMBOL_GPL(__scsi_init_queue); +static const struct blk_mq_ops scsi_mq_ops_no_commit = { + .get_budget = scsi_mq_get_budget, + .put_budget = scsi_mq_put_budget, + .queue_rq = scsi_queue_rq, + .complete = scsi_softirq_done, + .timeout = scsi_timeout, +#ifdef CONFIG_BLK_DEBUG_FS + .show_rq = scsi_show_rq, +#endif + .init_request = scsi_mq_init_request, + .exit_request = scsi_mq_exit_request, + .initialize_rq_fn = scsi_initialize_rq, + .cleanup_rq = scsi_cleanup_rq, + .busy = scsi_mq_lld_busy, + .map_queues = scsi_map_queues, +}; + + +static void scsi_commit_rqs(struct blk_mq_hw_ctx *hctx) +{ + struct request_queue *q = hctx->queue; + struct scsi_device *sdev = q->queuedata; + struct Scsi_Host *shost = sdev->host; + + shost->hostt->commit_rqs(shost, hctx->queue_num); +} + static const struct blk_mq_ops scsi_mq_ops = { .get_budget = scsi_mq_get_budget, .put_budget = scsi_mq_put_budget, .queue_rq = scsi_queue_rq, + .commit_rqs = scsi_commit_rqs, .complete = scsi_softirq_done, .timeout = scsi_timeout, #ifdef CONFIG_BLK_DEBUG_FS @@ -1800,6 +1862,7 @@ static const struct blk_mq_ops scsi_mq_ops = { .init_request = scsi_mq_init_request, .exit_request = scsi_mq_exit_request, .initialize_rq_fn = scsi_initialize_rq, + .cleanup_rq = scsi_cleanup_rq, .busy = scsi_mq_lld_busy, .map_queues = scsi_map_queues, }; @@ -1820,13 +1883,18 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost) { unsigned int cmd_size, sgl_size; - sgl_size = scsi_mq_sgl_size(shost); + sgl_size = max_t(unsigned int, sizeof(struct scatterlist), + scsi_mq_inline_sgl_size(shost)); cmd_size = sizeof(struct scsi_cmnd) + shost->hostt->cmd_size + sgl_size; if (scsi_host_get_prot(shost)) - cmd_size += sizeof(struct scsi_data_buffer) + sgl_size; + cmd_size += sizeof(struct scsi_data_buffer) + + sizeof(struct scatterlist) * SCSI_INLINE_PROT_SG_CNT; memset(&shost->tag_set, 0, sizeof(shost->tag_set)); - shost->tag_set.ops = &scsi_mq_ops; + if (shost->hostt->commit_rqs) + shost->tag_set.ops = &scsi_mq_ops; + else + shost->tag_set.ops = &scsi_mq_ops_no_commit; shost->tag_set.nr_hw_queues = shost->nr_hw_queues ? : 1; shost->tag_set.queue_depth = shost->can_queue; shost->tag_set.cmd_size = cmd_size; @@ -1855,7 +1923,8 @@ struct scsi_device *scsi_device_from_queue(struct request_queue *q) { struct scsi_device *sdev = NULL; - if (q->mq_ops == &scsi_mq_ops) + if (q->mq_ops == &scsi_mq_ops_no_commit || + q->mq_ops == &scsi_mq_ops) sdev = q->queuedata; if (!sdev || !get_device(&sdev->sdev_gendev)) sdev = NULL; @@ -2616,10 +2685,6 @@ EXPORT_SYMBOL_GPL(scsi_internal_device_block_nowait); * a legal transition). When the device is in this state, command processing * is paused until the device leaves the SDEV_BLOCK state. See also * scsi_internal_device_unblock(). - * - * To do: avoid that scsi_send_eh_cmnd() calls queuecommand() after - * scsi_internal_device_block() has blocked a SCSI device and also - * remove the rport mutex lock and unlock calls from srp_queuecommand(). */ static int scsi_internal_device_block(struct scsi_device *sdev) { @@ -2660,6 +2725,14 @@ void scsi_start_queue(struct scsi_device *sdev) int scsi_internal_device_unblock_nowait(struct scsi_device *sdev, enum scsi_device_state new_state) { + switch (new_state) { + case SDEV_RUNNING: + case SDEV_TRANSPORT_OFFLINE: + break; + default: + return -EINVAL; + } + /* * Try to transition the scsi device to SDEV_RUNNING or one of the * offlined states and goose the device queue if successful. @@ -2717,7 +2790,12 @@ static int scsi_internal_device_unblock(struct scsi_device *sdev, static void device_block(struct scsi_device *sdev, void *data) { - scsi_internal_device_block(sdev); + int ret; + + ret = scsi_internal_device_block(sdev); + + WARN_ONCE(ret, "scsi_internal_device_block(%s) failed: ret = %d\n", + dev_name(&sdev->sdev_gendev), ret); } static int diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c index 39b8cc4574b4..c6ed0b12e807 100644 --- a/drivers/scsi/scsi_logging.c +++ b/drivers/scsi/scsi_logging.c @@ -15,57 +15,15 @@ #include <scsi/scsi_eh.h> #include <scsi/scsi_dbg.h> -#define SCSI_LOG_SPOOLSIZE 4096 - -#if (SCSI_LOG_SPOOLSIZE / SCSI_LOG_BUFSIZE) > BITS_PER_LONG -#warning SCSI logging bitmask too large -#endif - -struct scsi_log_buf { - char buffer[SCSI_LOG_SPOOLSIZE]; - unsigned long map; -}; - -static DEFINE_PER_CPU(struct scsi_log_buf, scsi_format_log); - static char *scsi_log_reserve_buffer(size_t *len) { - struct scsi_log_buf *buf; - unsigned long map_bits = sizeof(buf->buffer) / SCSI_LOG_BUFSIZE; - unsigned long idx = 0; - - preempt_disable(); - buf = this_cpu_ptr(&scsi_format_log); - idx = find_first_zero_bit(&buf->map, map_bits); - if (likely(idx < map_bits)) { - while (test_and_set_bit(idx, &buf->map)) { - idx = find_next_zero_bit(&buf->map, map_bits, idx); - if (idx >= map_bits) - break; - } - } - if (WARN_ON(idx >= map_bits)) { - preempt_enable(); - return NULL; - } - *len = SCSI_LOG_BUFSIZE; - return buf->buffer + idx * SCSI_LOG_BUFSIZE; + *len = 128; + return kmalloc(*len, GFP_ATOMIC); } static void scsi_log_release_buffer(char *bufptr) { - struct scsi_log_buf *buf; - unsigned long idx; - int ret; - - buf = this_cpu_ptr(&scsi_format_log); - if (bufptr >= buf->buffer && - bufptr < buf->buffer + SCSI_LOG_SPOOLSIZE) { - idx = (bufptr - buf->buffer) / SCSI_LOG_BUFSIZE; - ret = test_and_clear_bit(idx, &buf->map); - WARN_ON(!ret); - } - preempt_enable(); + kfree(bufptr); } static inline const char *scmd_name(const struct scsi_cmnd *scmd) diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index 48ee68059fe6..3717eea37ecb 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -94,8 +94,7 @@ static int scsi_dev_type_resume(struct device *dev, if (!err && scsi_is_sdev_device(dev)) { struct scsi_device *sdev = to_scsi_device(dev); - if (sdev->request_queue->dev) - blk_set_runtime_active(sdev->request_queue); + blk_set_runtime_active(sdev->request_queue); } } @@ -176,11 +175,7 @@ static int scsi_bus_resume_common(struct device *dev, static int scsi_bus_prepare(struct device *dev) { - if (scsi_is_sdev_device(dev)) { - /* sd probing uses async_schedule. Wait until it finishes. */ - async_synchronize_full_domain(&scsi_sd_probe_domain); - - } else if (scsi_is_host_device(dev)) { + if (scsi_is_host_device(dev)) { /* Wait until async scanning is finished */ scsi_complete_async_scans(); } diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 5f21547b2ad2..cc2859d76d81 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -175,7 +175,6 @@ static inline void scsi_autopm_put_host(struct Scsi_Host *h) {} #endif /* CONFIG_PM */ extern struct async_domain scsi_sd_pm_domain; -extern struct async_domain scsi_sd_probe_domain; /* scsi_dh.c */ #ifdef CONFIG_SCSI_DH diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 7f0ceb65c3f3..5b313226f11c 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -372,15 +372,10 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, return err; } -static int always_match(struct device *dev, void *data) -{ - return 1; -} - static inline struct device *next_scsi_device(struct device *start) { - struct device *next = bus_find_device(&scsi_bus_type, start, NULL, - always_match); + struct device *next = bus_find_next_device(&scsi_bus_type, start); + put_device(start); return next; } diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index dbb206c90ecf..6d7362e7367e 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -730,6 +730,14 @@ sdev_store_delete(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct kernfs_node *kn; + struct scsi_device *sdev = to_scsi_device(dev); + + /* + * We need to try to get module, avoiding the module been removed + * during delete. + */ + if (scsi_device_get(sdev)) + return -ENODEV; kn = sysfs_break_active_protection(&dev->kobj, &attr->attr); WARN_ON_ONCE(!kn); @@ -744,9 +752,10 @@ sdev_store_delete(struct device *dev, struct device_attribute *attr, * state into SDEV_DEL. */ device_remove_file(dev, attr); - scsi_remove_device(to_scsi_device(dev)); + scsi_remove_device(sdev); if (kn) sysfs_unbreak_active_protection(kn); + scsi_device_put(sdev); return count; }; static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete); @@ -767,8 +776,13 @@ store_state_field(struct device *dev, struct device_attribute *attr, break; } } - if (!state) + switch (state) { + case SDEV_RUNNING: + case SDEV_OFFLINE: + break; + default: return -EINVAL; + } mutex_lock(&sdev->state_mutex); ret = scsi_device_set_state(sdev, state); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 118a687709ed..2732fa65119c 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -3,9 +3,6 @@ * FiberChannel transport specific attributes exported to sysfs. * * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. - * - * ======== - * * Copyright (C) 2004-2007 James Smart, Emulex Corporation * Rewrite for host, target, device, and remote port attributes, * statistics, and service functions... diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index a3406bd62391..470ee6dc3f7e 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -568,6 +568,7 @@ static struct scsi_driver sd_template = { .name = "sd", .owner = THIS_MODULE, .probe = sd_probe, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, .remove = sd_remove, .shutdown = sd_shutdown, .pm = &sd_pm_ops, @@ -1165,11 +1166,12 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) sector_t lba = sectors_to_logical(sdp, blk_rq_pos(rq)); sector_t threshold; unsigned int nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq)); - bool dif, dix; unsigned int mask = logical_to_sectors(sdp, 1) - 1; bool write = rq_data_dir(rq) == WRITE; unsigned char protect, fua; blk_status_t ret; + unsigned int dif; + bool dix; ret = scsi_init_io(cmd); if (ret != BLK_STS_OK) @@ -1210,9 +1212,6 @@ static blk_status_t sd_setup_read_write_cmnd(struct scsi_cmnd *cmd) dix = scsi_prot_sg_count(cmd); dif = scsi_host_dif_capable(cmd->device->host, sdkp->protection_type); - if (write && dix) - t10_pi_prepare(cmd->request, sdkp->protection_type); - if (dif || dix) protect = sd_setup_protect_cmnd(cmd, dix, dif); else @@ -1292,7 +1291,17 @@ static blk_status_t sd_init_command(struct scsi_cmnd *cmd) case REQ_OP_WRITE: return sd_setup_read_write_cmnd(cmd); case REQ_OP_ZONE_RESET: - return sd_zbc_setup_reset_cmnd(cmd); + return sd_zbc_setup_zone_mgmt_cmnd(cmd, ZO_RESET_WRITE_POINTER, + false); + case REQ_OP_ZONE_RESET_ALL: + return sd_zbc_setup_zone_mgmt_cmnd(cmd, ZO_RESET_WRITE_POINTER, + true); + case REQ_OP_ZONE_OPEN: + return sd_zbc_setup_zone_mgmt_cmnd(cmd, ZO_OPEN_ZONE, false); + case REQ_OP_ZONE_CLOSE: + return sd_zbc_setup_zone_mgmt_cmnd(cmd, ZO_CLOSE_ZONE, false); + case REQ_OP_ZONE_FINISH: + return sd_zbc_setup_zone_mgmt_cmnd(cmd, ZO_FINISH_ZONE, false); default: WARN_ON_ONCE(1); return BLK_STS_NOTSUPP; @@ -1654,7 +1663,8 @@ static int sd_sync_cache(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr) /* we need to evaluate the error return */ if (scsi_sense_valid(sshdr) && (sshdr->asc == 0x3a || /* medium not present */ - sshdr->asc == 0x20)) /* invalid command */ + sshdr->asc == 0x20 || /* invalid command */ + (sshdr->asc == 0x74 && sshdr->ascq == 0x71))) /* drive is password locked */ /* this is no error here */ return 0; @@ -1958,6 +1968,10 @@ static int sd_done(struct scsi_cmnd *SCpnt) case REQ_OP_WRITE_ZEROES: case REQ_OP_WRITE_SAME: case REQ_OP_ZONE_RESET: + case REQ_OP_ZONE_RESET_ALL: + case REQ_OP_ZONE_OPEN: + case REQ_OP_ZONE_CLOSE: + case REQ_OP_ZONE_FINISH: if (!result) { good_bytes = blk_rq_bytes(req); scsi_set_resid(SCpnt, 0); @@ -1977,6 +1991,7 @@ static int sd_done(struct scsi_cmnd *SCpnt) sd_printk(KERN_INFO, sdkp, "Unaligned partial completion (resid=%u, sector_sz=%u)\n", resid, sector_size); + scsi_print_command(SCpnt); resid = min(scsi_bufflen(SCpnt), round_up(resid, sector_size)); scsi_set_resid(SCpnt, resid); @@ -2050,11 +2065,6 @@ static int sd_done(struct scsi_cmnd *SCpnt) "sd_done: completed %d of %d bytes\n", good_bytes, scsi_bufflen(SCpnt))); - if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt) && - good_bytes) - t10_pi_complete(SCpnt->request, sdkp->protection_type, - good_bytes / scsi_prot_interval(SCpnt)); - return good_bytes; } @@ -3252,69 +3262,6 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) return 0; } -/* - * The asynchronous part of sd_probe - */ -static void sd_probe_async(void *data, async_cookie_t cookie) -{ - struct scsi_disk *sdkp = data; - struct scsi_device *sdp; - struct gendisk *gd; - u32 index; - struct device *dev; - - sdp = sdkp->device; - gd = sdkp->disk; - index = sdkp->index; - dev = &sdp->sdev_gendev; - - gd->major = sd_major((index & 0xf0) >> 4); - gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); - - gd->fops = &sd_fops; - gd->private_data = &sdkp->driver; - gd->queue = sdkp->device->request_queue; - - /* defaults, until the device tells us otherwise */ - sdp->sector_size = 512; - sdkp->capacity = 0; - sdkp->media_present = 1; - sdkp->write_prot = 0; - sdkp->cache_override = 0; - sdkp->WCE = 0; - sdkp->RCD = 0; - sdkp->ATO = 0; - sdkp->first_scan = 1; - sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS; - - sd_revalidate_disk(gd); - - gd->flags = GENHD_FL_EXT_DEVT; - if (sdp->removable) { - gd->flags |= GENHD_FL_REMOVABLE; - gd->events |= DISK_EVENT_MEDIA_CHANGE; - gd->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT; - } - - blk_pm_runtime_init(sdp->request_queue, dev); - device_add_disk(dev, gd, NULL); - if (sdkp->capacity) - sd_dif_config_host(sdkp); - - sd_revalidate_disk(gd); - - if (sdkp->security) { - sdkp->opal_dev = init_opal_dev(sdp, &sd_sec_submit); - if (sdkp->opal_dev) - sd_printk(KERN_NOTICE, sdkp, "supports TCG Opal\n"); - } - - sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", - sdp->removable ? "removable " : ""); - scsi_autopm_put_device(sdp); - put_device(&sdkp->dev); -} - /** * sd_probe - called during driver initialization and whenever a * new scsi device is attached to the system. It is called once @@ -3404,8 +3351,50 @@ static int sd_probe(struct device *dev) get_device(dev); dev_set_drvdata(dev, sdkp); - get_device(&sdkp->dev); /* prevent release before async_schedule */ - async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain); + gd->major = sd_major((index & 0xf0) >> 4); + gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); + + gd->fops = &sd_fops; + gd->private_data = &sdkp->driver; + gd->queue = sdkp->device->request_queue; + + /* defaults, until the device tells us otherwise */ + sdp->sector_size = 512; + sdkp->capacity = 0; + sdkp->media_present = 1; + sdkp->write_prot = 0; + sdkp->cache_override = 0; + sdkp->WCE = 0; + sdkp->RCD = 0; + sdkp->ATO = 0; + sdkp->first_scan = 1; + sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS; + + sd_revalidate_disk(gd); + + gd->flags = GENHD_FL_EXT_DEVT; + if (sdp->removable) { + gd->flags |= GENHD_FL_REMOVABLE; + gd->events |= DISK_EVENT_MEDIA_CHANGE; + gd->event_flags = DISK_EVENT_FLAG_POLL | DISK_EVENT_FLAG_UEVENT; + } + + blk_pm_runtime_init(sdp->request_queue, dev); + device_add_disk(dev, gd, NULL); + if (sdkp->capacity) + sd_dif_config_host(sdkp); + + sd_revalidate_disk(gd); + + if (sdkp->security) { + sdkp->opal_dev = init_opal_dev(sdp, &sd_sec_submit); + if (sdkp->opal_dev) + sd_printk(KERN_NOTICE, sdkp, "supports TCG Opal\n"); + } + + sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", + sdp->removable ? "removable " : ""); + scsi_autopm_put_device(sdp); return 0; @@ -3441,7 +3430,6 @@ static int sd_remove(struct device *dev) scsi_autopm_get_device(sdkp->device); async_synchronize_full_domain(&scsi_sd_pm_domain); - async_synchronize_full_domain(&scsi_sd_probe_domain); device_del(&sdkp->dev); del_gendisk(sdkp->disk); sd_shutdown(dev); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 5796ace76225..42fd3f00e4a5 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -209,12 +209,12 @@ static inline int sd_is_zoned(struct scsi_disk *sdkp) extern int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer); extern void sd_zbc_print_zones(struct scsi_disk *sdkp); -extern blk_status_t sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd); +blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd, + unsigned char op, bool all); extern void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes, struct scsi_sense_hdr *sshdr); -extern int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, - struct blk_zone *zones, unsigned int *nr_zones, - gfp_t gfp_mask); +int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, + unsigned int nr_zones, report_zones_cb cb, void *data); #else /* CONFIG_BLK_DEV_ZONED */ @@ -226,7 +226,9 @@ static inline int sd_zbc_read_zones(struct scsi_disk *sdkp, static inline void sd_zbc_print_zones(struct scsi_disk *sdkp) {} -static inline blk_status_t sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd) +static inline blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd, + unsigned char op, + bool all) { return BLK_STS_TARGET; } diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c index 7334024b64f1..0e5ede48f045 100644 --- a/drivers/scsi/sd_zbc.c +++ b/drivers/scsi/sd_zbc.c @@ -9,6 +9,8 @@ */ #include <linux/blkdev.h> +#include <linux/vmalloc.h> +#include <linux/sched/mm.h> #include <asm/unaligned.h> @@ -17,40 +19,33 @@ #include "sd.h" -/** - * sd_zbc_parse_report - Convert a zone descriptor to a struct blk_zone, - * @sdkp: The disk the report originated from - * @buf: Address of the report zone descriptor - * @zone: the destination zone structure - * - * All LBA sized values are converted to 512B sectors unit. - */ -static void sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf, - struct blk_zone *zone) +static int sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf, + unsigned int idx, report_zones_cb cb, void *data) { struct scsi_device *sdp = sdkp->device; + struct blk_zone zone = { 0 }; - memset(zone, 0, sizeof(struct blk_zone)); - - zone->type = buf[0] & 0x0f; - zone->cond = (buf[1] >> 4) & 0xf; + zone.type = buf[0] & 0x0f; + zone.cond = (buf[1] >> 4) & 0xf; if (buf[1] & 0x01) - zone->reset = 1; + zone.reset = 1; if (buf[1] & 0x02) - zone->non_seq = 1; - - zone->len = logical_to_sectors(sdp, get_unaligned_be64(&buf[8])); - zone->start = logical_to_sectors(sdp, get_unaligned_be64(&buf[16])); - zone->wp = logical_to_sectors(sdp, get_unaligned_be64(&buf[24])); - if (zone->type != ZBC_ZONE_TYPE_CONV && - zone->cond == ZBC_ZONE_COND_FULL) - zone->wp = zone->start + zone->len; + zone.non_seq = 1; + + zone.len = logical_to_sectors(sdp, get_unaligned_be64(&buf[8])); + zone.start = logical_to_sectors(sdp, get_unaligned_be64(&buf[16])); + zone.wp = logical_to_sectors(sdp, get_unaligned_be64(&buf[24])); + if (zone.type != ZBC_ZONE_TYPE_CONV && + zone.cond == ZBC_ZONE_COND_FULL) + zone.wp = zone.start + zone.len; + + return cb(&zone, idx, data); } /** * sd_zbc_do_report_zones - Issue a REPORT ZONES scsi command. * @sdkp: The target disk - * @buf: Buffer to use for the reply + * @buf: vmalloc-ed buffer to use for the reply * @buflen: the buffer size * @lba: Start LBA of the report * @partial: Do partial report @@ -79,7 +74,6 @@ static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf, put_unaligned_be32(buflen, &cmd[10]); if (partial) cmd[14] = ZBC_REPORT_ZONE_PARTIAL; - memset(buf, 0, buflen); result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, buf, buflen, &sshdr, @@ -104,76 +98,122 @@ static int sd_zbc_do_report_zones(struct scsi_disk *sdkp, unsigned char *buf, } /** - * sd_zbc_report_zones - Disk report zones operation. - * @disk: The target disk - * @sector: Start 512B sector of the report - * @zones: Array of zone descriptors - * @nr_zones: Number of descriptors in the array - * @gfp_mask: Memory allocation mask + * Allocate a buffer for report zones reply. + * @sdkp: The target disk + * @nr_zones: Maximum number of zones to report + * @buflen: Size of the buffer allocated + * + * Try to allocate a reply buffer for the number of requested zones. + * The size of the buffer allocated may be smaller than requested to + * satify the device constraint (max_hw_sectors, max_segments, etc). * - * Execute a report zones command on the target disk. + * Return the address of the allocated buffer and update @buflen with + * the size of the allocated buffer. + */ +static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp, + unsigned int nr_zones, size_t *buflen) +{ + struct request_queue *q = sdkp->disk->queue; + size_t bufsize; + void *buf; + + /* + * Report zone buffer size should be at most 64B times the number of + * zones requested plus the 64B reply header, but should be at least + * SECTOR_SIZE for ATA devices. + * Make sure that this size does not exceed the hardware capabilities. + * Furthermore, since the report zone command cannot be split, make + * sure that the allocated buffer can always be mapped by limiting the + * number of pages allocated to the HBA max segments limit. + */ + nr_zones = min(nr_zones, sdkp->nr_zones); + bufsize = roundup((nr_zones + 1) * 64, SECTOR_SIZE); + bufsize = min_t(size_t, bufsize, + queue_max_hw_sectors(q) << SECTOR_SHIFT); + bufsize = min_t(size_t, bufsize, queue_max_segments(q) << PAGE_SHIFT); + + while (bufsize >= SECTOR_SIZE) { + buf = __vmalloc(bufsize, + GFP_KERNEL | __GFP_ZERO | __GFP_NORETRY, + PAGE_KERNEL); + if (buf) { + *buflen = bufsize; + return buf; + } + bufsize >>= 1; + } + + return NULL; +} + +/** + * sd_zbc_zone_sectors - Get the device zone size in number of 512B sectors. + * @sdkp: The target disk */ +static inline sector_t sd_zbc_zone_sectors(struct scsi_disk *sdkp) +{ + return logical_to_sectors(sdkp->device, sdkp->zone_blocks); +} + int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, - struct blk_zone *zones, unsigned int *nr_zones, - gfp_t gfp_mask) + unsigned int nr_zones, report_zones_cb cb, void *data) { struct scsi_disk *sdkp = scsi_disk(disk); - unsigned int i, buflen, nrz = *nr_zones; + unsigned int nr, i; unsigned char *buf; - size_t offset = 0; - int ret = 0; + size_t offset, buflen = 0; + int zone_idx = 0; + int ret; if (!sd_is_zoned(sdkp)) /* Not a zoned device */ return -EOPNOTSUPP; - /* - * Get a reply buffer for the number of requested zones plus a header, - * without exceeding the device maximum command size. For ATA disks, - * buffers must be aligned to 512B. - */ - buflen = min(queue_max_hw_sectors(disk->queue) << 9, - roundup((nrz + 1) * 64, 512)); - buf = kmalloc(buflen, gfp_mask); + buf = sd_zbc_alloc_report_buffer(sdkp, nr_zones, &buflen); if (!buf) return -ENOMEM; - ret = sd_zbc_do_report_zones(sdkp, buf, buflen, - sectors_to_logical(sdkp->device, sector), true); - if (ret) - goto out_free_buf; + while (zone_idx < nr_zones && sector < get_capacity(disk)) { + ret = sd_zbc_do_report_zones(sdkp, buf, buflen, + sectors_to_logical(sdkp->device, sector), true); + if (ret) + goto out; + + offset = 0; + nr = min(nr_zones, get_unaligned_be32(&buf[0]) / 64); + if (!nr) + break; + + for (i = 0; i < nr && zone_idx < nr_zones; i++) { + offset += 64; + ret = sd_zbc_parse_report(sdkp, buf + offset, zone_idx, + cb, data); + if (ret) + goto out; + zone_idx++; + } - nrz = min(nrz, get_unaligned_be32(&buf[0]) / 64); - for (i = 0; i < nrz; i++) { - offset += 64; - sd_zbc_parse_report(sdkp, buf + offset, zones); - zones++; + sector += sd_zbc_zone_sectors(sdkp) * i; } - *nr_zones = nrz; - -out_free_buf: - kfree(buf); - + ret = zone_idx; +out: + kvfree(buf); return ret; } /** - * sd_zbc_zone_sectors - Get the device zone size in number of 512B sectors. - * @sdkp: The target disk - */ -static inline sector_t sd_zbc_zone_sectors(struct scsi_disk *sdkp) -{ - return logical_to_sectors(sdkp->device, sdkp->zone_blocks); -} - -/** - * sd_zbc_setup_reset_cmnd - Prepare a RESET WRITE POINTER scsi command. + * sd_zbc_setup_zone_mgmt_cmnd - Prepare a zone ZBC_OUT command. The operations + * can be RESET WRITE POINTER, OPEN, CLOSE or FINISH. * @cmd: the command to setup + * @op: Operation to be performed + * @all: All zones control * - * Called from sd_init_command() for a REQ_OP_ZONE_RESET request. + * Called from sd_init_command() for REQ_OP_ZONE_RESET, REQ_OP_ZONE_RESET_ALL, + * REQ_OP_ZONE_OPEN, REQ_OP_ZONE_CLOSE or REQ_OP_ZONE_FINISH requests. */ -blk_status_t sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd) +blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd, + unsigned char op, bool all) { struct request *rq = cmd->request; struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); @@ -194,8 +234,11 @@ blk_status_t sd_zbc_setup_reset_cmnd(struct scsi_cmnd *cmd) cmd->cmd_len = 16; memset(cmd->cmnd, 0, cmd->cmd_len); cmd->cmnd[0] = ZBC_OUT; - cmd->cmnd[1] = ZO_RESET_WRITE_POINTER; - put_unaligned_be64(block, &cmd->cmnd[2]); + cmd->cmnd[1] = op; + if (all) + cmd->cmnd[14] = 0x1; + else + put_unaligned_be64(block, &cmd->cmnd[2]); rq->timeout = SD_TIMEOUT; cmd->sc_data_direction = DMA_NONE; @@ -220,24 +263,16 @@ void sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes, int result = cmd->result; struct request *rq = cmd->request; - switch (req_op(rq)) { - case REQ_OP_ZONE_RESET: - - if (result && - sshdr->sense_key == ILLEGAL_REQUEST && - sshdr->asc == 0x24) - /* - * INVALID FIELD IN CDB error: reset of a conventional - * zone was attempted. Nothing to worry about, so be - * quiet about the error. - */ - rq->rq_flags |= RQF_QUIET; - break; - - case REQ_OP_WRITE: - case REQ_OP_WRITE_ZEROES: - case REQ_OP_WRITE_SAME: - break; + if (op_is_zone_mgmt(req_op(rq)) && + result && + sshdr->sense_key == ILLEGAL_REQUEST && + sshdr->asc == 0x24) { + /* + * INVALID FIELD IN CDB error: a zone management command was + * attempted on a conventional zone. Nothing to worry about, + * so be quiet about the error. + */ + rq->rq_flags |= RQF_QUIET; } } @@ -287,8 +322,6 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp, return 0; } -#define SD_ZBC_BUF_SIZE 131072U - /** * sd_zbc_check_zones - Check the device capacity and zone sizes * @sdkp: Target disk @@ -302,26 +335,18 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp, * Returns the zone size in number of blocks upon success or an error code * upon failure. */ -static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks) +static int sd_zbc_check_zones(struct scsi_disk *sdkp, unsigned char *buf, + u32 *zblocks) { u64 zone_blocks = 0; - sector_t max_lba, block = 0; - unsigned char *buf; + sector_t max_lba; unsigned char *rec; - unsigned int buf_len; - unsigned int list_length; int ret; - u8 same; - - /* Get a buffer */ - buf = kmalloc(SD_ZBC_BUF_SIZE, GFP_KERNEL); - if (!buf) - return -ENOMEM; - /* Do a report zone to get max_lba and the same field */ - ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0, false); + /* Do a report zone to get max_lba and the size of the first zone */ + ret = sd_zbc_do_report_zones(sdkp, buf, SD_BUF_SIZE, 0, false); if (ret) - goto out_free; + return ret; if (sdkp->rc_basis == 0) { /* The max_lba field is the capacity of this device */ @@ -336,88 +361,34 @@ static int sd_zbc_check_zones(struct scsi_disk *sdkp, u32 *zblocks) } } - /* - * Check same field: for any value other than 0, we know that all zones - * have the same size. - */ - same = buf[4] & 0x0f; - if (same > 0) { - rec = &buf[64]; - zone_blocks = get_unaligned_be64(&rec[8]); - goto out; - } - - /* - * Check the size of all zones: all zones must be of - * equal size, except the last zone which can be smaller - * than other zones. - */ - do { - - /* Parse REPORT ZONES header */ - list_length = get_unaligned_be32(&buf[0]) + 64; - rec = buf + 64; - buf_len = min(list_length, SD_ZBC_BUF_SIZE); - - /* Parse zone descriptors */ - while (rec < buf + buf_len) { - u64 this_zone_blocks = get_unaligned_be64(&rec[8]); - - if (zone_blocks == 0) { - zone_blocks = this_zone_blocks; - } else if (this_zone_blocks != zone_blocks && - (block + this_zone_blocks < sdkp->capacity - || this_zone_blocks > zone_blocks)) { - zone_blocks = 0; - goto out; - } - block += this_zone_blocks; - rec += 64; - } - - if (block < sdkp->capacity) { - ret = sd_zbc_do_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, - block, true); - if (ret) - goto out_free; - } - - } while (block < sdkp->capacity); - -out: - if (!zone_blocks) { - if (sdkp->first_scan) - sd_printk(KERN_NOTICE, sdkp, - "Devices with non constant zone " - "size are not supported\n"); - ret = -ENODEV; - } else if (!is_power_of_2(zone_blocks)) { + /* Parse REPORT ZONES header */ + rec = buf + 64; + zone_blocks = get_unaligned_be64(&rec[8]); + if (!zone_blocks || !is_power_of_2(zone_blocks)) { if (sdkp->first_scan) sd_printk(KERN_NOTICE, sdkp, "Devices with non power of 2 zone " "size are not supported\n"); - ret = -ENODEV; - } else if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) { + return -ENODEV; + } + + if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) { if (sdkp->first_scan) sd_printk(KERN_NOTICE, sdkp, "Zone size too large\n"); - ret = -EFBIG; - } else { - *zblocks = zone_blocks; - ret = 0; + return -EFBIG; } -out_free: - kfree(buf); + *zblocks = zone_blocks; - return ret; + return 0; } int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf) { struct gendisk *disk = sdkp->disk; unsigned int nr_zones; - u32 zone_blocks; + u32 zone_blocks = 0; int ret; if (!sd_is_zoned(sdkp)) @@ -436,13 +407,16 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf) * Check zone size: only devices with a constant zone size (except * an eventual last runt zone) that is a power of 2 are supported. */ - ret = sd_zbc_check_zones(sdkp, &zone_blocks); + ret = sd_zbc_check_zones(sdkp, buf, &zone_blocks); if (ret != 0) goto err; /* The drive satisfies the kernel restrictions: set it up */ blk_queue_chunk_sectors(sdkp->disk->queue, logical_to_sectors(sdkp->device, zone_blocks)); + blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, sdkp->disk->queue); + blk_queue_required_elevator_features(sdkp->disk->queue, + ELEVATOR_F_ZBD_SEQ_WRITE); nr_zones = round_up(sdkp->capacity, zone_blocks) >> ilog2(zone_blocks); /* READ16/WRITE16 is mandatory for ZBC disks */ diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 60f01a7b728c..c2afba2a5414 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -3,12 +3,7 @@ * SCSI Enclosure Services * * Copyright (C) 2008 James Bottomley <James.Bottomley@HansenPartnership.com> - * -**----------------------------------------------------------------------------- -** -** -**----------------------------------------------------------------------------- -*/ + */ #include <linux/slab.h> #include <linux/module.h> diff --git a/drivers/scsi/smartpqi/Kconfig b/drivers/scsi/smartpqi/Kconfig index 97e159c2cecd..bc6506884e3b 100644 --- a/drivers/scsi/smartpqi/Kconfig +++ b/drivers/scsi/smartpqi/Kconfig @@ -1,6 +1,8 @@ # # Kernel configuration file for the SMARTPQI # +# Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries +# Copyright (c) 2017-2018 Microsemi Corporation # Copyright (c) 2016 Microsemi Corporation # Copyright (c) 2016 PMC-Sierra, Inc. # (mailto:esc.storagedev@microsemi.com) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index e8e768849c70..79d2af36f655 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -822,6 +822,7 @@ union pqi_reset_register { #define PQI_HBA_BUS 2 #define PQI_EXTERNAL_RAID_VOLUME_BUS 3 #define PQI_MAX_BUS PQI_EXTERNAL_RAID_VOLUME_BUS +#define PQI_VSEP_CISS_BTL 379 struct report_lun_header { __be32 list_length; @@ -930,6 +931,9 @@ struct pqi_scsi_dev { u8 active_path_index; u8 path_map; u8 bay; + u8 box_index; + u8 phys_box_on_bus; + u8 phy_connected_dev_type; u8 box[8]; u16 phys_connector[8]; bool raid_bypass_configured; /* RAID bypass configured */ @@ -1073,6 +1077,9 @@ struct pqi_ctrl_info { unsigned int ctrl_id; struct pci_dev *pci_dev; char firmware_version[11]; + char serial_number[17]; + char model[17]; + char vendor[9]; void __iomem *iomem_base; struct pqi_ctrl_registers __iomem *registers; struct pqi_device_registers __iomem *pqi_registers; @@ -1224,12 +1231,21 @@ struct bmic_identify_controller { __le16 extended_logical_unit_count; u8 reserved1[34]; __le16 firmware_build_number; - u8 reserved2[100]; + u8 reserved2[8]; + u8 vendor_id[8]; + u8 product_id[16]; + u8 reserved3[68]; u8 controller_mode; - u8 reserved3[32]; + u8 reserved4[32]; +}; + +struct bmic_sense_subsystem_info { + u8 reserved[44]; + u8 ctrl_serial_number[16]; }; #define SA_EXPANDER_SMP_DEVICE 0x05 +#define SA_CONTROLLER_DEVICE 0x07 /*SCSI Invalid Device Type for SAS devices*/ #define PQI_SAS_SCSI_INVALID_DEVTYPE 0xff diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 8fd5ffc55792..ea5409bebf57 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -33,11 +33,11 @@ #define BUILD_TIMESTAMP #endif -#define DRIVER_VERSION "1.2.6-015" +#define DRIVER_VERSION "1.2.8-026" #define DRIVER_MAJOR 1 #define DRIVER_MINOR 2 -#define DRIVER_RELEASE 6 -#define DRIVER_REVISION 15 +#define DRIVER_RELEASE 8 +#define DRIVER_REVISION 26 #define DRIVER_NAME "Microsemi PQI Driver (v" \ DRIVER_VERSION BUILD_TIMESTAMP ")" @@ -145,6 +145,18 @@ MODULE_PARM_DESC(lockup_action, "Action to take when controller locked up.\n" "\t\tSupported: none, reboot, panic\n" "\t\tDefault: none"); +static int pqi_expose_ld_first; +module_param_named(expose_ld_first, + pqi_expose_ld_first, int, 0644); +MODULE_PARM_DESC(expose_ld_first, + "Expose logical drives before physical drives."); + +static int pqi_hide_vsep; +module_param_named(hide_vsep, + pqi_hide_vsep, int, 0644); +MODULE_PARM_DESC(hide_vsep, + "Hide the virtual SEP for direct attached drives."); + static char *raid_levels[] = { "RAID-0", "RAID-4", @@ -472,6 +484,7 @@ static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info, /* fall through */ case BMIC_IDENTIFY_CONTROLLER: case BMIC_IDENTIFY_PHYSICAL_DEVICE: + case BMIC_SENSE_SUBSYSTEM_INFORMATION: request->data_direction = SOP_READ_FLAG; cdb[0] = BMIC_READ; cdb[6] = cmd; @@ -600,6 +613,14 @@ static inline int pqi_identify_controller(struct pqi_ctrl_info *ctrl_info, buffer, sizeof(*buffer)); } +static inline int pqi_sense_subsystem_info(struct pqi_ctrl_info *ctrl_info, + struct bmic_sense_subsystem_info *sense_info) +{ + return pqi_send_ctrl_raid_request(ctrl_info, + BMIC_SENSE_SUBSYSTEM_INFORMATION, + sense_info, sizeof(*sense_info)); +} + static inline int pqi_scsi_inquiry(struct pqi_ctrl_info *ctrl_info, u8 *scsi3addr, u16 vpd_page, void *buffer, size_t buffer_length) { @@ -1392,7 +1413,9 @@ static void pqi_get_physical_disk_info(struct pqi_ctrl_info *ctrl_info, device->queue_depth = PQI_PHYSICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH; return; } - + device->box_index = id_phys->box_index; + device->phys_box_on_bus = id_phys->phys_box_on_bus; + device->phy_connected_dev_type = id_phys->phy_connected_dev_type[0]; device->queue_depth = get_unaligned_le16(&id_phys->current_queue_depth_limit); device->device_type = id_phys->device_type; @@ -1719,6 +1742,10 @@ static void pqi_scsi_update_device(struct pqi_scsi_dev *existing_device, existing_device->active_path_index = new_device->active_path_index; existing_device->path_map = new_device->path_map; existing_device->bay = new_device->bay; + existing_device->box_index = new_device->box_index; + existing_device->phys_box_on_bus = new_device->phys_box_on_bus; + existing_device->phy_connected_dev_type = + new_device->phy_connected_dev_type; memcpy(existing_device->box, new_device->box, sizeof(existing_device->box)); memcpy(existing_device->phys_connector, new_device->phys_connector, @@ -1945,6 +1972,11 @@ static inline bool pqi_skip_device(u8 *scsi3addr) return false; } +static inline void pqi_mask_device(u8 *scsi3addr) +{ + scsi3addr[3] |= 0xc0; +} + static inline bool pqi_is_device_with_sas_address(struct pqi_scsi_dev *device) { if (!device->is_physical_device) @@ -1988,6 +2020,8 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) unsigned int num_valid_devices; bool is_physical_device; u8 *scsi3addr; + unsigned int physical_index; + unsigned int logical_index; static char *out_of_memory_msg = "failed to allocate memory, device discovery stopped"; @@ -2023,6 +2057,21 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) rc = -ENOMEM; goto out; } + if (pqi_hide_vsep) { + int i; + + for (i = num_physicals - 1; i >= 0; i--) { + phys_lun_ext_entry = + &physdev_list->lun_entries[i]; + if (CISS_GET_DRIVE_NUMBER( + phys_lun_ext_entry->lunid) == + PQI_VSEP_CISS_BTL) { + pqi_mask_device( + phys_lun_ext_entry->lunid); + break; + } + } + } } num_new_devices = num_physicals + num_logicals; @@ -2050,19 +2099,23 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) device = NULL; num_valid_devices = 0; + physical_index = 0; + logical_index = 0; for (i = 0; i < num_new_devices; i++) { - if (i < num_physicals) { + if ((!pqi_expose_ld_first && i < num_physicals) || + (pqi_expose_ld_first && i >= num_logicals)) { is_physical_device = true; - phys_lun_ext_entry = &physdev_list->lun_entries[i]; + phys_lun_ext_entry = + &physdev_list->lun_entries[physical_index++]; log_lun_ext_entry = NULL; scsi3addr = phys_lun_ext_entry->lunid; } else { is_physical_device = false; phys_lun_ext_entry = NULL; log_lun_ext_entry = - &logdev_list->lun_entries[i - num_physicals]; + &logdev_list->lun_entries[logical_index++]; scsi3addr = log_lun_ext_entry->lunid; } @@ -2122,11 +2175,10 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) device->aio_handle = phys_lun_ext_entry->aio_handle; } - if (device->devtype == TYPE_DISK || - device->devtype == TYPE_ZBC) { + pqi_get_physical_disk_info(ctrl_info, device, id_phys); - } + } else { memcpy(device->volume_id, log_lun_ext_entry->volume_id, sizeof(device->volume_id)); @@ -2184,18 +2236,20 @@ static void pqi_remove_all_scsi_devices(struct pqi_ctrl_info *ctrl_info) static int pqi_scan_scsi_devices(struct pqi_ctrl_info *ctrl_info) { - int rc; + int rc = 0; if (pqi_ctrl_offline(ctrl_info)) return -ENXIO; - mutex_lock(&ctrl_info->scan_mutex); - - rc = pqi_update_scsi_devices(ctrl_info); - if (rc) + if (!mutex_trylock(&ctrl_info->scan_mutex)) { pqi_schedule_rescan_worker_delayed(ctrl_info); - - mutex_unlock(&ctrl_info->scan_mutex); + rc = -EINPROGRESS; + } else { + rc = pqi_update_scsi_devices(ctrl_info); + if (rc) + pqi_schedule_rescan_worker_delayed(ctrl_info); + mutex_unlock(&ctrl_info->scan_mutex); + } return rc; } @@ -6091,23 +6145,65 @@ static int pqi_ioctl(struct scsi_device *sdev, unsigned int cmd, return rc; } -static ssize_t pqi_version_show(struct device *dev, +static ssize_t pqi_firmware_version_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + struct Scsi_Host *shost; + struct pqi_ctrl_info *ctrl_info; + + shost = class_to_shost(dev); + ctrl_info = shost_to_hba(shost); + + return snprintf(buffer, PAGE_SIZE, "%s\n", ctrl_info->firmware_version); +} + +static ssize_t pqi_driver_version_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + struct Scsi_Host *shost; + struct pqi_ctrl_info *ctrl_info; + + shost = class_to_shost(dev); + ctrl_info = shost_to_hba(shost); + + return snprintf(buffer, PAGE_SIZE, + "%s\n", DRIVER_VERSION BUILD_TIMESTAMP); +} + +static ssize_t pqi_serial_number_show(struct device *dev, struct device_attribute *attr, char *buffer) { - ssize_t count = 0; struct Scsi_Host *shost; struct pqi_ctrl_info *ctrl_info; shost = class_to_shost(dev); ctrl_info = shost_to_hba(shost); - count += snprintf(buffer + count, PAGE_SIZE - count, - " driver: %s\n", DRIVER_VERSION BUILD_TIMESTAMP); + return snprintf(buffer, PAGE_SIZE, "%s\n", ctrl_info->serial_number); +} + +static ssize_t pqi_model_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + struct Scsi_Host *shost; + struct pqi_ctrl_info *ctrl_info; - count += snprintf(buffer + count, PAGE_SIZE - count, - "firmware: %s\n", ctrl_info->firmware_version); + shost = class_to_shost(dev); + ctrl_info = shost_to_hba(shost); - return count; + return snprintf(buffer, PAGE_SIZE, "%s\n", ctrl_info->model); +} + +static ssize_t pqi_vendor_show(struct device *dev, + struct device_attribute *attr, char *buffer) +{ + struct Scsi_Host *shost; + struct pqi_ctrl_info *ctrl_info; + + shost = class_to_shost(dev); + ctrl_info = shost_to_hba(shost); + + return snprintf(buffer, PAGE_SIZE, "%s\n", ctrl_info->vendor); } static ssize_t pqi_host_rescan_store(struct device *dev, @@ -6160,13 +6256,21 @@ static ssize_t pqi_lockup_action_store(struct device *dev, return -EINVAL; } -static DEVICE_ATTR(version, 0444, pqi_version_show, NULL); +static DEVICE_ATTR(driver_version, 0444, pqi_driver_version_show, NULL); +static DEVICE_ATTR(firmware_version, 0444, pqi_firmware_version_show, NULL); +static DEVICE_ATTR(model, 0444, pqi_model_show, NULL); +static DEVICE_ATTR(serial_number, 0444, pqi_serial_number_show, NULL); +static DEVICE_ATTR(vendor, 0444, pqi_vendor_show, NULL); static DEVICE_ATTR(rescan, 0200, NULL, pqi_host_rescan_store); static DEVICE_ATTR(lockup_action, 0644, pqi_lockup_action_show, pqi_lockup_action_store); static struct device_attribute *pqi_shost_attrs[] = { - &dev_attr_version, + &dev_attr_driver_version, + &dev_attr_firmware_version, + &dev_attr_model, + &dev_attr_serial_number, + &dev_attr_vendor, &dev_attr_rescan, &dev_attr_lockup_action, NULL @@ -6558,7 +6662,30 @@ static int pqi_reset(struct pqi_ctrl_info *ctrl_info) return rc; } -static int pqi_get_ctrl_firmware_version(struct pqi_ctrl_info *ctrl_info) +static int pqi_get_ctrl_serial_number(struct pqi_ctrl_info *ctrl_info) +{ + int rc; + struct bmic_sense_subsystem_info *sense_info; + + sense_info = kzalloc(sizeof(*sense_info), GFP_KERNEL); + if (!sense_info) + return -ENOMEM; + + rc = pqi_sense_subsystem_info(ctrl_info, sense_info); + if (rc) + goto out; + + memcpy(ctrl_info->serial_number, sense_info->ctrl_serial_number, + sizeof(sense_info->ctrl_serial_number)); + ctrl_info->serial_number[sizeof(sense_info->ctrl_serial_number)] = '\0'; + +out: + kfree(sense_info); + + return rc; +} + +static int pqi_get_ctrl_product_details(struct pqi_ctrl_info *ctrl_info) { int rc; struct bmic_identify_controller *identify; @@ -6579,6 +6706,14 @@ static int pqi_get_ctrl_firmware_version(struct pqi_ctrl_info *ctrl_info) sizeof(ctrl_info->firmware_version), "-%u", get_unaligned_le16(&identify->firmware_build_number)); + memcpy(ctrl_info->model, identify->product_id, + sizeof(identify->product_id)); + ctrl_info->model[sizeof(identify->product_id)] = '\0'; + + memcpy(ctrl_info->vendor, identify->vendor_id, + sizeof(identify->vendor_id)); + ctrl_info->vendor[sizeof(identify->vendor_id)] = '\0'; + out: kfree(identify); @@ -7098,10 +7233,17 @@ static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info) if (rc) return rc; - rc = pqi_get_ctrl_firmware_version(ctrl_info); + rc = pqi_get_ctrl_product_details(ctrl_info); if (rc) { dev_err(&ctrl_info->pci_dev->dev, - "error obtaining firmware version\n"); + "error obtaining product details\n"); + return rc; + } + + rc = pqi_get_ctrl_serial_number(ctrl_info); + if (rc) { + dev_err(&ctrl_info->pci_dev->dev, + "error obtaining ctrl serial number\n"); return rc; } @@ -7241,10 +7383,10 @@ static int pqi_ctrl_init_resume(struct pqi_ctrl_info *ctrl_info) return rc; } - rc = pqi_get_ctrl_firmware_version(ctrl_info); + rc = pqi_get_ctrl_product_details(ctrl_info); if (rc) { dev_err(&ctrl_info->pci_dev->dev, - "error obtaining firmware version\n"); + "error obtaining product detail\n"); return rc; } @@ -8024,6 +8166,10 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1bd4, 0x004f) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, 0x19e5, 0xd227) }, { @@ -8088,6 +8234,14 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_ADAPTEC2, 0x0808) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_ADAPTEC2, 0x0809) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_VENDOR_ID_ADAPTEC2, 0x0900) }, { @@ -8244,6 +8398,26 @@ static const struct pci_device_id pqi_pci_id_table[] = { }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1d8d, 0x0800) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1d8d, 0x0908) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1d8d, 0x0806) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + 0x1d8d, 0x0916) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, + PCI_VENDOR_ID_GIGABYTE, 0x1000) + }, + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f, PCI_ANY_ID, PCI_ANY_ID) }, { 0 } diff --git a/drivers/scsi/smartpqi/smartpqi_sas_transport.c b/drivers/scsi/smartpqi/smartpqi_sas_transport.c index 5cca1b9ef1f1..6776dfc1d317 100644 --- a/drivers/scsi/smartpqi/smartpqi_sas_transport.c +++ b/drivers/scsi/smartpqi/smartpqi_sas_transport.c @@ -312,12 +312,110 @@ static int pqi_sas_get_linkerrors(struct sas_phy *phy) static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) { - return 0; + + int rc; + unsigned long flags; + struct Scsi_Host *shost; + struct pqi_ctrl_info *ctrl_info; + struct pqi_scsi_dev *found_device; + struct pqi_scsi_dev *device; + + if (!rphy) + return -ENODEV; + + shost = rphy_to_shost(rphy); + ctrl_info = shost_to_hba(shost); + spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags); + found_device = pqi_find_device_by_sas_rphy(ctrl_info, rphy); + + if (!found_device) { + rc = -ENODEV; + goto out; + } + + if (found_device->devtype == TYPE_ENCLOSURE) { + *identifier = get_unaligned_be64(&found_device->wwid); + rc = 0; + goto out; + } + + if (found_device->box_index == 0xff || + found_device->phys_box_on_bus == 0 || + found_device->bay == 0xff) { + rc = -EINVAL; + goto out; + } + + list_for_each_entry(device, &ctrl_info->scsi_device_list, + scsi_device_list_entry) { + if (device->devtype == TYPE_ENCLOSURE && + device->box_index == found_device->box_index && + device->phys_box_on_bus == + found_device->phys_box_on_bus && + memcmp(device->phys_connector, + found_device->phys_connector, 2) == 0) { + *identifier = + get_unaligned_be64(&device->wwid); + rc = 0; + goto out; + } + } + + if (found_device->phy_connected_dev_type != SA_CONTROLLER_DEVICE) { + rc = -EINVAL; + goto out; + } + + list_for_each_entry(device, &ctrl_info->scsi_device_list, + scsi_device_list_entry) { + if (device->devtype == TYPE_ENCLOSURE && + CISS_GET_DRIVE_NUMBER(device->scsi3addr) == + PQI_VSEP_CISS_BTL) { + *identifier = get_unaligned_be64(&device->wwid); + rc = 0; + goto out; + } + } + + rc = -EINVAL; +out: + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); + + return rc; + } static int pqi_sas_get_bay_identifier(struct sas_rphy *rphy) { - return -ENXIO; + + int rc; + unsigned long flags; + struct pqi_ctrl_info *ctrl_info; + struct pqi_scsi_dev *device; + struct Scsi_Host *shost; + + if (!rphy) + return -ENODEV; + + shost = rphy_to_shost(rphy); + ctrl_info = shost_to_hba(shost); + spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags); + device = pqi_find_device_by_sas_rphy(ctrl_info, rphy); + + if (!device) { + rc = -ENODEV; + goto out; + } + + if (device->bay == 0xff) + rc = -EINVAL; + else + rc = device->bay; + +out: + spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); + + return rc; } static int pqi_sas_phy_reset(struct sas_phy *phy, int hard_reset) diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c index aef4881d8e21..a85d52b5dc32 100644 --- a/drivers/scsi/sni_53c710.c +++ b/drivers/scsi/sni_53c710.c @@ -66,10 +66,8 @@ static int snirm710_probe(struct platform_device *dev) base = res->start; hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL); - if (!hostdata) { - dev_printk(KERN_ERR, dev, "Failed to allocate host data\n"); + if (!hostdata) return -ENOMEM; - } hostdata->dev = &dev->dev; dma_set_mask(&dev->dev, DMA_BIT_MASK(32)); diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index baada5b50bb1..e3266a64a477 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -228,7 +228,6 @@ static DEFINE_IDR(st_index_idr); -#include "osst_detect.h" #ifndef SIGS_FROM_OSST #define SIGS_FROM_OSST \ {"OnStream", "SC-", "", "osst"}, \ @@ -4267,9 +4266,10 @@ static int st_probe(struct device *dev) if (SDp->type != TYPE_TAPE) return -ENODEV; if ((stp = st_incompatible(SDp))) { - sdev_printk(KERN_INFO, SDp, "Found incompatible tape\n"); sdev_printk(KERN_INFO, SDp, - "st: The suggested driver is %s.\n", stp); + "OnStream tapes are no longer supported;\n"); + sdev_printk(KERN_INFO, SDp, + "please mail to linux-scsi@vger.kernel.org.\n"); return -ENODEV; } diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index b89269120a2d..542d2bac2922 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -375,6 +375,7 @@ enum storvsc_request_type { static int storvsc_ringbuffer_size = (128 * 1024); static u32 max_outstanding_req_per_channel; +static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth); static int storvsc_vcpus_per_sub_channel = 4; @@ -1422,9 +1423,6 @@ static int storvsc_device_configure(struct scsi_device *sdevice) { blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ)); - /* Ensure there are no gaps in presented sgls */ - blk_queue_virt_boundary(sdevice->request_queue, PAGE_SIZE - 1); - sdevice->no_write_same = 1; /* @@ -1697,8 +1695,11 @@ static struct scsi_host_template scsi_driver = { .this_id = -1, /* Make sure we dont get a sg segment crosses a page boundary */ .dma_boundary = PAGE_SIZE-1, + /* Ensure there are no gaps in presented sgls */ + .virt_boundary_mask = PAGE_SIZE-1, .no_write_same = 1, .track_queue_depth = 1, + .change_queue_depth = storvsc_change_queue_depth, }; enum { @@ -1836,8 +1837,7 @@ static int storvsc_probe(struct hv_device *device, /* * Set the number of HW queues we are supporting. */ - if (stor_device->num_sc != 0) - host->nr_hw_queues = stor_device->num_sc + 1; + host->nr_hw_queues = num_present_cpus(); /* * Set the error handler work queue. @@ -1905,6 +1905,15 @@ err_out0: return ret; } +/* Change a scsi target's queue depth */ +static int storvsc_change_queue_depth(struct scsi_device *sdev, int queue_depth) +{ + if (queue_depth > scsi_driver.can_queue) + queue_depth = scsi_driver.can_queue; + + return scsi_change_queue_depth(sdev, queue_depth); +} + static int storvsc_remove(struct hv_device *dev) { struct storvsc_device *stor_device = hv_get_drvdata(dev); diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index 3d80ab67a626..955e4c938d49 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -397,10 +397,12 @@ static int sun3scsi_dma_finish(int write_flag) case CSR_LEFT_3: *vaddr = (dregs->bpack_lo & 0xff00) >> 8; vaddr--; + /* Fall through */ case CSR_LEFT_2: *vaddr = (dregs->bpack_hi & 0x00ff); vaddr--; + /* Fall through */ case CSR_LEFT_1: *vaddr = (dregs->bpack_hi & 0xff00) >> 8; diff --git a/drivers/scsi/sym53c8xx_2/sym_nvram.c b/drivers/scsi/sym53c8xx_2/sym_nvram.c index dd3f07b31612..9dc17f1288f9 100644 --- a/drivers/scsi/sym53c8xx_2/sym_nvram.c +++ b/drivers/scsi/sym53c8xx_2/sym_nvram.c @@ -648,7 +648,7 @@ static int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram) { u_char gpcntl, gpreg; u_char old_gpcntl, old_gpreg; - int retv = 1; + int retv; /* save current state of GPCNTL and GPREG */ old_gpreg = INB(np, nc_gpreg); diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c index 86dbb723f3ac..b2af04c57a39 100644 --- a/drivers/scsi/ufs/cdns-pltfrm.c +++ b/drivers/scsi/ufs/cdns-pltfrm.c @@ -62,23 +62,47 @@ static int cdns_ufs_set_hclkdiv(struct ufs_hba *hba) } /** - * Sets clocks used by the controller + * Called before and after HCE enable bit is set. * @hba: host controller instance - * @on: if true, enable clocks, otherwise disable * @status: notify stage (pre, post change) * * Return zero for success and non-zero for failure */ -static int cdns_ufs_setup_clocks(struct ufs_hba *hba, bool on, - enum ufs_notify_change_status status) +static int cdns_ufs_hce_enable_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) { - if ((!on) || (status == PRE_CHANGE)) + if (status != PRE_CHANGE) return 0; return cdns_ufs_set_hclkdiv(hba); } /** + * Called before and after Link startup is carried out. + * @hba: host controller instance + * @status: notify stage (pre, post change) + * + * Return zero for success and non-zero for failure + */ +static int cdns_ufs_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + if (status != PRE_CHANGE) + return 0; + + /* + * Some UFS devices have issues if LCC is enabled. + * So we are setting PA_Local_TX_LCC_Enable to 0 + * before link startup which will make sure that both host + * and device TX LCC are disabled once link startup is + * completed. + */ + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0); + + return 0; +} + +/** * cdns_ufs_init - performs additional ufs initialization * @hba: host controller instance * @@ -114,13 +138,15 @@ static int cdns_ufs_m31_16nm_phy_initialization(struct ufs_hba *hba) static const struct ufs_hba_variant_ops cdns_ufs_pltfm_hba_vops = { .name = "cdns-ufs-pltfm", - .setup_clocks = cdns_ufs_setup_clocks, + .hce_enable_notify = cdns_ufs_hce_enable_notify, + .link_startup_notify = cdns_ufs_link_startup_notify, }; static const struct ufs_hba_variant_ops cdns_ufs_m31_16nm_pltfm_hba_vops = { .name = "cdns-ufs-pltfm", .init = cdns_ufs_init, - .setup_clocks = cdns_ufs_setup_clocks, + .hce_enable_notify = cdns_ufs_hce_enable_notify, + .link_startup_notify = cdns_ufs_link_startup_notify, .phy_initialization = cdns_ufs_m31_16nm_phy_initialization, }; diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c index f4d1dca962c4..6bbb1679bb91 100644 --- a/drivers/scsi/ufs/ufs-hisi.c +++ b/drivers/scsi/ufs/ufs-hisi.c @@ -447,13 +447,11 @@ static int ufs_hisi_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) static int ufs_hisi_get_resource(struct ufs_hisi_host *host) { - struct resource *mem_res; struct device *dev = host->hba->dev; struct platform_device *pdev = to_platform_device(dev); /* get resource of ufs sys ctrl */ - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - host->ufs_sys_ctrl = devm_ioremap_resource(dev, mem_res); + host->ufs_sys_ctrl = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(host->ufs_sys_ctrl)) return PTR_ERR(host->ufs_sys_ctrl); diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index b4d1b5c22987..a5b71487a206 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -3,10 +3,12 @@ * Copyright (c) 2013-2016, Linux Foundation. All rights reserved. */ +#include <linux/acpi.h> #include <linux/time.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/phy/phy.h> +#include <linux/gpio/consumer.h> #include <linux/reset-controller.h> #include "ufshcd.h" @@ -161,6 +163,9 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) int err = 0; struct device *dev = host->hba->dev; + if (has_acpi_companion(dev)) + return 0; + err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk", &host->rx_l0_sync_clk, false); if (err) @@ -796,7 +801,6 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_max_params, struct ufs_pa_layer_attr *dev_req_params) { - u32 val; struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct ufs_dev_params ufs_qcom_cap; int ret = 0; @@ -865,8 +869,6 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, ret = -EINVAL; } - val = ~(MAX_U32 << dev_req_params->lane_tx); - /* cache the power mode parameters to use internally */ memcpy(&host->dev_req_params, dev_req_params, sizeof(*dev_req_params)); @@ -1127,8 +1129,21 @@ static int ufs_qcom_init(struct ufs_hba *hba) __func__, err); goto out_variant_clear; } else if (IS_ERR(host->generic_phy)) { - err = PTR_ERR(host->generic_phy); - dev_err(dev, "%s: PHY get failed %d\n", __func__, err); + if (has_acpi_companion(dev)) { + host->generic_phy = NULL; + } else { + err = PTR_ERR(host->generic_phy); + dev_err(dev, "%s: PHY get failed %d\n", __func__, err); + goto out_variant_clear; + } + } + + host->device_reset = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(host->device_reset)) { + err = PTR_ERR(host->device_reset); + if (err != -EPROBE_DEFER) + dev_err(dev, "failed to acquire reset gpio: %d\n", err); goto out_variant_clear; } @@ -1538,12 +1553,37 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba) } /** + * ufs_qcom_device_reset() - toggle the (optional) device reset line + * @hba: per-adapter instance + * + * Toggles the (optional) reset line to reset the attached device. + */ +static void ufs_qcom_device_reset(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + + /* reset gpio is optional */ + if (!host->device_reset) + return; + + /* + * The UFS device shall detect reset pulses of 1us, sleep for 10us to + * be on the safe side. + */ + gpiod_set_value_cansleep(host->device_reset, 1); + usleep_range(10, 15); + + gpiod_set_value_cansleep(host->device_reset, 0); + usleep_range(10, 15); +} + +/** * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations * * The variant operations configure the necessary controller and PHY * handshake during initialization. */ -static struct ufs_hba_variant_ops ufs_hba_qcom_vops = { +static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .name = "qcom", .init = ufs_qcom_init, .exit = ufs_qcom_exit, @@ -1557,6 +1597,7 @@ static struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .suspend = ufs_qcom_suspend, .resume = ufs_qcom_resume, .dbg_register_dump = ufs_qcom_dump_dbg_regs, + .device_reset = ufs_qcom_device_reset, }; /** @@ -1599,6 +1640,14 @@ static const struct of_device_id ufs_qcom_of_match[] = { }; MODULE_DEVICE_TABLE(of, ufs_qcom_of_match); +#ifdef CONFIG_ACPI +static const struct acpi_device_id ufs_qcom_acpi_match[] = { + { "QCOM24A5" }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, ufs_qcom_acpi_match); +#endif + static const struct dev_pm_ops ufs_qcom_pm_ops = { .suspend = ufshcd_pltfrm_suspend, .resume = ufshcd_pltfrm_resume, @@ -1615,6 +1664,7 @@ static struct platform_driver ufs_qcom_pltform = { .name = "ufshcd-qcom", .pm = &ufs_qcom_pm_ops, .of_match_table = of_match_ptr(ufs_qcom_of_match), + .acpi_match_table = ACPI_PTR(ufs_qcom_acpi_match), }, }; module_platform_driver(ufs_qcom_pltform); diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 001915d1e0e4..d401f174bb70 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -195,6 +195,8 @@ struct ufs_qcom_testbus { u8 select_minor; }; +struct gpio_desc; + struct ufs_qcom_host { /* * Set this capability if host controller supports the QUniPro mode @@ -232,6 +234,8 @@ struct ufs_qcom_host { struct ufs_qcom_testbus testbus; struct reset_controller_dev rcdev; + + struct gpio_desc *device_reset; }; static inline u32 diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c index 8d9332bb7d0c..969a36b15897 100644 --- a/drivers/scsi/ufs/ufs-sysfs.c +++ b/drivers/scsi/ufs/ufs-sysfs.c @@ -122,7 +122,7 @@ static void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit) { unsigned long flags; - if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT)) + if (!ufshcd_is_auto_hibern8_supported(hba)) return; spin_lock_irqsave(hba->host->host_lock, flags); @@ -164,7 +164,7 @@ static ssize_t auto_hibern8_show(struct device *dev, { struct ufs_hba *hba = dev_get_drvdata(dev); - if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT)) + if (!ufshcd_is_auto_hibern8_supported(hba)) return -EOPNOTSUPP; return snprintf(buf, PAGE_SIZE, "%d\n", ufshcd_ahit_to_us(hba->ahit)); @@ -177,7 +177,7 @@ static ssize_t auto_hibern8_store(struct device *dev, struct ufs_hba *hba = dev_get_drvdata(dev); unsigned int timer; - if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT)) + if (!ufshcd_is_auto_hibern8_supported(hba)) return -EOPNOTSUPP; if (kstrtouint(buf, 0, &timer)) @@ -571,9 +571,10 @@ static ssize_t _name##_show(struct device *dev, \ int ret; \ int desc_len = QUERY_DESC_MAX_SIZE; \ u8 *desc_buf; \ + \ desc_buf = kzalloc(QUERY_DESC_MAX_SIZE, GFP_ATOMIC); \ - if (!desc_buf) \ - return -ENOMEM; \ + if (!desc_buf) \ + return -ENOMEM; \ ret = ufshcd_query_descriptor_retry(hba, \ UPIU_QUERY_OPCODE_READ_DESC, QUERY_DESC_IDN_DEVICE, \ 0, 0, desc_buf, &desc_len); \ @@ -582,14 +583,13 @@ static ssize_t _name##_show(struct device *dev, \ goto out; \ } \ index = desc_buf[DEVICE_DESC_PARAM##_pname]; \ - memset(desc_buf, 0, QUERY_DESC_MAX_SIZE); \ - if (ufshcd_read_string_desc(hba, index, desc_buf, \ - QUERY_DESC_MAX_SIZE, true)) { \ - ret = -EINVAL; \ + kfree(desc_buf); \ + desc_buf = NULL; \ + ret = ufshcd_read_string_desc(hba, index, &desc_buf, \ + SD_ASCII_STD); \ + if (ret < 0) \ goto out; \ - } \ - ret = snprintf(buf, PAGE_SIZE, "%s\n", \ - desc_buf + QUERY_DESC_HDR_SIZE); \ + ret = snprintf(buf, PAGE_SIZE, "%s\n", desc_buf); \ out: \ kfree(desc_buf); \ return ret; \ diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 99a9c4d16f6b..3327981ef894 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -541,7 +541,7 @@ struct ufs_dev_info { */ struct ufs_dev_desc { u16 wmanufacturerid; - char model[MAX_MODEL_LEN + 1]; + u8 *model; }; /** diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c index 869e71f861d6..dc2f6d2b46ed 100644 --- a/drivers/scsi/ufs/ufs_bsg.c +++ b/drivers/scsi/ufs/ufs_bsg.c @@ -98,6 +98,8 @@ static int ufs_bsg_request(struct bsg_job *job) bsg_reply->reply_payload_rcv_len = 0; + pm_runtime_get_sync(hba->dev); + msgcode = bsg_request->msgcode; switch (msgcode) { case UPIU_TRANSACTION_QUERY_REQ: @@ -122,7 +124,7 @@ static int ufs_bsg_request(struct bsg_job *job) memcpy(&uc, &bsg_request->upiu_req.uc, UIC_CMD_SIZE); ret = ufshcd_send_uic_cmd(hba, &uc); if (ret) - dev_dbg(hba->dev, + dev_err(hba->dev, "send uic cmd: error code %d\n", ret); memcpy(&bsg_reply->upiu_rsp.uc, &uc, UIC_CMD_SIZE); @@ -135,6 +137,8 @@ static int ufs_bsg_request(struct bsg_job *job) break; } + pm_runtime_put_sync(hba->dev); + if (!desc_buff) goto out; @@ -149,7 +153,9 @@ static int ufs_bsg_request(struct bsg_job *job) out: bsg_reply->result = ret; job->reply_len = sizeof(struct ufs_bsg_reply); - bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len); + /* complete the job here only if no error */ + if (ret == 0) + bsg_job_done(job, ret, bsg_reply->reply_payload_rcv_len); return ret; } diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c index ffe6f82182ba..3b19de3ae9a3 100644 --- a/drivers/scsi/ufs/ufshcd-pci.c +++ b/drivers/scsi/ufs/ufshcd-pci.c @@ -200,6 +200,8 @@ static const struct dev_pm_ops ufshcd_pci_pm_ops = { static const struct pci_device_id ufshcd_pci_tbl[] = { { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VDEVICE(INTEL, 0x9DFA), (kernel_ulong_t)&ufs_intel_cnl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x4B41), (kernel_ulong_t)&ufs_intel_cnl_hba_vops }, + { PCI_VDEVICE(INTEL, 0x4B43), (kernel_ulong_t)&ufs_intel_cnl_hba_vops }, { } /* terminate list */ }; diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index d7d521b394c3..8d40dc918f4e 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -391,12 +391,10 @@ int ufshcd_pltfrm_init(struct platform_device *pdev, { struct ufs_hba *hba; void __iomem *mmio_base; - struct resource *mem_res; int irq, err; struct device *dev = &pdev->dev; - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mmio_base = devm_ioremap_resource(dev, mem_res); + mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mmio_base)) { err = PTR_ERR(mmio_base); goto out; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 3fe3029617a8..11a87f51c442 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -299,16 +299,6 @@ static void ufshcd_scsi_block_requests(struct ufs_hba *hba) scsi_block_requests(hba->host); } -/* replace non-printable or non-ASCII characters with spaces */ -static inline void ufshcd_remove_non_printable(char *val) -{ - if (!val) - return; - - if (*val < 0x20 || *val > 0x7e) - *val = ' '; -} - static void ufshcd_add_cmd_upiu_trace(struct ufs_hba *hba, unsigned int tag, const char *str) { @@ -390,24 +380,25 @@ static void ufshcd_print_clk_freqs(struct ufs_hba *hba) } } -static void ufshcd_print_uic_err_hist(struct ufs_hba *hba, - struct ufs_uic_err_reg_hist *err_hist, char *err_name) +static void ufshcd_print_err_hist(struct ufs_hba *hba, + struct ufs_err_reg_hist *err_hist, + char *err_name) { int i; bool found = false; - for (i = 0; i < UIC_ERR_REG_HIST_LENGTH; i++) { - int p = (i + err_hist->pos) % UIC_ERR_REG_HIST_LENGTH; + for (i = 0; i < UFS_ERR_REG_HIST_LENGTH; i++) { + int p = (i + err_hist->pos) % UFS_ERR_REG_HIST_LENGTH; if (err_hist->reg[p] == 0) continue; - dev_err(hba->dev, "%s[%d] = 0x%x at %lld us\n", err_name, i, + dev_err(hba->dev, "%s[%d] = 0x%x at %lld us\n", err_name, p, err_hist->reg[p], ktime_to_us(err_hist->tstamp[p])); found = true; } if (!found) - dev_err(hba->dev, "No record of %s uic errors\n", err_name); + dev_err(hba->dev, "No record of %s errors\n", err_name); } static void ufshcd_print_host_regs(struct ufs_hba *hba) @@ -423,11 +414,22 @@ static void ufshcd_print_host_regs(struct ufs_hba *hba) ktime_to_us(hba->ufs_stats.last_hibern8_exit_tstamp), hba->ufs_stats.hibern8_exit_cnt); - ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.pa_err, "pa_err"); - ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.dl_err, "dl_err"); - ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.nl_err, "nl_err"); - ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.tl_err, "tl_err"); - ufshcd_print_uic_err_hist(hba, &hba->ufs_stats.dme_err, "dme_err"); + ufshcd_print_err_hist(hba, &hba->ufs_stats.pa_err, "pa_err"); + ufshcd_print_err_hist(hba, &hba->ufs_stats.dl_err, "dl_err"); + ufshcd_print_err_hist(hba, &hba->ufs_stats.nl_err, "nl_err"); + ufshcd_print_err_hist(hba, &hba->ufs_stats.tl_err, "tl_err"); + ufshcd_print_err_hist(hba, &hba->ufs_stats.dme_err, "dme_err"); + ufshcd_print_err_hist(hba, &hba->ufs_stats.auto_hibern8_err, + "auto_hibern8_err"); + ufshcd_print_err_hist(hba, &hba->ufs_stats.fatal_err, "fatal_err"); + ufshcd_print_err_hist(hba, &hba->ufs_stats.link_startup_err, + "link_startup_fail"); + ufshcd_print_err_hist(hba, &hba->ufs_stats.resume_err, "resume_fail"); + ufshcd_print_err_hist(hba, &hba->ufs_stats.suspend_err, + "suspend_fail"); + ufshcd_print_err_hist(hba, &hba->ufs_stats.dev_reset, "dev_reset"); + ufshcd_print_err_hist(hba, &hba->ufs_stats.host_reset, "host_reset"); + ufshcd_print_err_hist(hba, &hba->ufs_stats.task_abort, "task_abort"); ufshcd_print_clk_freqs(hba); @@ -3199,7 +3201,7 @@ out: static inline int ufshcd_read_desc(struct ufs_hba *hba, enum desc_idn desc_id, int desc_index, - u8 *buf, + void *buf, u32 size) { return ufshcd_read_desc_param(hba, desc_id, desc_index, 0, buf, size); @@ -3218,48 +3220,77 @@ static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size) } /** + * struct uc_string_id - unicode string + * + * @len: size of this descriptor inclusive + * @type: descriptor type + * @uc: unicode string character + */ +struct uc_string_id { + u8 len; + u8 type; + wchar_t uc[0]; +} __packed; + +/* replace non-printable or non-ASCII characters with spaces */ +static inline char ufshcd_remove_non_printable(u8 ch) +{ + return (ch >= 0x20 && ch <= 0x7e) ? ch : ' '; +} + +/** * ufshcd_read_string_desc - read string descriptor * @hba: pointer to adapter instance * @desc_index: descriptor index - * @buf: pointer to buffer where descriptor would be read - * @size: size of buf + * @buf: pointer to buffer where descriptor would be read, + * the caller should free the memory. * @ascii: if true convert from unicode to ascii characters + * null terminated string. * - * Return 0 in case of success, non-zero otherwise + * Return: + * * string size on success. + * * -ENOMEM: on allocation failure + * * -EINVAL: on a wrong parameter */ -int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, - u8 *buf, u32 size, bool ascii) +int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, + u8 **buf, bool ascii) { - int err = 0; + struct uc_string_id *uc_str; + u8 *str; + int ret; - err = ufshcd_read_desc(hba, - QUERY_DESC_IDN_STRING, desc_index, buf, size); + if (!buf) + return -EINVAL; - if (err) { - dev_err(hba->dev, "%s: reading String Desc failed after %d retries. err = %d\n", - __func__, QUERY_REQ_RETRIES, err); + uc_str = kzalloc(QUERY_DESC_MAX_SIZE, GFP_KERNEL); + if (!uc_str) + return -ENOMEM; + + ret = ufshcd_read_desc(hba, QUERY_DESC_IDN_STRING, + desc_index, uc_str, + QUERY_DESC_MAX_SIZE); + if (ret < 0) { + dev_err(hba->dev, "Reading String Desc failed after %d retries. err = %d\n", + QUERY_REQ_RETRIES, ret); + str = NULL; + goto out; + } + + if (uc_str->len <= QUERY_DESC_HDR_SIZE) { + dev_dbg(hba->dev, "String Desc is of zero length\n"); + str = NULL; + ret = 0; goto out; } if (ascii) { - int desc_len; - int ascii_len; + ssize_t ascii_len; int i; - char *buff_ascii; - - desc_len = buf[0]; /* remove header and divide by 2 to move from UTF16 to UTF8 */ - ascii_len = (desc_len - QUERY_DESC_HDR_SIZE) / 2 + 1; - if (size < ascii_len + QUERY_DESC_HDR_SIZE) { - dev_err(hba->dev, "%s: buffer allocated size is too small\n", - __func__); - err = -ENOMEM; - goto out; - } - - buff_ascii = kmalloc(ascii_len, GFP_KERNEL); - if (!buff_ascii) { - err = -ENOMEM; + ascii_len = (uc_str->len - QUERY_DESC_HDR_SIZE) / 2 + 1; + str = kzalloc(ascii_len, GFP_KERNEL); + if (!str) { + ret = -ENOMEM; goto out; } @@ -3267,22 +3298,28 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, * the descriptor contains string in UTF16 format * we need to convert to utf-8 so it can be displayed */ - utf16s_to_utf8s((wchar_t *)&buf[QUERY_DESC_HDR_SIZE], - desc_len - QUERY_DESC_HDR_SIZE, - UTF16_BIG_ENDIAN, buff_ascii, ascii_len); + ret = utf16s_to_utf8s(uc_str->uc, + uc_str->len - QUERY_DESC_HDR_SIZE, + UTF16_BIG_ENDIAN, str, ascii_len); /* replace non-printable or non-ASCII characters with spaces */ - for (i = 0; i < ascii_len; i++) - ufshcd_remove_non_printable(&buff_ascii[i]); + for (i = 0; i < ret; i++) + str[i] = ufshcd_remove_non_printable(str[i]); + + str[ret++] = '\0'; - memset(buf + QUERY_DESC_HDR_SIZE, 0, - size - QUERY_DESC_HDR_SIZE); - memcpy(buf + QUERY_DESC_HDR_SIZE, buff_ascii, ascii_len); - buf[QUERY_DESC_LENGTH_OFFSET] = ascii_len + QUERY_DESC_HDR_SIZE; - kfree(buff_ascii); + } else { + str = kmemdup(uc_str, uc_str->len, GFP_KERNEL); + if (!str) { + ret = -ENOMEM; + goto out; + } + ret = uc_str->len; } out: - return err; + *buf = str; + kfree(uc_str); + return ret; } /** @@ -3908,7 +3945,7 @@ static void ufshcd_auto_hibern8_enable(struct ufs_hba *hba) { unsigned long flags; - if (!(hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) || !hba->ahit) + if (!ufshcd_is_auto_hibern8_supported(hba) || !hba->ahit) return; spin_lock_irqsave(hba->host->host_lock, flags); @@ -4214,12 +4251,6 @@ static int ufshcd_hba_execute_hce(struct ufs_hba *hba) { int retry; - /* - * msleep of 1 and 5 used in this function might result in msleep(20), - * but it was necessary to send the UFS FPGA to reset mode during - * development and testing of this driver. msleep can be changed to - * mdelay and retry count can be reduced based on the controller. - */ if (!ufshcd_is_hba_active(hba)) /* change controller state to "reset state" */ ufshcd_hba_stop(hba, true); @@ -4242,7 +4273,7 @@ static int ufshcd_hba_execute_hce(struct ufs_hba *hba) * instruction might be read back. * This delay can be changed based on the controller. */ - msleep(1); + usleep_range(1000, 1100); /* wait for the host controller to complete initialization */ retry = 10; @@ -4254,7 +4285,7 @@ static int ufshcd_hba_execute_hce(struct ufs_hba *hba) "Controller enable failed\n"); return -EIO; } - msleep(5); + usleep_range(5000, 5100); } /* enable UIC related interrupts */ @@ -4326,6 +4357,14 @@ static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba) return ufshcd_disable_tx_lcc(hba, true); } +static void ufshcd_update_reg_hist(struct ufs_err_reg_hist *reg_hist, + u32 reg) +{ + reg_hist->reg[reg_hist->pos] = reg; + reg_hist->tstamp[reg_hist->pos] = ktime_get(); + reg_hist->pos = (reg_hist->pos + 1) % UFS_ERR_REG_HIST_LENGTH; +} + /** * ufshcd_link_startup - Initialize unipro link startup * @hba: per adapter instance @@ -4353,6 +4392,8 @@ link_startup: /* check if device is detected by inter-connect layer */ if (!ret && !ufshcd_is_device_present(hba)) { + ufshcd_update_reg_hist(&hba->ufs_stats.link_startup_err, + 0); dev_err(hba->dev, "%s: Device not present\n", __func__); ret = -ENXIO; goto out; @@ -4363,13 +4404,19 @@ link_startup: * but we can't be sure if the link is up until link startup * succeeds. So reset the local Uni-Pro and try again. */ - if (ret && ufshcd_hba_enable(hba)) + if (ret && ufshcd_hba_enable(hba)) { + ufshcd_update_reg_hist(&hba->ufs_stats.link_startup_err, + (u32)ret); goto out; + } } while (ret && retries--); - if (ret) + if (ret) { /* failed to get the link up... retire */ + ufshcd_update_reg_hist(&hba->ufs_stats.link_startup_err, + (u32)ret); goto out; + } if (link_startup_again) { link_startup_again = false; @@ -4587,8 +4634,6 @@ static int ufshcd_slave_configure(struct scsi_device *sdev) struct request_queue *q = sdev->request_queue; blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1); - blk_queue_max_segment_size(q, PRDT_DATA_BYTE_COUNT_MAX); - return 0; } @@ -5255,6 +5300,7 @@ static void ufshcd_err_handler(struct work_struct *work) goto skip_err_handling; } if ((hba->saved_err & INT_FATAL_ERRORS) || + (hba->saved_err & UFSHCD_UIC_HIBERN8_MASK) || ((hba->saved_err & UIC_ERROR) && (hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR | UFSHCD_UIC_DL_NAC_RECEIVED_ERROR | @@ -5346,14 +5392,6 @@ out: pm_runtime_put_sync(hba->dev); } -static void ufshcd_update_uic_reg_hist(struct ufs_uic_err_reg_hist *reg_hist, - u32 reg) -{ - reg_hist->reg[reg_hist->pos] = reg; - reg_hist->tstamp[reg_hist->pos] = ktime_get(); - reg_hist->pos = (reg_hist->pos + 1) % UIC_ERR_REG_HIST_LENGTH; -} - /** * ufshcd_update_uic_error - check and set fatal UIC error flags. * @hba: per-adapter instance @@ -5372,13 +5410,13 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba) * must be checked but this error is handled separately. */ dev_dbg(hba->dev, "%s: UIC Lane error reported\n", __func__); - ufshcd_update_uic_reg_hist(&hba->ufs_stats.pa_err, reg); + ufshcd_update_reg_hist(&hba->ufs_stats.pa_err, reg); } /* PA_INIT_ERROR is fatal and needs UIC reset */ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER); if (reg) - ufshcd_update_uic_reg_hist(&hba->ufs_stats.dl_err, reg); + ufshcd_update_reg_hist(&hba->ufs_stats.dl_err, reg); if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR; @@ -5394,19 +5432,19 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba) /* UIC NL/TL/DME errors needs software retry */ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER); if (reg) { - ufshcd_update_uic_reg_hist(&hba->ufs_stats.nl_err, reg); + ufshcd_update_reg_hist(&hba->ufs_stats.nl_err, reg); hba->uic_error |= UFSHCD_UIC_NL_ERROR; } reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER); if (reg) { - ufshcd_update_uic_reg_hist(&hba->ufs_stats.tl_err, reg); + ufshcd_update_reg_hist(&hba->ufs_stats.tl_err, reg); hba->uic_error |= UFSHCD_UIC_TL_ERROR; } reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME); if (reg) { - ufshcd_update_uic_reg_hist(&hba->ufs_stats.dme_err, reg); + ufshcd_update_reg_hist(&hba->ufs_stats.dme_err, reg); hba->uic_error |= UFSHCD_UIC_DME_ERROR; } @@ -5414,6 +5452,23 @@ static void ufshcd_update_uic_error(struct ufs_hba *hba) __func__, hba->uic_error); } +static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba, + u32 intr_mask) +{ + if (!ufshcd_is_auto_hibern8_supported(hba)) + return false; + + if (!(intr_mask & UFSHCD_UIC_HIBERN8_MASK)) + return false; + + if (hba->active_uic_cmd && + (hba->active_uic_cmd->command == UIC_CMD_DME_HIBER_ENTER || + hba->active_uic_cmd->command == UIC_CMD_DME_HIBER_EXIT)) + return false; + + return true; +} + /** * ufshcd_check_errors - Check for errors that need s/w attention * @hba: per-adapter instance @@ -5422,8 +5477,10 @@ static void ufshcd_check_errors(struct ufs_hba *hba) { bool queue_eh_work = false; - if (hba->errors & INT_FATAL_ERRORS) + if (hba->errors & INT_FATAL_ERRORS) { + ufshcd_update_reg_hist(&hba->ufs_stats.fatal_err, hba->errors); queue_eh_work = true; + } if (hba->errors & UIC_ERROR) { hba->uic_error = 0; @@ -5432,6 +5489,17 @@ static void ufshcd_check_errors(struct ufs_hba *hba) queue_eh_work = true; } + if (hba->errors & UFSHCD_UIC_HIBERN8_MASK) { + dev_err(hba->dev, + "%s: Auto Hibern8 %s failed - status: 0x%08x, upmcrs: 0x%08x\n", + __func__, (hba->errors & UIC_HIBERNATE_ENTER) ? + "Enter" : "Exit", + hba->errors, ufshcd_get_upmcrs(hba)); + ufshcd_update_reg_hist(&hba->ufs_stats.auto_hibern8_err, + hba->errors); + queue_eh_work = true; + } + if (queue_eh_work) { /* * update the transfer error masks to sticky bits, let's do this @@ -5494,6 +5562,10 @@ static void ufshcd_tmc_handler(struct ufs_hba *hba) static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) { hba->errors = UFSHCD_ERROR_MASK & intr_status; + + if (ufshcd_is_auto_hibern8_error(hba, intr_status)) + hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status); + if (hba->errors) ufshcd_check_errors(hba); @@ -5623,13 +5695,12 @@ static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba, memcpy(treq, hba->utmrdl_base_addr + free_slot, sizeof(*treq)); ufshcd_add_tm_upiu_trace(hba, task_tag, "tm_complete"); - - spin_lock_irqsave(hba->host->host_lock, flags); - __clear_bit(free_slot, &hba->outstanding_tasks); - spin_unlock_irqrestore(hba->host->host_lock, flags); - } + spin_lock_irqsave(hba->host->host_lock, flags); + __clear_bit(free_slot, &hba->outstanding_tasks); + spin_unlock_irqrestore(hba->host->host_lock, flags); + clear_bit(free_slot, &hba->tm_condition); ufshcd_put_tm_slot(hba, free_slot); wake_up(&hba->tm_tag_wq); @@ -5912,6 +5983,7 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd) out: hba->req_abort_count = 0; + ufshcd_update_reg_hist(&hba->ufs_stats.dev_reset, (u32)err); if (!err) { err = SUCCESS; } else { @@ -6005,6 +6077,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd) */ scsi_print_command(hba->lrb[tag].cmd); if (!hba->req_abort_count) { + ufshcd_update_reg_hist(&hba->ufs_stats.task_abort, 0); ufshcd_print_host_regs(hba); ufshcd_print_host_state(hba); ufshcd_print_pwr_info(hba); @@ -6140,7 +6213,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) out: if (err) dev_err(hba->dev, "%s: Host init failed %d\n", __func__, err); - + ufshcd_update_reg_hist(&hba->ufs_stats.host_reset, (u32)err); return err; } @@ -6160,6 +6233,9 @@ static int ufshcd_reset_and_restore(struct ufs_hba *hba) int retries = MAX_HOST_RESET_RETRIES; do { + /* Reset the attached device */ + ufshcd_vops_device_reset(hba); + err = ufshcd_host_reset_and_restore(hba); } while (err && --retries); @@ -6424,6 +6500,9 @@ static int ufs_get_device_desc(struct ufs_hba *hba, u8 model_index; u8 *desc_buf; + if (!dev_desc) + return -EINVAL; + buff_len = max_t(size_t, hba->desc_size.dev_desc, QUERY_DESC_MAX_SIZE + 1); desc_buf = kmalloc(buff_len, GFP_KERNEL); @@ -6447,31 +6526,31 @@ static int ufs_get_device_desc(struct ufs_hba *hba, desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; - - /* Zero-pad entire buffer for string termination. */ - memset(desc_buf, 0, buff_len); - - err = ufshcd_read_string_desc(hba, model_index, desc_buf, - QUERY_DESC_MAX_SIZE, true/*ASCII*/); - if (err) { + err = ufshcd_read_string_desc(hba, model_index, + &dev_desc->model, SD_ASCII_STD); + if (err < 0) { dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n", __func__, err); goto out; } - desc_buf[QUERY_DESC_MAX_SIZE] = '\0'; - strlcpy(dev_desc->model, (desc_buf + QUERY_DESC_HDR_SIZE), - min_t(u8, desc_buf[QUERY_DESC_LENGTH_OFFSET], - MAX_MODEL_LEN)); - - /* Null terminate the model string */ - dev_desc->model[MAX_MODEL_LEN] = '\0'; + /* + * ufshcd_read_string_desc returns size of the string + * reset the error value + */ + err = 0; out: kfree(desc_buf); return err; } +static void ufs_put_device_desc(struct ufs_dev_desc *dev_desc) +{ + kfree(dev_desc->model); + dev_desc->model = NULL; +} + static void ufs_fixup_device_setup(struct ufs_hba *hba, struct ufs_dev_desc *dev_desc) { @@ -6480,8 +6559,9 @@ static void ufs_fixup_device_setup(struct ufs_hba *hba, for (f = ufs_fixups; f->quirk; f++) { if ((f->card.wmanufacturerid == dev_desc->wmanufacturerid || f->card.wmanufacturerid == UFS_ANY_VENDOR) && - (STR_PRFX_EQUAL(f->card.model, dev_desc->model) || - !strcmp(f->card.model, UFS_ANY_MODEL))) + ((dev_desc->model && + STR_PRFX_EQUAL(f->card.model, dev_desc->model)) || + !strcmp(f->card.model, UFS_ANY_MODEL))) hba->dev_quirks |= f->quirk; } } @@ -6652,17 +6732,8 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) static void ufshcd_clear_dbg_ufs_stats(struct ufs_hba *hba) { - int err_reg_hist_size = sizeof(struct ufs_uic_err_reg_hist); - hba->ufs_stats.hibern8_exit_cnt = 0; hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0); - - memset(&hba->ufs_stats.pa_err, 0, err_reg_hist_size); - memset(&hba->ufs_stats.dl_err, 0, err_reg_hist_size); - memset(&hba->ufs_stats.nl_err, 0, err_reg_hist_size); - memset(&hba->ufs_stats.tl_err, 0, err_reg_hist_size); - memset(&hba->ufs_stats.dme_err, 0, err_reg_hist_size); - hba->req_abort_count = 0; } @@ -6832,6 +6903,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) } ufs_fixup_device_setup(hba, &card); + ufs_put_device_desc(&card); + ufshcd_tune_unipro_params(hba); /* UFS device is also active now */ @@ -6991,6 +7064,7 @@ static struct scsi_host_template ufshcd_driver_template = { .sg_tablesize = SG_ALL, .cmd_per_lun = UFSHCD_CMD_PER_LUN, .can_queue = UFSHCD_CAN_QUEUE, + .max_segment_size = PRDT_DATA_BYTE_COUNT_MAX, .max_host_blocked = 1, .track_queue_depth = 1, .sdev_groups = ufshcd_driver_groups, @@ -7032,6 +7106,9 @@ static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba, static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba, struct ufs_vreg *vreg) { + if (!vreg) + return 0; + return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA); } @@ -7790,6 +7867,8 @@ enable_gating: ufshcd_release(hba); out: hba->pm_op_in_progress = 0; + if (ret) + ufshcd_update_reg_hist(&hba->ufs_stats.suspend_err, (u32)ret); return ret; } @@ -7892,6 +7971,8 @@ disable_irq_and_vops_clks: ufshcd_setup_clocks(hba, false); out: hba->pm_op_in_progress = 0; + if (ret) + ufshcd_update_reg_hist(&hba->ufs_stats.resume_err, (u32)ret); return ret; } @@ -8062,6 +8143,9 @@ int ufshcd_shutdown(struct ufs_hba *hba) { int ret = 0; + if (!hba->is_powered) + goto out; + if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba)) goto out; @@ -8291,6 +8375,9 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) goto exit_gating; } + /* Reset the attached device */ + ufshcd_vops_device_reset(hba); + /* Host controller enable */ err = ufshcd_hba_enable(hba); if (err) { @@ -8313,7 +8400,7 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) UIC_LINK_HIBERN8_STATE); /* Set the default auto-hiberate idle timer value to 150 ms */ - if (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT) { + if (ufshcd_is_auto_hibern8_supported(hba) && !hba->ahit) { hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 150) | FIELD_PREP(UFSHCI_AHIBERN8_SCALE_MASK, 3); } diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index ecfa898b9ccc..c94cfda52829 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -298,6 +298,7 @@ struct ufs_pwr_mode_info { * @resume: called during host controller PM callback * @dbg_register_dump: used to dump controller debug information * @phy_initialization: used to initialize phys + * @device_reset: called to issue a reset pulse on the UFS device */ struct ufs_hba_variant_ops { const char *name; @@ -326,6 +327,7 @@ struct ufs_hba_variant_ops { int (*resume)(struct ufs_hba *, enum ufs_pm_op); void (*dbg_register_dump)(struct ufs_hba *hba); int (*phy_initialization)(struct ufs_hba *); + void (*device_reset)(struct ufs_hba *hba); }; /* clock gating state */ @@ -412,17 +414,17 @@ struct ufs_init_prefetch { u32 icc_level; }; -#define UIC_ERR_REG_HIST_LENGTH 8 +#define UFS_ERR_REG_HIST_LENGTH 8 /** - * struct ufs_uic_err_reg_hist - keeps history of uic errors + * struct ufs_err_reg_hist - keeps history of errors * @pos: index to indicate cyclic buffer position * @reg: cyclic buffer for registers value * @tstamp: cyclic buffer for time stamp */ -struct ufs_uic_err_reg_hist { +struct ufs_err_reg_hist { int pos; - u32 reg[UIC_ERR_REG_HIST_LENGTH]; - ktime_t tstamp[UIC_ERR_REG_HIST_LENGTH]; + u32 reg[UFS_ERR_REG_HIST_LENGTH]; + ktime_t tstamp[UFS_ERR_REG_HIST_LENGTH]; }; /** @@ -436,15 +438,37 @@ struct ufs_uic_err_reg_hist { * @nl_err: tracks nl-uic errors * @tl_err: tracks tl-uic errors * @dme_err: tracks dme errors + * @auto_hibern8_err: tracks auto-hibernate errors + * @fatal_err: tracks fatal errors + * @linkup_err: tracks link-startup errors + * @resume_err: tracks resume errors + * @suspend_err: tracks suspend errors + * @dev_reset: tracks device reset events + * @host_reset: tracks host reset events + * @tsk_abort: tracks task abort events */ struct ufs_stats { u32 hibern8_exit_cnt; ktime_t last_hibern8_exit_tstamp; - struct ufs_uic_err_reg_hist pa_err; - struct ufs_uic_err_reg_hist dl_err; - struct ufs_uic_err_reg_hist nl_err; - struct ufs_uic_err_reg_hist tl_err; - struct ufs_uic_err_reg_hist dme_err; + + /* uic specific errors */ + struct ufs_err_reg_hist pa_err; + struct ufs_err_reg_hist dl_err; + struct ufs_err_reg_hist nl_err; + struct ufs_err_reg_hist tl_err; + struct ufs_err_reg_hist dme_err; + + /* fatal errors */ + struct ufs_err_reg_hist auto_hibern8_err; + struct ufs_err_reg_hist fatal_err; + struct ufs_err_reg_hist link_startup_err; + struct ufs_err_reg_hist resume_err; + struct ufs_err_reg_hist suspend_err; + + /* abnormal events */ + struct ufs_err_reg_hist dev_reset; + struct ufs_err_reg_hist host_reset; + struct ufs_err_reg_hist task_abort; }; /** @@ -740,6 +764,11 @@ return true; #endif } +static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba) +{ + return (hba->capabilities & MASK_AUTO_HIBERN8_SUPPORT); +} + #define ufshcd_writel(hba, val, reg) \ writel((val), (hba)->mmio_base + (reg)) #define ufshcd_readl(hba, reg) \ @@ -886,8 +915,11 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, enum attr_idn idn, u8 index, u8 selector, u32 *attr_val); int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, bool *flag_res); -int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, - u8 *buf, u32 size, bool ascii); + +#define SD_ASCII_STD true +#define SD_RAW false +int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, + u8 **buf, bool ascii); int ufshcd_hold(struct ufs_hba *hba, bool async); void ufshcd_release(struct ufs_hba *hba); @@ -1040,6 +1072,12 @@ static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba) hba->vops->dbg_register_dump(hba); } +static inline void ufshcd_vops_device_reset(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->device_reset) + hba->vops->device_reset(hba); +} + extern struct ufs_pm_lvl_states ufs_pm_lvl_states[]; /* diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 6fa889de5ee5..dbb75cd28dc8 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -144,8 +144,10 @@ enum { #define CONTROLLER_FATAL_ERROR 0x10000 #define SYSTEM_BUS_FATAL_ERROR 0x20000 -#define UFSHCD_UIC_PWR_MASK (UIC_HIBERNATE_ENTER |\ - UIC_HIBERNATE_EXIT |\ +#define UFSHCD_UIC_HIBERN8_MASK (UIC_HIBERNATE_ENTER |\ + UIC_HIBERNATE_EXIT) + +#define UFSHCD_UIC_PWR_MASK (UFSHCD_UIC_HIBERN8_MASK |\ UIC_POWER_MODE) #define UFSHCD_UIC_MASK (UIC_COMMAND_COMPL | UFSHCD_UIC_PWR_MASK) diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 13f1b3b9923a..bfec84aacd90 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -30,6 +30,8 @@ #include <linux/seqlock.h> #include <linux/blk-mq-virtio.h> +#include "sd.h" + #define VIRTIO_SCSI_MEMPOOL_SZ 64 #define VIRTIO_SCSI_EVENT_LEN 8 #define VIRTIO_SCSI_VQ_BASE 2 @@ -74,9 +76,6 @@ struct virtio_scsi { u32 num_queues; - /* If the affinity hint is set for virtqueues */ - bool affinity_hint_set; - struct hlist_node node; /* Protected by event_vq lock */ @@ -327,6 +326,36 @@ static void virtscsi_handle_param_change(struct virtio_scsi *vscsi, scsi_device_put(sdev); } +static void virtscsi_rescan_hotunplug(struct virtio_scsi *vscsi) +{ + struct scsi_device *sdev; + struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev); + unsigned char scsi_cmd[MAX_COMMAND_SIZE]; + int result, inquiry_len, inq_result_len = 256; + char *inq_result = kmalloc(inq_result_len, GFP_KERNEL); + + shost_for_each_device(sdev, shost) { + inquiry_len = sdev->inquiry_len ? sdev->inquiry_len : 36; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + scsi_cmd[0] = INQUIRY; + scsi_cmd[4] = (unsigned char) inquiry_len; + + memset(inq_result, 0, inq_result_len); + + result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, + inq_result, inquiry_len, NULL, + SD_TIMEOUT, SD_MAX_RETRIES, NULL); + + if (result == 0 && inq_result[0] >> 5) { + /* PQ indicates the LUN is not attached */ + scsi_remove_device(sdev); + } + } + + kfree(inq_result); +} + static void virtscsi_handle_event(struct work_struct *work) { struct virtio_scsi_event_node *event_node = @@ -338,6 +367,7 @@ static void virtscsi_handle_event(struct work_struct *work) cpu_to_virtio32(vscsi->vdev, VIRTIO_SCSI_T_EVENTS_MISSED)) { event->event &= ~cpu_to_virtio32(vscsi->vdev, VIRTIO_SCSI_T_EVENTS_MISSED); + virtscsi_rescan_hotunplug(vscsi); scsi_scan_host(virtio_scsi_host(vscsi->vdev)); } @@ -372,14 +402,7 @@ static void virtscsi_event_done(struct virtqueue *vq) virtscsi_vq_done(vscsi, &vscsi->event_vq, virtscsi_complete_event); }; -/** - * virtscsi_add_cmd - add a virtio_scsi_cmd to a virtqueue - * @vq : the struct virtqueue we're talking about - * @cmd : command structure - * @req_size : size of the request buffer - * @resp_size : size of the response buffer - */ -static int virtscsi_add_cmd(struct virtqueue *vq, +static int __virtscsi_add_cmd(struct virtqueue *vq, struct virtio_scsi_cmd *cmd, size_t req_size, size_t resp_size) { @@ -424,17 +447,39 @@ static int virtscsi_add_cmd(struct virtqueue *vq, return virtqueue_add_sgs(vq, sgs, out_num, in_num, cmd, GFP_ATOMIC); } -static int virtscsi_kick_cmd(struct virtio_scsi_vq *vq, +static void virtscsi_kick_vq(struct virtio_scsi_vq *vq) +{ + bool needs_kick; + unsigned long flags; + + spin_lock_irqsave(&vq->vq_lock, flags); + needs_kick = virtqueue_kick_prepare(vq->vq); + spin_unlock_irqrestore(&vq->vq_lock, flags); + + if (needs_kick) + virtqueue_notify(vq->vq); +} + +/** + * virtscsi_add_cmd - add a virtio_scsi_cmd to a virtqueue, optionally kick it + * @vq : the struct virtqueue we're talking about + * @cmd : command structure + * @req_size : size of the request buffer + * @resp_size : size of the response buffer + * @kick : whether to kick the virtqueue immediately + */ +static int virtscsi_add_cmd(struct virtio_scsi_vq *vq, struct virtio_scsi_cmd *cmd, - size_t req_size, size_t resp_size) + size_t req_size, size_t resp_size, + bool kick) { unsigned long flags; int err; bool needs_kick = false; spin_lock_irqsave(&vq->vq_lock, flags); - err = virtscsi_add_cmd(vq->vq, cmd, req_size, resp_size); - if (!err) + err = __virtscsi_add_cmd(vq->vq, cmd, req_size, resp_size); + if (!err && kick) needs_kick = virtqueue_kick_prepare(vq->vq); spin_unlock_irqrestore(&vq->vq_lock, flags); @@ -499,6 +544,7 @@ static int virtscsi_queuecommand(struct Scsi_Host *shost, struct virtio_scsi *vscsi = shost_priv(shost); struct virtio_scsi_vq *req_vq = virtscsi_pick_vq_mq(vscsi, sc); struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc); + bool kick; unsigned long flags; int req_size; int ret; @@ -528,7 +574,8 @@ static int virtscsi_queuecommand(struct Scsi_Host *shost, req_size = sizeof(cmd->req.cmd); } - ret = virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd)); + kick = (sc->flags & SCMD_LAST) != 0; + ret = virtscsi_add_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd), kick); if (ret == -EIO) { cmd->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; spin_lock_irqsave(&req_vq->vq_lock, flags); @@ -546,8 +593,8 @@ static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd) int ret = FAILED; cmd->comp = ∁ - if (virtscsi_kick_cmd(&vscsi->ctrl_vq, cmd, - sizeof cmd->req.tmf, sizeof cmd->resp.tmf) < 0) + if (virtscsi_add_cmd(&vscsi->ctrl_vq, cmd, + sizeof cmd->req.tmf, sizeof cmd->resp.tmf, true) < 0) goto out; wait_for_completion(&comp); @@ -661,6 +708,13 @@ static int virtscsi_map_queues(struct Scsi_Host *shost) return blk_mq_virtio_map_queues(qmap, vscsi->vdev, 2); } +static void virtscsi_commit_rqs(struct Scsi_Host *shost, u16 hwq) +{ + struct virtio_scsi *vscsi = shost_priv(shost); + + virtscsi_kick_vq(&vscsi->req_vqs[hwq]); +} + /* * The host guarantees to respond to each command, although I/O * latencies might be higher than on bare metal. Reset the timer @@ -678,6 +732,7 @@ static struct scsi_host_template virtscsi_host_template = { .this_id = -1, .cmd_size = sizeof(struct virtio_scsi_cmd), .queuecommand = virtscsi_queuecommand, + .commit_rqs = virtscsi_commit_rqs, .change_queue_depth = virtscsi_change_queue_depth, .eh_abort_handler = virtscsi_abort, .eh_device_reset_handler = virtscsi_device_reset, @@ -795,7 +850,7 @@ static int virtscsi_probe(struct virtio_device *vdev) num_targets = virtscsi_config_get(vdev, max_target) + 1; shost = scsi_host_alloc(&virtscsi_host_template, - sizeof(*vscsi) + sizeof(vscsi->req_vqs[0]) * num_queues); + struct_size(vscsi, req_vqs, num_queues)); if (!shost) return -ENOMEM; diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 377b07b2feeb..70008816c91f 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -335,7 +335,7 @@ static void pvscsi_create_sg(struct pvscsi_ctx *ctx, BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT); sge = &ctx->sgl->sge[0]; - for (i = 0; i < count; i++, sg++) { + for (i = 0; i < count; i++, sg = sg_next(sg)) { sge[i].addr = sg_dma_address(sg); sge[i].length = sg_dma_len(sg); sge[i].flags = 0; diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index f965a3ee9ce5..f81046f0e68a 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -735,7 +735,7 @@ transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd, * source or destination for THIS transfer. */ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; + cmd->SCp.buffer = sg_next(cmd->SCp.buffer); --cmd->SCp.buffers_residual; cmd->SCp.this_residual = cmd->SCp.buffer->length; cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); @@ -1854,6 +1854,7 @@ round_4(unsigned int x) case 1: --x; break; case 2: ++x; + /* fall through */ case 3: ++x; } return x; diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c index c2f40068f235..edc8a139a60d 100644 --- a/drivers/scsi/wd719x.c +++ b/drivers/scsi/wd719x.c @@ -108,8 +108,15 @@ static inline int wd719x_wait_done(struct wd719x *wd, int timeout) } if (status != WD719X_INT_NOERRORS) { + u8 sue = wd719x_readb(wd, WD719X_AMR_SCB_ERROR); + /* we get this after wd719x_dev_reset, it's not an error */ + if (sue == WD719X_SUE_TERM) + return 0; + /* we get this after wd719x_bus_reset, it's not an error */ + if (sue == WD719X_SUE_RESET) + return 0; dev_err(&wd->pdev->dev, "direct command failed, status 0x%02x, SUE 0x%02x\n", - status, wd719x_readb(wd, WD719X_AMR_SCB_ERROR)); + status, sue); return -EIO; } @@ -128,8 +135,10 @@ static int wd719x_direct_cmd(struct wd719x *wd, u8 opcode, u8 dev, u8 lun, if (wd719x_wait_ready(wd)) return -ETIMEDOUT; - /* make sure we get NO interrupts */ - dev |= WD719X_DISABLE_INT; + /* disable interrupts except for RESET/ABORT (it breaks them) */ + if (opcode != WD719X_CMD_BUSRESET && opcode != WD719X_CMD_ABORT && + opcode != WD719X_CMD_ABORT_TAG && opcode != WD719X_CMD_RESET) + dev |= WD719X_DISABLE_INT; wd719x_writeb(wd, WD719X_AMR_CMD_PARAM, dev); wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_2, lun); wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_3, tag); @@ -465,6 +474,7 @@ static int wd719x_abort(struct scsi_cmnd *cmd) spin_lock_irqsave(wd->sh->host_lock, flags); result = wd719x_direct_cmd(wd, action, cmd->device->id, cmd->device->lun, cmd->tag, scb->phys, 0); + wd719x_finish_cmd(scb, DID_ABORT); spin_unlock_irqrestore(wd->sh->host_lock, flags); if (result) return FAILED; @@ -477,6 +487,7 @@ static int wd719x_reset(struct scsi_cmnd *cmd, u8 opcode, u8 device) int result; unsigned long flags; struct wd719x *wd = shost_priv(cmd->device->host); + struct wd719x_scb *scb, *tmp; dev_info(&wd->pdev->dev, "%s reset requested\n", (opcode == WD719X_CMD_BUSRESET) ? "bus" : "device"); @@ -484,6 +495,12 @@ static int wd719x_reset(struct scsi_cmnd *cmd, u8 opcode, u8 device) spin_lock_irqsave(wd->sh->host_lock, flags); result = wd719x_direct_cmd(wd, opcode, device, 0, 0, 0, WD719X_WAIT_FOR_SCSI_RESET); + /* flush all SCBs (or all for a device if dev_reset) */ + list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list) { + if (opcode == WD719X_CMD_BUSRESET || + scb->cmd->device->id == device) + wd719x_finish_cmd(scb, DID_RESET); + } spin_unlock_irqrestore(wd->sh->host_lock, flags); if (result) return FAILED; @@ -506,22 +523,23 @@ static int wd719x_host_reset(struct scsi_cmnd *cmd) struct wd719x *wd = shost_priv(cmd->device->host); struct wd719x_scb *scb, *tmp; unsigned long flags; - int result; dev_info(&wd->pdev->dev, "host reset requested\n"); spin_lock_irqsave(wd->sh->host_lock, flags); - /* Try to reinit the RISC */ - if (wd719x_chip_init(wd) == 0) - result = SUCCESS; - else - result = FAILED; + /* stop the RISC */ + if (wd719x_direct_cmd(wd, WD719X_CMD_SLEEP, 0, 0, 0, 0, + WD719X_WAIT_FOR_RISC)) + dev_warn(&wd->pdev->dev, "RISC sleep command failed\n"); + /* disable RISC */ + wd719x_writeb(wd, WD719X_PCI_MODE_SELECT, 0); /* flush all SCBs */ list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list) - wd719x_finish_cmd(scb, result); + wd719x_finish_cmd(scb, DID_RESET); spin_unlock_irqrestore(wd->sh->host_lock, flags); - return result; + /* Try to reinit the RISC */ + return wd719x_chip_init(wd) == 0 ? SUCCESS : FAILED; } static int wd719x_biosparam(struct scsi_device *sdev, struct block_device *bdev, @@ -673,7 +691,7 @@ static irqreturn_t wd719x_interrupt(int irq, void *dev_id) else dev_err(&wd->pdev->dev, "card returned invalid SCB pointer\n"); } else - dev_warn(&wd->pdev->dev, "direct command 0x%x completed\n", + dev_dbg(&wd->pdev->dev, "direct command 0x%x completed\n", regs.bytes.OPC); break; case WD719X_INT_PIOREADY: |