diff --git a/Documentation/devicetree/bindings/ufs/qcom,sa8255p-ufshc.yaml b/Documentation/devicetree/bindings/ufs/qcom,sa8255p-ufshc.yaml new file mode 100644 index 000000000000..75fae9f1eba7 --- /dev/null +++ b/Documentation/devicetree/bindings/ufs/qcom,sa8255p-ufshc.yaml @@ -0,0 +1,56 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/ufs/qcom,sa8255p-ufshc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm SA8255P UFS Host Controller + +maintainers: + - Ram Kumar Dwivedi + +properties: + compatible: + const: qcom,sa8255p-ufshc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + iommus: + maxItems: 1 + + dma-coherent: true + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - power-domains + - iommus + - dma-coherent + +allOf: + - $ref: ufs-common.yaml + +unevaluatedProperties: false + +examples: + - | + #include + + ufshc@1d84000 { + compatible = "qcom,sa8255p-ufshc"; + reg = <0x01d84000 0x3000>; + interrupts = ; + lanes-per-direction = <2>; + + iommus = <&apps_smmu 0x100 0x0>; + power-domains = <&scmi3_pd 0>; + dma-coherent; + }; diff --git a/Documentation/scsi/scsi_mid_low_api.rst b/Documentation/scsi/scsi_mid_low_api.rst index 634f5c28a849..7f59dff43eb5 100644 --- a/Documentation/scsi/scsi_mid_low_api.rst +++ b/Documentation/scsi/scsi_mid_low_api.rst @@ -903,7 +903,8 @@ Details:: * * Defined in: LLD **/ - int queuecommand(struct Scsi_Host *shost, struct scsi_cmnd * scp) + enum scsi_qc_status queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scp) /** diff --git a/MAINTAINERS b/MAINTAINERS index 5b11839cba9d..70292bd3ed71 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26803,7 +26803,7 @@ M: Manivannan Sadhasivam L: linux-arm-msm@vger.kernel.org L: linux-scsi@vger.kernel.org S: Maintained -F: Documentation/devicetree/bindings/ufs/qcom,ufs.yaml +F: Documentation/devicetree/bindings/ufs/qcom* F: drivers/ufs/host/ufs-qcom* UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER RENESAS HOOKS diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 721d3f270c8e..2967a2900317 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -4309,7 +4309,8 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) return NULL; } -int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev) +enum scsi_qc_status __ata_scsi_queuecmd(struct scsi_cmnd *scmd, + struct ata_device *dev) { struct ata_port *ap = dev->link->ap; u8 scsi_op = scmd->cmnd[0]; @@ -4383,12 +4384,13 @@ int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev) * Return value from __ata_scsi_queuecmd() if @cmd can be queued, * 0 otherwise. */ -int ata_scsi_queuecmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd) +enum scsi_qc_status ata_scsi_queuecmd(struct Scsi_Host *shost, + struct scsi_cmnd *cmd) { struct ata_port *ap; struct ata_device *dev; struct scsi_device *scsidev = cmd->device; - int rc = 0; + enum scsi_qc_status rc = 0; unsigned long irq_flags; ap = ata_shost_to_port(shost); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 0e7ecac73680..0e48bd1c0c20 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -164,7 +164,8 @@ extern int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel, void ata_scsi_sdev_config(struct scsi_device *sdev); int ata_scsi_dev_config(struct scsi_device *sdev, struct queue_limits *lim, struct ata_device *dev); -int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, struct ata_device *dev); +enum scsi_qc_status __ata_scsi_queuecmd(struct scsi_cmnd *scmd, + struct ata_device *dev); /* libata-eh.c */ extern unsigned int ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd); diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c index 09ee2a1e35bb..69c6ac2e8263 100644 --- a/drivers/base/transport_class.c +++ b/drivers/base/transport_class.c @@ -169,6 +169,12 @@ static int transport_add_class_device(struct attribute_container *cont, goto err_del; } + if (tcont->encryption) { + error = sysfs_create_group(&classdev->kobj, tcont->encryption); + if (error) + goto err_del; + } + return 0; err_del: @@ -244,6 +250,8 @@ static int transport_remove_classdev(struct attribute_container *cont, if (tclass->remove != anon_transport_dummy_function) { if (tcont->statistics) sysfs_remove_group(&classdev->kobj, tcont->statistics); + if (tcont->encryption) + sysfs_remove_group(&classdev->kobj, tcont->encryption); attribute_container_class_device_del(classdev); } diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 1a19828114cf..bb1a510b6423 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -1440,13 +1440,14 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb, /* SCSI stack integration */ -static int sbp2_scsi_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *cmd) +static enum scsi_qc_status sbp2_scsi_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmd) { struct sbp2_logical_unit *lu = cmd->device->hostdata; struct fw_device *device = target_parent_device(lu->tgt); + enum scsi_qc_status retval = SCSI_MLQUEUE_HOST_BUSY; struct sbp2_command_orb *orb; - int generation, retval = SCSI_MLQUEUE_HOST_BUSY; + int generation; orb = kzalloc(sizeof(*orb), GFP_ATOMIC); if (orb == NULL) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 23ed2fc688f0..c4291071deb9 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -2148,7 +2148,8 @@ static void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc, target->qp_in_error = true; } -static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd) +static enum scsi_qc_status srp_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmnd) { struct request *rq = scsi_cmd_to_rq(scmnd); struct srp_target_port *target = host_to_target(shost); diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 8f587c0efd9d..cd52db6fe76c 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -97,7 +97,8 @@ static u8 mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; static int mptfc_target_alloc(struct scsi_target *starget); static int mptfc_sdev_init(struct scsi_device *sdev); -static int mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt); +static enum scsi_qc_status mptfc_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *SCpnt); static void mptfc_target_destroy(struct scsi_target *starget); static void mptfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout); static void mptfc_remove(struct pci_dev *pdev); @@ -676,8 +677,8 @@ mptfc_sdev_init(struct scsi_device *sdev) return 0; } -static int -mptfc_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) +static enum scsi_qc_status mptfc_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *SCpnt) { struct mptfc_rport_info *ri; struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device)); diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 185c08eab4ca..5276bdb7acc2 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1920,8 +1920,8 @@ mptsas_sdev_init(struct scsi_device *sdev) return 0; } -static int -mptsas_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) +static enum scsi_qc_status mptsas_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *SCpnt) { MPT_SCSI_HOST *hd; MPT_ADAPTER *ioc; diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 3304f8824cf7..ec6edcc4ef56 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -1309,8 +1309,7 @@ int mptscsih_show_info(struct seq_file *m, struct Scsi_Host *host) * * Returns 0. (rtn value discarded by linux scsi mid-layer) */ -int -mptscsih_qcmd(struct scsi_cmnd *SCpnt) +enum scsi_qc_status mptscsih_qcmd(struct scsi_cmnd *SCpnt) { MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index f9678d48100c..ac3f56801c92 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -113,7 +113,7 @@ extern int mptscsih_resume(struct pci_dev *pdev); #endif extern int mptscsih_show_info(struct seq_file *, struct Scsi_Host *); extern const char * mptscsih_info(struct Scsi_Host *SChost); -extern int mptscsih_qcmd(struct scsi_cmnd *SCpnt); +extern enum scsi_qc_status mptscsih_qcmd(struct scsi_cmnd *SCpnt); extern int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, u64 lun, int ctx2abort, ulong timeout); extern void mptscsih_sdev_destroy(struct scsi_device *device); diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index a3901fbfac4f..14707d19fbbd 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -774,8 +774,8 @@ static int mptspi_sdev_configure(struct scsi_device *sdev, return 0; } -static int -mptspi_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt) +static enum scsi_qc_status mptspi_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *SCpnt) { struct _MPT_SCSI_HOST *hd = shost_priv(shost); VirtDevice *vdevice = SCpnt->device->hostdata; diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 141476ea21bb..634bd8dceedd 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -63,8 +63,8 @@ static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) scsi_done(scpnt); } -static -int zfcp_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scpnt) +static enum scsi_qc_status zfcp_scsi_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scpnt) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); struct fc_rport *rport = starget_to_rport(scsi_target(scpnt->device)); diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index a377a6f6900a..e64a9a18ec6e 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1746,7 +1746,7 @@ static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt) } /* End twa_scsi_eh_reset() */ /* This is the main scsi queue function to handle scsi opcodes */ -static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status twa_scsi_queue_lck(struct scsi_cmnd *SCpnt) { void (*done)(struct scsi_cmnd *) = scsi_done; int request_id, retval; diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index e319be7d369c..fde12475b712 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -1453,11 +1453,13 @@ static int twl_scsi_eh_reset(struct scsi_cmnd *SCpnt) } /* End twl_scsi_eh_reset() */ /* This is the main scsi queue function to handle scsi opcodes */ -static int twl_scsi_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status twl_scsi_queue_lck(struct scsi_cmnd *SCpnt) { + TW_Device_Extension *tw_dev = + (TW_Device_Extension *)SCpnt->device->host->hostdata; void (*done)(struct scsi_cmnd *) = scsi_done; - int request_id, retval; - TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; + enum scsi_qc_status retval; + int request_id; /* If we are resetting due to timed out ioctl, report as busy */ if (test_bit(TW_IN_RESET, &tw_dev->flags)) { diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 0306a228c702..c68678fa72c1 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1920,7 +1920,7 @@ static int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int r } /* End tw_scsiop_test_unit_ready_complete() */ /* This is the main scsi queue function to handle scsi opcodes */ -static int tw_scsi_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status tw_scsi_queue_lck(struct scsi_cmnd *SCpnt) { void (*done)(struct scsi_cmnd *) = scsi_done; unsigned char *command = SCpnt->cmnd; diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 71b7ac027f48..860538c6f8cb 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -152,8 +152,8 @@ MODULE_LICENSE("GPL"); /* This is the script */ #include "53c700_d.h" - -STATIC int NCR_700_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *); +STATIC enum scsi_qc_status NCR_700_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *); STATIC int NCR_700_abort(struct scsi_cmnd * SCpnt); STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt); STATIC void NCR_700_chip_setup(struct Scsi_Host *host); @@ -1751,7 +1751,7 @@ NCR_700_intr(int irq, void *dev_id) return IRQ_RETVAL(handled); } -static int NCR_700_queuecommand_lck(struct scsi_cmnd *SCp) +static enum scsi_qc_status NCR_700_queuecommand_lck(struct scsi_cmnd *SCp) { struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0]; diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index a86d780d1ba4..865fcbac8fa1 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -2877,7 +2877,7 @@ static int blogic_hostreset(struct scsi_cmnd *SCpnt) Outgoing Mailbox for execution by the associated Host Adapter. */ -static int blogic_qcmd_lck(struct scsi_cmnd *command) +static enum scsi_qc_status blogic_qcmd_lck(struct scsi_cmnd *command) { void (*comp_cb)(struct scsi_cmnd *) = scsi_done; struct blogic_adapter *adapter = diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h index 79de815e33b0..24697a5bedc8 100644 --- a/drivers/scsi/BusLogic.h +++ b/drivers/scsi/BusLogic.h @@ -1272,7 +1272,8 @@ static inline void blogic_incszbucket(unsigned int *cmdsz_buckets, */ static const char *blogic_drvr_info(struct Scsi_Host *); -static int blogic_qcmd(struct Scsi_Host *h, struct scsi_cmnd *); +static enum scsi_qc_status blogic_qcmd(struct Scsi_Host *h, + struct scsi_cmnd *command); static int blogic_diskparam(struct scsi_device *, struct gendisk *, sector_t, int *); static int blogic_sdev_configure(struct scsi_device *, struct queue_limits *lim); diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 0e10502660de..006dcf981218 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -555,8 +555,8 @@ static void complete_cmd(struct Scsi_Host *instance, * main coroutine is not running, it is restarted. */ -static int NCR5380_queue_command(struct Scsi_Host *instance, - struct scsi_cmnd *cmd) +static enum scsi_qc_status NCR5380_queue_command(struct Scsi_Host *instance, + struct scsi_cmnd *cmd) { struct NCR5380_hostdata *hostdata = shost_priv(instance); struct NCR5380_cmd *ncmd = NCR5380_to_ncmd(cmd); diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c index a8979f9e30ff..4365b896f5c4 100644 --- a/drivers/scsi/a100u2w.c +++ b/drivers/scsi/a100u2w.c @@ -909,7 +909,7 @@ static int inia100_build_scb(struct orc_host * host, struct orc_scb * scb, struc * block, build the host specific scb structures and if there is room * queue the command down to the controller */ -static int inia100_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status inia100_queue_lck(struct scsi_cmnd *cmd) { struct orc_scb *scb; struct orc_host *host; /* Point to Host adapter control block */ diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 82c6e7c7cdaf..ea468666159a 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -237,8 +237,8 @@ static struct aac_driver_ident aac_drivers[] = { * TODO: unify with aac_scsi_cmd(). */ -static int aac_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *cmd) +static enum scsi_qc_status aac_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmd) { aac_priv(cmd)->owner = AAC_OWNER_LOWLEVEL; diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 06223b5ee6da..08bddac49757 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -8462,10 +8462,11 @@ static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp) * This function always returns 0. Command return status is saved * in the 'scp' result field. */ -static int advansys_queuecommand_lck(struct scsi_cmnd *scp) +static enum scsi_qc_status advansys_queuecommand_lck(struct scsi_cmnd *scp) { struct Scsi_Host *shost = scp->device->host; - int asc_res, result = 0; + enum scsi_qc_status result = 0; + int asc_res; ASC_STATS(shost, queuecommand); diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 182aa80ec4c6..e3ccb6bb62c0 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -924,7 +924,7 @@ static int setup_expected_interrupts(struct Scsi_Host *shpnt) /* * Queue a command and setup interrupts for a free bus. */ -static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, +static enum scsi_qc_status aha152x_internal_queue(struct scsi_cmnd *SCpnt, struct completion *complete, int phase) { struct aha152x_cmd_priv *acp = aha152x_priv(SCpnt); @@ -939,13 +939,13 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, if (acp->phase & (resetting | check_condition)) { if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) { scmd_printk(KERN_ERR, SCpnt, "cannot reuse command\n"); - return FAILED; + return SCSI_MLQUEUE_HOST_BUSY; } } else { SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC); if(!SCpnt->host_scribble) { scmd_printk(KERN_ERR, SCpnt, "allocation failed\n"); - return FAILED; + return SCSI_MLQUEUE_HOST_BUSY; } } @@ -995,7 +995,7 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt, * queue a command * */ -static int aha152x_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status aha152x_queue_lck(struct scsi_cmnd *SCpnt) { return aha152x_internal_queue(SCpnt, NULL, 0); } diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 371e8300f029..fd766282d4a4 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -411,7 +411,8 @@ static irqreturn_t aha1542_interrupt(int irq, void *dev_id) } } -static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +static enum scsi_qc_status aha1542_queuecommand(struct Scsi_Host *sh, + struct scsi_cmnd *cmd) { struct aha1542_cmd *acmd = scsi_cmd_priv(cmd); struct aha1542_hostdata *aha1542 = shost_priv(sh); diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index b234621f6b37..c435769359f2 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -319,7 +319,7 @@ static irqreturn_t aha1740_intr_handle(int irq, void *dev_id) return IRQ_RETVAL(handled); } -static int aha1740_queuecommand_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status aha1740_queuecommand_lck(struct scsi_cmnd *SCpnt) { void (*done)(struct scsi_cmnd *) = scsi_done; unchar direction; diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index c3d1b9dd24ae..c8b6dc48300a 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -359,7 +359,7 @@ static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); static void ahd_linux_device_queue_depth(struct scsi_device *); -static int ahd_linux_run_command(struct ahd_softc*, +static enum scsi_qc_status ahd_linux_run_command(struct ahd_softc*, struct ahd_linux_device *, struct scsi_cmnd *); static void ahd_linux_setup_tag_info_global(char *p); @@ -577,11 +577,11 @@ ahd_linux_info(struct Scsi_Host *host) /* * Queue an SCB to the controller. */ -static int ahd_linux_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ahd_linux_queue_lck(struct scsi_cmnd *cmd) { - struct ahd_softc *ahd; - struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); - int rtn = SCSI_MLQUEUE_HOST_BUSY; + struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); + enum scsi_qc_status rtn = SCSI_MLQUEUE_HOST_BUSY; + struct ahd_softc *ahd; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; @@ -1535,7 +1535,7 @@ ahd_linux_device_queue_depth(struct scsi_device *sdev) } } -static int +static enum scsi_qc_status ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, struct scsi_cmnd *cmd) { diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 8b2b98666d61..c71f80f8fa34 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -519,11 +519,11 @@ ahc_linux_info(struct Scsi_Host *host) /* * Queue an SCB to the controller. */ -static int ahc_linux_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ahc_linux_queue_lck(struct scsi_cmnd *cmd) { struct ahc_softc *ahc; struct ahc_linux_device *dev = scsi_transport_device_data(cmd->device); - int rtn = SCSI_MLQUEUE_HOST_BUSY; + enum scsi_qc_status rtn = SCSI_MLQUEUE_HOST_BUSY; unsigned long flags; ahc = *(struct ahc_softc **)cmd->device->host->hostdata; diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index f0c5a30ce51b..8aa948f06cac 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -113,7 +113,8 @@ static int arcmsr_abort(struct scsi_cmnd *); static int arcmsr_bus_reset(struct scsi_cmnd *); static int arcmsr_bios_param(struct scsi_device *sdev, struct gendisk *disk, sector_t capacity, int *info); -static int arcmsr_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); +static enum scsi_qc_status arcmsr_queue_command(struct Scsi_Host *h, + struct scsi_cmnd *cmd); static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id); static int __maybe_unused arcmsr_suspend(struct device *dev); @@ -3312,7 +3313,7 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, } } -static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status arcmsr_queue_command_lck(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index ef21b85cf014..79d7d7336b6a 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -2408,7 +2408,7 @@ acornscsi_intr(int irq, void *dev_id) * Params : cmd - SCSI command * Returns : 0, or < 0 on error. */ -static int acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt) { struct scsi_pointer *scsi_pointer = arm_scsi_pointer(SCpnt); void (*done)(struct scsi_cmnd *) = scsi_done; diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index b1a749ab18f8..fccfacaaf1d5 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2202,11 +2202,12 @@ static void fas216_done(FAS216_Info *info, unsigned int result) * Returns: 0 on success, else error. * Notes: io_request_lock is held, interrupts are disabled. */ -static int fas216_queue_command_internal(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) +static enum scsi_qc_status +fas216_queue_command_internal(struct scsi_cmnd *SCpnt, + void (*done)(struct scsi_cmnd *)) { FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - int result; + enum scsi_qc_status result; fas216_checkmagic(info); @@ -2243,7 +2244,7 @@ static int fas216_queue_command_internal(struct scsi_cmnd *SCpnt, return result; } -static int fas216_queue_command_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status fas216_queue_command_lck(struct scsi_cmnd *SCpnt) { return fas216_queue_command_internal(SCpnt, scsi_done); } @@ -2273,7 +2274,7 @@ static void fas216_internal_done(struct scsi_cmnd *SCpnt) * Returns: scsi result code. * Notes: io_request_lock is held, interrupts are disabled. */ -static int fas216_noqueue_command_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status fas216_noqueue_command_lck(struct scsi_cmnd *SCpnt) { FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h index 08113277a2a9..29f710f9cb51 100644 --- a/drivers/scsi/arm/fas216.h +++ b/drivers/scsi/arm/fas216.h @@ -338,21 +338,24 @@ extern int fas216_init (struct Scsi_Host *instance); */ extern int fas216_add (struct Scsi_Host *instance, struct device *dev); -/* Function: int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt) +/* Function: enum scsi_qc_status fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt) * Purpose : queue a command for adapter to process. * Params : h - host adapter * : SCpnt - Command to queue * Returns : 0 - success, else error */ -extern int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt); +extern enum scsi_qc_status fas216_queue_command(struct Scsi_Host *h, + struct scsi_cmnd *SCpnt); -/* Function: int fas216_noqueue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt) +/* Function: enum scsi_qc_status fas216_noqueue_command(struct Scsi_Host *h, + * struct scsi_cmnd *SCpnt) * Purpose : queue a command for adapter to process, and process it to completion. * Params : h - host adapter * : SCpnt - Command to queue * Returns : 0 - success, else error */ -extern int fas216_noqueue_command(struct Scsi_Host *, struct scsi_cmnd *); +extern enum scsi_qc_status fas216_noqueue_command(struct Scsi_Host *h, + struct scsi_cmnd *SCpnt); /* Function: irqreturn_t fas216_intr (FAS216_Info *info) * Purpose : handle interrupts from the interface to progress a command diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index df6f40b51deb..67459d81f479 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -617,7 +617,7 @@ static irqreturn_t atp870u_intr_handle(int irq, void *dev_id) * * Queue a command to the ATP queue. Called with the host lock held. */ -static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p) +static enum scsi_qc_status atp870u_queuecommand_lck(struct scsi_cmnd *req_p) { void (*done)(struct scsi_cmnd *) = scsi_done; unsigned char c; diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index f56e008ee52b..6c84982c4726 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -24,7 +24,8 @@ DEFINE_IDR(bfad_im_port_index); struct scsi_transport_template *bfad_im_scsi_transport_template; struct scsi_transport_template *bfad_im_scsi_vport_transport_template; static void bfad_im_itnim_work_handler(struct work_struct *work); -static int bfad_im_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmnd); +static enum scsi_qc_status bfad_im_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *cmnd); static int bfad_im_sdev_init(struct scsi_device *sdev); static void bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim); @@ -1199,7 +1200,7 @@ bfad_im_itnim_work_handler(struct work_struct *work) /* * Scsi_Host template entry, queue a SCSI command to the BFAD. */ -static int bfad_im_queuecommand_lck(struct scsi_cmnd *cmnd) +static enum scsi_qc_status bfad_im_queuecommand_lck(struct scsi_cmnd *cmnd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct bfad_im_port_s *im_port = diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 6d47a4d8eed6..8c8968ec8cb4 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -498,7 +498,8 @@ static inline struct bnx2fc_priv *bnx2fc_priv(struct scsi_cmnd *cmd) struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt); struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type); void bnx2fc_cmd_release(struct kref *ref); -int bnx2fc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd); +enum scsi_qc_status bnx2fc_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc_cmd); int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba); int bnx2fc_send_fw_fcoe_destroy_msg(struct bnx2fc_hba *hba); int bnx2fc_send_session_ofld_req(struct fcoe_port *port, diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 33057908f147..90b2b54c549a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1836,8 +1836,8 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, * * This is the IO strategy routine, called by SCSI-ML **/ -int bnx2fc_queuecommand(struct Scsi_Host *host, - struct scsi_cmnd *sc_cmd) +enum scsi_qc_status bnx2fc_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc_cmd) { struct fc_lport *lport = shost_priv(host); struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index fa07a6f54003..b6ca23a29ef5 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -894,9 +894,9 @@ static long ch_ioctl(struct file *file, /* ------------------------------------------------------------------------ */ -static int ch_probe(struct device *dev) +static int ch_probe(struct scsi_device *sd) { - struct scsi_device *sd = to_scsi_device(dev); + struct device *dev = &sd->sdev_gendev; struct device *class_dev; int ret; scsi_changer *ch; @@ -967,8 +967,9 @@ static int ch_probe(struct device *dev) return ret; } -static int ch_remove(struct device *dev) +static void ch_remove(struct scsi_device *sd) { + struct device *dev = &sd->sdev_gendev; scsi_changer *ch = dev_get_drvdata(dev); spin_lock(&ch_index_lock); @@ -979,15 +980,14 @@ static int ch_remove(struct device *dev) device_destroy(&ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR, ch->minor)); scsi_device_put(ch->device); kref_put(&ch->ref, ch_destroy); - return 0; } static struct scsi_driver ch_template = { - .gendrv = { + .probe = ch_probe, + .remove = ch_remove, + .gendrv = { .name = "ch", .owner = THIS_MODULE, - .probe = ch_probe, - .remove = ch_remove, }, }; @@ -1014,7 +1014,7 @@ static int __init init_ch_module(void) SCSI_CHANGER_MAJOR); goto fail1; } - rc = scsi_register_driver(&ch_template.gendrv); + rc = scsi_register_driver(&ch_template); if (rc < 0) goto fail2; return 0; @@ -1028,7 +1028,7 @@ static int __init init_ch_module(void) static void __exit exit_ch_module(void) { - scsi_unregister_driver(&ch_template.gendrv); + scsi_unregister_driver(&ch_template); unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); class_unregister(&ch_sysfs_class); idr_destroy(&ch_index_idr); diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index 34bde6650fae..c29bf2807e31 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -1775,8 +1775,8 @@ csio_scsi_cbfn(struct csio_hw *hw, struct csio_ioreq *req) * - Kicks off the SCSI state machine for this IO. * - Returns busy status on error. */ -static int -csio_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmnd) +static enum scsi_qc_status csio_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmnd) { struct csio_lnode *ln = shost_priv(host); struct csio_hw *hw = csio_lnode_to_hw(ln); diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index 386c8359e1cc..9dc499c89d3e 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -873,7 +873,7 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, * and is expected to be held on return. * */ -static int dc395x_queue_command_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status dc395x_queue_command_lck(struct scsi_cmnd *cmd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct DeviceCtlBlk *dcb; diff --git a/drivers/scsi/esas2r/esas2r.h b/drivers/scsi/esas2r/esas2r.h index c48275d53aef..a763edd05fe4 100644 --- a/drivers/scsi/esas2r/esas2r.h +++ b/drivers/scsi/esas2r/esas2r.h @@ -968,7 +968,8 @@ int esas2r_ioctl_handler(void *hostdata, unsigned int cmd, void __user *arg); int esas2r_ioctl(struct scsi_device *dev, unsigned int cmd, void __user *arg); u8 handle_hba_ioctl(struct esas2r_adapter *a, struct atto_ioctl *ioctl_hba); -int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd); +enum scsi_qc_status esas2r_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd); int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh); long esas2r_proc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg); diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index be6bf518eb7c..fdcffc871d19 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -818,7 +818,8 @@ static u32 get_physaddr_from_sgc(struct esas2r_sg_context *sgc, u64 *addr) return len; } -int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +enum scsi_qc_status esas2r_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { struct esas2r_adapter *a = (struct esas2r_adapter *)cmd->device->host->hostdata; diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 802718ffad84..05647ccc3c8a 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -952,7 +952,7 @@ static void esp_event_queue_full(struct esp *esp, struct esp_cmd_entry *ent) scsi_track_queue_full(dev, lp->num_tagged - 1); } -static int esp_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status esp_queuecommand_lck(struct scsi_cmnd *cmd) { struct scsi_device *dev = cmd->device; struct esp *esp = shost_priv(dev->host); diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index c0b2a980db34..22fbb0222f07 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -402,7 +402,8 @@ static irqreturn_t fdomain_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static int fdomain_queue(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +static enum scsi_qc_status fdomain_queue(struct Scsi_Host *sh, + struct scsi_cmnd *cmd) { struct scsi_pointer *scsi_pointer = fdomain_scsi_pointer(cmd); struct fdomain *fd = shost_priv(cmd->device->host); diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 1199d701c3f5..42237eb3222f 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -503,7 +503,8 @@ void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf); void fnic_flush_tx(struct work_struct *work); void fnic_update_mac_locked(struct fnic *, u8 *new); -int fnic_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc); int fnic_abort_cmd(struct scsi_cmnd *); int fnic_device_reset(struct scsi_cmnd *); int fnic_eh_host_reset_handler(struct scsi_cmnd *sc); diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 75b29a018d1f..29d7aca06958 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -454,7 +454,8 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, return 0; } -int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) +enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc) { struct request *const rq = scsi_cmd_to_rq(sc); uint32_t mqtag = 0; diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 1b3fbd328277..e047747d4ecf 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -626,9 +626,8 @@ int scsi_host_busy(struct Scsi_Host *shost) { int cnt = 0; - if (shost->tag_set.ops) - blk_mq_tagset_busy_iter(&shost->tag_set, - scsi_host_check_in_flight, &cnt); + blk_mq_tagset_busy_iter(&shost->tag_set, + scsi_host_check_in_flight, &cnt); return cnt; } EXPORT_SYMBOL(scsi_host_busy); diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3654b12c5d5a..3e235dbfb67a 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -276,7 +276,8 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h); #define VPD_PAGE (1 << 8) #define HPSA_SIMPLE_ERROR_BITS 0x03 -static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); +static enum scsi_qc_status hpsa_scsi_queue_command(struct Scsi_Host *h, + struct scsi_cmnd *cmd); static void hpsa_scan_start(struct Scsi_Host *); static int hpsa_scan_finished(struct Scsi_Host *sh, unsigned long elapsed_time); @@ -5667,7 +5668,8 @@ static void hpsa_command_resubmit_worker(struct work_struct *work) } /* Running in struct Scsi_Host->host_lock less mode */ -static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +static enum scsi_qc_status hpsa_scsi_queue_command(struct Scsi_Host *sh, + struct scsi_cmnd *cmd) { struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index 21f1d9871a33..7083c14c5302 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -993,7 +993,7 @@ static int hptiop_reset_comm_mvfrey(struct hptiop_hba *hba) return 0; } -static int hptiop_queuecommand_lck(struct scsi_cmnd *scp) +static enum scsi_qc_status hptiop_queuecommand_lck(struct scsi_cmnd *scp) { struct Scsi_Host *host = scp->device->host; struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata; diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 228daffb286d..1c370d11b6dd 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -1960,7 +1960,8 @@ static struct ibmvfc_cmd *ibmvfc_init_vfc_cmd(struct ibmvfc_event *evt, struct s * Returns: * 0 on success / other on failure **/ -static int ibmvfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) +static enum scsi_qc_status ibmvfc_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmnd) { struct ibmvfc_host *vhost = shost_priv(shost); struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 3d65a498b701..200debd6f7e8 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -868,9 +868,10 @@ static void ibmvscsi_timeout(struct timer_list *t) * Returns the value returned from ibmvscsi_send_crq(). (Zero for success) * Note that this routine assumes that host_lock is held for synchronization */ -static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, - struct ibmvscsi_host_data *hostdata, - unsigned long timeout) +static enum scsi_qc_status +ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, + struct ibmvscsi_host_data *hostdata, + unsigned long timeout) { __be64 *crq_as_u64 = (__be64 *)&evt_struct->crq; int request_status = 0; @@ -1040,7 +1041,7 @@ static inline u16 lun_from_dev(struct scsi_device *dev) * @cmnd: struct scsi_cmnd to be executed * @done: Callback function to be called when cmd is completed */ -static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd) +static enum scsi_qc_status ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct srp_cmd *srp_cmd; diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 45b0e33293a5..da7aaac10a73 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -925,7 +925,7 @@ static int imm_engine(imm_struct *dev, struct scsi_cmnd *const cmd) return 0; } -static int imm_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status imm_queuecommand_lck(struct scsi_cmnd *cmd) { imm_struct *dev = imm_dev(cmd->device->host); diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c index ed34ad92c807..06fbe85dccfa 100644 --- a/drivers/scsi/initio.c +++ b/drivers/scsi/initio.c @@ -2606,7 +2606,7 @@ static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * c * zero if successful or indicate a host busy condition if not (which * will cause the mid layer to call us again later with the command) */ -static int i91u_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status i91u_queuecommand_lck(struct scsi_cmnd *cmd) { struct initio_host *host = (struct initio_host *) cmd->device->host->hostdata; struct scsi_ctrl_blk *cmnd; diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index dbd58a7e7bc1..c0487ce38d8d 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6242,8 +6242,8 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd) * SCSI_MLQUEUE_DEVICE_BUSY if device is busy * SCSI_MLQUEUE_HOST_BUSY if host is busy **/ -static int ipr_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scsi_cmd) +static enum scsi_qc_status ipr_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scsi_cmd) { struct ipr_ioa_cfg *ioa_cfg; struct ipr_resource_entry *res; diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index 3393a288fd23..e2dce28a11c6 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -230,7 +230,7 @@ module_param(ips, charp, 0); */ static int ips_eh_abort(struct scsi_cmnd *); static int ips_eh_reset(struct scsi_cmnd *); -static int ips_queue(struct Scsi_Host *, struct scsi_cmnd *); +static enum scsi_qc_status ips_queue(struct Scsi_Host *, struct scsi_cmnd *); static const char *ips_info(struct Scsi_Host *); static irqreturn_t do_ipsintr(int, void *); static int ips_hainit(ips_ha_t *); @@ -1017,7 +1017,7 @@ static int ips_eh_reset(struct scsi_cmnd *SC) /* Linux obtains io_request_lock before calling this function */ /* */ /****************************************************************************/ -static int ips_queue_lck(struct scsi_cmnd *SC) +static enum scsi_qc_status ips_queue_lck(struct scsi_cmnd *SC) { void (*done)(struct scsi_cmnd *) = scsi_done; ips_ha_t *ha; diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 31d08c115521..2f93f6c65a86 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -1854,7 +1854,8 @@ static inline int fc_fcp_lport_queue_ready(struct fc_lport *lport) * * This is the i/o strategy routine, called by the SCSI layer. */ -int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd) +enum scsi_qc_status fc_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc_cmd) { struct fc_lport *lport = shost_priv(shost); struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index c9f410c50978..25857d6ed6e8 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1747,7 +1747,8 @@ enum { FAILURE_SESSION_NOT_READY, }; -int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc) +enum scsi_qc_status iscsi_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc) { struct iscsi_cls_session *cls_session; struct iscsi_host *ihost; diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index ffa5b49aaf08..58ee74562332 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -157,7 +157,8 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd, return task; } -int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +enum scsi_qc_status sas_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { struct sas_internal *i = to_sas_internal(host->transportt); struct domain_device *dev = cmd_to_domain_dev(cmd); diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 33582d48ec09..4af5c069635a 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -6979,6 +6979,42 @@ lpfc_reset_stats(struct Scsi_Host *shost) return; } +/** + * lpfc_get_enc_info - Return encryption information about the session for + * a given remote port. + * @rport: ptr to fc_rport from scsi transport fc + * + * Given an rport object, iterate through the fc_nodes list to find node + * corresponding with rport. Pass the encryption information from the node to + * rport's encryption attribute for reporting to upper layers. Information is + * passed through nlp_enc_info struct which contains encryption status. + * + * Returns: + * - Address of rport's fc_encryption_info struct + * - NULL when not found + **/ +static struct fc_encryption_info * +lpfc_get_enc_info(struct fc_rport *rport) +{ + struct Scsi_Host *shost = rport_to_shost(rport); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct fc_encryption_info *ef = NULL; + struct lpfc_nodelist *ndlp, *next_ndlp; + unsigned long iflags; + + spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags); + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (ndlp->rport && ndlp->rport == rport) { + ef = &rport->enc_info; + ef->status = ndlp->nlp_enc_info.status; + break; + } + } + spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags); + return ef; +} + + /* * The LPFC driver treats linkdown handling as target loss events so there * are no sysfs handlers for link_down_tmo. @@ -7196,6 +7232,8 @@ struct fc_function_template lpfc_transport_functions = { .get_fc_host_stats = lpfc_get_stats, .reset_fc_host_stats = lpfc_reset_stats, + .get_fc_rport_enc_info = lpfc_get_enc_info, + .dd_fcrport_size = sizeof(struct lpfc_rport_data), .show_rport_maxframe_size = 1, .show_rport_supported_classes = 1, @@ -7265,6 +7303,8 @@ struct fc_function_template lpfc_vport_transport_functions = { .get_fc_host_stats = lpfc_get_stats, .reset_fc_host_stats = lpfc_reset_stats, + .get_fc_rport_enc_info = lpfc_get_enc_info, + .dd_fcrport_size = sizeof(struct lpfc_rport_data), .show_rport_maxframe_size = 1, .show_rport_supported_classes = 1, diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 92b5b2dbe847..646f88c776f5 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -872,6 +872,13 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) ndlp->nlp_rpi); len += scnprintf(buf+len, size-len, "flag:x%08lx ", ndlp->nlp_flag); + if (ndlp->nlp_enc_info.status) { + len += scnprintf(buf + len, + size - len, "ENCRYPTED"); + len += scnprintf(buf + len, size - len, + ndlp->nlp_enc_info.level + ? "(CNSA2.0) " : "(CNSA1.0) "); + } if (!ndlp->nlp_type) len += scnprintf(buf+len, size-len, "UNKNOWN_TYPE "); if (ndlp->nlp_type & NLP_FC_NODE) diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 51cb8571c049..de0adeecf668 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -77,6 +77,11 @@ struct lpfc_node_rrqs { unsigned long xri_bitmap[XRI_BITMAP_ULONGS]; }; +struct lpfc_enc_info { + u8 status; /* encryption status for session */ + u8 level; /* CNSA encryption level */ +}; + enum lpfc_fc4_xpt_flags { NLP_XPT_REGD = 0x1, SCSI_XPT_REGD = 0x2, @@ -138,6 +143,8 @@ struct lpfc_nodelist { uint8_t vmid_support; /* destination VMID support */ #define NLP_NVME_NSLER 0x1 /* NVME NSLER device */ + struct lpfc_enc_info nlp_enc_info; /* Encryption information struct */ + struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ struct lpfc_hba *phba; struct fc_rport *rport; /* scsi_transport_fc port structure */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 02b6d31b9ad9..32da3c23c7f4 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2014,6 +2014,58 @@ lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_nlp_put(ndlp); return; } + +/** + * lpfc_check_encryption - Reports an ndlp's encryption information + * @phba: pointer to lpfc hba data structure. + * @ndlp: pointer to a node-list data structure. + * @cmdiocb: pointer to lpfc command iocbq data structure. + * @rspiocb: pointer to lpfc response iocbq data structure. + * + * This routine is called in the completion callback function for issuing + * or receiving a Port Login (PLOGI) command. In a PLOGI completion, if FEDIF + * is supported, encryption information will be provided in completion status + * data. If @phba supports FEDIF, a log message containing encryption + * information will be logged. Encryption status is also saved for encryption + * reporting with upper layer through the rport encryption attribute. + **/ +static void +lpfc_check_encryption(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, + struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) +{ + struct lpfc_vport *vport = cmdiocb->vport; + u32 did = ndlp->nlp_DID; + struct lpfc_enc_info *nlp_enc_info = &ndlp->nlp_enc_info; + char enc_status[FC_RPORT_ENCRYPTION_STATUS_MAX_LEN] = {0}; + char enc_level[8] = "N/A"; + u8 encryption; + + if (phba->sli4_hba.encryption_support && + ((did & Fabric_DID_MASK) != Fabric_DID_MASK)) { + encryption = bf_get(lpfc_wcqe_c_enc, + &rspiocb->wcqe_cmpl); + nlp_enc_info->status = encryption; + + strscpy(enc_status, encryption ? "Encrypted" : "Unencrypted", + sizeof(enc_status)); + + if (encryption) { + nlp_enc_info->level = bf_get(lpfc_wcqe_c_enc_lvl, + &rspiocb->wcqe_cmpl); + strscpy(enc_level, nlp_enc_info->level ? "CNSA2.0" : + "CNSA1.0", + sizeof(enc_level)); + } + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ENCRYPTION, + "0924 DID:x%06x %s Session " + "Established, Encryption Level:%s " + "rpi:x%x\n", + ndlp->nlp_DID, enc_status, enc_level, + ndlp->nlp_rpi); + } +} + /** * lpfc_cmpl_els_plogi - Completion callback function for plogi * @phba: pointer to lpfc hba data structure. @@ -2153,6 +2205,8 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp); + lpfc_check_encryption(phba, ndlp, cmdiocb, rspiocb); + sp = (struct serv_parm *)((u8 *)prsp->virt + sizeof(u32)); @@ -5407,6 +5461,9 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; } + if (!ulp_status && test_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag)) + lpfc_check_encryption(phba, ndlp, cmdiocb, rspiocb); + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, "ELS rsp cmpl: status:x%x/x%x did:x%x", ulp_status, ulp_word4, did); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index bb803f32bc1b..1aeebdc08073 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -5340,6 +5340,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) clear_bit(NLP_NPR_ADISC, &ndlp->nlp_flag); if (acc_plogi) clear_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); + memset(&ndlp->nlp_enc_info, 0, sizeof(ndlp->nlp_enc_info)); return 1; } clear_bit(NLP_LOGO_ACC, &ndlp->nlp_flag); diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index a7f7ed86d2b0..c000474c3066 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -437,6 +437,12 @@ struct lpfc_wcqe_complete { #define lpfc_wcqe_c_cmf_bw_MASK 0x0FFFFFFF #define lpfc_wcqe_c_cmf_bw_WORD total_data_placed uint32_t parameter; +#define lpfc_wcqe_c_enc_SHIFT 31 +#define lpfc_wcqe_c_enc_MASK 0x00000001 +#define lpfc_wcqe_c_enc_WORD parameter +#define lpfc_wcqe_c_enc_lvl_SHIFT 30 +#define lpfc_wcqe_c_enc_lvl_MASK 0x00000001 +#define lpfc_wcqe_c_enc_lvl_WORD parameter #define lpfc_wcqe_c_bg_edir_SHIFT 5 #define lpfc_wcqe_c_bg_edir_MASK 0x00000001 #define lpfc_wcqe_c_bg_edir_WORD parameter @@ -2942,7 +2948,10 @@ struct lpfc_mbx_read_config { #define lpfc_mbx_rd_conf_topology_SHIFT 24 #define lpfc_mbx_rd_conf_topology_MASK 0x000000FF #define lpfc_mbx_rd_conf_topology_WORD word2 - uint32_t rsvd_3; + uint32_t word3; +#define lpfc_mbx_rd_conf_fedif_SHIFT 6 +#define lpfc_mbx_rd_conf_fedif_MASK 0x00000001 +#define lpfc_mbx_rd_conf_fedif_WORD word3 uint32_t word4; #define lpfc_mbx_rd_conf_e_d_tov_SHIFT 0 #define lpfc_mbx_rd_conf_e_d_tov_MASK 0x0000FFFF diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index b1460b16dd91..a116a16c4a6f 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -9999,6 +9999,11 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) (phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0; phba->max_vports = phba->max_vpi; + if (bf_get(lpfc_mbx_rd_conf_fedif, rd_config)) + phba->sli4_hba.encryption_support = true; + else + phba->sli4_hba.encryption_support = false; + /* Next decide on FPIN or Signal E2E CGN support * For congestion alarms and warnings valid combination are: * 1. FPIN alarms / FPIN warnings diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h index 59bd2bafc73f..e00d101d548c 100644 --- a/drivers/scsi/lpfc/lpfc_logmsg.h +++ b/drivers/scsi/lpfc/lpfc_logmsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -47,6 +47,7 @@ #define LOG_RSVD1 0x01000000 /* Reserved */ #define LOG_RSVD2 0x02000000 /* Reserved */ #define LOG_CGN_MGMT 0x04000000 /* Congestion Mgmt events */ +#define LOG_ENCRYPTION 0x40000000 /* EDIF Encryption events. */ #define LOG_TRACE_EVENT 0x80000000 /* Dmp the DBG log on this err */ #define LOG_ALL_MSG 0x7fffffff /* LOG all messages */ diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 6d9d8c196936..df64948e55ee 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -5233,8 +5233,8 @@ static char *lpfc_is_command_vm_io(struct scsi_cmnd *cmd) * 0 - Success * SCSI_MLQUEUE_HOST_BUSY - Block all devices served by this host temporarily. **/ -static int -lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) +static enum scsi_qc_status lpfc_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmnd) { struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; @@ -6743,8 +6743,8 @@ lpfc_disable_oas_lun(struct lpfc_hba *phba, struct lpfc_name *vport_wwpn, return false; } -static int -lpfc_no_command(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) +static enum scsi_qc_status lpfc_no_command(struct Scsi_Host *shost, + struct scsi_cmnd *cmnd) { return SCSI_MLQUEUE_HOST_BUSY; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 73d77cfab5f8..734af3d039f8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -20432,62 +20432,36 @@ lpfc_check_next_fcf_pri_level(struct lpfc_hba *phba) uint16_t lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba) { - uint16_t next_fcf_index; + uint16_t next; -initial_priority: - /* Search start from next bit of currently registered FCF index */ - next_fcf_index = phba->fcf.current_rec.fcf_indx; - -next_priority: - /* Determine the next fcf index to check */ - next_fcf_index = (next_fcf_index + 1) % LPFC_SLI4_FCF_TBL_INDX_MAX; - next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask, - LPFC_SLI4_FCF_TBL_INDX_MAX, - next_fcf_index); + do { + for_each_set_bit_wrap(next, phba->fcf.fcf_rr_bmask, + LPFC_SLI4_FCF_TBL_INDX_MAX, phba->fcf.current_rec.fcf_indx) { + if (next == phba->fcf.current_rec.fcf_indx) + continue; - /* Wrap around condition on phba->fcf.fcf_rr_bmask */ - if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { - /* - * If we have wrapped then we need to clear the bits that - * have been tested so that we can detect when we should - * change the priority level. - */ - next_fcf_index = find_first_bit(phba->fcf.fcf_rr_bmask, - LPFC_SLI4_FCF_TBL_INDX_MAX); - } + if (!(phba->fcf.fcf_pri[next].fcf_rec.flag & LPFC_FCF_FLOGI_FAILED)) { + lpfc_printf_log(phba, KERN_INFO, LOG_FIP, + "2845 Get next roundrobin failover FCF (x%x)\n", next); + return next; + } + if (list_is_singular(&phba->fcf.fcf_pri_list)) + return LPFC_FCOE_FCF_NEXT_NONE; + } - /* Check roundrobin failover list empty condition */ - if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX || - next_fcf_index == phba->fcf.current_rec.fcf_indx) { /* * If next fcf index is not found check if there are lower * Priority level fcf's in the fcf_priority list. * Set up the rr_bmask with all of the avaiable fcf bits * at that level and continue the selection process. */ - if (lpfc_check_next_fcf_pri_level(phba)) - goto initial_priority; - lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, - "2844 No roundrobin failover FCF available\n"); - - return LPFC_FCOE_FCF_NEXT_NONE; - } - - if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX && - phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag & - LPFC_FCF_FLOGI_FAILED) { - if (list_is_singular(&phba->fcf.fcf_pri_list)) - return LPFC_FCOE_FCF_NEXT_NONE; + } while (lpfc_check_next_fcf_pri_level(phba)); - goto next_priority; - } - - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2845 Get next roundrobin failover FCF (x%x)\n", - next_fcf_index); + lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, + "2844 No roundrobin failover FCF available\n"); - return next_fcf_index; + return LPFC_FCOE_FCF_NEXT_NONE; } /** diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index fd6dab157887..ee58383492b2 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -888,6 +888,10 @@ struct lpfc_sli4_hba { #define LPFC_FP_EQ_MAX_INTR_SEC 10000 uint32_t intr_enable; + + /* Indicates whether SLI Port supports FEDIF */ + bool encryption_support; + struct lpfc_bmbx bmbx; struct lpfc_max_cfg_param max_cfg_param; uint16_t extents_in_use; /* must allocate resource extents. */ diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index f3dada5bf7c1..c4ca8bf5843a 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 "14.4.0.12" +#define LPFC_DRIVER_VERSION "14.4.0.13" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c index 377dcab32cd8..49f856be2e51 100644 --- a/drivers/scsi/mac53c94.c +++ b/drivers/scsi/mac53c94.c @@ -66,7 +66,7 @@ static irqreturn_t do_mac53c94_interrupt(int, void *); static void cmd_done(struct fsc_state *, int result); static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *); -static int mac53c94_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status mac53c94_queue_lck(struct scsi_cmnd *cmd) { struct fsc_state *state; diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index a00622c0c526..6b088bb049cc 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -372,11 +372,11 @@ mega_runpendq(adapter_t *adapter) * * The command queuing entry point for the mid-layer. */ -static int megaraid_queue_lck(struct scsi_cmnd *scmd) +static enum scsi_qc_status megaraid_queue_lck(struct scsi_cmnd *scmd) { adapter_t *adapter; scb_t *scb; - int busy=0; + enum scsi_qc_status busy = 0; unsigned long flags; adapter = (adapter_t *)scmd->device->host->hostdata; @@ -518,7 +518,8 @@ mega_get_ldrv_num(adapter_t *adapter, struct scsi_cmnd *cmd, int channel) * boot settings. */ static scb_t * -mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) +mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, + enum scsi_qc_status *busy) { mega_passthru *pthru; scb_t *scb; @@ -640,7 +641,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) } if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -688,7 +689,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) /* Allocate a SCB and initialize passthru */ if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } pthru = scb->pthru; @@ -730,7 +731,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) /* Allocate a SCB and initialize mailbox */ if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } mbox = (mbox_t *)scb->raw_mbox; @@ -870,7 +871,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) /* Allocate a SCB and initialize mailbox */ if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -898,7 +899,7 @@ mega_build_cmd(adapter_t *adapter, struct scsi_cmnd *cmd, int *busy) else { /* Allocate a SCB and initialize passthru */ if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index d6bfd26a8843..ecbaa0a0ab51 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -962,8 +962,10 @@ static int mega_query_adapter(adapter_t *); static int issue_scb(adapter_t *, scb_t *); static int mega_setup_mailbox(adapter_t *); -static int megaraid_queue (struct Scsi_Host *, struct scsi_cmnd *); -static scb_t * mega_build_cmd(adapter_t *, struct scsi_cmnd *, int *); +static enum scsi_qc_status megaraid_queue(struct Scsi_Host *, + struct scsi_cmnd *); +static scb_t *mega_build_cmd(adapter_t *, struct scsi_cmnd *, + enum scsi_qc_status *); static void __mega_runpendq(adapter_t *); static int issue_scb_block(adapter_t *, u_char *); diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c index b610cad83321..b6a32bb0bd19 100644 --- a/drivers/scsi/megaraid/megaraid_mbox.c +++ b/drivers/scsi/megaraid/megaraid_mbox.c @@ -109,8 +109,10 @@ static int megaraid_mbox_fire_sync_cmd(adapter_t *); static void megaraid_mbox_display_scb(adapter_t *, scb_t *); static void megaraid_mbox_setup_device_map(adapter_t *); -static int megaraid_queue_command(struct Scsi_Host *, struct scsi_cmnd *); -static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *); +static enum scsi_qc_status megaraid_queue_command(struct Scsi_Host *, + struct scsi_cmnd *); +static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, + enum scsi_qc_status *); static void megaraid_mbox_runpendq(adapter_t *, scb_t *); static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *, struct scsi_cmnd *); @@ -1434,12 +1436,12 @@ mbox_post_cmd(adapter_t *adapter, scb_t *scb) * * Queue entry point for mailbox based controllers. */ -static int megaraid_queue_command_lck(struct scsi_cmnd *scp) +static enum scsi_qc_status megaraid_queue_command_lck(struct scsi_cmnd *scp) { void (*done)(struct scsi_cmnd *) = scsi_done; adapter_t *adapter; scb_t *scb; - int if_busy; + enum scsi_qc_status if_busy; adapter = SCP2ADAPTER(scp); scp->result = 0; @@ -1477,7 +1479,8 @@ static DEF_SCSI_QCMD(megaraid_queue_command) * firmware. We also complete certain commands without sending them to firmware. */ static scb_t * -megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) +megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, + enum scsi_qc_status *busy) { mraid_device_t *rdev = ADAP2RAIDDEV(adapter); int channel; @@ -1516,7 +1519,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -1599,7 +1602,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) /* Allocate a SCB and initialize passthru */ if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -1644,7 +1647,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) */ if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } ccb = (mbox_ccb_t *)scb->ccb; @@ -1740,7 +1743,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) */ if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } @@ -1808,7 +1811,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) // Allocate a SCB and initialize passthru if (!(scb = megaraid_alloc_scb(adapter, scp))) { scp->result = (DID_ERROR << 16); - *busy = 1; + *busy = SCSI_MLQUEUE_HOST_BUSY; return NULL; } diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index abbbc4b36cd1..52894e892a92 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1781,8 +1781,8 @@ megasas_build_and_issue_cmd(struct megasas_instance *instance, * @shost: adapter SCSI host * @scmd: SCSI command to be queued */ -static int -megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) +static enum scsi_qc_status megasas_queue_command(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct megasas_instance *instance; struct MR_PRIV_DEVICE *mr_device_priv_data; diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 768b85eecc8f..dc1402b321da 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1625,7 +1625,7 @@ static void cmd_complete(struct mesh_state *ms) * Called by midlayer with host locked to queue a new * request */ -static int mesh_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status mesh_queue_lck(struct scsi_cmnd *cmd) { struct mesh_state *ms; diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h index 8c8bfbbdd34e..33dd303c97bb 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_cnfg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2017-2023 Broadcom Inc. All rights reserved. + * Copyright 2017-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_CNFG_H #define MPI30_CNFG_H 1 @@ -1037,6 +1037,7 @@ struct mpi3_io_unit_page5 { #define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_SSD_SHIFT (2) #define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_SSD_MASK (0x0003) #define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_SSD_SHIFT (0) +#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_HDD_SPINDOWN_ENABLE (0x8000) #define MPI3_IOUNIT5_FLAGS_SATAPUIS_MASK (0x0c) #define MPI3_IOUNIT5_FLAGS_SATAPUIS_NOT_SUPPORTED (0x00) #define MPI3_IOUNIT5_FLAGS_SATAPUIS_OS_CONTROLLED (0x04) @@ -1074,7 +1075,8 @@ struct mpi3_io_unit_page8 { u8 current_key_encryption_algo; u8 key_digest_hash_algo; union mpi3_version_union current_svn; - __le32 reserved14; + __le16 pending_svn_time; + __le16 reserved16; __le32 current_key[128]; union mpi3_iounit8_digest digest[MPI3_IOUNIT8_DIGEST_MAX]; }; @@ -1406,6 +1408,7 @@ struct mpi3_driver_page1 { }; #define MPI3_DRIVER1_PAGEVERSION (0x00) +#define MPI3_DRIVER1_FLAGS_DEVICE_SHUTDOWN_ON_UNLOAD_DISABLE (0x0001) #ifndef MPI3_DRIVER2_TRIGGER_MAX #define MPI3_DRIVER2_TRIGGER_MAX (1) #endif @@ -1561,7 +1564,9 @@ struct mpi3_security1_key_record { u8 consumer; __le16 key_data_size; __le32 additional_key_data; - __le32 reserved08[2]; + u8 library_version; + u8 reserved09[3]; + __le32 reserved0c; union mpi3_security1_key_data key_data; }; @@ -1614,6 +1619,85 @@ struct mpi3_security_page2 { u8 reserved9d[3]; struct mpi3_security2_trusted_root trusted_root[MPI3_SECURITY2_TRUSTED_ROOT_MAX]; }; + +struct mpi3_security_page3 { + struct mpi3_config_page_header header; + __le16 key_data_length; + __le16 reserved0a; + u8 key_number; + u8 reserved0d[3]; + union mpi3_security_mac mac; + union mpi3_security_nonce nonce; + __le32 reserved90[12]; + u8 flags; + u8 consumer; + __le16 key_data_size; + __le32 additional_key_data; + u8 library_version; + u8 reserved_c9[3]; + __le32 reserved_cc; + u8 key_data[]; +}; + +#define MPI3_SECURITY3_PAGEVERSION (0x00) +#define MPI3_SECURITY3_FLAGS_TYPE_MASK (0x0f) +#define MPI3_SECURITY3_FLAGS_TYPE_SHIFT (0) +#define MPI3_SECURITY3_FLAGS_TYPE_NOT_VALID (0) +#define MPI3_SECURITY3_FLAGS_TYPE_MLDSA_PRIVATE (1) +#define MPI3_SECURITY3_FLAGS_TYPE_MLDSA_PUBLIC (2) +struct mpi3_security_page10 { + struct mpi3_config_page_header header; + __le32 reserved08[2]; + union mpi3_security_mac mac; + union mpi3_security_nonce nonce; + __le64 current_token_nonce; + __le64 previous_token_nonce; + __le32 reserved_a0[8]; + u8 diagnostic_auth_id[64]; +}; +#define MPI3_SECURITY10_PAGEVERSION (0x00) + +struct mpi3_security_page11 { + struct mpi3_config_page_header header; + u8 flags; + u8 reserved09[3]; + __le32 reserved0c; + __le32 diagnostic_token_length; + __le32 reserved14[3]; + u8 diagnostic_token[]; +}; +#define MPI3_SECURITY11_PAGEVERSION (0x00) +#define MPI3_SECURITY11_FLAGS_TOKEN_ENABLED (0x01) + +struct mpi3_security12_diag_feature { + __le32 feature_identifier; + u8 feature_size; + u8 feature_type; + __le16 reserved06; + u8 status; + u8 section; + __le16 reserved0a; + __le32 reserved0c; + u8 feature_data[64]; +}; +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_MASK (0x03) +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_SHIFT (0) +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_UNKNOWN (0x00) +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_DISABLED (0x01) +#define MPI3_SECURITY12_DIAG_FEATURE_STATUS_ENABLED (0x02) +#define MPI3_SECURITY12_DIAG_FEATURE_SECTION_PROTECTED (0x00) +#define MPI3_SECURITY12_DIAG_FEATURE_SECTION_UNPROTECTED (0x01) +#define MPI3_SECURITY12_DIAG_FEATURE_SECTION_PAYLOAD (0x02) +#define MPI3_SECURITY12_DIAG_FEATURE_SECTION_SIGNATURE (0x03) +struct mpi3_security_page12 { + struct mpi3_config_page_header header; + __le32 reserved08[2]; + u8 num_diag_features; + u8 reserved11[3]; + __le32 reserved14[3]; + struct mpi3_security12_diag_feature diag_feature[]; +}; + #define MPI3_SECURITY2_PAGEVERSION (0x00) struct mpi3_sas_io_unit0_phy_data { u8 io_unit_port; @@ -2314,6 +2398,8 @@ struct mpi3_device0_sas_sata_format { u8 attached_phy_identifier; u8 max_port_connections; u8 zone_group; + u8 reserved10[3]; + u8 negotiated_link_rate; }; #define MPI3_DEVICE0_SASSATA_FLAGS_WRITE_SAME_UNMAP_NCQ (0x0400) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_image.h b/drivers/scsi/mpi3mr/mpi/mpi30_image.h index 8d824107a678..62ddf094d46c 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_image.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_image.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2018-2023 Broadcom Inc. All rights reserved. + * Copyright 2018-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_IMAGE_H #define MPI30_IMAGE_H 1 @@ -135,7 +135,7 @@ struct mpi3_ci_manifest_mpi { __le32 package_version_string_offset; __le32 package_build_date_string_offset; __le32 package_build_time_string_offset; - __le32 reserved4c; + __le32 diag_authorization_key_offset; __le32 diag_authorization_identifier[16]; struct mpi3_ci_manifest_mpi_comp_image_ref component_image_ref[MPI3_CI_MANIFEST_MPI_MAX]; }; @@ -148,16 +148,112 @@ struct mpi3_ci_manifest_mpi { #define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_GCA (0x50) #define MPI3_CI_MANIFEST_MPI_RELEASE_LEVEL_POINT (0x60) #define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTHORIZATION (0x01) +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTH_ANCHOR_MASK (0x06) +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTH_ANCHOR_SHIFT (1) +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTH_ANCHOR_IDENTIFIER (0x00) +#define MPI3_CI_MANIFEST_MPI_FLAGS_DIAG_AUTH_ANCHOR_KEY_OFFSET (0x02) #define MPI3_CI_MANIFEST_MPI_SUBSYSTEMID_IGNORED (0xffff) #define MPI3_CI_MANIFEST_MPI_PKG_VER_STR_OFF_UNSPECIFIED (0x00000000) #define MPI3_CI_MANIFEST_MPI_PKG_BUILD_DATE_STR_OFF_UNSPECIFIED (0x00000000) #define MPI3_CI_MANIFEST_MPI_PKG_BUILD_TIME_STR_OFF_UNSPECIFIED (0x00000000) + +struct mpi3_sb_manifest_ci_digest { + __le32 signature1; + __le32 reserved04[2]; + u8 hash_algorithm; + u8 reserved09[3]; + struct mpi3_comp_image_version component_image_version; + __le32 component_image_version_string_offset; + __le32 digest[16]; +}; + +struct mpi3_sb_manifest_ci_ref_element { + u8 num_ci_digests; + u8 reserved01[3]; + struct mpi3_sb_manifest_ci_digest ci_digest[]; +}; + +struct mpi3_sb_manifest_embedded_key_element { + __le32 reserved00[3]; + u8 key_algorithm; + u8 flags; + __le16 public_key_size; + __le32 start_tag; + __le32 public_key[]; +}; + +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_FLAGS_KEYINDEX_MASK (0x03) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_FLAGS_KEYINDEX_STRT (0x00) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_FLAGS_KEYINDEX_K2GO (0x01) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_STARTTAG_STRT (0x54525453) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_STARTTAG_K2GO (0x4f47324b) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_ENDTAG_STOP (0x504f5453) +#define MPI3_SB_MANIFEST_EMBEDDED_KEY_ENDTAG_K2ST (0x5453324b) + +struct mpi3_sb_manifest_diag_key_element { + __le32 reserved00[3]; + u8 key_algorithm; + u8 flags; + __le16 public_key_size; + __le32 public_key[]; +}; + +#define MPI3_SB_MANIFEST_DIAG_KEY_FLAGS_KEYINDEX_MASK (0x03) +#define MPI3_SB_MANIFEST_DIAG_KEY_FLAGS_KEYSELECT_FW_KEY (0x04) +union mpi3_sb_manifest_element_data { + struct mpi3_sb_manifest_ci_ref_element ci_ref; + struct mpi3_sb_manifest_embedded_key_element embed_key; + struct mpi3_sb_manifest_diag_key_element diag_key; + __le32 dword; +}; +struct mpi3_sb_manifest_element { + u8 manifest_element_form; + u8 reserved01[3]; + union mpi3_sb_manifest_element_data form_specific[]; +}; +#define MPI3_SB_MANIFEST_ELEMENT_FORM_CI_REFS (0x01) +#define MPI3_SB_MANIFEST_ELEMENT_FORM_EMBED_KEY (0x02) +#define MPI3_SB_MANIFEST_ELEMENT_FORM_DIAG_KEY (0x03) +struct mpi3_sb_manifest_mpi { + u8 manifest_type; + u8 reserved01[3]; + __le32 reserved04[3]; + u8 reserved10; + u8 release_level; + __le16 reserved12; + __le16 reserved14; + __le16 flags; + __le32 reserved18[2]; + __le16 vendor_id; + __le16 device_id; + __le16 subsystem_vendor_id; + __le16 subsystem_id; + __le32 reserved28[2]; + union mpi3_version_union package_security_version; + __le32 reserved34; + struct mpi3_comp_image_version package_version; + __le32 package_version_string_offset; + __le32 package_build_date_string_offset; + __le32 package_build_time_string_offset; + __le32 component_image_references_offset; + __le32 embedded_key0offset; + __le32 embedded_key1offset; + __le32 diag_authorization_key_offset; + __le32 reserved5c[9]; + struct mpi3_sb_manifest_element manifest_elements[]; +}; + union mpi3_ci_manifest { struct mpi3_ci_manifest_mpi mpi; + struct mpi3_sb_manifest_mpi sb_mpi; __le32 dword[1]; }; -#define MPI3_CI_MANIFEST_TYPE_MPI (0x00) +#define MPI3_SB_MANIFEST_APU_IMMEDIATE_DEFER_APU_ENABLE (0x01) + +#define MPI3_CI_MANIFEST_TYPE_MPI (0x00) +#define MPI3_CI_MANIFEST_TYPE_SB (0x01) + struct mpi3_extended_image_header { u8 image_type; u8 reserved01[3]; diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_init.h b/drivers/scsi/mpi3mr/mpi/mpi30_init.h index bbef5bac92ed..745e1101ebf4 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_init.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_init.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2023 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_INIT_H #define MPI30_INIT_H 1 diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h index b42933fcd423..76dc18684be1 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h @@ -661,6 +661,7 @@ struct mpi3_event_data_diag_buffer_status_change { #define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_RELEASED (0x01) #define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_PAUSED (0x02) #define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_RESUMED (0x03) +#define MPI3_EVENT_DIAG_BUFFER_STATUS_CHANGE_RC_CLEARED (0x04) #define MPI3_PEL_LOCALE_FLAGS_NON_BLOCKING_BOOT_EVENT (0x0200) #define MPI3_PEL_LOCALE_FLAGS_BLOCKING_BOOT_EVENT (0x0100) #define MPI3_PEL_LOCALE_FLAGS_PCIE (0x0080) diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_pci.h b/drivers/scsi/mpi3mr/mpi/mpi30_pci.h index 4eeb11c3c73e..3092dfe6d952 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_pci.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_pci.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2023 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. * */ #ifndef MPI30_PCI_H diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_sas.h b/drivers/scsi/mpi3mr/mpi/mpi30_sas.h index 190b06508b00..f86da445df1e 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_sas.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_sas.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2023 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_SAS_H #define MPI30_SAS_H 1 diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_tool.h b/drivers/scsi/mpi3mr/mpi/mpi30_tool.h index 50a65b16a818..72d3e6bc52ec 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_tool.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_tool.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2024 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_TOOL_H #define MPI30_TOOL_H 1 @@ -8,6 +8,10 @@ #define MPI3_DIAG_BUFFER_TYPE_TRACE (0x01) #define MPI3_DIAG_BUFFER_TYPE_FW (0x02) #define MPI3_DIAG_BUFFER_ACTION_RELEASE (0x01) +#define MPI3_DIAG_BUFFER_ACTION_PAUSE (0x02) +#define MPI3_DIAG_BUFFER_ACTION_RESUME (0x03) +#define MPI3_DIAG_BUFFER_ACTION_CLEAR (0x04) + #define MPI3_DIAG_BUFFER_POST_MSGFLAGS_SEGMENTED (0x01) struct mpi3_diag_buffer_post_request { diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h index 28ab2efb3baa..290a1f5c2924 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_transport.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_transport.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright 2016-2023 Broadcom Inc. All rights reserved. + * Copyright 2016-2026 Broadcom Inc. All rights reserved. */ #ifndef MPI30_TRANSPORT_H #define MPI30_TRANSPORT_H 1 @@ -18,7 +18,7 @@ union mpi3_version_union { #define MPI3_VERSION_MAJOR (3) #define MPI3_VERSION_MINOR (0) -#define MPI3_VERSION_UNIT (37) +#define MPI3_VERSION_UNIT (39) #define MPI3_VERSION_DEV (0) #define MPI3_DEVHANDLE_INVALID (0xffff) struct mpi3_sysif_oper_queue_indexes { diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 31d68c151b20..6e962092577d 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -56,8 +56,8 @@ extern struct list_head mrioc_list; extern int prot_mask; extern atomic64_t event_counter; -#define MPI3MR_DRIVER_VERSION "8.15.0.5.51" -#define MPI3MR_DRIVER_RELDATE "18-November-2025" +#define MPI3MR_DRIVER_VERSION "8.17.0.3.50" +#define MPI3MR_DRIVER_RELDATE "09-January-2026" #define MPI3MR_DRIVER_NAME "mpi3mr" #define MPI3MR_DRIVER_LICENSE "GPL" @@ -643,6 +643,7 @@ struct mpi3mr_enclosure_node { * @dev_info: Device information bits * @phy_id: Phy identifier provided in device page 0 * @attached_phy_id: Attached phy identifier provided in device page 0 + * @negotiated_link_rate: Negotiated link rate from device page 0 * @sas_transport_attached: Is this device exposed to transport * @pend_sas_rphy_add: Flag to check device is in process of add * @hba_port: HBA port entry @@ -654,6 +655,7 @@ struct tgt_dev_sas_sata { u16 dev_info; u8 phy_id; u8 attached_phy_id; + u8 negotiated_link_rate; u8 sas_transport_attached; u8 pend_sas_rphy_add; struct mpi3mr_hba_port *hba_port; @@ -1076,7 +1078,6 @@ struct scmd_priv { * @fwevt_worker_thread: Firmware event worker thread * @fwevt_lock: Firmware event lock * @fwevt_list: Firmware event list - * @watchdog_work_q_name: Fault watchdog worker thread name * @watchdog_work_q: Fault watchdog worker thread * @watchdog_work: Fault watchdog work * @watchdog_lock: Fault watchdog lock @@ -1135,6 +1136,10 @@ struct scmd_priv { * @default_qcount: Total Default queues * @active_poll_qcount: Currently active poll queue count * @requested_poll_qcount: User requested poll queue count + * @fault_during_init: Indicates a firmware fault occurred during initialization + * @saved_fault_code: Firmware fault code captured at the time of failure + * @saved_fault_info: Additional firmware-provided fault information + * @fwfault_counter: Count of firmware faults detected by the driver * @bsg_dev: BSG device structure * @bsg_queue: Request queue for BSG device * @stop_bsgs: Stop BSG request flag @@ -1265,7 +1270,6 @@ struct mpi3mr_ioc { spinlock_t fwevt_lock; struct list_head fwevt_list; - char watchdog_work_q_name[50]; struct workqueue_struct *watchdog_work_q; struct delayed_work watchdog_work; spinlock_t watchdog_lock; @@ -1338,6 +1342,10 @@ struct mpi3mr_ioc { u16 default_qcount; u16 active_poll_qcount; u16 requested_poll_qcount; + u8 fault_during_init; + u32 saved_fault_code; + u32 saved_fault_info[3]; + u64 fwfault_counter; struct device bsg_dev; struct request_queue *bsg_queue; @@ -1508,7 +1516,7 @@ void mpi3mr_pel_get_seqnum_complete(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd); int mpi3mr_pel_get_seqnum_post(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd); -void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data, +void mpi3mr_app_save_logdata_th(struct mpi3mr_ioc *mrioc, char *event_data, u16 event_data_size); struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle( struct mpi3mr_ioc *mrioc, u16 handle); diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c index 0e5478d62580..1353a8ff9c85 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_app.c +++ b/drivers/scsi/mpi3mr/mpi3mr_app.c @@ -2920,7 +2920,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) } /** - * mpi3mr_app_save_logdata - Save Log Data events + * mpi3mr_app_save_logdata_th - Save Log Data events * @mrioc: Adapter instance reference * @event_data: event data associated with log data event * @event_data_size: event data size to copy @@ -2932,7 +2932,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) * * Return:Nothing */ -void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data, +void mpi3mr_app_save_logdata_th(struct mpi3mr_ioc *mrioc, char *event_data, u16 event_data_size) { u32 index = mrioc->logdata_buf_idx, sz; @@ -3255,6 +3255,29 @@ adp_state_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RO(adp_state); +/** + * fwfault_count_show() - SysFS callback to show firmware fault count + * @dev: class device + * @attr: Device attribute + * @buf: Buffer to copy data into + * + * Displays the total number of firmware faults detected by the driver + * since the controller was initialized. + * + * Return: Number of bytes written to @buf + */ + +static ssize_t +fwfault_count_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct mpi3mr_ioc *mrioc = shost_priv(shost); + + return snprintf(buf, PAGE_SIZE, "%llu\n", mrioc->fwfault_counter); +} +static DEVICE_ATTR_RO(fwfault_count); + static struct attribute *mpi3mr_host_attrs[] = { &dev_attr_version_fw.attr, &dev_attr_fw_queue_depth.attr, @@ -3263,6 +3286,7 @@ static struct attribute *mpi3mr_host_attrs[] = { &dev_attr_reply_qfull_count.attr, &dev_attr_logging_level.attr, &dev_attr_adp_state.attr, + &dev_attr_fwfault_count.attr, NULL, }; diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 8fe6e0bf342e..1cfbdb773353 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -21,6 +21,10 @@ static int mpi3mr_check_op_admin_proc(struct mpi3mr_ioc *mrioc); static int poll_queues; module_param(poll_queues, int, 0444); MODULE_PARM_DESC(poll_queues, "Number of queues for io_uring poll mode. (Range 1 - 126)"); +static bool threaded_isr_poll = true; +module_param(threaded_isr_poll, bool, 0444); +MODULE_PARM_DESC(threaded_isr_poll, + "Enablement of IRQ polling thread (default=true)"); #if defined(writeq) && defined(CONFIG_64BIT) static inline void mpi3mr_writeq(__u64 b, void __iomem *addr, @@ -595,7 +599,8 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, * Exit completion loop to avoid CPU lockup * Ensure remaining completion happens from threaded ISR. */ - if (num_op_reply > mrioc->max_host_ios) { + if ((num_op_reply > mrioc->max_host_ios) && + (threaded_isr_poll == true)) { op_reply_q->enable_irq_poll = true; break; } @@ -692,7 +697,7 @@ static irqreturn_t mpi3mr_isr(int irq, void *privdata) * If more IOs are expected, schedule IRQ polling thread. * Otherwise exit from ISR. */ - if (!intr_info->op_reply_q) + if ((threaded_isr_poll == false) || !intr_info->op_reply_q) return ret; if (!intr_info->op_reply_q->enable_irq_poll || @@ -771,8 +776,8 @@ static inline int mpi3mr_request_irq(struct mpi3mr_ioc *mrioc, u16 index) intr_info->msix_index = index; intr_info->op_reply_q = NULL; - snprintf(intr_info->name, MPI3MR_NAME_LENGTH, "%s%d-msix%d", - mrioc->driver_name, mrioc->id, index); + scnprintf(intr_info->name, MPI3MR_NAME_LENGTH, + "%.32s%d-msix%u", mrioc->driver_name, mrioc->id, index); #ifndef CONFIG_PREEMPT_RT retval = request_threaded_irq(pci_irq_vector(pdev, index), mpi3mr_isr, @@ -1103,6 +1108,31 @@ void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc) } } +/** + * mpi3mr_save_fault_info - Save fault information + * @mrioc: Adapter instance reference + * + * Save the controller fault information if there is a + * controller fault. + * + * Return: Nothing. + */ +static void mpi3mr_save_fault_info(struct mpi3mr_ioc *mrioc) +{ + u32 ioc_status, i; + + ioc_status = readl(&mrioc->sysif_regs->ioc_status); + + if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) { + mrioc->saved_fault_code = readl(&mrioc->sysif_regs->fault) & + MPI3_SYSIF_FAULT_CODE_MASK; + for (i = 0; i < 3; i++) { + mrioc->saved_fault_info[i] = + readl(&mrioc->sysif_regs->fault_info[i]); + } + } +} + /** * mpi3mr_get_iocstate - Get IOC State * @mrioc: Adapter instance reference @@ -1244,6 +1274,60 @@ static void mpi3mr_alloc_ioctl_dma_memory(struct mpi3mr_ioc *mrioc) mpi3mr_free_ioctl_dma_memory(mrioc); } +/** + * mpi3mr_fault_uevent_emit - Emit uevent for any controller + * fault + * @mrioc: Pointer to the mpi3mr_ioc structure for the controller instance + * + * This function is invoked when the controller undergoes any + * type of fault. + */ + +static void mpi3mr_fault_uevent_emit(struct mpi3mr_ioc *mrioc) +{ + struct kobj_uevent_env *env; + int ret; + + env = kzalloc(sizeof(*env), GFP_KERNEL); + if (!env) + return; + + ret = add_uevent_var(env, "DRIVER=%s", mrioc->driver_name); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "IOC_ID=%u", mrioc->id); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "FAULT_CODE=0x%08x", + mrioc->saved_fault_code); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "FAULT_INFO0=0x%08x", + mrioc->saved_fault_info[0]); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "FAULT_INFO1=0x%08x", + mrioc->saved_fault_info[1]); + if (ret) + goto out_free; + + ret = add_uevent_var(env, "FAULT_INFO2=0x%08x", + mrioc->saved_fault_info[2]); + if (ret) + goto out_free; + + kobject_uevent_env(&mrioc->shost->shost_gendev.kobj, + KOBJ_CHANGE, env->envp); + +out_free: + kfree(env); + +} + /** * mpi3mr_clear_reset_history - clear reset history * @mrioc: Adapter instance reference @@ -1475,6 +1559,10 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) if (ioc_state == MRIOC_STATE_FAULT) { timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; mpi3mr_print_fault_info(mrioc); + mpi3mr_save_fault_info(mrioc); + mrioc->fault_during_init = 1; + mrioc->fwfault_counter++; + do { host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); @@ -1701,7 +1789,9 @@ static int mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, scratch_pad0 = ((MPI3MR_RESET_REASON_OSTYPE_LINUX << MPI3MR_RESET_REASON_OSTYPE_SHIFT) | (mrioc->facts.ioc_num << MPI3MR_RESET_REASON_IOCNUM_SHIFT) | reset_reason); - writel(reset_reason, &mrioc->sysif_regs->scratchpad[0]); + writel(scratch_pad0, &mrioc->sysif_regs->scratchpad[0]); + if (reset_type == MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT) + mpi3mr_set_diagsave(mrioc); writel(host_diagnostic | reset_type, &mrioc->sysif_regs->host_diagnostic); switch (reset_type) { @@ -2570,6 +2660,9 @@ void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code) mpi3mr_set_trigger_data_in_all_hdb(mrioc, MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0); mpi3mr_print_fault_info(mrioc); + mpi3mr_save_fault_info(mrioc); + mrioc->fault_during_init = 1; + mrioc->fwfault_counter++; return; } @@ -2587,6 +2680,10 @@ void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code) break; msleep(100); } while (--timeout); + + mpi3mr_save_fault_info(mrioc); + mrioc->fault_during_init = 1; + mrioc->fwfault_counter++; } /** @@ -2763,6 +2860,11 @@ static void mpi3mr_watchdog_work(struct work_struct *work) union mpi3mr_trigger_data trigger_data; u16 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH; + if (mrioc->fault_during_init) { + mpi3mr_fault_uevent_emit(mrioc); + mrioc->fault_during_init = 0; + } + if (mrioc->reset_in_progress || mrioc->pci_err_recovery) return; @@ -2835,6 +2937,10 @@ static void mpi3mr_watchdog_work(struct work_struct *work) goto schedule_work; } + mpi3mr_save_fault_info(mrioc); + mpi3mr_fault_uevent_emit(mrioc); + mrioc->fwfault_counter++; + switch (trigger_data.fault) { case MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED: case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED: @@ -2878,11 +2984,8 @@ void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc) return; INIT_DELAYED_WORK(&mrioc->watchdog_work, mpi3mr_watchdog_work); - snprintf(mrioc->watchdog_work_q_name, - sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name, - mrioc->id); mrioc->watchdog_work_q = alloc_ordered_workqueue( - "%s", WQ_MEM_RECLAIM, mrioc->watchdog_work_q_name); + "watchdog_%s%d", WQ_MEM_RECLAIM, mrioc->name, mrioc->id); if (!mrioc->watchdog_work_q) { ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__); return; @@ -5399,6 +5502,7 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, { int retval = 0, i; unsigned long flags; + enum mpi3mr_iocstate ioc_state; u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; union mpi3mr_trigger_data trigger_data; @@ -5457,7 +5561,6 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, mrioc->io_admin_reset_sync = 1; if (snapdump) { - mpi3mr_set_diagsave(mrioc); retval = mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); if (!retval) { @@ -5471,6 +5574,10 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, break; msleep(100); } while (--timeout); + + mpi3mr_save_fault_info(mrioc); + mpi3mr_fault_uevent_emit(mrioc); + mrioc->fwfault_counter++; mpi3mr_set_trigger_data_in_all_hdb(mrioc, MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0); } @@ -5559,8 +5666,13 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc, if (mrioc->pel_enabled) atomic64_inc(&event_counter); } else { - mpi3mr_issue_reset(mrioc, - MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); + dprint_reset(mrioc, + "soft_reset_handler failed, marking controller as unrecoverable\n"); + ioc_state = mpi3mr_get_iocstate(mrioc); + + if (ioc_state != MRIOC_STATE_FAULT) + mpi3mr_issue_reset(mrioc, + MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); mrioc->device_refresh_on = 0; mrioc->unrecoverable = 1; mrioc->reset_in_progress = 0; diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index d4ca878d0886..e697ae6b7871 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -1138,6 +1138,89 @@ static void mpi3mr_refresh_tgtdevs(struct mpi3mr_ioc *mrioc) } } +/** + * mpi3mr_debug_dump_devpg0 - Dump device page0 + * @mrioc: Adapter instance reference + * @dev_pg0: Device page 0. + * + * Prints pertinent details of the device page 0. + * + * Return: Nothing. + */ +static void +mpi3mr_debug_dump_devpg0(struct mpi3mr_ioc *mrioc, struct mpi3_device_page0 *dev_pg0) +{ + ioc_info(mrioc, + "device_pg0: handle(0x%04x), perst_id(%d), wwid(0x%016llx), encl_handle(0x%04x), slot(%d)\n", + le16_to_cpu(dev_pg0->dev_handle), + le16_to_cpu(dev_pg0->persistent_id), + le64_to_cpu(dev_pg0->wwid), le16_to_cpu(dev_pg0->enclosure_handle), + le16_to_cpu(dev_pg0->slot)); + ioc_info(mrioc, "device_pg0: access_status(0x%02x), flags(0x%04x), device_form(0x%02x), queue_depth(%d)\n", + dev_pg0->access_status, le16_to_cpu(dev_pg0->flags), + dev_pg0->device_form, le16_to_cpu(dev_pg0->queue_depth)); + ioc_info(mrioc, "device_pg0: parent_handle(0x%04x), iounit_port(%d)\n", + le16_to_cpu(dev_pg0->parent_dev_handle), dev_pg0->io_unit_port); + + switch (dev_pg0->device_form) { + case MPI3_DEVICE_DEVFORM_SAS_SATA: + { + + struct mpi3_device0_sas_sata_format *sasinf = + &dev_pg0->device_specific.sas_sata_format; + ioc_info(mrioc, + "device_pg0: sas_sata: sas_address(0x%016llx),flags(0x%04x),\n" + "device_info(0x%04x), phy_num(%d), attached_phy_id(%d),negotiated_link_rate(0x%02x)\n", + le64_to_cpu(sasinf->sas_address), + le16_to_cpu(sasinf->flags), + le16_to_cpu(sasinf->device_info), sasinf->phy_num, + sasinf->attached_phy_identifier, sasinf->negotiated_link_rate); + break; + } + case MPI3_DEVICE_DEVFORM_PCIE: + { + + struct mpi3_device0_pcie_format *pcieinf = + &dev_pg0->device_specific.pcie_format; + ioc_info(mrioc, + "device_pg0: pcie: port_num(%d), device_info(0x%04x), mdts(%d), page_sz(0x%02x)\n", + pcieinf->port_num, le16_to_cpu(pcieinf->device_info), + le32_to_cpu(pcieinf->maximum_data_transfer_size), + pcieinf->page_size); + ioc_info(mrioc, + "device_pg0: pcie: abort_timeout(%d), reset_timeout(%d) capabilities (0x%08x)\n", + pcieinf->nvme_abort_to, pcieinf->controller_reset_to, + le32_to_cpu(pcieinf->capabilities)); + break; + } + case MPI3_DEVICE_DEVFORM_VD: + { + + struct mpi3_device0_vd_format *vdinf = + &dev_pg0->device_specific.vd_format; + + ioc_info(mrioc, + "device_pg0: vd: state(0x%02x), raid_level(%d), flags(0x%04x),\n" + "device_info(0x%04x) abort_timeout(%d), reset_timeout(%d)\n", + vdinf->vd_state, vdinf->raid_level, + le16_to_cpu(vdinf->flags), + le16_to_cpu(vdinf->device_info), + vdinf->vd_abort_to, vdinf->vd_reset_to); + ioc_info(mrioc, + "device_pg0: vd: tg_id(%d), high(%dMiB), low(%dMiB), qd_reduction_factor(%d)\n", + vdinf->io_throttle_group, + le16_to_cpu(vdinf->io_throttle_group_high), + le16_to_cpu(vdinf->io_throttle_group_low), + ((le16_to_cpu(vdinf->flags) & + MPI3_DEVICE0_VD_FLAGS_IO_THROTTLE_GROUP_QD_MASK) >> 12)); + break; + + } + default: + break; + } +} + /** * mpi3mr_update_tgtdev - DevStatusChange evt bottomhalf * @mrioc: Adapter instance reference @@ -1159,6 +1242,10 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, struct mpi3mr_enclosure_node *enclosure_dev = NULL; u8 prot_mask = 0; + if (mrioc->logging_level & + (MPI3_DEBUG_EVENT | MPI3_DEBUG_EVENT_WORK_TASK)) + mpi3mr_debug_dump_devpg0(mrioc, dev_pg0); + tgtdev->perst_id = le16_to_cpu(dev_pg0->persistent_id); tgtdev->dev_handle = le16_to_cpu(dev_pg0->dev_handle); tgtdev->dev_type = dev_pg0->device_form; @@ -1237,6 +1324,8 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc, tgtdev->dev_spec.sas_sata_inf.phy_id = sasinf->phy_num; tgtdev->dev_spec.sas_sata_inf.attached_phy_id = sasinf->attached_phy_identifier; + tgtdev->dev_spec.sas_sata_inf.negotiated_link_rate = + sasinf->negotiated_link_rate; if ((dev_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) != MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE) tgtdev->is_hidden = 1; @@ -1962,7 +2051,7 @@ static void mpi3mr_pcietopochg_evt_bh(struct mpi3mr_ioc *mrioc, static void mpi3mr_logdata_evt_bh(struct mpi3mr_ioc *mrioc, struct mpi3mr_fwevt *fwevt) { - mpi3mr_app_save_logdata(mrioc, fwevt->event_data, + mpi3mr_app_save_logdata_th(mrioc, fwevt->event_data, fwevt->event_data_size); } @@ -3058,6 +3147,11 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc, } case MPI3_EVENT_DEVICE_INFO_CHANGED: case MPI3_EVENT_LOG_DATA: + + sz = event_reply->event_data_length * 4; + mpi3mr_app_save_logdata_th(mrioc, + (char *)event_reply->event_data, sz); + break; case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE: case MPI3_EVENT_ENCL_DEVICE_ADDED: { @@ -5029,8 +5123,8 @@ inline bool mpi3mr_allow_scmd_to_fw(struct scsi_cmnd *scmd) * SCSI_MLQUEUE_DEVICE_BUSY when the device is busy. * SCSI_MLQUEUE_HOST_BUSY when the host queue is full. */ -static int mpi3mr_qcmd(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status mpi3mr_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct mpi3mr_ioc *mrioc = shost_priv(shost); struct mpi3mr_stgt_priv_data *stgt_priv_data; @@ -5381,8 +5475,10 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (retval < 0) goto id_alloc_failed; mrioc->id = (u8)retval; - sprintf(mrioc->driver_name, "%s", MPI3MR_DRIVER_NAME); - sprintf(mrioc->name, "%s%d", mrioc->driver_name, mrioc->id); + strscpy(mrioc->driver_name, MPI3MR_DRIVER_NAME, + sizeof(mrioc->driver_name)); + scnprintf(mrioc->name, sizeof(mrioc->name), + "%s%u", mrioc->driver_name, mrioc->id); INIT_LIST_HEAD(&mrioc->list); spin_lock(&mrioc_list_lock); list_add_tail(&mrioc->list, &mrioc_list); diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c index d70f002d6487..101161554ef1 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c @@ -2284,11 +2284,11 @@ void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address, * @mrioc: Adapter instance reference * @tgtdev: Target device * - * This function identifies whether the target device is - * attached directly or through expander and issues sas phy - * page0 or expander phy page1 and gets the link rate, if there - * is any failure in reading the pages then this returns link - * rate of 1.5. + * This function first tries to use the link rate from DevicePage0 + * (populated by firmware during device discovery). If the cached + * value is not available or invalid, it falls back to reading from + * sas phy page0 or expander phy page1. + * * * Return: logical link rate. */ @@ -2301,6 +2301,14 @@ static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc, u32 phynum_handle; u16 ioc_status; + /* First, try to use link rate from DevicePage0 (populated by firmware) */ + if (tgtdev->dev_spec.sas_sata_inf.negotiated_link_rate >= + MPI3_SAS_NEG_LINK_RATE_1_5) { + link_rate = tgtdev->dev_spec.sas_sata_inf.negotiated_link_rate; + goto out; + } + + /* Fallback to reading from phy pages if DevicePage0 value not available */ phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id; if (!(tgtdev->devpg0_flag & MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)) { phynum_handle = ((phy_number<> - MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT; + link_rate = expander_pg1.negotiated_link_rate; goto out; } if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0, @@ -2335,11 +2341,11 @@ static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc, __FILE__, __LINE__, __func__); goto out; } - link_rate = (phy_pg0.negotiated_link_rate & - MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >> - MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT; + link_rate = phy_pg0.negotiated_link_rate; + out: - return link_rate; + return ((link_rate & MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >> + MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT); } /** diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 0d652db8fe24..2f2183f405c9 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -843,11 +843,8 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc) /* initialize fault polling */ INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); - snprintf(ioc->fault_reset_work_q_name, - sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status", - ioc->driver_name, ioc->id); ioc->fault_reset_work_q = alloc_ordered_workqueue( - "%s", WQ_MEM_RECLAIM, ioc->fault_reset_work_q_name); + "poll_%s%d_status", WQ_MEM_RECLAIM, ioc->driver_name, ioc->id); if (!ioc->fault_reset_work_q) { ioc_err(ioc, "%s: failed (line=%d)\n", __func__, __LINE__); return; @@ -1564,6 +1561,8 @@ _base_get_cb_idx(struct MPT3SAS_ADAPTER *ioc, u16 smid) int i; u16 ctl_smid = ioc->scsiio_depth - INTERNAL_SCSIIO_CMDS_COUNT + 1; u8 cb_idx = 0xFF; + u16 discovery_smid = + ioc->shost->can_queue + INTERNAL_SCSIIO_FOR_DISCOVERY; if (smid < ioc->hi_priority_smid) { struct scsiio_tracker *st; @@ -1572,8 +1571,10 @@ _base_get_cb_idx(struct MPT3SAS_ADAPTER *ioc, u16 smid) st = _get_st_from_smid(ioc, smid); if (st) cb_idx = st->cb_idx; - } else if (smid == ctl_smid) + } else if (smid < discovery_smid) cb_idx = ioc->ctl_cb_idx; + else + cb_idx = ioc->scsih_cb_idx; } else if (smid < ioc->internal_smid) { i = smid - ioc->hi_priority_smid; cb_idx = ioc->hpr_lookup[i].cb_idx; @@ -3174,7 +3175,7 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index) if (index >= ioc->iopoll_q_start_index) { qid = index - ioc->iopoll_q_start_index; - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-mq-poll%d", + scnprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-mq-poll%d", ioc->driver_name, ioc->id, qid); reply_q->is_iouring_poll_q = 1; ioc->io_uring_poll_queues[qid].reply_q = reply_q; @@ -3183,10 +3184,10 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index) if (ioc->msix_enable) - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", + scnprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", ioc->driver_name, ioc->id, index); else - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", + scnprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", ioc->driver_name, ioc->id); r = request_irq(pci_irq_vector(pdev, index), _base_interrupt, IRQF_SHARED, reply_q->name, reply_q); diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index e6a6f21d309b..d4597d058705 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -147,6 +147,7 @@ #define INTERNAL_CMDS_COUNT 10 /* reserved cmds */ /* reserved for issuing internally framed scsi io cmds */ #define INTERNAL_SCSIIO_CMDS_COUNT 3 +#define INTERNAL_SCSIIO_FOR_DISCOVERY 2 #define MPI3_HIM_MASK 0xFFFFFFFF /* mask every bit*/ @@ -480,6 +481,7 @@ struct MPT3SAS_DEVICE { u32 flags; u8 configured_lun; u8 block; + u8 deleted; u8 tlr_snoop_check; u8 ignore_delay_remove; /* Iopriority Command Handling */ @@ -577,7 +579,9 @@ struct _sas_device { u8 chassis_slot; u8 is_chassis_slot_valid; u8 connector_name[5]; + u8 ssd_device; struct kref refcount; + u8 port_type; struct hba_port *port; struct sas_rphy *rphy; @@ -1159,9 +1163,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @mask_interrupts: ignore interrupt * @pci_access_mutex: Mutex to synchronize ioctl, sysfs show path and * pci resource handling - * @fault_reset_work_q_name: fw fault work queue - * @fault_reset_work_q: "" - * @fault_reset_work: "" + * @fault_reset_work_q: fw fault workqueue + * @fault_reset_work: fw fault work * @firmware_event_thread: fw event work queue * @fw_event_lock: * @fw_event_list: list of fw events @@ -1345,7 +1348,6 @@ struct MPT3SAS_ADAPTER { u8 mask_interrupts; /* fw fault handler */ - char fault_reset_work_q_name[20]; struct workqueue_struct *fault_reset_work_q; struct delayed_work fault_reset_work; diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 7092d0debef3..26a13b622c95 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -61,6 +61,8 @@ #define PCIE_CHANNEL 2 +#define MPT3_MAX_LUNS (255) + /* forward proto's */ static void _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_expander); @@ -70,13 +72,24 @@ static void _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, struct _sas_device *sas_device); static int _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 retry_count, u8 is_pd); -static int _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle); +static int _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count); static void _scsih_pcie_device_remove_from_sml(struct MPT3SAS_ADAPTER *ioc, struct _pcie_device *pcie_device); static void _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle); static u8 _scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid); static void _scsih_complete_devices_scanning(struct MPT3SAS_ADAPTER *ioc); +static enum device_responsive_state +_scsih_wait_for_target_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count, u8 is_pd, u8 tr_timeout, u8 tr_method); +static enum device_responsive_state +_scsih_ata_pass_thru_idd(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 *is_ssd_device, + u8 tr_timeout, u8 tr_method); +static enum device_responsive_state +_scsih_wait_for_device_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count, u8 is_pd, int lun, u8 tr_timeout, u8 tr_method); +static void _firmware_event_work_delayed(struct work_struct *work); /* global parameters */ LIST_HEAD(mpt3sas_ioc_list); @@ -159,6 +172,15 @@ 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)"); +/* + * permit overriding the SCSI command issuing capability of + * the driver to bring the drive to READY state + */ +static int issue_scsi_cmd_to_bringup_drive = 1; +module_param(issue_scsi_cmd_to_bringup_drive, int, 0444); +MODULE_PARM_DESC(issue_scsi_cmd_to_bringup_drive, "allow host driver to\n" + "issue SCSI commands to bring the drive to READY state, default=1 "); + static int multipath_on_hba = -1; module_param(multipath_on_hba, int, 0); MODULE_PARM_DESC(multipath_on_hba, @@ -173,10 +195,33 @@ module_param(host_tagset_enable, int, 0444); MODULE_PARM_DESC(host_tagset_enable, "Shared host tagset enable/disable Default: enable(1)"); +static int command_retry_count = 144; +module_param(command_retry_count, int, 0444); +MODULE_PARM_DESC(command_retry_count, "Device discovery TUR command retry\n" + "count: (default=144)"); + /* raid transport support */ static struct raid_template *mpt3sas_raid_template; static struct raid_template *mpt2sas_raid_template; +/** + * enum device_responsive_state - responsive state + * @DEVICE_READY: device is ready to be added + * @DEVICE_RETRY: device can be retried later + * @DEVICE_RETRY_UA: retry unit attentions + * @DEVICE_START_UNIT: requires start unit + * @DEVICE_STOP_UNIT: requires stop unit + * @DEVICE_ERROR: device reported some fatal error + * + */ +enum device_responsive_state { + DEVICE_READY, + DEVICE_RETRY, + DEVICE_RETRY_UA, + DEVICE_START_UNIT, + DEVICE_STOP_UNIT, + DEVICE_ERROR, +}; /** * struct sense_info - common structure for obtaining sense keys @@ -205,6 +250,9 @@ struct sense_info { /** * struct fw_event_work - firmware event struct + * @retries: retry count for processing the event + * @delayed_work_active: flag indicating if delayed work is active + * @delayed_work: delayed work item for deferred event handling * @list: link list framework * @work: work object (ioc->fault_reset_work_q) * @ioc: per adapter object @@ -219,6 +267,9 @@ struct sense_info { * This object stored on ioc->fw_event_list. */ struct fw_event_work { + u8 *retries; + u8 delayed_work_active; + struct delayed_work delayed_work; struct list_head list; struct work_struct work; @@ -230,11 +281,16 @@ struct fw_event_work { u16 event; struct kref refcount; char event_data[] __aligned(4); + }; static void fw_event_work_free(struct kref *r) { - kfree(container_of(r, struct fw_event_work, refcount)); + struct fw_event_work *fw_work; + + fw_work = container_of(r, struct fw_event_work, refcount); + kfree(fw_work->retries); + kfree(fw_work); } static void fw_event_work_get(struct fw_event_work *fw_work) @@ -955,6 +1011,7 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, sas_device_put(sas_device); } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + } /** @@ -2528,6 +2585,8 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) char *r_level = ""; u16 handle, volume_handle = 0; u64 volume_wwid = 0; + enum device_responsive_state retval; + u8 count = 0; qdepth = 1; sas_device_priv_data = sdev->hostdata; @@ -2686,6 +2745,7 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) pcie_device_put(pcie_device); spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); + mpt3sas_scsih_change_queue_depth(sdev, qdepth); lim->virt_boundary_mask = ioc->page_size - 1; return 0; @@ -2737,9 +2797,16 @@ scsih_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) sas_device_put(sas_device); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!ssp_target) + if (!ssp_target) { _scsih_display_sata_capabilities(ioc, handle, sdev); + do { + retval = _scsih_ata_pass_thru_idd(ioc, handle, + &sas_device->ssd_device, 30, 0); + } while ((retval == DEVICE_RETRY || retval == DEVICE_RETRY_UA) + && count++ < 3); + } + mpt3sas_scsih_change_queue_depth(sdev, qdepth); @@ -3595,6 +3662,37 @@ _scsih_fw_event_del_from_list(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } +/** + * _scsih_fw_event_requeue - requeue an event + * @ioc: per adapter object + * @fw_event: object describing the event + * @delay: time in milliseconds to wait before retrying the event + * + * Context: This function will acquire ioc->fw_event_lock. + * + * Return nothing. + */ +static void +_scsih_fw_event_requeue(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work + *fw_event, unsigned long delay) +{ + unsigned long flags; + + if (ioc->firmware_event_thread == NULL) + return; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + fw_event_work_get(fw_event); + list_add_tail(&fw_event->list, &ioc->fw_event_list); + if (!fw_event->delayed_work_active) { + fw_event->delayed_work_active = 1; + INIT_DELAYED_WORK(&fw_event->delayed_work, + _firmware_event_work_delayed); + } + queue_delayed_work(ioc->firmware_event_thread, &fw_event->delayed_work, + msecs_to_jiffies(delay)); + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); +} /** * mpt3sas_send_trigger_data_event - send event for processing trigger data @@ -3825,29 +3923,235 @@ _scsih_internal_device_unblock(struct scsi_device *sdev, /** * _scsih_ublock_io_all_device - unblock every device * @ioc: per adapter object + * @no_turs: flag to disable TEST UNIT READY checks during device unblocking * * change the device state from block to running */ static void -_scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc) +_scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc, u8 no_turs) { struct MPT3SAS_DEVICE *sas_device_priv_data; struct scsi_device *sdev; + struct MPT3SAS_TARGET *sas_target; + enum device_responsive_state rc; + struct _sas_device *sas_device = NULL; + struct _pcie_device *pcie_device = NULL; + int count = 0; + u8 tr_method = 0; + u8 tr_timeout = 30; + shost_for_each_device(sdev, ioc->shost) { sas_device_priv_data = sdev->hostdata; if (!sas_device_priv_data) continue; + + sas_target = sas_device_priv_data->sas_target; + if (!sas_target || sas_target->deleted) + continue; + if (!sas_device_priv_data->block) continue; - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, - "device_running, handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle)); + if ((no_turs) || (!issue_scsi_cmd_to_bringup_drive)) { + sdev_printk(KERN_WARNING, sdev, "device_unblocked handle(0x%04x)\n", + sas_device_priv_data->sas_target->handle); + _scsih_internal_device_unblock(sdev, sas_device_priv_data); + continue; + } + + do { + pcie_device = mpt3sas_get_pdev_by_handle(ioc, sas_target->handle); + 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; + } + rc = _scsih_wait_for_device_to_become_ready(ioc, + sas_target->handle, 0, (sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT), sdev->lun, tr_timeout, tr_method); + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + ssleep(1); + if (pcie_device) + pcie_device_put(pcie_device); + } while ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + && count++ < command_retry_count); + sas_device_priv_data->block = 0; + if (rc != DEVICE_READY) + sas_device_priv_data->deleted = 1; + _scsih_internal_device_unblock(sdev, sas_device_priv_data); + + if (rc != DEVICE_READY) { + sdev_printk(KERN_WARNING, sdev, "%s: device_offlined,\n" + "handle(0x%04x)\n", + __func__, sas_device_priv_data->sas_target->handle); + scsi_device_set_state(sdev, SDEV_OFFLINE); + sas_device = mpt3sas_get_sdev_by_addr(ioc, + sas_device_priv_data->sas_target->sas_address, + sas_device_priv_data->sas_target->port); + if (sas_device) { + _scsih_display_enclosure_chassis_info(NULL, sas_device, sdev, NULL); + sas_device_put(sas_device); + } else { + pcie_device = mpt3sas_get_pdev_by_wwid(ioc, + sas_device_priv_data->sas_target->sas_address); + if (pcie_device) { + if (pcie_device->enclosure_handle != 0) + sdev_printk(KERN_INFO, sdev, "enclosure logical id\n" + "(0x%016llx), slot(%d)\n", (unsigned long long) + pcie_device->enclosure_logical_id, + pcie_device->slot); + if (pcie_device->connector_name[0] != '\0') + sdev_printk(KERN_INFO, sdev, "enclosure level(0x%04x),\n" + " connector name( %s)\n", + pcie_device->enclosure_level, + pcie_device->connector_name); + pcie_device_put(pcie_device); + } + } + } else + sdev_printk(KERN_WARNING, sdev, "device_unblocked,\n" + "handle(0x%04x)\n", + sas_device_priv_data->sas_target->handle); } } +/** + * _scsih_ublock_io_device_wait - unblock IO for target + * @ioc: per adapter object + * @sas_address: sas address + * @port: hba port entry + * + * make sure device is reponsponding before unblocking + */ +static void +_scsih_ublock_io_device_wait(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, + struct hba_port *port) +{ + struct MPT3SAS_DEVICE *sas_device_priv_data; + struct MPT3SAS_TARGET *sas_target; + enum device_responsive_state rc; + struct scsi_device *sdev; + int host_reset_completion_count; + struct _sas_device *sas_device; + struct _pcie_device *pcie_device; + u8 tr_timeout = 30; + u8 tr_method = 0; + int count = 0; + + /* moving devices from SDEV_OFFLINE to SDEV_BLOCK */ + shost_for_each_device(sdev, ioc->shost) { + sas_device_priv_data = sdev->hostdata; + if (!sas_device_priv_data) + continue; + sas_target = sas_device_priv_data->sas_target; + if (!sas_target) + continue; + if (sas_target->sas_address != sas_address || + sas_target->port != port) + continue; + if (sdev->sdev_state == SDEV_OFFLINE) { + sas_device_priv_data->block = 1; + sas_device_priv_data->deleted = 0; + scsi_device_set_state(sdev, SDEV_RUNNING); + scsi_internal_device_block_nowait(sdev); + } + } + + /* moving devices from SDEV_BLOCK to SDEV_RUNNING state */ + shost_for_each_device(sdev, ioc->shost) { + sas_device_priv_data = sdev->hostdata; + if (!sas_device_priv_data) + continue; + sas_target = sas_device_priv_data->sas_target; + if (!sas_target) + continue; + if (sas_target->sas_address != sas_address || + sas_target->port != port) + continue; + if (!sas_device_priv_data->block) + continue; + + do { + host_reset_completion_count = 0; + pcie_device = mpt3sas_get_pdev_by_handle(ioc, sas_target->handle); + 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; + } + rc = _scsih_wait_for_device_to_become_ready(ioc, + sas_target->handle, 0, (sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT), sdev->lun, tr_timeout, tr_method); + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) { + do { + msleep(500); + host_reset_completion_count++; + } while (rc == DEVICE_RETRY && + ioc->shost_recovery); + if (host_reset_completion_count > 1) { + rc = _scsih_wait_for_device_to_become_ready(ioc, + sas_target->handle, 0, (sas_target->flags & + MPT_TARGET_FLAGS_RAID_COMPONENT), sdev->lun, + tr_timeout, tr_method); + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + msleep(500); + } + continue; + } + if (pcie_device) + pcie_device_put(pcie_device); + } while ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + && count++ <= command_retry_count); + + sas_device_priv_data->block = 0; + if (rc != DEVICE_READY) + sas_device_priv_data->deleted = 1; + scsi_internal_device_unblock_nowait(sdev, SDEV_RUNNING); + + if (rc != DEVICE_READY) { + sdev_printk(KERN_WARNING, sdev, + "%s: device_offlined, handle(0x%04x)\n", + __func__, sas_device_priv_data->sas_target->handle); + + sas_device = mpt3sas_get_sdev_by_handle(ioc, + sas_device_priv_data->sas_target->handle); + if (sas_device) { + _scsih_display_enclosure_chassis_info(NULL, sas_device, sdev, NULL); + sas_device_put(sas_device); + } else { + pcie_device = mpt3sas_get_pdev_by_handle(ioc, + sas_device_priv_data->sas_target->handle); + if (pcie_device) { + if (pcie_device->enclosure_handle != 0) + sdev_printk(KERN_INFO, sdev, + "device_offlined, enclosure logical id(0x%016llx),\n" + " slot(%d)\n", (unsigned long long) + pcie_device->enclosure_logical_id, + pcie_device->slot); + if (pcie_device->connector_name[0] != '\0') + sdev_printk(KERN_WARNING, sdev, + "device_offlined, enclosure level(0x%04x),\n" + "connector name( %s)\n", + pcie_device->enclosure_level, + pcie_device->connector_name); + pcie_device_put(pcie_device); + } + } + scsi_device_set_state(sdev, SDEV_OFFLINE); + } else { + sdev_printk(KERN_WARNING, sdev, + "device_unblocked, handle(0x%04x)\n", + sas_device_priv_data->sas_target->handle); + } + } +} /** * _scsih_ublock_io_device - prepare device to be deleted @@ -5118,8 +5422,8 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full */ -static int -scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) +static enum scsi_qc_status scsih_qcmd(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); struct MPT3SAS_DEVICE *sas_device_priv_data; @@ -7108,90 +7412,849 @@ _scsih_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) return 1; } - - - -#define MPT3_MAX_LUNS (255) - - /** - * _scsih_check_access_status - check access flags + * _scsi_send_scsi_io - send internal SCSI_IO to target * @ioc: per adapter object - * @sas_address: sas address - * @handle: sas device handle - * @access_status: errors returned during discovery of the device + * @transfer_packet: packet describing the transfer + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * Context: user * - * Return: 0 for success, else failure + * Returns 0 for success, non-zero for failure. */ -static u8 -_scsih_check_access_status(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, - u16 handle, u8 access_status) +static int +_scsi_send_scsi_io(struct MPT3SAS_ADAPTER *ioc, struct _scsi_io_transfer + *transfer_packet, u8 tr_timeout, u8 tr_method) { - u8 rc = 1; - char *desc = NULL; + Mpi2SCSIIOReply_t *mpi_reply; + Mpi2SCSIIORequest_t *mpi_request; + u16 smid; + u8 issue_reset = 0; + int rc; + void *priv_sense; + u32 mpi_control; + void *psge; + dma_addr_t data_out_dma = 0; + dma_addr_t data_in_dma = 0; + size_t data_in_sz = 0; + size_t data_out_sz = 0; + u16 handle; + u8 retry_count = 0, host_reset_count = 0; + int tm_return_code; - switch (access_status) { - case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS: - case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION: - rc = 0; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED: - desc = "sata capability failed"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT: - desc = "sata affiliation conflict"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE: - desc = "route not addressable"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE: - desc = "smp error not addressable"; + if (ioc->pci_error_recovery) { + pr_info("%s: pci error recovery in progress!\n", __func__); + return -EFAULT; + } + + if (ioc->shost_recovery) { + pr_info("%s: host recovery in progress!\n", __func__); + return -EAGAIN; + } + + handle = transfer_packet->handle; + if (handle == MPT3SAS_INVALID_DEVICE_HANDLE) { + pr_info("%s: no device!\n", __func__); + return -EFAULT; + } + + mutex_lock(&ioc->scsih_cmds.mutex); + + if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) { + pr_err("%s: scsih_cmd in use\n", __func__); + rc = -EAGAIN; + goto out; + } + + retry_loop: + if (test_bit(handle, ioc->device_remove_in_progress)) { + pr_info("%s: device removal in progress\n", __func__); + rc = -EFAULT; + goto out; + } + + ioc->scsih_cmds.status = MPT3_CMD_PENDING; + + rc = mpt3sas_wait_for_ioc(ioc, 10); + if (rc) + goto out; + + /* Use second reserved smid for discovery related IOs */ + smid = ioc->shost->can_queue + INTERNAL_SCSIIO_FOR_DISCOVERY; + + rc = 0; + mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); + ioc->scsih_cmds.smid = smid; + memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t)); + if (transfer_packet->is_raid) + mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; + else + mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; + mpi_request->DevHandle = cpu_to_le16(handle); + + switch (transfer_packet->dir) { + case DMA_TO_DEVICE: + mpi_control = MPI2_SCSIIO_CONTROL_WRITE; + data_out_dma = transfer_packet->data_dma; + data_out_sz = transfer_packet->data_length; break; - case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED: - desc = "device blocked"; + case DMA_FROM_DEVICE: + mpi_control = MPI2_SCSIIO_CONTROL_READ; + data_in_dma = transfer_packet->data_dma; + data_in_sz = transfer_packet->data_length; break; - case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX: - desc = "sata initialization failed"; + case DMA_BIDIRECTIONAL: + mpi_control = MPI2_SCSIIO_CONTROL_BIDIRECTIONAL; + /* TODO - is BIDI support needed ?? */ + WARN_ON_ONCE(true); break; default: - desc = "unknown"; + case DMA_NONE: + mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; break; } - if (!rc) - return 0; + psge = &mpi_request->SGL; + ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma, + data_in_sz); - ioc_err(ioc, "discovery errors(%s): sas_address(0x%016llx), handle(0x%04x)\n", - desc, (u64)sas_address, handle); + mpi_request->Control = cpu_to_le32(mpi_control | + MPI2_SCSIIO_CONTROL_SIMPLEQ); + mpi_request->DataLength = cpu_to_le32(transfer_packet->data_length); + mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR; + mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; + mpi_request->SenseBufferLowAddress = + mpt3sas_base_get_sense_buffer_dma(ioc, smid); + priv_sense = mpt3sas_base_get_sense_buffer(ioc, smid); + mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4; + mpi_request->IoFlags = cpu_to_le16(transfer_packet->cdb_length); + int_to_scsilun(transfer_packet->lun, (struct scsi_lun *) + mpi_request->LUN); + memcpy(mpi_request->CDB.CDB32, transfer_packet->cdb, + transfer_packet->cdb_length); + init_completion(&ioc->scsih_cmds.done); + if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) + ioc->put_smid_scsi_io(ioc, smid, handle); + else + ioc->put_smid_default(ioc, smid); + wait_for_completion_timeout(&ioc->scsih_cmds.done, + transfer_packet->timeout*HZ); + if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) { + mpt3sas_check_cmd_timeout(ioc, + ioc->scsih_cmds.status, mpi_request, + sizeof(Mpi2SCSIIORequest_t)/4, issue_reset); + goto issue_target_reset; + } + if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) { + transfer_packet->valid_reply = 1; + mpi_reply = ioc->scsih_cmds.reply; + transfer_packet->sense_length = + le32_to_cpu(mpi_reply->SenseCount); + if (transfer_packet->sense_length) + memcpy(transfer_packet->sense, priv_sense, + transfer_packet->sense_length); + transfer_packet->transfer_length = + le32_to_cpu(mpi_reply->TransferCount); + transfer_packet->ioc_status = + le16_to_cpu(mpi_reply->IOCStatus) & + MPI2_IOCSTATUS_MASK; + transfer_packet->scsi_state = mpi_reply->SCSIState; + transfer_packet->scsi_status = mpi_reply->SCSIStatus; + transfer_packet->log_info = + le32_to_cpu(mpi_reply->IOCLogInfo); + } + goto out; + + issue_target_reset: + if (issue_reset) { + pr_info("issue target reset: handle (0x%04x)\n", handle); + tm_return_code = + mpt3sas_scsih_issue_locked_tm(ioc, handle, + 0xFFFFFFFF, 0xFFFFFFFF, 0, + MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, smid, 0, + tr_timeout, tr_method); + + if (tm_return_code == SUCCESS) { + pr_info("target reset completed: handle (0x%04x)\n", handle); + /* If the command is successfully aborted due to + * target reset TM then do up to three retries else + * command will be terminated by the host reset TM and + * hence retry once. + */ + if (((ioc->scsih_cmds.status & MPT3_CMD_COMPLETE) && + retry_count++ < 3) || + ((ioc->scsih_cmds.status & MPT3_CMD_RESET) && + host_reset_count++ == 0)) { + pr_info("issue retry: handle (0x%04x)\n", handle); + goto retry_loop; + } + } else + pr_info("target reset didn't complete: handle(0x%04x)\n", handle); + rc = -EFAULT; + } else + rc = -EAGAIN; + + out: + ioc->scsih_cmds.status = MPT3_CMD_NOT_USED; + mutex_unlock(&ioc->scsih_cmds.mutex); return rc; } /** - * _scsih_check_device - checking device responsiveness + * _scsih_determine_disposition - * @ioc: per adapter object - * @parent_sas_address: sas address of parent expander or sas host - * @handle: attached device handle - * @phy_number: phy number - * @link_rate: new link rate + * @transfer_packet: packet describing the transfer + * Context: user + * + * Determines if an internal generated scsi_io is good data, or + * whether it needs to be retried or treated as an error. + * + * Returns device_responsive_state */ -static void -_scsih_check_device(struct MPT3SAS_ADAPTER *ioc, - u64 parent_sas_address, u16 handle, u8 phy_number, u8 link_rate) +static enum device_responsive_state +_scsih_determine_disposition(struct MPT3SAS_ADAPTER *ioc, + struct _scsi_io_transfer *transfer_packet) { - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - struct _sas_device *sas_device = NULL; + static enum device_responsive_state rc; + struct sense_info sense_info = {0, 0, 0}; + u8 check_sense = 0; + char *desc = NULL; + + if (!transfer_packet->valid_reply) + return DEVICE_READY; + + switch (transfer_packet->ioc_status) { + case MPI2_IOCSTATUS_BUSY: + case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: + case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: + case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: + case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: + rc = DEVICE_RETRY; + break; + case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: + if (transfer_packet->log_info == 0x31170000) { + rc = DEVICE_RETRY; + break; + } + if (transfer_packet->cdb[0] == REPORT_LUNS) + rc = DEVICE_READY; + else + rc = DEVICE_RETRY; + break; + case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: + case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: + case MPI2_IOCSTATUS_SUCCESS: + if (!transfer_packet->scsi_state && + !transfer_packet->scsi_status) { + rc = DEVICE_READY; + break; + } + if (transfer_packet->scsi_state & + MPI2_SCSI_STATE_AUTOSENSE_VALID) { + rc = DEVICE_ERROR; + check_sense = 1; + break; + } + if (transfer_packet->scsi_state & + (MPI2_SCSI_STATE_AUTOSENSE_FAILED | + MPI2_SCSI_STATE_NO_SCSI_STATUS | + MPI2_SCSI_STATE_TERMINATED)) { + rc = DEVICE_RETRY; + break; + } + if (transfer_packet->scsi_status >= + MPI2_SCSI_STATUS_BUSY) { + rc = DEVICE_RETRY; + break; + } + rc = DEVICE_READY; + break; + case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: + if (transfer_packet->scsi_state & + MPI2_SCSI_STATE_TERMINATED) + rc = DEVICE_RETRY; + else + rc = DEVICE_ERROR; + break; + case MPI2_IOCSTATUS_INSUFFICIENT_POWER: + default: + rc = DEVICE_ERROR; + break; + } + + if (check_sense) { + _scsih_normalize_sense(transfer_packet->sense, &sense_info); + if (sense_info.skey == UNIT_ATTENTION) + rc = DEVICE_RETRY_UA; + else if (sense_info.skey == NOT_READY) { + /* medium isn't present */ + if (sense_info.asc == 0x3a) + rc = DEVICE_READY; + /* LOGICAL UNIT NOT READY */ + else if (sense_info.asc == 0x04) { + if (sense_info.ascq == 0x03 || + sense_info.ascq == 0x0b || + sense_info.ascq == 0x0c) { + rc = DEVICE_ERROR; + } else + rc = DEVICE_START_UNIT; + } + /* LOGICAL UNIT HAS NOT SELF-CONFIGURED YET */ + else if (sense_info.asc == 0x3e && !sense_info.ascq) + rc = DEVICE_START_UNIT; + } else if (sense_info.skey == ILLEGAL_REQUEST && + transfer_packet->cdb[0] == REPORT_LUNS) { + rc = DEVICE_READY; + } else if (sense_info.skey == MEDIUM_ERROR) { + + /* medium is corrupt, lets add the device so + * users can collect some info as needed + */ + + if (sense_info.asc == 0x31) + rc = DEVICE_READY; + } else if (sense_info.skey == HARDWARE_ERROR) { + /* Defect List Error, still add the device */ + if (sense_info.asc == 0x19) + rc = DEVICE_READY; + } + } + + if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { + switch (rc) { + case DEVICE_READY: + desc = "ready"; + break; + case DEVICE_RETRY: + desc = "retry"; + break; + case DEVICE_RETRY_UA: + desc = "retry_ua"; + break; + case DEVICE_START_UNIT: + desc = "start_unit"; + break; + case DEVICE_STOP_UNIT: + desc = "stop_unit"; + break; + case DEVICE_ERROR: + desc = "error"; + break; + } + + pr_info("ioc_status(0x%04x),\n" + "loginfo(0x%08x), scsi_status(0x%02x),\n" + "scsi_state(0x%02x), rc(%s)\n", + transfer_packet->ioc_status, + transfer_packet->log_info, transfer_packet->scsi_status, + transfer_packet->scsi_state, desc); + + if (check_sense) + pr_info("\t[sense_key,asc,ascq]:\n" + "[0x%02x,0x%02x,0x%02x]\n", + sense_info.skey, sense_info.asc, sense_info.ascq); + } + return rc; +} + +/** + * _scsih_report_luns - send REPORT_LUNS to target + * @ioc: per adapter object + * @handle: expander handle + * @data: report luns data payload + * @data_length: length of data in bytes + * @retry_count: Requeue count + * @is_pd: is this hidden raid component + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * Context: user + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_report_luns(struct MPT3SAS_ADAPTER *ioc, u16 handle, void *data, + u32 data_length, u8 retry_count, u8 is_pd, u8 tr_timeout, u8 tr_method) +{ + struct _scsi_io_transfer *transfer_packet; + enum device_responsive_state rc; + void *lun_data; + int return_code; + int retries; + + lun_data = NULL; + transfer_packet = kzalloc(sizeof(struct _scsi_io_transfer), GFP_KERNEL); + if (!transfer_packet) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + + lun_data = dma_alloc_coherent(&ioc->pdev->dev, data_length, + &transfer_packet->data_dma, GFP_ATOMIC); + if (!lun_data) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + + for (retries = 0; retries < 4; retries++) { + rc = DEVICE_ERROR; + ioc_info(ioc, "REPORT_LUNS: handle(0x%04x),\n" + "retries(%d)\n", handle, retries); + memset(lun_data, 0, data_length); + transfer_packet->handle = handle; + transfer_packet->dir = DMA_FROM_DEVICE; + transfer_packet->data_length = data_length; + transfer_packet->cdb_length = 12; + transfer_packet->cdb[0] = REPORT_LUNS; + transfer_packet->cdb[6] = (data_length >> 24) & 0xFF; + transfer_packet->cdb[7] = (data_length >> 16) & 0xFF; + transfer_packet->cdb[8] = (data_length >> 8) & 0xFF; + transfer_packet->cdb[9] = data_length & 0xFF; + transfer_packet->timeout = 30; + transfer_packet->is_raid = is_pd; + + return_code = _scsi_send_scsi_io(ioc, transfer_packet, tr_timeout, tr_method); + switch (return_code) { + case 0: + rc = _scsih_determine_disposition(ioc, transfer_packet); + if (rc == DEVICE_READY) { + memcpy(data, lun_data, data_length); + goto out; + } else if (rc == DEVICE_ERROR) + goto out; + break; + case -EAGAIN: + rc = DEVICE_RETRY; + break; + case -EFAULT: + default: + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + goto out; + } + } + out: + + if (lun_data) + dma_free_coherent(&ioc->pdev->dev, data_length, lun_data, + transfer_packet->data_dma); + kfree(transfer_packet); + + if ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_RETRY_UA) && retry_count >= command_retry_count) + rc = DEVICE_ERROR; + + return rc; +} + +/** + * _scsih_start_unit - send START_UNIT to target + * @ioc: per adapter object + * @handle: expander handle + * @lun: lun number + * @is_pd: is this hidden raid component + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * Context: user + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_start_unit(struct MPT3SAS_ADAPTER *ioc, u16 handle, u32 lun, u8 is_pd, + u8 tr_timeout, u8 tr_method) +{ + struct _scsi_io_transfer *transfer_packet; + enum device_responsive_state rc; + int return_code; + + transfer_packet = kzalloc(sizeof(struct _scsi_io_transfer), GFP_KERNEL); + if (!transfer_packet) { + + pr_info("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + + rc = DEVICE_READY; + transfer_packet->handle = handle; + transfer_packet->dir = DMA_NONE; + transfer_packet->lun = lun; + transfer_packet->cdb_length = 6; + transfer_packet->cdb[0] = START_STOP; + transfer_packet->cdb[1] = 1; + transfer_packet->cdb[4] = 1; + transfer_packet->timeout = 30; + transfer_packet->is_raid = is_pd; + + pr_info("START_UNIT: handle(0x%04x), lun(%d)\n", handle, lun); + + return_code = _scsi_send_scsi_io(ioc, transfer_packet, tr_timeout, tr_method); + switch (return_code) { + case 0: + rc = _scsih_determine_disposition(ioc, transfer_packet); + break; + case -EAGAIN: + rc = DEVICE_RETRY; + break; + case -EFAULT: + default: + pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_ERROR; + break; + } + out: + kfree(transfer_packet); + return rc; +} + +/** + * _scsih_test_unit_ready - send TUR to target + * @ioc: per adapter object + * @handle: expander handle + * @lun: lun number + * @is_pd: is this hidden raid component + * @tr_timeout: Target Reset timeout value for Pcie devie + * @tr_method: pcie device Target reset method + * Context: user + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_test_unit_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, u32 lun, + u8 is_pd, u8 tr_timeout, u8 tr_method) +{ + struct _scsi_io_transfer *transfer_packet; + enum device_responsive_state rc; + int return_code; + int sata_init_failure = 0; + + transfer_packet = kzalloc(sizeof(struct _scsi_io_transfer), GFP_KERNEL); + if (!transfer_packet) { + + pr_info("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + + rc = DEVICE_READY; + transfer_packet->handle = handle; + transfer_packet->dir = DMA_NONE; + transfer_packet->lun = lun; + transfer_packet->cdb_length = 6; + transfer_packet->cdb[0] = TEST_UNIT_READY; + transfer_packet->timeout = 30; + transfer_packet->is_raid = is_pd; + + sata_init_retry: + pr_info("TEST_UNIT_READY: handle(0x%04x) lun(%d)\n", handle, lun); + + return_code = _scsi_send_scsi_io(ioc, transfer_packet, tr_timeout, tr_method); + switch (return_code) { + case 0: + rc = _scsih_determine_disposition(ioc, transfer_packet); + if (rc == DEVICE_RETRY && + transfer_packet->log_info == 0x31111000) { + if (!sata_init_failure++) { + pr_info("SATA Initialization Timeout sending a retry\n"); + rc = DEVICE_READY; + goto sata_init_retry; + } else { + pr_err("SATA Initialization Failed\n"); + rc = DEVICE_ERROR; + } + } + break; + case -EAGAIN: + rc = DEVICE_RETRY; + break; + case -EFAULT: + default: + pr_err("failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_ERROR; + break; + } + out: + kfree(transfer_packet); + return rc; +} + +/** + * _scsih_ata_pass_thru_idd - obtain SATA device Identify Device Data + * @ioc: per adapter object + * @handle: device handle + * @is_ssd_device : is this SATA SSD device + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * Context: user + * + * Returns device_responsive_state + */ +static enum device_responsive_state +_scsih_ata_pass_thru_idd(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 *is_ssd_device, u8 tr_timeout, u8 tr_method) +{ + struct _scsi_io_transfer *transfer_packet; + enum device_responsive_state rc; + u16 *idd_data; + int return_code; + u32 data_length; + + idd_data = NULL; + transfer_packet = kzalloc(sizeof(struct _scsi_io_transfer), GFP_KERNEL); + if (!transfer_packet) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + data_length = 512; + idd_data = dma_alloc_coherent(&ioc->pdev->dev, data_length, + &transfer_packet->data_dma, GFP_ATOMIC); + if (!idd_data) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_RETRY; + goto out; + } + rc = DEVICE_READY; + memset(idd_data, 0, data_length); + transfer_packet->handle = handle; + transfer_packet->dir = DMA_FROM_DEVICE; + transfer_packet->data_length = data_length; + transfer_packet->cdb_length = 12; + transfer_packet->cdb[0] = ATA_12; + transfer_packet->cdb[1] = 0x8; + transfer_packet->cdb[2] = 0xd; + transfer_packet->cdb[3] = 0x1; + transfer_packet->cdb[9] = 0xec; + transfer_packet->timeout = 30; + + return_code = _scsi_send_scsi_io(ioc, transfer_packet, 30, 0); + switch (return_code) { + case 0: + rc = _scsih_determine_disposition(ioc, transfer_packet); + if (rc == DEVICE_READY) { + // Check if nominal media rotation rate is set to 1 i.e. SSD device + if (idd_data[217] == 1) + *is_ssd_device = 1; + } + break; + case -EAGAIN: + rc = DEVICE_RETRY; + break; + case -EFAULT: + default: + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + rc = DEVICE_ERROR; + break; + } + + out: + if (idd_data) { + dma_free_coherent(&ioc->pdev->dev, data_length, idd_data, + transfer_packet->data_dma); + } + kfree(transfer_packet); + return rc; +} + +/** + * _scsih_wait_for_device_to_become_ready - handle busy devices + * @ioc: per adapter object + * @handle: expander handle + * @retry_count: number of times this event has been retried + * @is_pd: is this hidden raid component + * @lun: lun number + * @tr_timeout: Target Reset Timeout + * @tr_method: Target Reset Method + * + * Some devices spend too much time in busy state, queue event later + * + * Return the device_responsive_state. + */ + +static enum device_responsive_state +_scsih_wait_for_device_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count, u8 is_pd, int lun, u8 tr_timeout, u8 tr_method) +{ + enum device_responsive_state rc; + + if (ioc->pci_error_recovery) + return DEVICE_ERROR; + + if (ioc->shost_recovery) + return DEVICE_RETRY; + + rc = _scsih_test_unit_ready(ioc, handle, lun, is_pd, tr_timeout, tr_method); + if (rc == DEVICE_READY || rc == DEVICE_ERROR) + return rc; + else if (rc == DEVICE_START_UNIT) { + rc = _scsih_start_unit(ioc, handle, lun, is_pd, tr_timeout, tr_method); + if (rc == DEVICE_ERROR) + return rc; + rc = _scsih_test_unit_ready(ioc, handle, lun, is_pd, tr_timeout, tr_method); + } + + if ((rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_RETRY_UA) && retry_count >= command_retry_count) + rc = DEVICE_ERROR; + return rc; +} + +static inline int mpt_scsilun_to_int(struct scsi_lun *scsilun) +{ + return scsilun_to_int(scsilun); +} + +/** + * _scsih_wait_for_target_to_become_ready - handle busy devices + * @ioc: per adapter object + * @handle: expander handle + * @retry_count: number of times this event has been retried + * @is_pd: is this hidden raid component + * @tr_timeout: Target Reset timeout value + * @tr_method: Target Reset method Hot/Protocol level. + * + * Some devices spend too much time in busy state, queue event later + * + * Return the device_responsive_state. + */ +static enum device_responsive_state +_scsih_wait_for_target_to_become_ready(struct MPT3SAS_ADAPTER *ioc, u16 handle, + u8 retry_count, u8 is_pd, u8 tr_timeout, u8 tr_method) +{ + enum device_responsive_state rc; + struct scsi_lun *lun_data; + u32 length, num_luns; + u8 *data; + int lun; + struct scsi_lun *lunp; + + lun_data = kcalloc(MPT3_MAX_LUNS, sizeof(struct scsi_lun), GFP_KERNEL); + if (!lun_data) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + return DEVICE_RETRY; + } + + rc = _scsih_report_luns(ioc, handle, lun_data, + MPT3_MAX_LUNS * sizeof(struct scsi_lun), retry_count, is_pd, + tr_timeout, tr_method); + + if (rc != DEVICE_READY) + goto out; + + /* some debug bits*/ + data = (u8 *)lun_data; + length = ((data[0] << 24) | (data[1] << 16) | + (data[2] << 8) | (data[3] << 0)); + + num_luns = (length / sizeof(struct scsi_lun)); + + lunp = &lun_data[1]; + lun = (num_luns) ? mpt_scsilun_to_int(&lun_data[1]) : 0; + rc = _scsih_wait_for_device_to_become_ready(ioc, handle, retry_count, + is_pd, lun, tr_timeout, tr_method); + + if (rc == DEVICE_ERROR) { + struct scsi_lun *lunq; + + for (lunq = lunp++; lunq <= &lun_data[num_luns]; lunq++) { + + rc = _scsih_wait_for_device_to_become_ready(ioc, handle, + retry_count, is_pd, mpt_scsilun_to_int(lunq), + tr_timeout, tr_method); + if (rc != DEVICE_ERROR) + goto out; + } + } +out: + kfree(lun_data); + return rc; +} + + +/** + * _scsih_check_access_status - check access flags + * @ioc: per adapter object + * @sas_address: sas address + * @handle: sas device handle + * @access_status: errors returned during discovery of the device + * + * Return: 0 for success, else failure + */ +static u8 +_scsih_check_access_status(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, + u16 handle, u8 access_status) +{ + u8 rc = 1; + char *desc = NULL; + + switch (access_status) { + case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS: + case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION: + rc = 0; + break; + case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED: + desc = "sata capability failed"; + break; + case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT: + desc = "sata affiliation conflict"; + break; + case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE: + desc = "route not addressable"; + break; + case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE: + desc = "smp error not addressable"; + break; + case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED: + desc = "device blocked"; + break; + case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE: + case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX: + desc = "sata initialization failed"; + break; + default: + desc = "unknown"; + break; + } + + if (!rc) + return 0; + + ioc_err(ioc, "discovery errors(%s): sas_address(0x%016llx), handle(0x%04x)\n", + desc, (u64)sas_address, handle); + return rc; +} + +/** + * _scsih_check_device - checking device responsiveness + * @ioc: per adapter object + * @parent_sas_address: sas address of parent expander or sas host + * @handle: attached device handle + * @phy_number: phy number + * @link_rate: new link rate + */ +static void +_scsih_check_device(struct MPT3SAS_ADAPTER *ioc, + u64 parent_sas_address, u16 handle, u8 phy_number, u8 link_rate) +{ + Mpi2ConfigReply_t mpi_reply; + Mpi2SasDevicePage0_t sas_device_pg0; + struct _sas_device *sas_device = NULL; struct _enclosure_node *enclosure_dev = NULL; u32 ioc_status; unsigned long flags; @@ -7239,8 +8302,8 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, sas_device->handle, handle); sas_target_priv_data->handle = handle; sas_device->handle = handle; - if (le16_to_cpu(sas_device_pg0.Flags) & - MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { + if ((le16_to_cpu(sas_device_pg0.Flags) & MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) + && (ioc->hba_mpi_version_belonged != MPI2_VERSION)) { sas_device->enclosure_level = sas_device_pg0.EnclosureLevel; memcpy(sas_device->connector_name, @@ -7282,7 +8345,11 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, goto out_unlock; spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - _scsih_ublock_io_device(ioc, sas_address, port); + + if (issue_scsi_cmd_to_bringup_drive) + _scsih_ublock_io_device_wait(ioc, sas_address, port); + else + _scsih_ublock_io_device(ioc, sas_address, port); if (sas_device) sas_device_put(sas_device); @@ -7298,7 +8365,7 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, * _scsih_add_device - creating sas device object * @ioc: per adapter object * @handle: sas device handle - * @phy_num: phy number end device attached to + * @retry_count: number of times this event has been retried * @is_pd: is this hidden raid component * * Creating end device object, stored in ioc->sas_device_list. @@ -7306,16 +8373,18 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, * Return: 0 for success, non-zero for failure. */ static int -_scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, +_scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 retry_count, u8 is_pd) { Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t sas_device_pg0; struct _sas_device *sas_device; struct _enclosure_node *enclosure_dev = NULL; + enum device_responsive_state rc; u32 ioc_status; u64 sas_address; u32 device_info; + u8 connector_name[5]; u8 port_id; if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, @@ -7371,6 +8440,48 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, sas_device_pg0.EnclosureHandle); } + /* + * Wait for device that is becoming ready + * queue request later if device is busy. + */ + if ((!ioc->wait_for_discovery_to_complete) && + (issue_scsi_cmd_to_bringup_drive)) { + ioc_info(ioc, "detecting: handle(0x%04x),\n" + "sas_address(0x%016llx), phy(%d)\n", handle, + (unsigned long long)sas_address, sas_device_pg0.PhyNum); + rc = _scsih_wait_for_target_to_become_ready(ioc, handle, + retry_count, is_pd, 30, 0); + if (rc != DEVICE_READY) { + if (le16_to_cpu(sas_device_pg0.EnclosureHandle) != 0) + dewtprintk(ioc, ioc_info(ioc, "%s:\n" + "device not ready: slot(%d)\n", __func__, + le16_to_cpu(sas_device_pg0.Slot))); + if ((le16_to_cpu(sas_device_pg0.Flags) & + MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) && + (ioc->hba_mpi_version_belonged != MPI2_VERSION)) { + memcpy(connector_name, + sas_device_pg0.ConnectorName, 4); + connector_name[4] = '\0'; + dewtprintk(ioc, ioc_info(ioc, "%s:\n" + "device not ready:\n" + "enclosure level(0x%04x),\n" + "connector name( %s)\n", __func__, + sas_device_pg0.EnclosureLevel, connector_name)); + } + + if ((enclosure_dev) && (le16_to_cpu(enclosure_dev->pg0.Flags) & + MPI2_SAS_ENCLS0_FLAGS_CHASSIS_SLOT_VALID)) + ioc_info(ioc, "chassis slot(0x%04x)\n", + enclosure_dev->pg0.ChassisSlot); + + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + return 1; + else if (rc == DEVICE_ERROR) + return 0; + } + } + sas_device = kzalloc(sizeof(struct _sas_device), GFP_KERNEL); if (!sas_device) { @@ -7586,10 +8697,13 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { int i; + int rc; + int requeue_event; u16 parent_handle, handle; u16 reason_code; u8 phy_number, max_phys; struct _sas_node *sas_expander; + struct _sas_device *sas_device; u64 sas_address; unsigned long flags; u8 link_rate, prev_link_rate; @@ -7639,7 +8753,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, spin_unlock_irqrestore(&ioc->sas_node_lock, flags); /* handle siblings events */ - for (i = 0; i < event_data->NumEntries; i++) { + for (i = 0, requeue_event = 0; i < event_data->NumEntries; i++) { if (fw_event->ignore) { dewtprintk(ioc, ioc_info(ioc, "ignoring expander event\n")); @@ -7656,6 +8770,20 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code != MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) continue; + if (fw_event->delayed_work_active && (reason_code == + MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) { + dewtprintk(ioc, ioc_info(ioc, "ignoring\n" + "Target not responding event phy in re-queued event processing\n")); + continue; + } + + if (fw_event->delayed_work_active && (reason_code == + MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) { + dewtprintk(ioc, ioc_info(ioc, "ignoring Target not responding\n" + "event phy in re-queued event processing\n")); + continue; + } + handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); if (!handle) continue; @@ -7679,9 +8807,32 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, _scsih_check_device(ioc, sas_address, handle, phy_number, link_rate); + /* This code after this point handles the test case + * where a device has been added, however its returning + * BUSY for sometime. Then before the Device Missing + * Delay expires and the device becomes READY, the + * device is removed and added back. + */ + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = __mpt3sas_get_sdev_by_handle(ioc, + handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, + flags); + + if (sas_device) { + sas_device_put(sas_device); + break; + } + if (!test_bit(handle, ioc->pend_os_device_add)) break; + dewtprintk(ioc, ioc_info(ioc, "handle(0x%04x) device not found: convert\n" + "event to a device add\n", handle)); + event_data->PHY[i].PhyStatus &= 0xF0; + event_data->PHY[i].PhyStatus |= + MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED; + fallthrough; case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: @@ -7692,7 +8843,18 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, mpt3sas_transport_update_links(ioc, sas_address, handle, phy_number, link_rate, port); - _scsih_add_device(ioc, handle, phy_number, 0); + if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) + break; + + rc = _scsih_add_device(ioc, handle, + fw_event->retries[i], 0); + if (rc) {/* retry due to busy device */ + fw_event->retries[i]++; + requeue_event = 1; + } else {/* mark entry vacant */ + event_data->PHY[i].PhyStatus |= + MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT; + } break; case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: @@ -7707,7 +8869,7 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, sas_expander) mpt3sas_expander_remove(ioc, sas_address, port); - return 0; + return requeue_event; } /** @@ -8078,7 +9240,10 @@ _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); pcie_device_put(pcie_device); - _scsih_ublock_io_device(ioc, wwid, NULL); + if (issue_scsi_cmd_to_bringup_drive) + _scsih_ublock_io_device_wait(ioc, wwid, NULL); + else + _scsih_ublock_io_device(ioc, wwid, NULL); return; } @@ -8087,19 +9252,24 @@ _scsih_pcie_check_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) * _scsih_pcie_add_device - creating pcie device object * @ioc: per adapter object * @handle: pcie device handle + * @retry_count: number of times this event has been retried * * Creating end device object, stored in ioc->pcie_device_list. * * Return: 1 means queue the event later, 0 means complete the event */ static int -_scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) +_scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 retry_count) { Mpi26PCIeDevicePage0_t pcie_device_pg0; Mpi26PCIeDevicePage2_t pcie_device_pg2; Mpi2ConfigReply_t mpi_reply; struct _pcie_device *pcie_device; struct _enclosure_node *enclosure_dev; + enum device_responsive_state rc; + u8 connector_name[5]; + u8 tr_timeout = 30; + u8 tr_method = 0; u32 ioc_status; u64 wwid; @@ -8167,6 +9337,53 @@ _scsih_pcie_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) __LINE__, __func__); return 0; } + + if (!ioc->tm_custom_handling) { + tr_method = MPI26_SCSITASKMGMT_MSGFLAGS_PROTOCOL_LVL_RST_PCIE; + if (pcie_device_pg2.ControllerResetTO) + tr_timeout = pcie_device_pg2.ControllerResetTO; + + } + } + + /* + * Wait for device that is becoming ready + * queue request later if device is busy. + */ + if ((!ioc->wait_for_discovery_to_complete) && + (issue_scsi_cmd_to_bringup_drive) && + (pcie_device_pg0.AccessStatus != + MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED)) { + ioc_info(ioc, "detecting: handle(0x%04x),\n" + "wwid(0x%016llx), port(%d)\n", handle, + (unsigned long long)wwid, pcie_device_pg0.PortNum); + + rc = _scsih_wait_for_target_to_become_ready(ioc, handle, + retry_count, 0, tr_timeout, tr_method); + if (rc != DEVICE_READY) { + if (le16_to_cpu(pcie_device_pg0.EnclosureHandle) != 0) + dewtprintk(ioc, ioc_info(ioc, "%s:\n" + "device not ready: slot(%d)\n", + __func__, + le16_to_cpu(pcie_device_pg0.Slot))); + + if (le32_to_cpu(pcie_device_pg0.Flags) & + MPI26_PCIEDEV0_FLAGS_ENCL_LEVEL_VALID) { + memcpy(connector_name, + pcie_device_pg0.ConnectorName, 4); + connector_name[4] = '\0'; + dewtprintk(ioc, ioc_info(ioc, "%s: device not ready: enclosure\n" + "level(0x%04x), connector name( %s)\n", __func__, + pcie_device_pg0.EnclosureLevel, + connector_name)); + } + + if (rc == DEVICE_RETRY || rc == DEVICE_START_UNIT || + rc == DEVICE_STOP_UNIT || rc == DEVICE_RETRY_UA) + return 1; + else if (rc == DEVICE_ERROR) + return 0; + } } pcie_device = kzalloc(sizeof(struct _pcie_device), GFP_KERNEL); @@ -8330,7 +9547,7 @@ _scsih_pcie_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc, * Context: user. * */ -static void +static int _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { @@ -8340,6 +9557,7 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, u8 link_rate, prev_link_rate; unsigned long flags; int rc; + int requeue_event; Mpi26EventDataPCIeTopologyChangeList_t *event_data = (Mpi26EventDataPCIeTopologyChangeList_t *) fw_event->event_data; struct _pcie_device *pcie_device; @@ -8349,22 +9567,22 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery) - return; + return 0; if (fw_event->ignore) { dewtprintk(ioc, ioc_info(ioc, "ignoring switch event\n")); - return; + return 0; } /* handle siblings events */ - for (i = 0; i < event_data->NumEntries; i++) { + for (i = 0, requeue_event = 0; i < event_data->NumEntries; i++) { if (fw_event->ignore) { dewtprintk(ioc, ioc_info(ioc, "ignoring switch event\n")); - return; + return 0; } if (ioc->remove_host || ioc->pci_error_recovery) - return; + return 0; reason_code = event_data->PortEntry[i].PortStatus; handle = le16_to_cpu(event_data->PortEntry[i].AttachedDevHandle); @@ -8418,8 +9636,11 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, if (link_rate < MPI26_EVENT_PCIE_TOPO_PI_RATE_2_5) break; - rc = _scsih_pcie_add_device(ioc, handle); - if (!rc) { + rc = _scsih_pcie_add_device(ioc, handle, fw_event->retries[i]); + if (rc) {/* retry due to busy device */ + fw_event->retries[i]++; + requeue_event = 1; + } else { /* mark entry vacant */ /* TODO This needs to be reviewed and fixed, * we dont have an entry @@ -8434,11 +9655,12 @@ _scsih_pcie_topology_change_event(struct MPT3SAS_ADAPTER *ioc, break; } } + return requeue_event; } /** * _scsih_pcie_device_status_change_event_debug - debug for device event - * @ioc: ? + * @ioc: per adapter object * @event_data: event data payload * Context: user. */ @@ -8810,7 +10032,7 @@ _scsih_sas_broadcast_primitive_event(struct MPT3SAS_ADAPTER *ioc, ioc->broadcast_aen_busy = 0; if (!ioc->shost_recovery) - _scsih_ublock_io_all_device(ioc); + _scsih_ublock_io_all_device(ioc, 1); mutex_unlock(&ioc->tm_cmds.mutex); } @@ -10344,7 +11566,7 @@ _scsih_remove_unresponding_devices(struct MPT3SAS_ADAPTER *ioc) ioc_info(ioc, "removing unresponding devices: complete\n"); /* unblock devices */ - _scsih_ublock_io_all_device(ioc); + _scsih_ublock_io_all_device(ioc, 0); } static void @@ -10624,7 +11846,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) } retry_count = 0; parent_handle = le16_to_cpu(pcie_device_pg0.ParentDevHandle); - _scsih_pcie_add_device(ioc, handle); + while (_scsih_pcie_add_device(ioc, handle, retry_count++)) + ssleep(1); ioc_info(ioc, "\tAFTER adding pcie end device: handle (0x%04x), wwid(0x%016llx)\n", handle, (u64)le64_to_cpu(pcie_device_pg0.WWID)); @@ -10768,7 +11991,11 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) _scsih_turn_on_pfa_led(ioc, fw_event->device_handle); break; case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: - _scsih_sas_topology_change_event(ioc, fw_event); + if (_scsih_sas_topology_change_event(ioc, fw_event)) { + _scsih_fw_event_requeue(ioc, fw_event, 1000); + ioc->current_event = NULL; + return; + } break; case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) @@ -10808,7 +12035,11 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) _scsih_pcie_enumeration_event(ioc, fw_event); break; case MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST: - _scsih_pcie_topology_change_event(ioc, fw_event); + if (_scsih_pcie_topology_change_event(ioc, fw_event)) { + _scsih_fw_event_requeue(ioc, fw_event, 1000); + ioc->current_event = NULL; + return; + } break; } out: @@ -10833,6 +12064,15 @@ _firmware_event_work(struct work_struct *work) _mpt3sas_fw_work(fw_event->ioc, fw_event); } +static void +_firmware_event_work_delayed(struct work_struct *work) +{ + struct fw_event_work *fw_event = container_of(work, + struct fw_event_work, delayed_work.work); + + _mpt3sas_fw_work(fw_event->ioc, fw_event); +} + /** * mpt3sas_scsih_event_callback - firmware event handler (called at ISR time) * @ioc: per adapter object @@ -11013,6 +12253,34 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, return 1; } + if (event == MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST) { + Mpi2EventDataSasTopologyChangeList_t *topo_event_data = + (Mpi2EventDataSasTopologyChangeList_t *) + mpi_reply->EventData; + fw_event->retries = kzalloc(topo_event_data->NumEntries, + GFP_ATOMIC); + if (!fw_event->retries) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + kfree(fw_event->event_data); + fw_event_work_put(fw_event); + return 1; + } + } + + if (event == MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST) { + Mpi26EventDataPCIeTopologyChangeList_t *topo_event_data = + (Mpi26EventDataPCIeTopologyChangeList_t *) mpi_reply->EventData; + fw_event->retries = kzalloc(topo_event_data->NumEntries, + GFP_ATOMIC); + if (!fw_event->retries) { + + ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); + fw_event_work_put(fw_event); + return 1; + } + } + memcpy(fw_event->event_data, mpi_reply->EventData, sz); fw_event->ioc = ioc; fw_event->VF_ID = mpi_reply->VF_ID; diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index bdc2f2f17753..cda8bd083a38 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -2077,8 +2077,8 @@ static unsigned char mvumi_build_frame(struct mvumi_hba *mhba, * @shost: Scsi host to queue command on * @scmd: SCSI command to be queued */ -static int mvumi_queue_command(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status mvumi_queue_command(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct mvumi_cmd *cmd; struct mvumi_hba *mhba; diff --git a/drivers/scsi/myrb.c b/drivers/scsi/myrb.c index b8453c0333dc..efeacb9ffd7c 100644 --- a/drivers/scsi/myrb.c +++ b/drivers/scsi/myrb.c @@ -1260,8 +1260,8 @@ static int myrb_host_reset(struct scsi_cmnd *scmd) return SUCCESS; } -static int myrb_pthru_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status myrb_pthru_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct request *rq = scsi_cmd_to_rq(scmd); struct myrb_hba *cb = shost_priv(shost); @@ -1416,8 +1416,8 @@ static void myrb_read_capacity(struct myrb_hba *cb, struct scsi_cmnd *scmd, scsi_sg_copy_from_buffer(scmd, data, 8); } -static int myrb_ldev_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status myrb_ldev_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct myrb_hba *cb = shost_priv(shost); struct myrb_cmdblk *cmd_blk = scsi_cmd_priv(scmd); @@ -1603,8 +1603,8 @@ static int myrb_ldev_queuecommand(struct Scsi_Host *shost, return 0; } -static int myrb_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status myrb_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct scsi_device *sdev = scmd->device; diff --git a/drivers/scsi/myrs.c b/drivers/scsi/myrs.c index a58abd796603..7e8bb533c669 100644 --- a/drivers/scsi/myrs.c +++ b/drivers/scsi/myrs.c @@ -1581,8 +1581,8 @@ static void myrs_mode_sense(struct myrs_hba *cs, struct scsi_cmnd *scmd, scsi_sg_copy_from_buffer(scmd, modes, mode_len); } -static int myrs_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) +static enum scsi_qc_status myrs_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { struct request *rq = scsi_cmd_to_rq(scmd); struct myrs_hba *cs = shost_priv(shost); diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 34ba9b137789..4a255aafed80 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -7852,7 +7852,7 @@ static int ncr53c8xx_sdev_configure(struct scsi_device *device, return 0; } -static int ncr53c8xx_queue_command_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ncr53c8xx_queue_command_lck(struct scsi_cmnd *cmd) { struct ncr_cmd_priv *cmd_priv = scsi_cmd_priv(cmd); void (*done)(struct scsi_cmnd *) = scsi_done; diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index abc4ce9eae74..e893d5677241 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -185,7 +185,8 @@ static void __exit exit_nsp32 (void); static int nsp32_show_info (struct seq_file *, struct Scsi_Host *); static int nsp32_detect (struct pci_dev *pdev); -static int nsp32_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +static enum scsi_qc_status nsp32_queuecommand(struct Scsi_Host *, + struct scsi_cmnd *); static const char *nsp32_info (struct Scsi_Host *); static int nsp32_release (struct Scsi_Host *); @@ -905,7 +906,7 @@ static int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt) return TRUE; } -static int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt) { void (*done)(struct scsi_cmnd *) = scsi_done; nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index a5a1406a2bde..fb3a1b43d8bd 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -186,7 +186,7 @@ static void nsp_scsi_done(struct scsi_cmnd *SCpnt) scsi_done(SCpnt); } -static int nsp_queuecommand_lck(struct scsi_cmnd *const SCpnt) +static enum scsi_qc_status nsp_queuecommand_lck(struct scsi_cmnd *const SCpnt) { struct scsi_pointer *scsi_pointer = nsp_priv(SCpnt); #ifdef NSP_DEBUG diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h index e1ee8ef90ad3..12e58386bb8f 100644 --- a/drivers/scsi/pcmcia/nsp_cs.h +++ b/drivers/scsi/pcmcia/nsp_cs.h @@ -294,7 +294,8 @@ static struct Scsi_Host *nsp_detect (struct scsi_host_template *sht); static const char *nsp_info (struct Scsi_Host *shpnt); static int nsp_show_info (struct seq_file *m, struct Scsi_Host *host); -static int nsp_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *SCpnt); +static enum scsi_qc_status nsp_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *SCpnt); /* Error handler */ /*static int nsp_eh_abort (struct scsi_cmnd *SCpnt);*/ diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index a3b505240351..8f56f7277dee 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c @@ -544,7 +544,7 @@ SYM53C500_info(struct Scsi_Host *SChost) return (info_msg); } -static int SYM53C500_queue_lck(struct scsi_cmnd *SCpnt) +static enum scsi_qc_status SYM53C500_queue_lck(struct scsi_cmnd *SCpnt) { struct sym53c500_cmd_priv *scp = scsi_cmd_priv(SCpnt); int i; diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index 33f403e307eb..cf163e63054b 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -3242,14 +3242,14 @@ static int pmcraid_build_ioadl( * SCSI_MLQUEUE_DEVICE_BUSY if device is busy * SCSI_MLQUEUE_HOST_BUSY if host is busy */ -static int pmcraid_queuecommand_lck(struct scsi_cmnd *scsi_cmd) +static enum scsi_qc_status pmcraid_queuecommand_lck(struct scsi_cmnd *scsi_cmd) { struct pmcraid_instance *pinstance; struct pmcraid_resource_entry *res; struct pmcraid_ioarcb *ioarcb; + enum scsi_qc_status rc = 0; struct pmcraid_cmd *cmd; u32 fw_version; - int rc = 0; pinstance = (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index ea682f3044b6..ddcef40789e5 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -816,7 +816,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd) return 0; } -static int ppa_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ppa_queuecommand_lck(struct scsi_cmnd *cmd) { ppa_struct *dev = ppa_dev(cmd->device->host); diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c index 92fe5c5c5bb0..a9c727d22931 100644 --- a/drivers/scsi/ps3rom.c +++ b/drivers/scsi/ps3rom.c @@ -201,7 +201,7 @@ static int ps3rom_write_request(struct ps3_storage_device *dev, return 0; } -static int ps3rom_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status ps3rom_queuecommand_lck(struct scsi_cmnd *cmd) { struct ps3rom_private *priv = shost_priv(cmd->device->host); struct ps3_storage_device *dev = priv->dev; diff --git a/drivers/scsi/qedf/qedf.h b/drivers/scsi/qedf/qedf.h index 98afdfe63600..5b330a3203e1 100644 --- a/drivers/scsi/qedf/qedf.h +++ b/drivers/scsi/qedf/qedf.h @@ -487,8 +487,8 @@ extern uint qedf_debug; extern struct qedf_cmd_mgr *qedf_cmd_mgr_alloc(struct qedf_ctx *qedf); extern void qedf_cmd_mgr_free(struct qedf_cmd_mgr *cmgr); -extern int qedf_queuecommand(struct Scsi_Host *host, - struct scsi_cmnd *sc_cmd); +extern enum scsi_qc_status qedf_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc_cmd); extern void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb); extern u8 *qedf_get_src_mac(struct fc_lport *lport); extern void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb); diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index fcfc3bed02c6..d12c47be016e 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -930,8 +930,8 @@ int qedf_post_io_req(struct qedf_rport *fcport, struct qedf_ioreq *io_req) return false; } -int -qedf_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd) +enum scsi_qc_status qedf_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc_cmd) { struct fc_lport *lport = shost_priv(host); struct qedf_ctx *qedf = lport_priv(lport); diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 26c312a48a19..cdd6fe002c32 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -406,9 +406,11 @@ static int qla1280_device_reset(struct scsi_qla_host *, int, int); static int qla1280_abort_command(struct scsi_qla_host *, struct srb *, int); static int qla1280_abort_isp(struct scsi_qla_host *); #ifdef QLA_64BIT_PTR -static int qla1280_64bit_start_scsi(struct scsi_qla_host *, struct srb *); +static enum scsi_qc_status qla1280_64bit_start_scsi(struct scsi_qla_host *, + struct srb *); #else -static int qla1280_32bit_start_scsi(struct scsi_qla_host *, struct srb *); +static enum scsi_qc_status qla1280_32bit_start_scsi(struct scsi_qla_host *, + struct srb *); #endif static void qla1280_nv_write(struct scsi_qla_host *, uint16_t); static void qla1280_poll(struct scsi_qla_host *); @@ -682,12 +684,12 @@ qla1280_info(struct Scsi_Host *host) * handling). Unfortunately, it sometimes calls the scheduler in interrupt * context which is a big NO! NO!. **************************************************************************/ -static int qla1280_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status qla1280_queuecommand_lck(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; struct srb *sp = scsi_cmd_priv(cmd); - int status; + enum scsi_qc_status status; sp->cmd = cmd; sp->flags = 0; @@ -2730,7 +2732,7 @@ qla1280_marker(struct scsi_qla_host *ha, int bus, int id, int lun, u8 type) * 0 = success, was able to issue command. */ #ifdef QLA_64BIT_PTR -static int +static enum scsi_qc_status qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) { struct device_reg __iomem *reg = ha->iobase; @@ -2738,7 +2740,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) cmd_a64_entry_t *pkt; __le32 *dword_ptr; dma_addr_t dma_handle; - int status = 0; + enum scsi_qc_status status = 0; int cnt; int req_cnt; int seg_cnt; @@ -2984,14 +2986,14 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) * Returns: * 0 = success, was able to issue command. */ -static int +static enum scsi_qc_status qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) { struct device_reg __iomem *reg = ha->iobase; struct scsi_cmnd *cmd = sp->cmd; struct cmd_entry *pkt; __le32 *dword_ptr; - int status = 0; + enum scsi_qc_status status = 0; int cnt; int req_cnt; int seg_cnt; diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index ccfc2d26dd37..2c44a379cb23 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -11,6 +11,8 @@ #include #include +static int qla28xx_validate_flash_image(struct bsg_job *bsg_job); + static void qla2xxx_free_fcport_work(struct work_struct *work) { struct fc_port *fcport = container_of(work, typeof(*fcport), @@ -1546,8 +1548,9 @@ qla2x00_update_optrom(struct bsg_job *bsg_job) ha->optrom_buffer = NULL; ha->optrom_state = QLA_SWAITING; mutex_unlock(&ha->optrom_mutex); - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); + if (!rval) + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); return rval; } @@ -2549,6 +2552,30 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job) return 0; } +static int +qla2x00_get_drv_attr(struct bsg_job *bsg_job) +{ + struct qla_drv_attr drv_attr; + struct fc_bsg_reply *bsg_reply = bsg_job->reply; + + memset(&drv_attr, 0, sizeof(struct qla_drv_attr)); + drv_attr.ext_attributes |= QLA_IMG_SET_VALID_SUPPORT; + + + sg_copy_from_buffer(bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, &drv_attr, + sizeof(struct qla_drv_attr)); + + bsg_reply->reply_payload_rcv_len = sizeof(struct qla_drv_attr); + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; + + bsg_job->reply_len = sizeof(struct fc_bsg_reply); + bsg_reply->result = DID_OK << 16; + bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + + return 0; +} + static int qla2x00_manage_host_stats(struct bsg_job *bsg_job) { @@ -2612,8 +2639,9 @@ qla2x00_manage_host_stats(struct bsg_job *bsg_job) sizeof(struct ql_vnd_mng_host_stats_resp)); bsg_reply->result = DID_OK; - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); + if (!ret) + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); return ret; } @@ -2702,8 +2730,9 @@ qla2x00_get_host_stats(struct bsg_job *bsg_job) bsg_job->reply_payload.sg_cnt, data, response_len); bsg_reply->result = DID_OK; - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); + if (!ret) + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); kfree(data); host_stat_out: @@ -2802,8 +2831,9 @@ qla2x00_get_tgt_stats(struct bsg_job *bsg_job) bsg_job->reply_payload.sg_cnt, data, response_len); bsg_reply->result = DID_OK; - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); + if (!ret) + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); tgt_stat_out: kfree(data); @@ -2864,8 +2894,9 @@ qla2x00_manage_host_port(struct bsg_job *bsg_job) bsg_job->reply_payload.sg_cnt, &rsp_data, sizeof(struct ql_vnd_mng_host_port_resp)); bsg_reply->result = DID_OK; - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); + if (!ret) + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); return ret; } @@ -2933,6 +2964,12 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_j case QL_VND_GET_FLASH_UPDATE_CAPS: return qla27xx_get_flash_upd_cap(bsg_job); + case QL_VND_GET_DRV_ATTR: + return qla2x00_get_drv_attr(bsg_job); + + case QL_VND_IMG_SET_VALID: + return qla28xx_validate_flash_image(bsg_job); + case QL_VND_SET_FLASH_UPDATE_CAPS: return qla27xx_set_flash_upd_cap(bsg_job); @@ -3240,9 +3277,97 @@ int qla2x00_mailbox_passthru(struct bsg_job *bsg_job) bsg_job->reply_len = sizeof(*bsg_job->reply); bsg_reply->result = DID_OK << 16; - bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); + if (!ret) + bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len); kfree(req_data); return ret; } + +static int +qla28xx_do_validate_flash_image(struct bsg_job *bsg_job, uint16_t *state) +{ + struct fc_bsg_request *bsg_request = bsg_job->request; + scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); + uint16_t mstate[16]; + uint16_t mpi_state = 0; + uint16_t img_idx; + int rval = QLA_SUCCESS; + + memset(mstate, 0, sizeof(mstate)); + + rval = qla2x00_get_firmware_state(vha, mstate); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "MBC to get MPI state failed (%d)\n", rval); + rval = -EINVAL; + goto exit_flash_img; + } + + mpi_state = mstate[11]; + + if (!(mpi_state & BIT_9 && mpi_state & BIT_8 && mpi_state & BIT_15)) { + ql_log(ql_log_warn, vha, 0xffff, + "MPI firmware state failed (0x%02x)\n", mpi_state); + rval = -EINVAL; + goto exit_flash_img; + } + + rval = qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_LOCK); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "Unable to lock flash semaphore."); + goto exit_flash_img; + } + + img_idx = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; + + rval = qla_mpipt_validate_fw(vha, img_idx, state); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0xffff, + "Failed to validate Firmware image index [0x%x].\n", + img_idx); + } + + qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK); + +exit_flash_img: + return rval; +} + +static int qla28xx_validate_flash_image(struct bsg_job *bsg_job) +{ + scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job)); + struct fc_bsg_reply *bsg_reply = bsg_job->reply; + struct qla_hw_data *ha = vha->hw; + uint16_t state = 0; + int rval = 0; + + if (!IS_QLA28XX(ha) || vha->vp_idx != 0) + return -EPERM; + + mutex_lock(&ha->optrom_mutex); + rval = qla28xx_do_validate_flash_image(bsg_job, &state); + if (rval) + rval = -EINVAL; + mutex_unlock(&ha->optrom_mutex); + + bsg_job->reply_len = sizeof(struct fc_bsg_reply); + + if (rval) + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = + (state == 39) ? EXT_STATUS_IMG_SET_VALID_ERR : + EXT_STATUS_IMG_SET_CONFIG_ERR; + else + bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK; + + bsg_reply->result = DID_OK << 16; + bsg_reply->reply_payload_rcv_len = 0; + bsg_job->reply_len = sizeof(struct fc_bsg_reply); + if (!rval) + bsg_job_done(bsg_job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); + + return QLA_SUCCESS; +} diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h index d38dab0a07e8..a920c8e482bc 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.h +++ b/drivers/scsi/qla2xxx/qla_bsg.h @@ -32,12 +32,14 @@ #define QL_VND_GET_PRIV_STATS_EX 0x1A #define QL_VND_SS_GET_FLASH_IMAGE_STATUS 0x1E #define QL_VND_EDIF_MGMT 0X1F +#define QL_VND_GET_DRV_ATTR 0x22 #define QL_VND_MANAGE_HOST_STATS 0x23 #define QL_VND_GET_HOST_STATS 0x24 #define QL_VND_GET_TGT_STATS 0x25 #define QL_VND_MANAGE_HOST_PORT 0x26 #define QL_VND_MBX_PASSTHRU 0x2B #define QL_VND_DPORT_DIAGNOSTICS_V2 0x2C +#define QL_VND_IMG_SET_VALID 0x30 /* BSG Vendor specific subcode returns */ #define EXT_STATUS_OK 0 @@ -50,6 +52,8 @@ #define EXT_STATUS_BUFFER_TOO_SMALL 16 #define EXT_STATUS_NO_MEMORY 17 #define EXT_STATUS_DEVICE_OFFLINE 22 +#define EXT_STATUS_IMG_SET_VALID_ERR 47 +#define EXT_STATUS_IMG_SET_CONFIG_ERR 48 /* * To support bidirectional iocb @@ -318,6 +322,14 @@ struct qla_active_regions { uint8_t reserved[31]; } __packed; +struct qla_drv_attr { + uint32_t attributes; + u32 ext_attributes; +#define QLA_IMG_SET_VALID_SUPPORT BIT_4 + u32 status_flags; + uint8_t reserved[20]; +} __packed; + #include "qla_edif_bsg.h" #endif diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index b3265952c4be..5593ad7fad27 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1270,6 +1270,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) */ #define MBC_LOAD_RAM 1 /* Load RAM. */ #define MBC_EXECUTE_FIRMWARE 2 /* Execute firmware. */ +#define MBC_LOAD_FLASH_FIRMWARE 3 /* Load flash firmware. */ #define MBC_READ_RAM_WORD 5 /* Read RAM word. */ #define MBC_MAILBOX_REGISTER_TEST 6 /* Wrap incoming mailboxes */ #define MBC_VERIFY_CHECKSUM 7 /* Verify checksum. */ @@ -1385,6 +1386,26 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs) #define HCS_WRITE_SERDES 0x3 #define HCS_READ_SERDES 0x4 +/* + * ISP2[7|8]xx mailbox commands. + */ +#define MBC_MPI_PASSTHROUGH 0x200 + +/* MBC_MPI_PASSTHROUGH */ +#define MPIPT_REQ_V1 1 +enum { + MPIPT_SUBCMD_GET_SUP_CMD = 0x10, + MPIPT_SUBCMD_GET_SUP_FEATURE, + MPIPT_SUBCMD_GET_STATUS, + MPIPT_SUBCMD_VALIDATE_FW, +}; + +enum { + MPIPT_MPI_STATUS = 1, + MPIPT_FCORE_STATUS, + MPIPT_LOCKDOWN_STATUS, +}; + /* Firmware return data sizes */ #define FCAL_MAP_SIZE 128 @@ -4149,6 +4170,7 @@ struct qla_hw_data { uint32_t eeh_flush:2; #define EEH_FLUSH_RDY 1 #define EEH_FLUSH_DONE 2 + uint32_t secure_mcu:1; } flags; uint16_t max_exchg; @@ -4414,6 +4436,8 @@ struct qla_hw_data { ((IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) &&\ (ha->zio_mode == QLA_ZIO_MODE_6)) +#define IS_QLA28XX_SECURED(ha) (IS_QLA28XX(ha) && ha->flags.secure_mcu) + /* HBA serial number */ uint8_t serial0; uint8_t serial1; @@ -5368,7 +5392,7 @@ struct edif_sa_index_entry { struct list_head next; }; -/* Refer to SNIA SFF 8247 */ +/* Refer to SNIA SFF 8472 */ struct sff_8247_a0 { u8 txid; /* transceiver id */ u8 ext_txid; @@ -5412,6 +5436,7 @@ struct sff_8247_a0 { #define FC_SP_32 BIT_3 #define FC_SP_2 BIT_2 #define FC_SP_1 BIT_0 +#define FC_SPEED_2 BIT_1 u8 fc_sp_cc10; u8 encode; u8 bitrate; @@ -5430,7 +5455,8 @@ struct sff_8247_a0 { u8 vendor_pn[SFF_PART_NAME_LEN]; /* part number */ u8 vendor_rev[4]; u8 wavelength[2]; - u8 resv; +#define FC_SP_64 BIT_0 + u8 fiber_channel_speed2; u8 cc_base; u8 options[2]; /* offset 64 */ u8 br_max; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 55d531c19e6b..9e328c235e39 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -344,6 +344,9 @@ qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t); extern int qla2x00_execute_fw(scsi_qla_host_t *, uint32_t); +extern int +qla28xx_load_flash_firmware(scsi_qla_host_t *vha); + extern int qla2x00_get_fw_version(scsi_qla_host_t *); @@ -839,6 +842,8 @@ extern int qla82xx_write_optrom_data(struct scsi_qla_host *, void *, extern int qla82xx_abort_isp(scsi_qla_host_t *); extern int qla82xx_restart_isp(scsi_qla_host_t *); +extern int qla_mpipt_validate_fw(scsi_qla_host_t *vha, u16 img_idx, u16 *state); + /* IOCB related functions */ extern int qla82xx_start_scsi(srb_t *); extern void qla2x00_sp_free(srb_t *sp); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 51c7cea71f90..880cd73feaca 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3266,9 +3266,6 @@ void qla_fab_scan_finish(scsi_qla_host_t *vha, srb_t *sp) atomic_read(&fcport->state) == FCS_ONLINE) || do_delete) { if (fcport->loop_id != FC_NO_LOOP_ID) { - if (fcport->flags & FCF_FCP2_DEVICE) - continue; - ql_log(ql_log_warn, vha, 0x20f0, "%s %d %8phC post del sess\n", __func__, __LINE__, @@ -3535,8 +3532,8 @@ int qla_fab_async_scan(scsi_qla_host_t *vha, srb_t *sp) if (vha->scan.scan_flags & SF_SCANNING) { spin_unlock_irqrestore(&vha->work_lock, flags); ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x2012, - "%s: scan active\n", __func__); - return rval; + "%s: scan active for sp:%p\n", __func__, sp); + goto done_free_sp; } vha->scan.scan_flags |= SF_SCANNING; if (!sp) @@ -3701,23 +3698,25 @@ int qla_fab_async_scan(scsi_qla_host_t *vha, srb_t *sp) return rval; done_free_sp: - 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; - } + if (sp) { + 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; + } - /* ref: INIT */ - kref_put(&sp->cmd_kref, qla2x00_sp_release); + /* ref: INIT */ + kref_put(&sp->cmd_kref, qla2x00_sp_release); + } spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &= ~SF_SCANNING; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d395cbfe6802..689f909943b4 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1859,15 +1859,6 @@ void qla2x00_handle_rscn(scsi_qla_host_t *vha, struct event_arg *ea) case RSCN_PORT_ADDR: fcport = qla2x00_find_fcport_by_nportid(vha, &ea->id, 1); if (fcport) { - if (ql2xfc2target && - fcport->flags & FCF_FCP2_DEVICE && - atomic_read(&fcport->state) == FCS_ONLINE) { - ql_dbg(ql_dbg_disc, vha, 0x2115, - "Delaying session delete for FCP2 portid=%06x %8phC ", - fcport->d_id.b24, fcport->port_name); - return; - } - if (vha->hw->flags.edif_enabled && DBELL_ACTIVE(vha)) { /* * On ipsec start by remote port, Target port @@ -2471,8 +2462,23 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) ea->sp->gen1, fcport->rscn_gen, ea->data[0], ea->data[1], ea->iop[0], ea->iop[1]); - if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || - (fcport->fw_login_state == DSC_LS_PRLI_PEND)) { + if (fcport->fw_login_state == DSC_LS_PLOGI_PEND) { + ql_dbg(ql_dbg_disc, vha, 0x20ea, + "%s %d %8phC Remote is trying to login\n", + __func__, __LINE__, fcport->port_name); + /* + * If we get here, there is port thats already logged in, + * but it's state has not moved ahead. Recheck with FW on + * what state it is in and proceed ahead + */ + if (!N2N_TOPO(vha->hw)) { + fcport->fw_login_state = DSC_LS_PRLI_COMP; + qla24xx_post_gpdb_work(vha, fcport, 0); + } + return; + } + + if (fcport->fw_login_state == DSC_LS_PRLI_PEND) { ql_dbg(ql_dbg_disc, vha, 0x20ea, "%s %d %8phC Remote is trying to login\n", __func__, __LINE__, fcport->port_name); @@ -4074,6 +4080,22 @@ static void qla2xxx_print_sfp_info(struct scsi_qla_host *vha) u8 str[STR_LEN], *ptr, p; int leftover, len; + ql_dbg(ql_dbg_init, vha, 0x015a, + "SFP: %.*s -> %.*s ->%s%s%s%s%s%s%s\n", + (int)sizeof(a0->vendor_name), a0->vendor_name, + (int)sizeof(a0->vendor_pn), a0->vendor_pn, + a0->fc_sp_cc10 & FC_SP_2 ? a0->fiber_channel_speed2 & FC_SP_64 ? + " 64G" : "" : "", + a0->fc_sp_cc10 & FC_SP_32 ? " 32G" : "", + a0->fc_sp_cc10 & FC_SP_16 ? " 16G" : "", + a0->fc_sp_cc10 & FC_SP_8 ? " 8G" : "", + a0->fc_sp_cc10 & FC_SP_4 ? " 4G" : "", + a0->fc_sp_cc10 & FC_SP_2 ? " 2G" : "", + a0->fc_sp_cc10 & FC_SP_1 ? " 1G" : ""); + + if (!(ql2xextended_error_logging & ql_dbg_verbose)) + return; + memset(str, 0, STR_LEN); snprintf(str, SFF_VEN_NAME_LEN+1, a0->vendor_name); ql_dbg(ql_dbg_init, vha, 0x015a, @@ -8442,6 +8464,148 @@ bool qla24xx_risc_firmware_invalid(uint32_t *dword) !(~dword[4] | ~dword[5] | ~dword[6] | ~dword[7]); } +static int +qla28xx_get_srisc_addr(scsi_qla_host_t *vha, uint32_t *srisc_addr, + uint32_t faddr) +{ + struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; + uint32_t *dcode; + int rval; + + *srisc_addr = 0; + dcode = (uint32_t *)req->ring; + + rval = qla24xx_read_flash_data(vha, dcode, faddr, 10); + if (rval) { + ql_log(ql_log_fatal, vha, 0x01aa, + "-> Failed to read flash addr + size .\n"); + return QLA_FUNCTION_FAILED; + } + + *srisc_addr = be32_to_cpu((__force __be32)dcode[2]); + return QLA_SUCCESS; +} + +static int +qla28xx_load_fw_template(scsi_qla_host_t *vha, uint32_t faddr) +{ + struct qla_hw_data *ha = vha->hw; + struct fwdt *fwdt = ha->fwdt; + struct req_que *req = ha->req_q_map[0]; + uint32_t risc_size, risc_attr = 0; + uint templates, segments, fragment; + uint32_t *dcode; + ulong dlen; + int rval; + uint j; + + dcode = (uint32_t *)req->ring; + segments = FA_RISC_CODE_SEGMENTS; + + for (j = 0; j < segments; j++) { + rval = qla24xx_read_flash_data(vha, dcode, faddr, 10); + if (rval) { + ql_log(ql_log_fatal, vha, 0x01a1, + "-> Failed to read flash addr + size .\n"); + return QLA_FUNCTION_FAILED; + } + + risc_size = be32_to_cpu((__force __be32)dcode[3]); + + if (risc_attr == 0) + risc_attr = be32_to_cpu((__force __be32)dcode[9]); + + dlen = ha->fw_transfer_size >> 2; + for (fragment = 0; fragment < risc_size; fragment++) { + if (dlen > risc_size) + dlen = risc_size; + + faddr += dlen; + risc_size -= dlen; + } + } + + templates = (risc_attr & BIT_9) ? 2 : 1; + + ql_dbg(ql_dbg_init, vha, 0x01a1, "-> templates = %u\n", templates); + + for (j = 0; j < templates; j++, fwdt++) { + vfree(fwdt->template); + fwdt->template = NULL; + fwdt->length = 0; + + dcode = (uint32_t *)req->ring; + + rval = qla24xx_read_flash_data(vha, dcode, faddr, 7); + if (rval) { + ql_log(ql_log_fatal, vha, 0x01a2, + "-> Unable to read template size.\n"); + goto failed; + } + + risc_size = be32_to_cpu((__force __be32)dcode[2]); + ql_dbg(ql_dbg_init, vha, 0x01a3, + "-> fwdt%u template array at %#x (%#x dwords)\n", + j, faddr, risc_size); + if (!risc_size || !~risc_size) { + ql_dbg(ql_dbg_init, vha, 0x01a4, + "-> fwdt%u failed to read array\n", j); + goto failed; + } + + /* skip header and ignore checksum */ + faddr += 7; + risc_size -= 8; + + ql_dbg(ql_dbg_init, vha, 0x01a5, + "-> fwdt%u template allocate template %#x words...\n", + j, risc_size); + fwdt->template = vmalloc(risc_size * sizeof(*dcode)); + if (!fwdt->template) { + ql_log(ql_log_warn, vha, 0x01a6, + "-> fwdt%u failed allocate template.\n", j); + goto failed; + } + + dcode = fwdt->template; + rval = qla24xx_read_flash_data(vha, dcode, faddr, risc_size); + + if (rval || !qla27xx_fwdt_template_valid(dcode)) { + ql_log(ql_log_warn, vha, 0x01a7, + "-> fwdt%u failed template validate (rval %x)\n", + j, rval); + goto failed; + } + + dlen = qla27xx_fwdt_template_size(dcode); + ql_dbg(ql_dbg_init, vha, 0x01a7, + "-> fwdt%u template size %#lx bytes (%#lx words)\n", + j, dlen, dlen / sizeof(*dcode)); + if (dlen > risc_size * sizeof(*dcode)) { + ql_log(ql_log_warn, vha, 0x01a8, + "-> fwdt%u template exceeds array (%-lu bytes)\n", + j, dlen - risc_size * sizeof(*dcode)); + goto failed; + } + + fwdt->length = dlen; + ql_dbg(ql_dbg_init, vha, 0x01a9, + "-> fwdt%u loaded template ok\n", j); + + faddr += risc_size + 1; + } + + return QLA_SUCCESS; + +failed: + vfree(fwdt->template); + fwdt->template = NULL; + fwdt->length = 0; + + return QLA_SUCCESS; +} + static int qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr, uint32_t faddr) @@ -8881,16 +9045,18 @@ int qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) { int rval; + uint32_t f_region = 0; struct qla_hw_data *ha = vha->hw; struct active_regions active_regions = { }; - if (ql2xfwloadbin == 2) + if (ql2xfwloadbin == 2 && !IS_QLA28XX(ha)) goto try_blob_fw; /* FW Load priority: - * 1) Firmware residing in flash. - * 2) Firmware via request-firmware interface (.bin file). - * 3) Golden-Firmware residing in flash -- (limited operation). + * 1) If 28xxx, ROM cmd to load flash firmware. + * 2) Firmware residing in flash. + * 3) Firmware via request-firmware interface (.bin file). + * 4) Golden-Firmware residing in flash -- (limited operation). */ if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) @@ -8898,6 +9064,40 @@ qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) qla27xx_get_active_image(vha, &active_regions); + /* For 28XXX, always load the flash firmware using rom mbx */ + if (IS_QLA28XX_SECURED(ha)) { + rval = qla28xx_load_flash_firmware(vha); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_fatal, vha, 0x019e, + "Failed to load flash firmware.\n"); + goto exit_load_risc; + } + + f_region = + (active_regions.global != QLA27XX_SECONDARY_IMAGE) ? + ha->flt_region_fw : ha->flt_region_fw_sec; + + ql_log(ql_log_info, vha, 0x019f, + "Load flash firmware successful (%s).\n", + ((active_regions.global != QLA27XX_SECONDARY_IMAGE) ? + "Primary" : "Secondary")); + + rval = qla28xx_get_srisc_addr(vha, srisc_addr, f_region); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x019f, + "failed to read srisc address\n"); + goto exit_load_risc; + } + + rval = qla28xx_load_fw_template(vha, f_region); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x01a0, + "failed to read firmware template\n"); + } + + goto exit_load_risc; + } + if (active_regions.global != QLA27XX_SECONDARY_IMAGE) goto try_primary_fw; @@ -8927,6 +9127,8 @@ qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) ql_log(ql_log_info, vha, 0x009a, "Need firmware flash update.\n"); ha->flags.running_gold_fw = 1; + +exit_load_risc: return rval; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index a3971afc2dd1..a4dda4fcb52c 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1669,13 +1669,28 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) /* Port logout */ fcport = qla2x00_find_fcport_by_loopid(vha, mb[1]); - if (!fcport) + if (!fcport) { + ql_dbg(ql_dbg_async, vha, 0x5011, + "Could not find fcport:%04x %04x %04x\n", + mb[1], mb[2], mb[3]); break; - if (atomic_read(&fcport->state) != FCS_ONLINE) + } + + if (atomic_read(&fcport->state) != FCS_ONLINE) { + ql_dbg(ql_dbg_async, vha, 0x5012, + "Port state is not online State:0x%x \n", + atomic_read(&fcport->state)); + ql_dbg(ql_dbg_async, vha, 0x5012, + "Scheduling session for deletion \n"); + fcport->logout_on_delete = 0; + qlt_schedule_sess_for_deletion(fcport); break; + } + ql_dbg(ql_dbg_async, vha, 0x508a, "Marking port lost loopid=%04x portid=%06x.\n", fcport->loop_id, fcport->d_id.b24); + if (qla_ini_mode_enabled(vha)) { fcport->logout_on_delete = 0; qlt_schedule_sess_for_deletion(fcport); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 1f01576f044b..0d598be6f3ea 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -43,6 +43,7 @@ static struct rom_cmd { } rom_cmds[] = { { MBC_LOAD_RAM }, { MBC_EXECUTE_FIRMWARE }, + { MBC_LOAD_FLASH_FIRMWARE }, { MBC_READ_RAM_WORD }, { MBC_MAILBOX_REGISTER_TEST }, { MBC_VERIFY_CHECKSUM }, @@ -824,6 +825,53 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) return rval; } +/* + * qla2x00_load_flash_firmware + * Load firmware from flash. + * + * Input: + * vha = adapter block pointer. + * + * Returns: + * qla28xx local function return status code. + * + * Context: + * Kernel context. + */ +int +qla28xx_load_flash_firmware(scsi_qla_host_t *vha) +{ + struct qla_hw_data *ha = vha->hw; + int rval = QLA_COMMAND_ERROR; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA28XX(ha)) + return rval; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x11a6, + "Entered %s.\n", __func__); + + mcp->mb[0] = MBC_LOAD_FLASH_FIRMWARE; + mcp->out_mb = MBX_2 | MBX_1 | MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_log_info, vha, 0x11a7, + "Failed=%x cmd error=%x img error=%x.\n", + rval, mcp->mb[1], mcp->mb[2]); + } else { + ql_dbg(ql_log_info, vha, 0x11a8, + "Done %s.\n", __func__); + } + + return rval; +} + + /* * qla_get_exlogin_status * Get extended login status @@ -7157,3 +7205,43 @@ int qla_mailbox_passthru(scsi_qla_host_t *vha, return rval; } + +int qla_mpipt_validate_fw(scsi_qla_host_t *vha, u16 img_idx, uint16_t *state) +{ + struct qla_hw_data *ha = vha->hw; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + int rval; + + if (!IS_QLA28XX(ha)) { + ql_dbg(ql_dbg_mbx, vha, 0xffff, "%s %d\n", __func__, __LINE__); + return QLA_FUNCTION_FAILED; + } + + if (img_idx > 1) { + ql_log(ql_log_info, vha, 0xffff, + "%s %d Invalid flash image index [%d]\n", + __func__, __LINE__, img_idx); + return QLA_INVALID_COMMAND; + } + + memset(&mc, 0, sizeof(mc)); + mcp->mb[0] = MBC_MPI_PASSTHROUGH; + mcp->mb[1] = MPIPT_SUBCMD_VALIDATE_FW; + mcp->mb[2] = img_idx; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_2|MBX_1|MBX_0; + + /* send mb via iocb */ + rval = qla24xx_send_mb_cmd(vha, &mc); + if (rval) { + ql_log(ql_log_info, vha, 0xffff, "%s:Failed %x (mb=%x,%x)\n", + __func__, rval, mcp->mb[0], mcp->mb[1]); + *state = mcp->mb[1]; + } else { + ql_log(ql_log_info, vha, 0xffff, "%s: mb=%x,%x,%x\n", __func__, + mcp->mb[0], mcp->mb[1], mcp->mb[2]); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index 5d1bdc15b75c..8e7a7f5f0adb 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -892,6 +892,7 @@ struct ct6_dsd { #define FA_VPD_SIZE_82XX 0x400 #define FA_FLASH_LAYOUT_ADDR_82 0xFC400 +#define FA_FLASH_MCU_OFF 0x13000 /****************************************************************************** * diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 16a44c0917e1..08d2dcf6d7da 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -402,8 +402,9 @@ static int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t, struct req_que **, struct rsp_que **); static void qla2x00_free_fw_dump(struct qla_hw_data *); static void qla2x00_mem_free(struct qla_hw_data *); -int qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, - struct qla_qpair *qpair); +static enum scsi_qc_status qla2xxx_mqueuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd, + struct qla_qpair *qpair); /* -------------------------------------------------------------------------- */ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req, @@ -858,8 +859,8 @@ void qla2xxx_qpair_sp_compl(srb_t *sp, int res) complete(comp); } -static int -qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +static enum scsi_qc_status qla2xxx_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { scsi_qla_host_t *vha = shost_priv(host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; @@ -981,9 +982,9 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) } /* For MQ supported I/O */ -int +static enum scsi_qc_status qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, - struct qla_qpair *qpair) + struct qla_qpair *qpair) { scsi_qla_host_t *vha = shost_priv(host); fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; @@ -1183,7 +1184,8 @@ qla2x00_wait_for_hba_ready(scsi_qla_host_t *vha) while ((qla2x00_reset_active(vha) || ha->dpc_active || ha->flags.mbox_busy) || test_bit(FX00_RESET_RECOVERY, &vha->dpc_flags) || - test_bit(FX00_TARGET_SCAN, &vha->dpc_flags)) { + test_bit(FX00_TARGET_SCAN, &vha->dpc_flags) || + (vha->scan.scan_flags & SF_SCANNING)) { if (test_bit(UNLOADING, &base_vha->dpc_flags)) break; msleep(1000); diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 9e7a407ba1b9..b6c36a8a2d60 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -1084,6 +1084,32 @@ qla2xxx_get_idc_param(scsi_qla_host_t *vha) return; } +static int qla28xx_validate_mcu_signature(scsi_qla_host_t *vha) +{ + struct qla_hw_data *ha = vha->hw; + struct req_que *req = ha->req_q_map[0]; + uint32_t *dcode = (uint32_t *)req->ring; + uint32_t signature[2] = {0x000c0000, 0x00050000}; + int ret = QLA_SUCCESS; + + ret = qla24xx_read_flash_data(vha, dcode, FA_FLASH_MCU_OFF >> 2, 2); + if (ret) { + ql_log(ql_log_fatal, vha, 0x01ab, + "-> Failed to read flash mcu signature.\n"); + ret = QLA_FUNCTION_FAILED; + goto done; + } + + ql_dbg(ql_dbg_init, vha, 0x01ac, + "Flash data 0x%08x 0x%08x.\n", dcode[0], dcode[1]); + + if (!(dcode[0] == signature[0] && dcode[1] == signature[1])) + ret = QLA_FUNCTION_FAILED; + +done: + return ret; +} + int qla2xxx_get_flash_info(scsi_qla_host_t *vha) { @@ -1096,6 +1122,9 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha) !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) return QLA_SUCCESS; + if (IS_QLA28XX(ha) && !qla28xx_validate_mcu_signature(vha)) + ha->flags.secure_mcu = 1; + ret = qla2xxx_find_flt_start(vha, &flt_addr); if (ret != QLA_SUCCESS) return ret; diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index d772136984c9..ef3a5fac2b48 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -8390,7 +8390,7 @@ int __init qlt_init(void) goto out_plogi_cachep; } - qla_tgt_wq = alloc_workqueue("qla_tgt_wq", 0, 0); + qla_tgt_wq = alloc_workqueue("qla_tgt_wq", WQ_PERCPU, 0); if (!qla_tgt_wq) { ql_log(ql_log_fatal, NULL, 0xe06f, "alloc_workqueue for qla_tgt_wq failed\n"); diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index a491d6ee5c94..9564beafdab7 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -6,9 +6,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.02.09.400-k" +#define QLA2XXX_VERSION "10.02.10.100-k" #define QLA_DRIVER_MAJOR_VER 10 -#define QLA_DRIVER_MINOR_VER 2 -#define QLA_DRIVER_PATCH_VER 9 -#define QLA_DRIVER_BETA_VER 400 +#define QLA_DRIVER_MINOR_VER 02 +#define QLA_DRIVER_PATCH_VER 10 +#define QLA_DRIVER_BETA_VER 100 diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 2fff68935338..b00ae7a664da 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1901,7 +1901,7 @@ static int tcm_qla2xxx_register_configfs(void) goto out_fabric; tcm_qla2xxx_free_wq = alloc_workqueue("tcm_qla2xxx_free", - WQ_MEM_RECLAIM, 0); + WQ_MEM_RECLAIM | WQ_PERCPU, 0); if (!tcm_qla2xxx_free_wq) { ret = -ENOMEM; goto out_fabric_npiv; diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 97329c97332f..d598ab4126f8 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -155,7 +155,8 @@ static int qla4xxx_get_host_stats(struct Scsi_Host *shost, char *buf, int len); /* * SCSI host template entry points */ -static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); +static enum scsi_qc_status qla4xxx_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *cmd); static int qla4xxx_eh_abort(struct scsi_cmnd *cmd); static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); @@ -4107,7 +4108,8 @@ void qla4xxx_srb_compl(struct kref *ref) * completion handling). Unfortunately, it sometimes calls the scheduler * in interrupt context which is a big NO! NO!. **/ -static int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +static enum scsi_qc_status qla4xxx_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { struct scsi_qla_host *ha = to_qla_host(host); struct ddb_entry *ddb_entry = cmd->device->hostdata; @@ -8819,7 +8821,7 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev, } INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); - ha->task_wq = alloc_workqueue("qla4xxx_%lu_task", WQ_MEM_RECLAIM, 1, + ha->task_wq = alloc_workqueue("qla4xxx_%lu_task", WQ_MEM_RECLAIM | WQ_PERCPU, 1, ha->host_no); if (!ha->task_wq) { ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n"); diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c index 1ce469b7db99..d36293bc2717 100644 --- a/drivers/scsi/qlogicfas408.c +++ b/drivers/scsi/qlogicfas408.c @@ -464,7 +464,7 @@ irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id) * Queued command */ -static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); diff --git a/drivers/scsi/qlogicfas408.h b/drivers/scsi/qlogicfas408.h index 83ef86c71f2f..a589c7656f57 100644 --- a/drivers/scsi/qlogicfas408.h +++ b/drivers/scsi/qlogicfas408.h @@ -104,7 +104,8 @@ struct qlogicfas408_priv { #define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0]) irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id); -int qlogicfas408_queuecommand(struct Scsi_Host *h, struct scsi_cmnd * cmd); +enum scsi_qc_status qlogicfas408_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *cmd); int qlogicfas408_biosparam(struct scsi_device * disk, struct gendisk *unused, sector_t capacity, int ip[]); diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index c9984ef57f26..ea0a2b5a0a42 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1015,7 +1015,7 @@ static int qlogicpti_sdev_configure(struct scsi_device *sdev, * * "This code must fly." -davem */ -static int qlogicpti_queuecommand_lck(struct scsi_cmnd *Cmnd) +static enum scsi_qc_status qlogicpti_queuecommand_lck(struct scsi_cmnd *Cmnd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct Scsi_Host *host = Cmnd->device->host; diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 1f2a53ba5dd9..b8c1c77e9c78 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1371,8 +1371,7 @@ static void mk_sense_invalid_fld(struct scsi_cmnd *scp, sbuff = scp->sense_buffer; if (!sbuff) { - sdev_printk(KERN_ERR, scp->device, - "%s: sense_buffer is NULL\n", __func__); + sdev_printk(KERN_ERR, scp->device, "sense_buffer is NULL\n"); return; } asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; @@ -1404,8 +1403,7 @@ static void mk_sense_invalid_fld(struct scsi_cmnd *scp, static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) { if (!scp->sense_buffer) { - sdev_printk(KERN_ERR, scp->device, - "%s: sense_buffer is NULL\n", __func__); + sdev_printk(KERN_ERR, scp->device, "sense_buffer is NULL\n"); return; } memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); @@ -1423,8 +1421,7 @@ static void mk_sense_info_tape(struct scsi_cmnd *scp, int key, int asc, int asq, unsigned int information, unsigned char tape_flags) { if (!scp->sense_buffer) { - sdev_printk(KERN_ERR, scp->device, - "%s: sense_buffer is NULL\n", __func__); + sdev_printk(KERN_ERR, scp->device, "sense_buffer is NULL\n"); return; } memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); @@ -1452,15 +1449,12 @@ static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd, { if (sdebug_verbose) { if (0x1261 == cmd) - sdev_printk(KERN_INFO, dev, - "%s: BLKFLSBUF [0x1261]\n", __func__); + sdev_printk(KERN_INFO, dev, "BLKFLSBUF [0x1261]\n"); else if (0x5331 == cmd) sdev_printk(KERN_INFO, dev, - "%s: CDROM_GET_CAPABILITY [0x5331]\n", - __func__); + "CDROM_GET_CAPABILITY [0x5331]\n"); else - sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", - __func__, cmd); + sdev_printk(KERN_INFO, dev, "cmd=0x%x\n", cmd); } return -EINVAL; /* return -ENOTTY; // correct return but upsets fdisk */ @@ -1664,8 +1658,8 @@ static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, arr, arr_len, skip); - pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", - __func__, off_dst, scsi_bufflen(scp), act_len, + pr_debug("off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", + off_dst, scsi_bufflen(scp), act_len, scsi_get_resid(scp)); n = scsi_bufflen(scp) - (off_dst + act_len); scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n)); @@ -3188,8 +3182,8 @@ static int resp_mode_select(struct scsi_cmnd *scp, return DID_ERROR << 16; else if (sdebug_verbose && (res < param_len)) sdev_printk(KERN_INFO, scp->device, - "%s: cdb indicated=%d, IO sent=%d bytes\n", - __func__, param_len, res); + "cdb indicated=%d, IO sent=%d bytes\n", + param_len, res); md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); off = (mselect6 ? 4 : 8); @@ -5133,8 +5127,7 @@ static int resp_write_scat(struct scsi_cmnd *scp, if (lbdof == 0) { if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: LB Data Offset field bad\n", - my_name, __func__); + "%s: LB Data Offset field bad\n", my_name); mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return illegal_condition_result; } @@ -5142,8 +5135,7 @@ static int resp_write_scat(struct scsi_cmnd *scp, if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) { if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: LBA range descriptors don't fit\n", - my_name, __func__); + "%s: LBA range descriptors don't fit\n", my_name); mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return illegal_condition_result; } @@ -5152,8 +5144,8 @@ static int resp_write_scat(struct scsi_cmnd *scp, return SCSI_MLQUEUE_HOST_BUSY; if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n", - my_name, __func__, lbdof_blen); + "%s: Fetch header+scatter_list, lbdof_blen=%u\n", + my_name, lbdof_blen); res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen); if (res == -1) { ret = DID_ERROR << 16; @@ -5170,8 +5162,8 @@ static int resp_write_scat(struct scsi_cmnd *scp, num = get_unaligned_be32(up + 8); if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n", - my_name, __func__, k, lba, num, sg_off); + "%s: k=%d LBA=0x%llx num=%u sg_off=%u\n", + my_name, k, lba, num, sg_off); if (num == 0) continue; ret = check_device_access_params(scp, lba, num, true); @@ -5183,8 +5175,8 @@ static int resp_write_scat(struct scsi_cmnd *scp, if ((cum_lb + num) > bt_len) { if (sdebug_verbose) sdev_printk(KERN_INFO, scp->device, - "%s: %s: sum of blocks > data provided\n", - my_name, __func__); + "%s: sum of blocks > data provided\n", + my_name); mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC, 0); ret = illegal_condition_result; @@ -5876,8 +5868,8 @@ static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) goto cleanup; } else if (sdebug_verbose && (ret < (a_num * lb_size))) { sdev_printk(KERN_INFO, scp->device, - "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", - my_name, __func__, a_num * lb_size, ret); + "%s: cdb indicated=%u, IO sent=%d bytes\n", + my_name, a_num * lb_size, ret); } if (is_bytchk3) { for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size) @@ -6404,11 +6396,6 @@ static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) atomic_inc(&sdebug_miss_cpus); } - if (!scp) { - pr_err("scmd=NULL\n"); - return; - } - spin_lock_irqsave(&sdsc->lock, flags); aborted = sd_dp->aborted; if (unlikely(aborted)) @@ -6685,14 +6672,14 @@ static int scsi_debug_sdev_configure(struct scsi_device *sdp, devip->debugfs_entry = debugfs_create_dir(dev_name(&sdp->sdev_dev), sdebug_debugfs_root); if (IS_ERR_OR_NULL(devip->debugfs_entry)) - pr_info("%s: failed to create debugfs directory for device %s\n", - __func__, dev_name(&sdp->sdev_gendev)); + pr_info("failed to create debugfs directory for device %s\n", + dev_name(&sdp->sdev_gendev)); dentry = debugfs_create_file("error", 0600, devip->debugfs_entry, sdp, &sdebug_error_fops); if (IS_ERR_OR_NULL(dentry)) - pr_info("%s: failed to create error file for device %s\n", - __func__, dev_name(&sdp->sdev_gendev)); + pr_info("failed to create error file for device %s\n", + dev_name(&sdp->sdev_gendev)); return 0; } @@ -6734,7 +6721,7 @@ static bool scsi_debug_stop_cmnd(struct scsi_cmnd *cmnd) { struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd); struct sdebug_defer *sd_dp = &sdsc->sd_dp; - enum sdeb_defer_type defer_t = READ_ONCE(sd_dp->defer_t); + enum sdeb_defer_type defer_t = sd_dp->defer_t; lockdep_assert_held(&sdsc->lock); @@ -6880,7 +6867,7 @@ static int scsi_debug_abort(struct scsi_cmnd *SCpnt) if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) sdev_printk(KERN_INFO, SCpnt->device, - "%s: command%s found\n", __func__, + "command%s found\n", aborted ? "" : " not"); @@ -6968,7 +6955,7 @@ static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) ++num_dev_resets; if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, sdp, "%s\n", __func__); + sdev_printk(KERN_INFO, sdp, "doing device reset"); scsi_debug_stop_all_queued(sdp); if (devip) { @@ -7008,7 +6995,7 @@ static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) ++num_target_resets; if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, sdp, "%s\n", __func__); + sdev_printk(KERN_INFO, sdp, "doing target reset\n"); list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { if (devip->target == sdp->id) { @@ -7021,7 +7008,7 @@ static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) sdev_printk(KERN_INFO, sdp, - "%s: %d device(s) found in target\n", __func__, k); + "%d device(s) found in target\n", k); if (sdebug_fail_target_reset(SCpnt)) { scmd_printk(KERN_INFO, SCpnt, "fail target reset 0x%x\n", @@ -7042,7 +7029,7 @@ static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) ++num_bus_resets; if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, sdp, "%s\n", __func__); + sdev_printk(KERN_INFO, sdp, "doing bus reset\n"); list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); @@ -7053,7 +7040,7 @@ static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) sdev_printk(KERN_INFO, sdp, - "%s: %d device(s) found in host\n", __func__, k); + "%d device(s) found in host\n", k); return SUCCESS; } @@ -7065,7 +7052,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) ++num_host_resets; if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); + sdev_printk(KERN_INFO, SCpnt->device, "doing host reset\n"); mutex_lock(&sdebug_host_list_mutex); list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { list_for_each_entry(devip, &sdbg_host->dev_info_list, @@ -7080,7 +7067,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) stop_all_queued(); if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) sdev_printk(KERN_INFO, SCpnt->device, - "%s: %d device(s) found\n", __func__, k); + "%d device(s) found\n", k); return SUCCESS; } @@ -7231,8 +7218,8 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, scsi_result = device_qfull_result; if (unlikely(SDEBUG_OPT_Q_NOISE & sdebug_opts)) - sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, status: TASK SET FULL\n", - __func__, num_in_q); + sdev_printk(KERN_INFO, sdp, "num_in_q=%d +1, status: TASK SET FULL\n", + num_in_q); } } @@ -7258,8 +7245,8 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, } if (unlikely(sdebug_verbose && cmnd->result)) - sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", - __func__, cmnd->result); + sdev_printk(KERN_INFO, sdp, "non-zero result=0x%x\n", + cmnd->result); if (delta_jiff > 0 || ndelay > 0) { ktime_t kt; @@ -7296,12 +7283,12 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, if (polled) { spin_lock_irqsave(&sdsc->lock, flags); sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt); - WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); + sd_dp->defer_t = SDEB_DEFER_POLL; spin_unlock_irqrestore(&sdsc->lock, flags); } else { /* schedule the invocation of scsi_done() for a later time */ spin_lock_irqsave(&sdsc->lock, flags); - WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT); + sd_dp->defer_t = SDEB_DEFER_HRT; hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); /* * The completion handler will try to grab sqcp->lock, @@ -7325,11 +7312,11 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, if (polled) { spin_lock_irqsave(&sdsc->lock, flags); sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot); - WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); + sd_dp->defer_t = SDEB_DEFER_POLL; spin_unlock_irqrestore(&sdsc->lock, flags); } else { spin_lock_irqsave(&sdsc->lock, flags); - WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ); + sd_dp->defer_t = SDEB_DEFER_WQ; schedule_work(&sd_dp->ew.work); spin_unlock_irqrestore(&sdsc->lock, flags); } @@ -8697,7 +8684,7 @@ static int __init scsi_debug_init(void) sdebug_debugfs_root = debugfs_create_dir("scsi_debug", NULL); if (IS_ERR_OR_NULL(sdebug_debugfs_root)) - pr_info("%s: failed to create initial debugfs directory\n", __func__); + pr_info("failed to create initial debugfs directory\n"); for (k = 0; k < hosts_to_add; k++) { if (want_store && k == 0) { @@ -8813,7 +8800,7 @@ static int sdebug_add_store(void) if (unlikely(res < 0)) { xa_unlock_irqrestore(per_store_ap, iflags); kfree(sip); - pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res); + pr_warn("xa_alloc() errno=%d\n", -res); return res; } sdeb_most_recent_idx = n_idx; @@ -8870,7 +8857,7 @@ static int sdebug_add_store(void) return (int)n_idx; err: sdebug_erase_store((int)n_idx, sip); - pr_warn("%s: failed, errno=%d\n", __func__, -res); + pr_warn("failed, errno=%d\n", -res); return res; } @@ -8929,7 +8916,7 @@ static int sdebug_add_host_helper(int per_host_idx) put_device(&sdbg_host->dev); else kfree(sdbg_host); - pr_warn("%s: failed, errno=%d\n", __func__, -error); + pr_warn("failed, errno=%d\n", -error); return error; } @@ -8997,7 +8984,7 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) if (qdepth > SDEBUG_CANQUEUE) { qdepth = SDEBUG_CANQUEUE; - pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__, + pr_warn("requested qdepth [%d] exceeds canqueue [%d], trim\n", qdepth, SDEBUG_CANQUEUE); } if (qdepth < 1) @@ -9009,7 +8996,7 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) mutex_unlock(&sdebug_host_list_mutex); if (SDEBUG_OPT_Q_NOISE & sdebug_opts) - sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d\n", __func__, qdepth); + sdev_printk(KERN_INFO, sdev, "qdepth=%d\n", qdepth); return sdev->queue_depth; } @@ -9133,7 +9120,7 @@ static bool sdebug_blk_mq_poll_iter(struct request *rq, void *opaque) spin_lock_irqsave(&sdsc->lock, flags); sd_dp = &sdsc->sd_dp; - if (READ_ONCE(sd_dp->defer_t) != SDEB_DEFER_POLL) { + if (sd_dp->defer_t != SDEB_DEFER_POLL) { spin_unlock_irqrestore(&sdsc->lock, flags); return true; } @@ -9282,8 +9269,7 @@ static void scsi_debug_abort_cmd(struct Scsi_Host *shost, struct scsi_cmnd *scp) bool res = false; if (!to_be_aborted_scmd) { - pr_err("%s: command with tag %#x not found\n", __func__, - unique_tag); + pr_err("command with tag %#x not found\n", unique_tag); return; } @@ -9291,17 +9277,16 @@ static void scsi_debug_abort_cmd(struct Scsi_Host *shost, struct scsi_cmnd *scp) res = scsi_debug_stop_cmnd(to_be_aborted_scmd); if (res) - pr_info("%s: aborted command with tag %#x\n", - __func__, unique_tag); + pr_info("aborted command with tag %#x\n", unique_tag); else - pr_err("%s: failed to abort command with tag %#x\n", - __func__, unique_tag); + pr_err("failed to abort command with tag %#x\n", unique_tag); set_host_byte(scp, res ? DID_OK : DID_ERROR); } -static int scsi_debug_process_reserved_command(struct Scsi_Host *shost, - struct scsi_cmnd *scp) +static enum scsi_qc_status +scsi_debug_process_reserved_command(struct Scsi_Host *shost, + struct scsi_cmnd *scp) { struct sdebug_internal_cmd *internal_cmd = scsi_cmd_priv(scp); @@ -9319,8 +9304,8 @@ static int scsi_debug_process_reserved_command(struct Scsi_Host *shost, return 0; } -static int scsi_debug_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *scp) +static enum scsi_qc_status scsi_debug_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *scp) { u8 sdeb_i; struct scsi_device *sdp = scp->device; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 93031326ac3e..3b860b369692 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -76,7 +76,7 @@ int scsi_init_sense_cache(struct Scsi_Host *shost) } static void -scsi_set_blocked(struct scsi_cmnd *cmd, int reason) +scsi_set_blocked(struct scsi_cmnd *cmd, enum scsi_qc_status reason) { struct Scsi_Host *host = cmd->device->host; struct scsi_device *device = cmd->device; @@ -139,7 +139,8 @@ static void scsi_mq_requeue_cmd(struct scsi_cmnd *cmd, unsigned long msecs) * for a requeue after completion, which should only occur in this * file. */ -static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, bool unbusy) +static void __scsi_queue_insert(struct scsi_cmnd *cmd, + enum scsi_qc_status reason, bool unbusy) { struct scsi_device *device = cmd->device; @@ -179,7 +180,7 @@ static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, bool unbusy) * Context: This could be called either from an interrupt context or a normal * process context. */ -void scsi_queue_insert(struct scsi_cmnd *cmd, int reason) +void scsi_queue_insert(struct scsi_cmnd *cmd, enum scsi_qc_status reason) { __scsi_queue_insert(cmd, reason, true); } @@ -1577,7 +1578,7 @@ static void scsi_complete(struct request *rq) * Return: nonzero return request was rejected and device's queue needs to be * plugged. */ -static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) +static enum scsi_qc_status scsi_dispatch_cmd(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; int rtn = 0; @@ -1826,7 +1827,7 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, struct Scsi_Host *shost = sdev->host; struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(req); blk_status_t ret; - int reason; + enum scsi_qc_status reason; WARN_ON_ONCE(cmd->budget_token < 0); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index d07ec15d6c00..7a193cc04e5b 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -102,7 +102,8 @@ void scsi_eh_done(struct scsi_cmnd *scmd); /* scsi_lib.c */ extern void scsi_device_unbusy(struct scsi_device *sdev, struct scsi_cmnd *cmd); -extern void scsi_queue_insert(struct scsi_cmnd *cmd, int reason); +extern void scsi_queue_insert(struct scsi_cmnd *cmd, + enum scsi_qc_status reason); extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); extern void scsi_run_host_queues(struct Scsi_Host *shost); extern void scsi_requeue_run_queue(struct work_struct *work); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 99eb0a30df61..6b8c5c05f294 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -554,10 +554,48 @@ static int scsi_bus_uevent(const struct device *dev, struct kobj_uevent_env *env return 0; } +static int scsi_bus_probe(struct device *dev) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_driver *drv = to_scsi_driver(dev->driver); + + if (drv->probe) + return drv->probe(sdp); + else + return 0; +} + +static void scsi_bus_remove(struct device *dev) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_driver *drv = to_scsi_driver(dev->driver); + + if (drv->remove) + drv->remove(sdp); +} + +static void scsi_bus_shutdown(struct device *dev) +{ + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_driver *drv; + + if (!dev->driver) + return; + + drv = to_scsi_driver(dev->driver); + + if (drv->shutdown) + drv->shutdown(sdp); +} + + const struct bus_type scsi_bus_type = { - .name = "scsi", - .match = scsi_bus_match, + .name = "scsi", + .match = scsi_bus_match, .uevent = scsi_bus_uevent, + .probe = scsi_bus_probe, + .remove = scsi_bus_remove, + .shutdown = scsi_bus_shutdown, #ifdef CONFIG_PM .pm = &scsi_bus_pm_ops, #endif @@ -1554,11 +1592,44 @@ void scsi_remove_target(struct device *dev) } EXPORT_SYMBOL(scsi_remove_target); -int __scsi_register_driver(struct device_driver *drv, struct module *owner) +static int scsi_legacy_probe(struct scsi_device *sdp) +{ + struct device *dev = &sdp->sdev_gendev; + struct device_driver *driver = dev->driver; + + return driver->probe(dev); +} + +static void scsi_legacy_remove(struct scsi_device *sdp) +{ + struct device *dev = &sdp->sdev_gendev; + struct device_driver *driver = dev->driver; + + driver->remove(dev); +} + +static void scsi_legacy_shutdown(struct scsi_device *sdp) +{ + struct device *dev = &sdp->sdev_gendev; + struct device_driver *driver = dev->driver; + + driver->shutdown(dev); +} + +int __scsi_register_driver(struct scsi_driver *sdrv, struct module *owner) { + struct device_driver *drv = &sdrv->gendrv; + drv->bus = &scsi_bus_type; drv->owner = owner; + if (!sdrv->probe && drv->probe) + sdrv->probe = scsi_legacy_probe; + if (!sdrv->remove && drv->remove) + sdrv->remove = scsi_legacy_remove; + if (!sdrv->shutdown && drv->shutdown) + sdrv->shutdown = scsi_legacy_shutdown; + return driver_register(drv); } EXPORT_SYMBOL(__scsi_register_driver); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 987befb02408..b95c46a346fb 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -1328,6 +1328,46 @@ store_fc_rport_fast_io_fail_tmo(struct device *dev, static FC_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR, show_fc_rport_fast_io_fail_tmo, store_fc_rport_fast_io_fail_tmo); +#define fc_rport_encryption(name) \ +static ssize_t fc_rport_encinfo_##name(struct device *cd, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct fc_rport *rport = transport_class_to_rport(cd); \ + struct Scsi_Host *shost = rport_to_shost(rport); \ + struct fc_internal *i = to_fc_internal(shost->transportt); \ + struct fc_encryption_info *info; \ + ssize_t ret = -ENOENT; \ + u32 data; \ + \ + if (i->f->get_fc_rport_enc_info) { \ + info = (i->f->get_fc_rport_enc_info)(rport); \ + if (info) { \ + data = info->name; \ + if (!strcmp(#name, "status")) { \ + ret = scnprintf(buf, \ + FC_RPORT_ENCRYPTION_STATUS_MAX_LEN, \ + "%s\n", \ + data ? "Encrypted" : "Unencrypted"); \ + } \ + } \ + } \ + return ret; \ +} \ +static FC_DEVICE_ATTR(rport, encryption_##name, 0444, fc_rport_encinfo_##name, NULL) \ + +fc_rport_encryption(status); + +static struct attribute *fc_rport_encryption_attrs[] = { + &device_attr_rport_encryption_status.attr, + NULL +}; + +static struct attribute_group fc_rport_encryption_group = { + .name = "encryption", + .attrs = fc_rport_encryption_attrs, +}; + #define fc_rport_fpin_statistic(name) \ static ssize_t fc_rport_fpinstat_##name(struct device *cd, \ struct device_attribute *attr, \ @@ -2633,6 +2673,8 @@ fc_attach_transport(struct fc_function_template *ft) i->rport_attr_cont.ac.attrs = &i->rport_attrs[0]; i->rport_attr_cont.ac.class = &fc_rport_class.class; i->rport_attr_cont.ac.match = fc_rport_match; + if (ft->get_fc_rport_enc_info) + i->rport_attr_cont.encryption = &fc_rport_encryption_group; i->rport_attr_cont.statistics = &fc_rport_statistics_group; transport_container_register(&i->rport_attr_cont); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index f50b92e63201..d76996d6cbc9 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -102,14 +102,9 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_ZBC); #define SD_MINORS 16 -static void sd_config_discard(struct scsi_disk *sdkp, struct queue_limits *lim, - unsigned int mode); static void sd_config_write_same(struct scsi_disk *sdkp, struct queue_limits *lim); static void sd_revalidate_disk(struct gendisk *); -static void sd_unlock_native_capacity(struct gendisk *disk); -static void sd_shutdown(struct device *); -static void scsi_disk_release(struct device *cdev); static DEFINE_IDA(sd_index_ida); @@ -121,6 +116,62 @@ static const char *sd_cache_types[] = { "write back, no read (daft)" }; +static void sd_disable_discard(struct scsi_disk *sdkp) +{ + sdkp->provisioning_mode = SD_LBP_DISABLE; + blk_queue_disable_discard(sdkp->disk->queue); +} + +static void sd_config_discard(struct scsi_disk *sdkp, struct queue_limits *lim, + unsigned int mode) +{ + unsigned int logical_block_size = sdkp->device->sector_size; + unsigned int max_blocks = 0; + + lim->discard_alignment = sdkp->unmap_alignment * logical_block_size; + lim->discard_granularity = max(sdkp->physical_block_size, + sdkp->unmap_granularity * logical_block_size); + sdkp->provisioning_mode = mode; + + switch (mode) { + + case SD_LBP_FULL: + case SD_LBP_DISABLE: + break; + + case SD_LBP_UNMAP: + max_blocks = min_not_zero(sdkp->max_unmap_blocks, + (u32)SD_MAX_WS16_BLOCKS); + break; + + case SD_LBP_WS16: + if (sdkp->device->unmap_limit_for_ws) + max_blocks = sdkp->max_unmap_blocks; + else + max_blocks = sdkp->max_ws_blocks; + + max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS16_BLOCKS); + break; + + case SD_LBP_WS10: + if (sdkp->device->unmap_limit_for_ws) + max_blocks = sdkp->max_unmap_blocks; + else + max_blocks = sdkp->max_ws_blocks; + + max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS10_BLOCKS); + break; + + case SD_LBP_ZERO: + max_blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS10_BLOCKS); + break; + } + + lim->max_hw_discard_sectors = max_blocks * + (logical_block_size >> SECTOR_SHIFT); +} + static void sd_set_flush_flag(struct scsi_disk *sdkp, struct queue_limits *lim) { @@ -698,6 +749,17 @@ static struct attribute *sd_disk_attrs[] = { }; ATTRIBUTE_GROUPS(sd_disk); +static void scsi_disk_release(struct device *dev) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + + ida_free(&sd_index_ida, sdkp->index); + put_device(&sdkp->device->sdev_gendev); + free_opal_dev(sdkp->opal_dev); + + kfree(sdkp); +} + static struct class sd_disk_class = { .name = "scsi_disk", .dev_release = scsi_disk_release, @@ -866,62 +928,6 @@ static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd, return protect; } -static void sd_disable_discard(struct scsi_disk *sdkp) -{ - sdkp->provisioning_mode = SD_LBP_DISABLE; - blk_queue_disable_discard(sdkp->disk->queue); -} - -static void sd_config_discard(struct scsi_disk *sdkp, struct queue_limits *lim, - unsigned int mode) -{ - unsigned int logical_block_size = sdkp->device->sector_size; - unsigned int max_blocks = 0; - - lim->discard_alignment = sdkp->unmap_alignment * logical_block_size; - lim->discard_granularity = max(sdkp->physical_block_size, - sdkp->unmap_granularity * logical_block_size); - sdkp->provisioning_mode = mode; - - switch (mode) { - - case SD_LBP_FULL: - case SD_LBP_DISABLE: - break; - - case SD_LBP_UNMAP: - max_blocks = min_not_zero(sdkp->max_unmap_blocks, - (u32)SD_MAX_WS16_BLOCKS); - break; - - case SD_LBP_WS16: - if (sdkp->device->unmap_limit_for_ws) - max_blocks = sdkp->max_unmap_blocks; - else - max_blocks = sdkp->max_ws_blocks; - - max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS16_BLOCKS); - break; - - case SD_LBP_WS10: - if (sdkp->device->unmap_limit_for_ws) - max_blocks = sdkp->max_unmap_blocks; - else - max_blocks = sdkp->max_ws_blocks; - - max_blocks = min_not_zero(max_blocks, (u32)SD_MAX_WS10_BLOCKS); - break; - - case SD_LBP_ZERO: - max_blocks = min_not_zero(sdkp->max_ws_blocks, - (u32)SD_MAX_WS10_BLOCKS); - break; - } - - lim->max_hw_discard_sectors = max_blocks * - (logical_block_size >> SECTOR_SHIFT); -} - static void *sd_set_special_bvec(struct request *rq, unsigned int data_len) { struct page *page; @@ -1676,9 +1682,10 @@ static int sd_ioctl(struct block_device *bdev, blk_mode_t mode, struct scsi_device *sdp = sdkp->device; void __user *p = (void __user *)arg; int error; - - SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, " - "cmd=0x%x\n", disk->disk_name, cmd)); + + SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, + "sd_ioctl: disk=%s, cmd=0x%x\n", + disk->disk_name, cmd)); if (bdev_is_partition(bdev) && !capable(CAP_SYS_RAWIO)) return -ENOIOCTLCMD; @@ -2177,21 +2184,6 @@ static void scsi_disk_free_disk(struct gendisk *disk) put_device(&sdkp->disk_dev); } -static const struct block_device_operations sd_fops = { - .owner = THIS_MODULE, - .open = sd_open, - .release = sd_release, - .ioctl = sd_ioctl, - .getgeo = sd_getgeo, - .compat_ioctl = blkdev_compat_ptr_ioctl, - .check_events = sd_check_events, - .unlock_native_capacity = sd_unlock_native_capacity, - .report_zones = sd_zbc_report_zones, - .get_unique_id = sd_get_unique_id, - .free_disk = scsi_disk_free_disk, - .pr_ops = &sd_pr_ops, -}; - /** * sd_eh_reset - reset error handling callback * @scmd: sd-issued command that has failed @@ -2602,8 +2594,8 @@ static int sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ if (type > T10_PI_TYPE3_PROTECTION) { - sd_printk(KERN_ERR, sdkp, "formatted with unsupported" \ - " protection type %u. Disabling disk!\n", + sd_printk(KERN_ERR, sdkp, + "formatted with unsupported protection type %u. Disabling disk!\n", type); sdkp->protection_type = 0; return -ENODEV; @@ -2880,8 +2872,8 @@ sd_read_capacity(struct scsi_disk *sdkp, struct queue_limits *lim, if ((sizeof(sdkp->capacity) > 4) && (sdkp->capacity > 0xffffffffULL)) { int old_sector_size = sector_size; - sd_printk(KERN_NOTICE, sdkp, "Very big device. " - "Trying to use READ CAPACITY(16).\n"); + sd_printk(KERN_NOTICE, sdkp, + "Very big device. Trying to use READ CAPACITY(16).\n"); sector_size = read_capacity_16(sdkp, sdp, lim, buffer); if (sector_size < 0) { sd_printk(KERN_NOTICE, sdkp, @@ -2907,17 +2899,17 @@ sd_read_capacity(struct scsi_disk *sdkp, struct queue_limits *lim, */ if (sdp->fix_capacity || (sdp->guess_capacity && (sdkp->capacity & 0x01))) { - sd_printk(KERN_INFO, sdkp, "Adjusting the sector count " - "from its reported value: %llu\n", - (unsigned long long) sdkp->capacity); + sd_printk(KERN_INFO, sdkp, + "Adjusting the sector count from its reported value: %llu\n", + (unsigned long long) sdkp->capacity); --sdkp->capacity; } got_data: if (sector_size == 0) { sector_size = 512; - sd_printk(KERN_NOTICE, sdkp, "Sector size 0 reported, " - "assuming 512.\n"); + sd_printk(KERN_NOTICE, sdkp, + "Sector size 0 reported, assuming 512.\n"); } if (sector_size != 512 && @@ -3122,8 +3114,9 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) if (len < 3) goto bad_sense; else if (len > SD_BUF_SIZE) { - sd_first_printk(KERN_NOTICE, sdkp, "Truncating mode parameter " - "data from %d to %d bytes\n", len, SD_BUF_SIZE); + sd_first_printk(KERN_NOTICE, sdkp, + "Truncating mode parameter data from %d to %d bytes\n", + len, SD_BUF_SIZE); len = SD_BUF_SIZE; } if (modepage == 0x3F && sdp->use_192_bytes_for_3f) @@ -3146,8 +3139,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) */ if (len - offset <= 2) { sd_first_printk(KERN_ERR, sdkp, - "Incomplete mode parameter " - "data\n"); + "Incomplete mode parameter data\n"); goto defaults; } else { modepage = page_code; @@ -3162,8 +3154,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) offset += 2 + buffer[offset+1]; else { sd_first_printk(KERN_ERR, sdkp, - "Incomplete mode " - "parameter data\n"); + "Incomplete mode parameter data\n"); goto defaults; } } @@ -3626,8 +3617,7 @@ static bool sd_validate_min_xfer_size(struct scsi_disk *sdkp) if (min_xfer_bytes & (sdkp->physical_block_size - 1)) { sd_first_printk(KERN_WARNING, sdkp, - "Preferred minimum I/O size %u bytes not a " \ - "multiple of physical block size (%u bytes)\n", + "Preferred minimum I/O size %u bytes not a multiple of physical block size (%u bytes)\n", min_xfer_bytes, sdkp->physical_block_size); sdkp->min_xfer_blocks = 0; return false; @@ -3657,41 +3647,35 @@ static bool sd_validate_opt_xfer_size(struct scsi_disk *sdkp, if (sdkp->opt_xfer_blocks > dev_max) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u logical blocks " \ - "> dev_max (%u logical blocks)\n", + "Optimal transfer size %u logical blocks > dev_max (%u logical blocks)\n", sdkp->opt_xfer_blocks, dev_max); return false; } if (sdkp->opt_xfer_blocks > SD_DEF_XFER_BLOCKS) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u logical blocks " \ - "> sd driver limit (%u logical blocks)\n", + "Optimal transfer size %u logical blocks > sd driver limit (%u logical blocks)\n", sdkp->opt_xfer_blocks, SD_DEF_XFER_BLOCKS); return false; } if (opt_xfer_bytes < PAGE_SIZE) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u bytes < " \ - "PAGE_SIZE (%u bytes)\n", + "Optimal transfer size %u bytes < PAGE_SIZE (%u bytes)\n", opt_xfer_bytes, (unsigned int)PAGE_SIZE); return false; } if (min_xfer_bytes && opt_xfer_bytes % min_xfer_bytes) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u bytes not a " \ - "multiple of preferred minimum block " \ - "size (%u bytes)\n", + "Optimal transfer size %u bytes not a multiple of preferred minimum block size (%u bytes)\n", opt_xfer_bytes, min_xfer_bytes); return false; } if (opt_xfer_bytes & (sdkp->physical_block_size - 1)) { sd_first_printk(KERN_WARNING, sdkp, - "Optimal transfer size %u bytes not a " \ - "multiple of physical block size (%u bytes)\n", + "Optimal transfer size %u bytes not a multiple of physical block size (%u bytes)\n", opt_xfer_bytes, sdkp->physical_block_size); return false; } @@ -3885,6 +3869,21 @@ static void sd_unlock_native_capacity(struct gendisk *disk) sdev->host->hostt->unlock_native_capacity(sdev); } +static const struct block_device_operations sd_fops = { + .owner = THIS_MODULE, + .open = sd_open, + .release = sd_release, + .ioctl = sd_ioctl, + .getgeo = sd_getgeo, + .compat_ioctl = blkdev_compat_ptr_ioctl, + .check_events = sd_check_events, + .unlock_native_capacity = sd_unlock_native_capacity, + .report_zones = sd_zbc_report_zones, + .get_unique_id = sd_get_unique_id, + .free_disk = scsi_disk_free_disk, + .pr_ops = &sd_pr_ops, +}; + /** * sd_format_disk_name - format disk name * @prefix: name prefix - ie. "sd" for SCSI disks @@ -3935,7 +3934,7 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) * sd_probe - called during driver initialization and whenever a * new scsi device is attached to the system. It is called once * for each scsi device (not just disks) present. - * @dev: pointer to device object + * @sdp: pointer to device object * * Returns 0 if successful (or not interested in this scsi device * (e.g. scanner)); 1 when there is an error. @@ -3949,9 +3948,9 @@ static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) * Assume sd_probe is not re-entrant (for time being) * Also think about sd_probe() and sd_remove() running coincidentally. **/ -static int sd_probe(struct device *dev) +static int sd_probe(struct scsi_device *sdp) { - struct scsi_device *sdp = to_scsi_device(dev); + struct device *dev = &sdp->sdev_gendev; struct scsi_disk *sdkp; struct gendisk *gd; int index; @@ -4087,43 +4086,6 @@ static int sd_probe(struct device *dev) return error; } -/** - * sd_remove - called whenever a scsi disk (previously recognized by - * sd_probe) is detached from the system. It is called (potentially - * multiple times) during sd module unload. - * @dev: pointer to device object - * - * Note: this function is invoked from the scsi mid-level. - * This function potentially frees up a device name (e.g. /dev/sdc) - * that could be re-used by a subsequent sd_probe(). - * This function is not called when the built-in sd driver is "exit-ed". - **/ -static int sd_remove(struct device *dev) -{ - struct scsi_disk *sdkp = dev_get_drvdata(dev); - - scsi_autopm_get_device(sdkp->device); - - device_del(&sdkp->disk_dev); - del_gendisk(sdkp->disk); - if (!sdkp->suspended) - sd_shutdown(dev); - - put_disk(sdkp->disk); - return 0; -} - -static void scsi_disk_release(struct device *dev) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - - ida_free(&sd_index_ida, sdkp->index); - put_device(&sdkp->device->sdev_gendev); - free_opal_dev(sdkp->opal_dev); - - kfree(sdkp); -} - static int sd_start_stop_device(struct scsi_disk *sdkp, int start) { unsigned char cmd[6] = { START_STOP }; /* START_VALID */ @@ -4197,8 +4159,9 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start) * the normal SCSI command structure. Wait for the command to * complete. */ -static void sd_shutdown(struct device *dev) +static void sd_shutdown(struct scsi_device *sdp) { + struct device *dev = &sdp->sdev_gendev; struct scsi_disk *sdkp = dev_get_drvdata(dev); if (!sdkp) @@ -4225,6 +4188,32 @@ static void sd_shutdown(struct device *dev) } } +/** + * sd_remove - called whenever a scsi disk (previously recognized by + * sd_probe) is detached from the system. It is called (potentially + * multiple times) during sd module unload. + * @sdp: pointer to device object + * + * Note: this function is invoked from the scsi mid-level. + * This function potentially frees up a device name (e.g. /dev/sdc) + * that could be re-used by a subsequent sd_probe(). + * This function is not called when the built-in sd driver is "exit-ed". + **/ +static void sd_remove(struct scsi_device *sdp) +{ + struct device *dev = &sdp->sdev_gendev; + struct scsi_disk *sdkp = dev_get_drvdata(dev); + + scsi_autopm_get_device(sdkp->device); + + device_del(&sdkp->disk_dev); + del_gendisk(sdkp->disk); + if (!sdkp->suspended) + sd_shutdown(sdp); + + put_disk(sdkp->disk); +} + static inline bool sd_do_start_stop(struct scsi_device *sdev, bool runtime) { return (sdev->manage_system_start_stop && !runtime) || @@ -4368,12 +4357,12 @@ static const struct dev_pm_ops sd_pm_ops = { }; static struct scsi_driver sd_template = { + .probe = sd_probe, + .remove = sd_remove, + .shutdown = sd_shutdown, .gendrv = { .name = "sd", - .probe = sd_probe, .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .remove = sd_remove, - .shutdown = sd_shutdown, .pm = &sd_pm_ops, }, .rescan = sd_rescan, @@ -4417,7 +4406,7 @@ static int __init init_sd(void) goto err_out_class; } - err = scsi_register_driver(&sd_template.gendrv); + err = scsi_register_driver(&sd_template); if (err) goto err_out_driver; @@ -4444,7 +4433,7 @@ static void __exit exit_sd(void) SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); - scsi_unregister_driver(&sd_template.gendrv); + scsi_unregister_driver(&sd_template); mempool_destroy(sd_page_pool); class_unregister(&sd_disk_class); diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 2c61624cb4b0..789b170da652 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -42,9 +42,8 @@ static bool ses_page2_supported(struct enclosure_device *edev) return (ses_dev->page2 != NULL); } -static int ses_probe(struct device *dev) +static int ses_probe(struct scsi_device *sdev) { - struct scsi_device *sdev = to_scsi_device(dev); int err = -ENODEV; if (sdev->type != TYPE_ENCLOSURE) @@ -847,11 +846,6 @@ static int ses_intf_add(struct device *cdev) return err; } -static int ses_remove(struct device *dev) -{ - return 0; -} - static void ses_intf_remove_component(struct scsi_device *sdev) { struct enclosure_device *edev, *prev = NULL; @@ -906,10 +900,9 @@ static struct class_interface ses_interface = { }; static struct scsi_driver ses_template = { + .probe = ses_probe, .gendrv = { .name = "ses", - .probe = ses_probe, - .remove = ses_remove, }, }; @@ -921,7 +914,7 @@ static int __init ses_init(void) if (err) return err; - err = scsi_register_driver(&ses_template.gendrv); + err = scsi_register_driver(&ses_template); if (err) goto out_unreg; @@ -934,7 +927,7 @@ static int __init ses_init(void) static void __exit ses_exit(void) { - scsi_unregister_driver(&ses_template.gendrv); + scsi_unregister_driver(&ses_template); scsi_unregister_interface(&ses_interface); } diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index fe549e2b7c94..36834768fec1 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -6047,7 +6047,8 @@ static bool pqi_is_parity_write_stream(struct pqi_ctrl_info *ctrl_info, return false; } -static int pqi_scsi_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) +static enum scsi_qc_status pqi_scsi_queue_command(struct Scsi_Host *shost, + struct scsi_cmnd *scmd) { int rc; struct pqi_ctrl_info *ctrl_info; diff --git a/drivers/scsi/snic/snic.h b/drivers/scsi/snic/snic.h index 32f5a34b6987..ebaf6d63a59b 100644 --- a/drivers/scsi/snic/snic.h +++ b/drivers/scsi/snic/snic.h @@ -362,7 +362,8 @@ void snic_glob_cleanup(void); extern struct workqueue_struct *snic_event_queue; extern const struct attribute_group *snic_host_groups[]; -int snic_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +enum scsi_qc_status snic_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc); int snic_abort_cmd(struct scsi_cmnd *); int snic_device_reset(struct scsi_cmnd *); int snic_host_reset(struct scsi_cmnd *); diff --git a/drivers/scsi/snic/snic_scsi.c b/drivers/scsi/snic/snic_scsi.c index 84973f0f771e..c6af3b8d2523 100644 --- a/drivers/scsi/snic/snic_scsi.c +++ b/drivers/scsi/snic/snic_scsi.c @@ -315,8 +315,8 @@ snic_issue_scsi_req(struct snic *snic, * Routine to send a scsi cdb to LLD * Called with host_lock held and interrupts disabled */ -int -snic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) +enum scsi_qc_status snic_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc) { struct snic_tgt *tgt = NULL; struct snic *snic = shost_priv(shost); diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index add13e306898..1fb85f548955 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -82,8 +82,8 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM); CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \ CDC_MRW|CDC_MRW_W|CDC_RAM) -static int sr_probe(struct device *); -static int sr_remove(struct device *); +static int sr_probe(struct scsi_device *); +static void sr_remove(struct scsi_device *); static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt); static int sr_done(struct scsi_cmnd *); static int sr_runtime_suspend(struct device *dev); @@ -93,10 +93,10 @@ static const struct dev_pm_ops sr_pm_ops = { }; static struct scsi_driver sr_template = { + .probe = sr_probe, + .remove = sr_remove, .gendrv = { .name = "sr", - .probe = sr_probe, - .remove = sr_remove, .pm = &sr_pm_ops, }, .init_command = sr_init_command, @@ -616,9 +616,9 @@ static void sr_release(struct cdrom_device_info *cdi) { } -static int sr_probe(struct device *dev) +static int sr_probe(struct scsi_device *sdev) { - struct scsi_device *sdev = to_scsi_device(dev); + struct device *dev = &sdev->sdev_gendev; struct gendisk *disk; struct scsi_cd *cd; int minor, error; @@ -982,16 +982,15 @@ static int sr_read_cdda_bpc(struct cdrom_device_info *cdi, void __user *ubuf, return ret; } -static int sr_remove(struct device *dev) +static void sr_remove(struct scsi_device *sdev) { + struct device *dev = &sdev->sdev_gendev; struct scsi_cd *cd = dev_get_drvdata(dev); scsi_autopm_get_device(cd->device); del_gendisk(cd->disk); put_disk(cd->disk); - - return 0; } static int __init init_sr(void) @@ -1001,7 +1000,7 @@ static int __init init_sr(void) rc = register_blkdev(SCSI_CDROM_MAJOR, "sr"); if (rc) return rc; - rc = scsi_register_driver(&sr_template.gendrv); + rc = scsi_register_driver(&sr_template); if (rc) unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); @@ -1010,7 +1009,7 @@ static int __init init_sr(void) static void __exit exit_sr(void) { - scsi_unregister_driver(&sr_template.gendrv); + scsi_unregister_driver(&sr_template); unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); } diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 168f25e4aaa3..40d88bbb4388 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -202,14 +202,14 @@ static int sgl_map_user_pages(struct st_buffer *, const unsigned int, unsigned long, size_t, int); static int sgl_unmap_user_pages(struct st_buffer *, const unsigned int, int); -static int st_probe(struct device *); -static int st_remove(struct device *); +static int st_probe(struct scsi_device *); +static void st_remove(struct scsi_device *); static struct scsi_driver st_template = { + .probe = st_probe, + .remove = st_remove, .gendrv = { .name = "st", - .probe = st_probe, - .remove = st_remove, .groups = st_drv_groups, }, }; @@ -4342,9 +4342,9 @@ static void remove_cdevs(struct scsi_tape *tape) } } -static int st_probe(struct device *dev) +static int st_probe(struct scsi_device *SDp) { - struct scsi_device *SDp = to_scsi_device(dev); + struct device *dev = &SDp->sdev_gendev; struct scsi_tape *tpnt = NULL; struct st_modedef *STm; struct st_partstat *STps; @@ -4499,12 +4499,13 @@ static int st_probe(struct device *dev) }; -static int st_remove(struct device *dev) +static void st_remove(struct scsi_device *SDp) { + struct device *dev = &SDp->sdev_gendev; struct scsi_tape *tpnt = dev_get_drvdata(dev); int index = tpnt->index; - scsi_autopm_get_device(to_scsi_device(dev)); + scsi_autopm_get_device(SDp); remove_cdevs(tpnt); mutex_lock(&st_ref_mutex); @@ -4513,7 +4514,6 @@ static int st_remove(struct device *dev) spin_lock(&st_index_lock); idr_remove(&st_index_idr, index); spin_unlock(&st_index_lock); - return 0; } /** @@ -4576,7 +4576,7 @@ static int __init init_st(void) goto err_class; } - err = scsi_register_driver(&st_template.gendrv); + err = scsi_register_driver(&st_template); if (err) goto err_chrdev; @@ -4592,7 +4592,7 @@ static int __init init_st(void) static void __exit exit_st(void) { - scsi_unregister_driver(&st_template.gendrv); + scsi_unregister_driver(&st_template); unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), ST_MAX_TAPE_ENTRIES); class_unregister(&st_sysfs_class); diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 93c223e0a777..5a3f6fe22ae9 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -593,7 +593,7 @@ stex_sdev_configure(struct scsi_device *sdev, struct queue_limits *lim) return 0; } -static int stex_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status stex_queuecommand_lck(struct scsi_cmnd *cmd) { void (*done)(struct scsi_cmnd *) = scsi_done; struct st_hba *hba; diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 6e4112143c76..19e18939d3a5 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1714,7 +1714,8 @@ static bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd) return allowed; } -static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) +static enum scsi_qc_status storvsc_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *scmnd) { int ret; struct hv_host_device *host_dev = shost_priv(host); diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 57637a81776d..27e22acaf1a7 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -485,7 +485,7 @@ void sym_log_bus_error(struct Scsi_Host *shost) * queuecommand method. Entered with the host adapter lock held and * interrupts disabled. */ -static int sym53c8xx_queue_command_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status sym53c8xx_queue_command_lck(struct scsi_cmnd *cmd) { struct sym_hcb *np = SYM_SOFTC_PTR(cmd); struct sym_ucmd *ucp = SYM_UCMD_PTR(cmd); diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 96a69edddbe5..6b1d8bcd06b9 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -561,8 +561,8 @@ static struct virtio_scsi_vq *virtscsi_pick_vq_mq(struct virtio_scsi *vscsi, return &vscsi->req_vqs[hwq]; } -static int virtscsi_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *sc) +static enum scsi_qc_status virtscsi_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc) { struct virtio_scsi *vscsi = shost_priv(shost); struct virtio_scsi_vq *req_vq = virtscsi_pick_vq_mq(vscsi, sc); diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c index 32242d86cf5b..11f86c76f391 100644 --- a/drivers/scsi/vmw_pvscsi.c +++ b/drivers/scsi/vmw_pvscsi.c @@ -771,7 +771,7 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter, return 0; } -static int pvscsi_queue_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status pvscsi_queue_lck(struct scsi_cmnd *cmd) { struct Scsi_Host *host = cmd->device->host; struct pvscsi_adapter *adapter = shost_priv(host); diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index dd1fef9226f2..1e49d0402f0b 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -302,7 +302,7 @@ calc_sync_msg(unsigned int period, unsigned int offset, unsigned int fast, msg[1] = offset; } -static int wd33c93_queuecommand_lck(struct scsi_cmnd *cmd) +static enum scsi_qc_status wd33c93_queuecommand_lck(struct scsi_cmnd *cmd) { struct scsi_pointer *scsi_pointer = WD33C93_scsi_pointer(cmd); struct WD33C93_hostdata *hostdata; diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h index e5e4254b1477..e1e98280aad1 100644 --- a/drivers/scsi/wd33c93.h +++ b/drivers/scsi/wd33c93.h @@ -332,7 +332,8 @@ static inline struct scsi_pointer *WD33C93_scsi_pointer(struct scsi_cmnd *cmd) void wd33c93_init (struct Scsi_Host *instance, const wd33c93_regs regs, dma_setup_t setup, dma_stop_t stop, int clock_freq); int wd33c93_abort (struct scsi_cmnd *cmd); -int wd33c93_queuecommand (struct Scsi_Host *h, struct scsi_cmnd *cmd); +enum scsi_qc_status wd33c93_queuecommand(struct Scsi_Host *h, + struct scsi_cmnd *cmd); void wd33c93_intr (struct Scsi_Host *instance); int wd33c93_show_info(struct seq_file *, struct Scsi_Host *); int wd33c93_write_info(struct Scsi_Host *, char *, int); diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c index 0c9987828774..830d40f57f6a 100644 --- a/drivers/scsi/wd719x.c +++ b/drivers/scsi/wd719x.c @@ -204,7 +204,8 @@ static void wd719x_finish_cmd(struct wd719x_scb *scb, int result) } /* Build a SCB and send it to the card */ -static int wd719x_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd) +static enum scsi_qc_status wd719x_queuecommand(struct Scsi_Host *sh, + struct scsi_cmnd *cmd) { int i, count_sg; unsigned long flags; diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c index 924025305753..bf36c07c2b47 100644 --- a/drivers/scsi/xen-scsifront.c +++ b/drivers/scsi/xen-scsifront.c @@ -603,8 +603,8 @@ static void scsifront_return(struct vscsifrnt_info *info) wake_up(&info->wq_pause); } -static int scsifront_queuecommand(struct Scsi_Host *shost, - struct scsi_cmnd *sc) +static enum scsi_qc_status scsifront_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *sc) { struct vscsifrnt_info *info = shost_priv(shost); struct vscsifrnt_shadow *shadow = scsi_cmd_priv(sc); diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 01a8e349dc4d..0821a149573e 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -165,7 +165,8 @@ static void tcm_loop_target_queue_cmd(struct tcm_loop_cmd *tl_cmd) * ->queuecommand can be and usually is called from interrupt context, so * defer the actual submission to a workqueue. */ -static int tcm_loop_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) +static enum scsi_qc_status tcm_loop_queuecommand(struct Scsi_Host *sh, + struct scsi_cmnd *sc) { struct tcm_loop_cmd *tl_cmd = scsi_cmd_priv(sc); diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 9f167ff8da7b..09120a538a40 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -1960,12 +1960,12 @@ static struct se_portal_group *sbp_make_tpg(struct se_wwn *wwn, container_of(wwn, struct sbp_tport, tport_wwn); struct sbp_tpg *tpg; - unsigned long tpgt; + u16 tpgt; int ret; if (strstr(name, "tpgt_") != name) return ERR_PTR(-EINVAL); - if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX) + if (kstrtou16(name + 5, 10, &tpgt)) return ERR_PTR(-EINVAL); if (tport->tpg) { diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index f7868b41c5e6..b27a3b8dd767 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -288,7 +288,7 @@ static void target_core_deregister_fabric( config_item_put(item); } -static struct configfs_group_operations target_core_fabric_group_ops = { +static const struct configfs_group_operations target_core_fabric_group_ops = { .make_group = &target_core_register_fabric, .drop_item = &target_core_deregister_fabric, }; @@ -1741,6 +1741,54 @@ static ssize_t target_wwn_vpd_protocol_identifier_show(struct config_item *item, return len; } +static ssize_t target_wwn_pd_text_id_info_show(struct config_item *item, + char *page) +{ + return sysfs_emit(page, "%s\n", &to_t10_wwn(item)->pd_text_id_info[0]); +} + +static ssize_t target_wwn_pd_text_id_info_store(struct config_item *item, + const char *page, size_t count) +{ + struct t10_wwn *t10_wwn = to_t10_wwn(item); + struct se_device *dev = t10_wwn->t10_dev; + + /* +2 to allow for a trailing (stripped) '\n' and null-terminator */ + unsigned char buf[PD_TEXT_ID_INFO_LEN + 2]; + char *stripped; + + /* + * Check to see if any active exports exist. If they do exist, fail + * here as changing this information on the fly (underneath the + * initiator side OS dependent multipath code) could cause negative + * effects. + */ + if (dev->export_count) { + pr_err("Unable to set the peripheral device text id info while active %d exports exist\n", + dev->export_count); + return -EINVAL; + } + + if (strscpy(buf, page, sizeof(buf)) < 0) + return -EOVERFLOW; + + /* Strip any newline added from userspace. */ + stripped = strstrip(buf); + if (strlen(stripped) >= PD_TEXT_ID_INFO_LEN) { + pr_err("Emulated peripheral device text id info exceeds PD_TEXT_ID_INFO_LEN: " __stringify(PD_TEXT_ID_INFO_LEN "\n")); + return -EOVERFLOW; + } + + BUILD_BUG_ON(sizeof(dev->t10_wwn.pd_text_id_info) != PD_TEXT_ID_INFO_LEN); + strscpy(dev->t10_wwn.pd_text_id_info, stripped, + sizeof(dev->t10_wwn.pd_text_id_info)); + + pr_debug("Target_Core_ConfigFS: Set emulated peripheral dev text id info:" + " %s\n", dev->t10_wwn.pd_text_id_info); + + return count; +} + /* * Generic wrapper for dumping VPD identifiers by association. */ @@ -1797,6 +1845,7 @@ CONFIGFS_ATTR_RO(target_wwn_, vpd_protocol_identifier); CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_logical_unit); CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_target_port); CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_scsi_target_device); +CONFIGFS_ATTR(target_wwn_, pd_text_id_info); static struct configfs_attribute *target_core_dev_wwn_attrs[] = { &target_wwn_attr_vendor_id, @@ -1808,6 +1857,7 @@ static struct configfs_attribute *target_core_dev_wwn_attrs[] = { &target_wwn_attr_vpd_assoc_logical_unit, &target_wwn_attr_vpd_assoc_target_port, &target_wwn_attr_vpd_assoc_scsi_target_device, + &target_wwn_attr_pd_text_id_info, NULL, }; @@ -2810,7 +2860,7 @@ static void target_core_alua_lu_gp_release(struct config_item *item) core_alua_free_lu_gp(lu_gp); } -static struct configfs_item_operations target_core_alua_lu_gp_ops = { +static const struct configfs_item_operations target_core_alua_lu_gp_ops = { .release = target_core_alua_lu_gp_release, }; @@ -2867,7 +2917,7 @@ static void target_core_alua_drop_lu_gp( config_item_put(item); } -static struct configfs_group_operations target_core_alua_lu_gps_group_ops = { +static const struct configfs_group_operations target_core_alua_lu_gps_group_ops = { .make_group = &target_core_alua_create_lu_gp, .drop_item = &target_core_alua_drop_lu_gp, }; @@ -3240,7 +3290,7 @@ static void target_core_alua_tg_pt_gp_release(struct config_item *item) core_alua_free_tg_pt_gp(tg_pt_gp); } -static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = { +static const struct configfs_item_operations target_core_alua_tg_pt_gp_ops = { .release = target_core_alua_tg_pt_gp_release, }; @@ -3298,7 +3348,7 @@ static void target_core_alua_drop_tg_pt_gp( config_item_put(item); } -static struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = { +static const struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = { .make_group = &target_core_alua_create_tg_pt_gp, .drop_item = &target_core_alua_drop_tg_pt_gp, }; @@ -3339,7 +3389,7 @@ static void target_core_stat_rmdir( return; } -static struct configfs_group_operations target_core_stat_group_ops = { +static const struct configfs_group_operations target_core_stat_group_ops = { .make_group = &target_core_stat_mkdir, .drop_item = &target_core_stat_rmdir, }; @@ -3466,7 +3516,7 @@ static void target_core_drop_subdev( mutex_unlock(&hba->hba_access_mutex); } -static struct configfs_group_operations target_core_hba_group_ops = { +static const struct configfs_group_operations target_core_hba_group_ops = { .make_group = target_core_make_subdev, .drop_item = target_core_drop_subdev, }; @@ -3545,7 +3595,7 @@ static struct configfs_attribute *target_core_hba_attrs[] = { NULL, }; -static struct configfs_item_operations target_core_hba_item_ops = { +static const struct configfs_item_operations target_core_hba_item_ops = { .release = target_core_hba_release, }; @@ -3626,7 +3676,7 @@ static void target_core_call_delhbafromtarget( config_item_put(item); } -static struct configfs_group_operations target_core_group_ops = { +static const struct configfs_group_operations target_core_group_ops = { .make_group = target_core_call_addhbatotarget, .drop_item = target_core_call_delhbafromtarget, }; diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index 13159928e365..59713e9be10a 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -59,7 +59,7 @@ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) pr_debug("Setup generic %s\n", __stringify(_name)); \ } -static struct configfs_item_operations target_fabric_port_item_ops; +static const struct configfs_item_operations target_fabric_port_item_ops; /* Start of tfc_tpg_mappedlun_cit */ @@ -219,7 +219,7 @@ static void target_fabric_mappedlun_release(struct config_item *item) core_dev_free_initiator_node_lun_acl(se_tpg, lacl); } -static struct configfs_item_operations target_fabric_mappedlun_item_ops = { +static const struct configfs_item_operations target_fabric_mappedlun_item_ops = { .release = target_fabric_mappedlun_release, .allow_link = target_fabric_mappedlun_link, .drop_link = target_fabric_mappedlun_unlink, @@ -246,7 +246,7 @@ static void target_core_mappedlun_stat_rmdir( return; } -static struct configfs_group_operations target_fabric_mappedlun_stat_group_ops = { +static const struct configfs_group_operations target_fabric_mappedlun_stat_group_ops = { .make_group = target_core_mappedlun_stat_mkdir, .drop_item = target_core_mappedlun_stat_rmdir, }; @@ -345,11 +345,11 @@ static void target_fabric_nacl_base_release(struct config_item *item) core_tpg_del_initiator_node_acl(se_nacl); } -static struct configfs_item_operations target_fabric_nacl_base_item_ops = { +static const struct configfs_item_operations target_fabric_nacl_base_item_ops = { .release = target_fabric_nacl_base_release, }; -static struct configfs_group_operations target_fabric_nacl_base_group_ops = { +static const struct configfs_group_operations target_fabric_nacl_base_group_ops = { .make_group = target_fabric_make_mappedlun, .drop_item = target_fabric_drop_mappedlun, }; @@ -433,7 +433,7 @@ static void target_fabric_drop_nodeacl( config_item_put(item); } -static struct configfs_group_operations target_fabric_nacl_group_ops = { +static const struct configfs_group_operations target_fabric_nacl_group_ops = { .make_group = target_fabric_make_nodeacl, .drop_item = target_fabric_drop_nodeacl, }; @@ -454,7 +454,7 @@ static void target_fabric_np_base_release(struct config_item *item) tf->tf_ops->fabric_drop_np(se_tpg_np); } -static struct configfs_item_operations target_fabric_np_base_item_ops = { +static const struct configfs_item_operations target_fabric_np_base_item_ops = { .release = target_fabric_np_base_release, }; @@ -499,7 +499,7 @@ static void target_fabric_drop_np( config_item_put(item); } -static struct configfs_group_operations target_fabric_np_group_ops = { +static const struct configfs_group_operations target_fabric_np_group_ops = { .make_group = &target_fabric_make_np, .drop_item = &target_fabric_drop_np, }; @@ -700,7 +700,7 @@ static void target_fabric_port_release(struct config_item *item) call_rcu(&lun->rcu_head, target_tpg_free_lun); } -static struct configfs_item_operations target_fabric_port_item_ops = { +static const struct configfs_item_operations target_fabric_port_item_ops = { .release = target_fabric_port_release, .allow_link = target_fabric_port_link, .drop_link = target_fabric_port_unlink, @@ -726,7 +726,7 @@ static void target_core_port_stat_rmdir( return; } -static struct configfs_group_operations target_fabric_port_stat_group_ops = { +static const struct configfs_group_operations target_fabric_port_stat_group_ops = { .make_group = target_core_port_stat_mkdir, .drop_item = target_core_port_stat_rmdir, }; @@ -787,7 +787,7 @@ static void target_fabric_drop_lun( config_item_put(item); } -static struct configfs_group_operations target_fabric_lun_group_ops = { +static const struct configfs_group_operations target_fabric_lun_group_ops = { .make_group = &target_fabric_make_lun, .drop_item = &target_fabric_drop_lun, }; @@ -812,7 +812,7 @@ static void target_fabric_tpg_release(struct config_item *item) tf->tf_ops->fabric_drop_tpg(se_tpg); } -static struct configfs_item_operations target_fabric_tpg_base_item_ops = { +static const struct configfs_item_operations target_fabric_tpg_base_item_ops = { .release = target_fabric_tpg_release, }; @@ -998,11 +998,11 @@ static void target_fabric_release_wwn(struct config_item *item) tf->tf_ops->fabric_drop_wwn(wwn); } -static struct configfs_item_operations target_fabric_tpg_item_ops = { +static const struct configfs_item_operations target_fabric_tpg_item_ops = { .release = target_fabric_release_wwn, }; -static struct configfs_group_operations target_fabric_tpg_group_ops = { +static const struct configfs_group_operations target_fabric_tpg_group_ops = { .make_group = target_fabric_make_tpg, .drop_item = target_fabric_drop_tpg, }; @@ -1144,7 +1144,7 @@ static void target_fabric_drop_wwn( config_item_put(item); } -static struct configfs_group_operations target_fabric_wwn_group_ops = { +static const struct configfs_group_operations target_fabric_wwn_group_ops = { .make_group = target_fabric_make_wwn, .drop_item = target_fabric_drop_wwn, }; diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index fe2b888bcb43..f20bc6ea019b 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -25,6 +25,8 @@ #include "target_core_ua.h" #include "target_core_xcopy.h" +#define PD_TEXT_ID_INFO_HDR_LEN 4 + static void spc_fill_alua_data(struct se_lun *lun, unsigned char *buf) { struct t10_alua_tg_pt_gp *tg_pt_gp; @@ -1999,6 +2001,18 @@ static const struct target_opcode_descriptor tcm_opcode_report_supp_opcodes = { .enabled = spc_rsoc_enabled, }; +static struct target_opcode_descriptor tcm_opcode_report_identifying_information = { + .support = SCSI_SUPPORT_FULL, + .serv_action_valid = 1, + .opcode = MAINTENANCE_IN, + .service_action = MI_REPORT_IDENTIFYING_INFORMATION, + .cdb_size = 12, + .usage_bits = {MAINTENANCE_IN, MI_REPORT_IDENTIFYING_INFORMATION, + 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, SCSI_CONTROL_MASK}, +}; + static bool tcm_is_set_tpg_enabled(const struct target_opcode_descriptor *descr, struct se_cmd *cmd) { @@ -2086,6 +2100,7 @@ static const struct target_opcode_descriptor *tcm_supported_opcodes[] = { &tcm_opcode_report_target_pgs, &tcm_opcode_report_supp_opcodes, &tcm_opcode_set_tpg, + &tcm_opcode_report_identifying_information, }; static int @@ -2303,6 +2318,72 @@ spc_emulate_report_supp_op_codes(struct se_cmd *cmd) return ret; } +static sense_reason_t +spc_fill_pd_text_id_info(struct se_cmd *cmd, u8 *cdb) +{ + struct se_device *dev = cmd->se_dev; + unsigned char *buf; + unsigned char *rbuf; + u32 buf_len; + u16 data_len; + + buf_len = get_unaligned_be32(&cdb[6]); + if (buf_len < PD_TEXT_ID_INFO_HDR_LEN) + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + + data_len = strlen(dev->t10_wwn.pd_text_id_info); + if (data_len > 0) + /* trailing null */ + data_len += 1; + + data_len = data_len + PD_TEXT_ID_INFO_HDR_LEN; + + if (data_len < buf_len) + buf_len = data_len; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) { + pr_err("Unable to allocate response buffer for IDENTITY INFO\n"); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } + + scnprintf(&buf[PD_TEXT_ID_INFO_HDR_LEN], buf_len - PD_TEXT_ID_INFO_HDR_LEN, "%s", + dev->t10_wwn.pd_text_id_info); + + put_unaligned_be16(data_len, &buf[2]); + + rbuf = transport_kmap_data_sg(cmd); + if (!rbuf) { + pr_err("transport_kmap_data_sg() failed in %s\n", __func__); + kfree(buf); + return TCM_OUT_OF_RESOURCES; + } + + memcpy(rbuf, buf, buf_len); + transport_kunmap_data_sg(cmd); + kfree(buf); + + target_complete_cmd_with_length(cmd, SAM_STAT_GOOD, buf_len); + return TCM_NO_SENSE; +} + +static sense_reason_t +spc_emulate_report_id_info(struct se_cmd *cmd) +{ + u8 *cdb = cmd->t_task_cdb; + sense_reason_t rc; + + switch ((cdb[10] >> 1)) { + case 2: + rc = spc_fill_pd_text_id_info(cmd, cdb); + break; + default: + return TCM_UNSUPPORTED_SCSI_OPCODE; + } + + return rc; +} + sense_reason_t spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) { @@ -2442,6 +2523,11 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) MI_REPORT_SUPPORTED_OPERATION_CODES) cmd->execute_cmd = spc_emulate_report_supp_op_codes; + if ((cdb[1] & 0x1f) == + MI_REPORT_IDENTIFYING_INFORMATION) { + cmd->execute_cmd = + spc_emulate_report_id_info; + } *size = get_unaligned_be32(&cdb[6]); } else { /* diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index 9ab91b4c05b0..64c234096e23 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -431,8 +431,7 @@ void ufshcd_mcq_disable(struct ufs_hba *hba) void ufshcd_mcq_enable_esi(struct ufs_hba *hba) { - ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x2, - REG_UFS_MEM_CFG); + ufshcd_rmwl(hba, ESI_ENABLE, ESI_ENABLE, REG_UFS_MEM_CFG); } EXPORT_SYMBOL_GPL(ufshcd_mcq_enable_esi); diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index b33f8656edb5..384d958615d7 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -141,7 +141,7 @@ static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev, if (kstrtoul(buf, 0, &value)) return -EINVAL; - if (value >= UFS_PM_LVL_MAX) + if (value >= UFS_PM_LVL_MAX || value < hba->pm_lvl_min) return -EINVAL; if (ufs_pm_lvl_states[value].dev_state == UFS_DEEPSLEEP_PWR_MODE && @@ -1847,6 +1847,7 @@ static ssize_t defrag_trigger_store(struct device *dev, static DEVICE_ATTR_WO(defrag_trigger); +#define UFS_HID_AVAILABLE_SIZE_INVALID 0xFFFFFFFFU static ssize_t fragmented_size_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1859,6 +1860,9 @@ static ssize_t fragmented_size_show(struct device *dev, if (ret) return ret; + if (value == UFS_HID_AVAILABLE_SIZE_INVALID) + return -ENODATA; + return sysfs_emit(buf, "%u\n", value); } diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 80c0b49f30b0..0369043ca010 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -283,7 +283,8 @@ static bool ufshcd_has_pending_tasks(struct ufs_hba *hba) static bool ufshcd_is_ufs_dev_busy(struct ufs_hba *hba) { - return scsi_host_busy(hba->host) || ufshcd_has_pending_tasks(hba); + return (hba->scsi_host_added && scsi_host_busy(hba->host)) || + ufshcd_has_pending_tasks(hba); } static const struct ufs_dev_quirk ufs_fixups[] = { @@ -678,7 +679,8 @@ static void ufshcd_print_host_state(struct ufs_hba *hba) dev_err(hba->dev, "UFS Host state=%d\n", hba->ufshcd_state); dev_err(hba->dev, "%d outstanding reqs, tasks=0x%lx\n", - scsi_host_busy(hba->host), hba->outstanding_tasks); + hba->scsi_host_added ? scsi_host_busy(hba->host) : 0, + hba->outstanding_tasks); dev_err(hba->dev, "saved_err=0x%x, saved_uic_err=0x%x\n", hba->saved_err, hba->saved_uic_err); dev_err(hba->dev, "Device power mode=%d, UIC link state=%d\n", @@ -3031,7 +3033,8 @@ static int ufshcd_init_cmd_priv(struct Scsi_Host *host, struct scsi_cmnd *cmd) * * Return: 0 for success, non-zero in case of failure. */ -static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) +static enum scsi_qc_status ufshcd_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { struct ufs_hba *hba = shost_priv(host); int tag = scsi_cmd_to_rq(cmd)->tag; @@ -3111,8 +3114,8 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) return err; } -static int ufshcd_queue_reserved_command(struct Scsi_Host *host, - struct scsi_cmnd *cmd) +static enum scsi_qc_status ufshcd_queue_reserved_command(struct Scsi_Host *host, + struct scsi_cmnd *cmd) { struct ufshcd_lrb *lrbp = scsi_cmd_priv(cmd); struct request *rq = scsi_cmd_to_rq(cmd); @@ -10525,9 +10528,8 @@ int ufshcd_runtime_resume(struct device *dev) EXPORT_SYMBOL(ufshcd_runtime_resume); #endif /* CONFIG_PM */ -static void ufshcd_wl_shutdown(struct device *dev) +static void ufshcd_wl_shutdown(struct scsi_device *sdev) { - struct scsi_device *sdev = to_scsi_device(dev); struct ufs_hba *hba = shost_priv(sdev->host); down(&hba->host_sem); @@ -11133,9 +11135,9 @@ static int ufshcd_wl_poweroff(struct device *dev) } #endif -static int ufshcd_wl_probe(struct device *dev) +static int ufshcd_wl_probe(struct scsi_device *sdev) { - struct scsi_device *sdev = to_scsi_device(dev); + struct device *dev = &sdev->sdev_gendev; if (!is_device_wlun(sdev)) return -ENODEV; @@ -11147,10 +11149,11 @@ static int ufshcd_wl_probe(struct device *dev) return 0; } -static int ufshcd_wl_remove(struct device *dev) +static void ufshcd_wl_remove(struct scsi_device *sdev) { + struct device *dev = &sdev->sdev_gendev; + pm_runtime_forbid(dev); - return 0; } static const struct dev_pm_ops ufshcd_wl_pm_ops = { @@ -11223,12 +11226,12 @@ static void ufshcd_check_header_layout(void) * Hence register a scsi driver for ufs wluns only. */ static struct scsi_driver ufs_dev_wlun_template = { + .probe = ufshcd_wl_probe, + .remove = ufshcd_wl_remove, + .shutdown = ufshcd_wl_shutdown, .gendrv = { .name = "ufs_device_wlun", - .probe = ufshcd_wl_probe, - .remove = ufshcd_wl_remove, .pm = &ufshcd_wl_pm_ops, - .shutdown = ufshcd_wl_shutdown, }, }; @@ -11240,7 +11243,7 @@ static int __init ufshcd_core_init(void) ufs_debugfs_init(); - ret = scsi_register_driver(&ufs_dev_wlun_template.gendrv); + ret = scsi_register_driver(&ufs_dev_wlun_template); if (ret) ufs_debugfs_exit(); return ret; @@ -11249,7 +11252,7 @@ static int __init ufshcd_core_init(void) static void __exit ufshcd_core_exit(void) { ufs_debugfs_exit(); - scsi_unregister_driver(&ufs_dev_wlun_template.gendrv); + scsi_unregister_driver(&ufs_dev_wlun_template); } module_init(ufshcd_core_init); diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c index 70d195179eba..76fee3a79c77 100644 --- a/drivers/ufs/host/ufs-exynos.c +++ b/drivers/ufs/host/ufs-exynos.c @@ -1568,12 +1568,17 @@ static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd) { struct exynos_ufs *ufs = ufshcd_get_variant(hba); struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr; + static const union phy_notify phystate = { + .ufs_state = PHY_UFS_HIBERN8_EXIT + }; if (cmd == UIC_CMD_DME_HIBER_EXIT) { if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL) exynos_ufs_disable_auto_ctrl_hcc(ufs); exynos_ufs_ungate_clks(ufs); + phy_notify_state(ufs->phy, phystate); + if (ufs->opts & EXYNOS_UFS_OPT_USE_SW_HIBERN8_TIMER) { static const unsigned int granularity_tbl[] = { 1, 4, 8, 16, 32, 100 @@ -1600,12 +1605,17 @@ static void exynos_ufs_pre_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd) static void exynos_ufs_post_hibern8(struct ufs_hba *hba, enum uic_cmd_dme cmd) { struct exynos_ufs *ufs = ufshcd_get_variant(hba); + static const union phy_notify phystate = { + .ufs_state = PHY_UFS_HIBERN8_ENTER + }; if (cmd == UIC_CMD_DME_HIBER_ENTER) { ufs->entry_hibern8_t = ktime_get(); exynos_ufs_gate_clks(ufs); if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL) exynos_ufs_enable_auto_ctrl_hcc(ufs); + + phy_notify_state(ufs->phy, phystate); } } diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 8ebee0cc5313..375fd24ba458 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -619,6 +620,27 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, return err; } +static int ufs_qcom_fw_managed_hce_enable_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + + switch (status) { + case PRE_CHANGE: + ufs_qcom_select_unipro_mode(host); + break; + case POST_CHANGE: + ufs_qcom_enable_hw_clk_gating(hba); + ufs_qcom_ice_enable(host); + break; + default: + dev_err(hba->dev, "Invalid status %d\n", status); + return -EINVAL; + } + + return 0; +} + /** * ufs_qcom_cfg_timers - Configure ufs qcom cfg timers * @@ -789,6 +811,33 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) return ufs_qcom_ice_resume(host); } +static int ufs_qcom_fw_managed_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op, + enum ufs_notify_change_status status) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + + if (status == PRE_CHANGE) + return 0; + + pm_runtime_put_sync(hba->dev); + + return ufs_qcom_ice_suspend(host); +} + +static int ufs_qcom_fw_managed_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + int err; + + err = pm_runtime_resume_and_get(hba->dev); + if (err) { + dev_err(hba->dev, "PM runtime resume failed: %d\n", err); + return err; + } + + return ufs_qcom_ice_resume(host); +} + static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable) { if (host->dev_ref_clk_ctrl_mmio && @@ -1421,6 +1470,54 @@ static void ufs_qcom_exit(struct ufs_hba *hba) phy_exit(host->generic_phy); } +static int ufs_qcom_fw_managed_init(struct ufs_hba *hba) +{ + struct device *dev = hba->dev; + struct ufs_qcom_host *host; + int err; + + host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); + if (!host) + return -ENOMEM; + + host->hba = hba; + ufshcd_set_variant(hba, host); + + ufs_qcom_get_controller_revision(hba, &host->hw_ver.major, + &host->hw_ver.minor, &host->hw_ver.step); + + err = ufs_qcom_ice_init(host); + if (err) + goto out_variant_clear; + + ufs_qcom_get_default_testbus_cfg(host); + err = ufs_qcom_testbus_config(host); + if (err) + /* Failure is non-fatal */ + dev_warn(dev, "Failed to configure the testbus %d\n", err); + + hba->caps |= UFSHCD_CAP_WB_EN; + + ufs_qcom_advertise_quirks(hba); + host->hba->quirks &= ~UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; + + hba->spm_lvl = hba->rpm_lvl = hba->pm_lvl_min = UFS_PM_LVL_5; + + ufs_qcom_set_host_params(hba); + ufs_qcom_parse_gear_limits(hba); + + return 0; + +out_variant_clear: + ufshcd_set_variant(hba, NULL); + return err; +} + +static void ufs_qcom_fw_managed_exit(struct ufs_hba *hba) +{ + pm_runtime_put_sync(hba->dev); +} + /** * ufs_qcom_set_clk_40ns_cycles - Configure 40ns clk cycles * @@ -1950,6 +2047,37 @@ static int ufs_qcom_device_reset(struct ufs_hba *hba) return 0; } +/** + * ufs_qcom_fw_managed_device_reset - Reset UFS device under FW-managed design + * @hba: pointer to UFS host bus adapter + * + * In the firmware-managed reset model, the power domain is powered on by genpd + * before the UFS controller driver probes. For subsequent resets (such as + * suspend/resume or recovery), the UFS driver must explicitly invoke PM runtime + * + * Return: 0 on success or a negative error code on failure. + */ +static int ufs_qcom_fw_managed_device_reset(struct ufs_hba *hba) +{ + static bool is_boot = true; + int err; + + /* Skip reset on cold boot; perform it on subsequent calls */ + if (is_boot) { + is_boot = false; + return 0; + } + + pm_runtime_put_sync(hba->dev); + err = pm_runtime_resume_and_get(hba->dev); + if (err < 0) { + dev_err(hba->dev, "PM runtime resume failed: %d\n", err); + return err; + } + + return 0; +} + static void ufs_qcom_config_scaling_param(struct ufs_hba *hba, struct devfreq_dev_profile *p, struct devfreq_simple_ondemand_data *d) @@ -2229,6 +2357,20 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .freq_to_gear_speed = ufs_qcom_freq_to_gear_speed, }; +static const struct ufs_hba_variant_ops ufs_hba_qcom_sa8255p_vops = { + .name = "qcom-sa8255p", + .init = ufs_qcom_fw_managed_init, + .exit = ufs_qcom_fw_managed_exit, + .hce_enable_notify = ufs_qcom_fw_managed_hce_enable_notify, + .pwr_change_notify = ufs_qcom_pwr_change_notify, + .apply_dev_quirks = ufs_qcom_apply_dev_quirks, + .fixup_dev_quirks = ufs_qcom_fixup_dev_quirks, + .suspend = ufs_qcom_fw_managed_suspend, + .resume = ufs_qcom_fw_managed_resume, + .dbg_register_dump = ufs_qcom_dump_dbg_regs, + .device_reset = ufs_qcom_fw_managed_device_reset, +}; + /** * ufs_qcom_probe - probe routine of the driver * @pdev: pointer to Platform device handle @@ -2239,9 +2381,16 @@ static int ufs_qcom_probe(struct platform_device *pdev) { int err; struct device *dev = &pdev->dev; + const struct ufs_hba_variant_ops *vops; + const struct ufs_qcom_drvdata *drvdata = device_get_match_data(dev); + + if (drvdata && drvdata->vops) + vops = drvdata->vops; + else + vops = &ufs_hba_qcom_vops; /* Perform generic probe */ - err = ufshcd_pltfrm_init(pdev, &ufs_hba_qcom_vops); + err = ufshcd_pltfrm_init(pdev, vops); if (err) return dev_err_probe(dev, err, "ufshcd_pltfrm_init() failed\n"); @@ -2269,10 +2418,15 @@ static const struct ufs_qcom_drvdata ufs_qcom_sm8550_drvdata = { .no_phy_retention = true, }; +static const struct ufs_qcom_drvdata ufs_qcom_sa8255p_drvdata = { + .vops = &ufs_hba_qcom_sa8255p_vops +}; + static const struct of_device_id ufs_qcom_of_match[] __maybe_unused = { { .compatible = "qcom,ufshc" }, { .compatible = "qcom,sm8550-ufshc", .data = &ufs_qcom_sm8550_drvdata }, { .compatible = "qcom,sm8650-ufshc", .data = &ufs_qcom_sm8550_drvdata }, + { .compatible = "qcom,sa8255p-ufshc", .data = &ufs_qcom_sa8255p_drvdata }, {}, }; MODULE_DEVICE_TABLE(of, ufs_qcom_of_match); diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 380d02333d38..1111ab34da01 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -313,6 +313,7 @@ struct ufs_qcom_host { struct ufs_qcom_drvdata { enum ufshcd_quirks quirks; bool no_phy_retention; + const struct ufs_hba_variant_ops *vops; }; static inline u32 diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 934ec5310fb9..82859374f302 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -355,8 +355,8 @@ static int mts_scsi_host_reset(struct scsi_cmnd *srb) return result ? FAILED : SUCCESS; } -static int -mts_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *srb); +static enum scsi_qc_status mts_scsi_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *srb); static void mts_transfer_cleanup( struct urb *transfer ); static void mts_do_sg(struct urb * transfer); @@ -559,7 +559,7 @@ mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc) desc->context.data_pipe = pipe; } -static int mts_scsi_queuecommand_lck(struct scsi_cmnd *srb) +static enum scsi_qc_status mts_scsi_queuecommand_lck(struct scsi_cmnd *srb) { mts_scsi_cmnd_callback callback = scsi_done; struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]); diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index d2f476e48d0c..97de28e85562 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -357,7 +357,7 @@ static int target_alloc(struct scsi_target *starget) /* queue a command */ /* This is always called with scsi_lock(host) held */ -static int queuecommand_lck(struct scsi_cmnd *srb) +static enum scsi_qc_status queuecommand_lck(struct scsi_cmnd *srb) { void (*done)(struct scsi_cmnd *) = scsi_done; struct us_data *us = host_to_us(srb->device->host); diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 73b1981cb1d5..ac3c0b919fdd 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -636,7 +636,7 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd, return 0; } -static int uas_queuecommand_lck(struct scsi_cmnd *cmnd) +static enum scsi_qc_status uas_queuecommand_lck(struct scsi_cmnd *cmnd) { struct scsi_device *sdev = cmnd->device; struct uas_dev_info *devinfo = sdev->hostdata; diff --git a/include/linux/libata.h b/include/linux/libata.h index 39534fafa36a..44117814d672 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -1150,7 +1150,8 @@ extern int ata_scsi_ioctl(struct scsi_device *dev, unsigned int cmd, #else #define ATA_SCSI_COMPAT_IOCTL /* empty */ #endif -extern int ata_scsi_queuecmd(struct Scsi_Host *h, struct scsi_cmnd *cmd); +extern enum scsi_qc_status ata_scsi_queuecmd(struct Scsi_Host *h, + struct scsi_cmnd *cmd); #if IS_REACHABLE(CONFIG_ATA) bool ata_scsi_dma_need_drain(struct request *rq); #else diff --git a/include/linux/transport_class.h b/include/linux/transport_class.h index 2efc271a96fa..a009d66db15a 100644 --- a/include/linux/transport_class.h +++ b/include/linux/transport_class.h @@ -56,6 +56,7 @@ struct anon_transport_class cls = { \ struct transport_container { struct attribute_container ac; const struct attribute_group *statistics; + const struct attribute_group *encryption; }; #define attribute_container_to_transport_container(x) \ diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h index 183d9fd50d2d..be0ffe1e3395 100644 --- a/include/scsi/libfc.h +++ b/include/scsi/libfc.h @@ -959,7 +959,8 @@ void fc_fcp_destroy(struct fc_lport *); /* * SCSI INTERACTION LAYER *****************************/ -int fc_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +enum scsi_qc_status fc_queuecommand(struct Scsi_Host *shost, + struct scsi_cmnd *cmnd); int fc_eh_abort(struct scsi_cmnd *); int fc_eh_device_reset(struct scsi_cmnd *); int fc_eh_host_reset(struct scsi_cmnd *); diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 7282555adfd5..3d765c77bcd9 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -392,7 +392,8 @@ extern int iscsi_eh_abort(struct scsi_cmnd *sc); extern int iscsi_eh_recover_target(struct scsi_cmnd *sc); extern int iscsi_eh_session_reset(struct scsi_cmnd *sc); extern int iscsi_eh_device_reset(struct scsi_cmnd *sc); -extern int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc); +extern enum scsi_qc_status iscsi_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *sc); extern enum scsi_timeout_action iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc); /* diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index a0635b128d7a..e76f5744941b 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -689,7 +689,8 @@ extern void sas_suspend_ha(struct sas_ha_struct *sas_ha); int sas_phy_reset(struct sas_phy *phy, int hard_reset); int sas_phy_enable(struct sas_phy *phy, int enable); -extern int sas_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +extern enum scsi_qc_status sas_queuecommand(struct Scsi_Host *host, + struct scsi_cmnd *cmd); extern int sas_target_alloc(struct scsi_target *); int sas_sdev_configure(struct scsi_device *dev, struct queue_limits *lim); extern int sas_change_queue_depth(struct scsi_device *, int new_depth); diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 96b350366670..08ac3200b4a4 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -106,12 +106,15 @@ enum scsi_disposition { }; /* - * Midlevel queue return values. + * Status values returned by the .queuecommand() callback if a command has not + * been queued. */ -#define SCSI_MLQUEUE_HOST_BUSY 0x1055 -#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 -#define SCSI_MLQUEUE_EH_RETRY 0x1057 -#define SCSI_MLQUEUE_TARGET_BUSY 0x1058 +enum scsi_qc_status { + SCSI_MLQUEUE_HOST_BUSY = 0x1055, + SCSI_MLQUEUE_DEVICE_BUSY = 0x1056, + SCSI_MLQUEUE_EH_RETRY = 0x1057, + SCSI_MLQUEUE_TARGET_BUSY = 0x1058, +}; /* * Use these to separate status msg and our bytes diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h index c0e89996bdb3..249cea724abd 100644 --- a/include/scsi/scsi_driver.h +++ b/include/scsi/scsi_driver.h @@ -12,6 +12,9 @@ struct request; struct scsi_driver { struct device_driver gendrv; + int (*probe)(struct scsi_device *); + void (*remove)(struct scsi_device *); + void (*shutdown)(struct scsi_device *); int (*resume)(struct device *); void (*rescan)(struct device *); blk_status_t (*init_command)(struct scsi_cmnd *); @@ -25,9 +28,9 @@ struct scsi_driver { #define scsi_register_driver(drv) \ __scsi_register_driver(drv, THIS_MODULE) -int __scsi_register_driver(struct device_driver *, struct module *); +int __scsi_register_driver(struct scsi_driver *, struct module *); #define scsi_unregister_driver(drv) \ - driver_unregister(drv); + driver_unregister(&(drv)->gendrv); extern int scsi_register_interface(struct class_interface *); #define scsi_unregister_interface(intf) \ diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index e87cf7eadd26..f6e12565a81d 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -84,13 +84,15 @@ struct scsi_host_template { * * STATUS: REQUIRED */ - int (* queuecommand)(struct Scsi_Host *, struct scsi_cmnd *); + enum scsi_qc_status (*queuecommand)(struct Scsi_Host *, + struct scsi_cmnd *); /* * Queue a reserved command (BLK_MQ_REQ_RESERVED). The .queuecommand() * documentation also applies to the .queue_reserved_command() callback. */ - int (*queue_reserved_command)(struct Scsi_Host *, struct scsi_cmnd *); + enum scsi_qc_status (*queue_reserved_command)(struct Scsi_Host *, + struct scsi_cmnd *); /* * The commit_rqs function is used to trigger a hardware @@ -525,10 +527,12 @@ struct scsi_host_template { * */ #define DEF_SCSI_QCMD(func_name) \ - int func_name(struct Scsi_Host *shost, struct scsi_cmnd *cmd) \ + enum scsi_qc_status func_name(struct Scsi_Host *shost, \ + struct scsi_cmnd *cmd) \ { \ unsigned long irq_flags; \ - int rc; \ + enum scsi_qc_status rc; \ + \ spin_lock_irqsave(shost->host_lock, irq_flags); \ rc = func_name##_lck(cmd); \ spin_unlock_irqrestore(shost->host_lock, irq_flags); \ diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index b908aacfef48..9f30625aa0d3 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -317,6 +317,15 @@ struct fc_fpin_stats { u64 cn_device_specific; }; +#define FC_RPORT_ENCRYPTION_STATUS_MAX_LEN 14 +/* + * Encryption Information + */ +struct fc_encryption_info { + /* Encryption Status */ + u8 status; +}; + /* Macro for use in defining Remote Port attributes */ #define FC_RPORT_ATTR(_name,_mode,_show,_store) \ struct device_attribute dev_attr_rport_##_name = \ @@ -364,6 +373,7 @@ struct fc_rport { /* aka fc_starget_attrs */ u64 port_name; u32 port_id; u32 roles; + struct fc_encryption_info enc_info; enum fc_port_state port_state; /* Will only be ONLINE or UNKNOWN */ u32 scsi_target_id; u32 fast_io_fail_tmo; @@ -691,6 +701,8 @@ struct fc_function_template { struct fc_host_statistics * (*get_fc_host_stats)(struct Scsi_Host *); void (*reset_fc_host_stats)(struct Scsi_Host *); + struct fc_encryption_info * (*get_fc_rport_enc_info)(struct fc_rport *); + int (*issue_fc_host_lip)(struct Scsi_Host *); void (*dev_loss_tmo_callbk)(struct fc_rport *); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 7016d93fa383..b62d5fcce950 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -108,6 +108,9 @@ #define SE_MODE_PAGE_BUF 512 #define SE_SENSE_BUF 96 +/* Peripheral Device Text Identification Information */ +#define PD_TEXT_ID_INFO_LEN 256 + enum target_submit_type { /* Use the fabric driver's default submission type */ TARGET_FABRIC_DEFAULT_SUBMIT, @@ -348,6 +351,7 @@ struct t10_wwn { struct se_device *t10_dev; struct config_group t10_wwn_group; struct list_head t10_vpd_list; + char pd_text_id_info[PD_TEXT_ID_INFO_LEN]; }; struct t10_pr_registration { diff --git a/include/uapi/scsi/scsi_bsg_ufs.h b/include/uapi/scsi/scsi_bsg_ufs.h index 8c29e498ef98..06f88d1b1876 100644 --- a/include/uapi/scsi/scsi_bsg_ufs.h +++ b/include/uapi/scsi/scsi_bsg_ufs.h @@ -94,16 +94,15 @@ struct utp_upiu_header { }; /** - * struct utp_upiu_query - upiu request buffer structure for - * query request. - * @opcode: command to perform B-0 - * @idn: a value that indicates the particular type of data B-1 - * @index: Index to further identify data B-2 - * @selector: Index to further identify data B-3 + * struct utp_upiu_query - QUERY REQUEST UPIU structure. + * @opcode: query function to perform B-0 + * @idn: descriptor or attribute identification number B-1 + * @index: Index that further identifies which data to access B-2 + * @selector: Index that further identifies which data to access B-3 * @reserved_osf: spec reserved field B-4,5 - * @length: number of descriptor bytes to read/write B-6,7 - * @value: Attribute value to be written DW-5 - * @reserved: spec reserved DW-6,7 + * @length: number of descriptor bytes to read or write B-6,7 + * @value: if @opcode == UPIU_QUERY_OPCODE_WRITE_ATTR, the value to be written B-6,7 + * @reserved: reserved for future use DW-6,7 */ struct utp_upiu_query { __u8 opcode; diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index ab8f6c07b5a2..602aa34c9822 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -21,6 +21,7 @@ * in this header file of the size of struct utp_upiu_header. */ static_assert(sizeof(struct utp_upiu_header) == 12); +static_assert(sizeof(struct utp_upiu_query) == 20); #define GENERAL_UPIU_REQUEST_SIZE (sizeof(struct utp_upiu_req)) #define QUERY_DESC_MAX_SIZE 255 @@ -561,7 +562,7 @@ enum ufs_dev_pwr_mode { #define UFS_WB_BUF_REMAIN_PERCENT(val) ((val) / 10) /** - * struct utp_cmd_rsp - Response UPIU structure + * struct utp_cmd_rsp - RESPONSE UPIU structure * @residual_transfer_count: Residual transfer count DW-3 * @reserved: Reserved double words DW-4 to DW-7 * @sense_data_len: Sense data length DW-8 U16 @@ -574,6 +575,8 @@ struct utp_cmd_rsp { u8 sense_data[UFS_SENSE_SIZE]; }; +static_assert(sizeof(struct utp_cmd_rsp) == 40); + /** * struct utp_upiu_rsp - general upiu response structure * @header: UPIU header structure DW-0 to DW-2 diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 19154228780b..a64c19563b03 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -834,6 +834,7 @@ enum ufshcd_mcq_opr { * @uic_link_state: active state of the link to the UFS device. * @rpm_lvl: desired UFS power management level during runtime PM. * @spm_lvl: desired UFS power management level during system PM. + * @pm_lvl_min: minimum supported power management level. * @pm_op_in_progress: whether or not a PM operation is in progress. * @ahit: value of Auto-Hibernate Idle Timer register. * @outstanding_tasks: Bits representing outstanding task requests @@ -972,6 +973,7 @@ struct ufs_hba { enum ufs_pm_level rpm_lvl; /* Desired UFS power management level during system PM */ enum ufs_pm_level spm_lvl; + enum ufs_pm_level pm_lvl_min; int pm_op_in_progress; /* Auto-Hibernate Idle Timer register value */ diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index d36df24242a3..806fdaf52bd9 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -288,6 +288,7 @@ enum { /* REG_UFS_MEM_CFG - Global Config Registers 300h */ #define MCQ_MODE_SELECT BIT(0) +#define ESI_ENABLE BIT(1) /* CQISy - CQ y Interrupt Status Register */ #define UFSHCD_MCQ_CQIS_TAIL_ENT_PUSH_STS 0x1