summaryrefslogtreecommitdiff
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/aacraid/aacraid.h2
-rw-r--r--drivers/scsi/aha152x.c235
-rw-r--r--drivers/scsi/aha1542.c20
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_pci.c6
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_pci.c4
-rw-r--r--drivers/scsi/bfa/bfad_debugfs.c3
-rw-r--r--drivers/scsi/bfa/bfad_im.c1
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c22
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_hwi.c6
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c17
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c6
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c2
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.c6
-rw-r--r--drivers/scsi/dc395x.c15
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c3
-rw-r--r--drivers/scsi/dpt_i2o.c1
-rw-r--r--drivers/scsi/elx/efct/efct_hw.c1
-rw-r--r--drivers/scsi/elx/efct/efct_io.c1
-rw-r--r--drivers/scsi/elx/efct/efct_lio.c3
-rw-r--r--drivers/scsi/fcoe/fcoe.c46
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c28
-rw-r--r--drivers/scsi/fcoe/fcoe_transport.c6
-rw-r--r--drivers/scsi/fnic/fnic.h2
-rw-r--r--drivers/scsi/fnic/fnic_debugfs.c3
-rw-r--r--drivers/scsi/fnic/fnic_main.c10
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_main.c69
-rw-r--r--drivers/scsi/hisi_sas/hisi_sas_v3_hw.c10
-rw-r--r--drivers/scsi/hosts.c8
-rw-r--r--drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c2
-rw-r--r--drivers/scsi/ipr.c13
-rw-r--r--drivers/scsi/isci/host.c6
-rw-r--r--drivers/scsi/libfc/fc_exch.c3
-rw-r--r--drivers/scsi/libfc/fc_fcp.c29
-rw-r--r--drivers/scsi/libfc/fc_lport.c30
-rw-r--r--drivers/scsi/libiscsi.c28
-rw-r--r--drivers/scsi/libiscsi_tcp.c2
-rw-r--r--drivers/scsi/libsas/sas_ata.c41
-rw-r--r--drivers/scsi/lpfc/lpfc.h17
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c55
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c81
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h8
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c366
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c717
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c284
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h75
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h17
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c362
-rw-r--r--drivers/scsi/lpfc/lpfc_logmsg.h8
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c203
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c79
-rw-r--r--drivers/scsi/lpfc/lpfc_nvme.c71
-rw-r--r--drivers/scsi/lpfc/lpfc_nvmet.c73
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c88
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c351
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h34
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c31
-rw-r--r--drivers/scsi/mac53c94.c2
-rw-r--r--drivers/scsi/megaraid.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h3
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c9
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c2
-rw-r--r--drivers/scsi/mpi3mr/Kconfig1
-rw-r--r--drivers/scsi/mpi3mr/Makefile1
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_init.h53
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_ioc.h27
-rw-r--r--drivers/scsi/mpi3mr/mpi/mpi30_pci.h31
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr.h137
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_app.c1864
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_debug.h37
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_fw.c335
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_os.c71
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c37
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.h6
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_config.c9
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.c11
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c29
-rw-r--r--drivers/scsi/mvsas/mv_init.c1
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c52
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c33
-rw-r--r--drivers/scsi/pmcraid.c493
-rw-r--r--drivers/scsi/pmcraid.h33
-rw-r--r--drivers/scsi/qedf/qedf_attr.c2
-rw-r--r--drivers/scsi/qedf/qedf_io.c3
-rw-r--r--drivers/scsi/qedf/qedf_main.c13
-rw-r--r--drivers/scsi/qedi/qedi_iscsi.c69
-rw-r--r--drivers/scsi/qla2xxx/qla_edif.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c1
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c5
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h1
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c1
-rw-r--r--drivers/scsi/scsi.c116
-rw-r--r--drivers/scsi/scsi_debug.c354
-rw-r--r--drivers/scsi/scsi_lib.c2
-rw-r--r--drivers/scsi/scsi_logging.c2
-rw-r--r--drivers/scsi/scsi_scan.c17
-rw-r--r--drivers/scsi/scsi_sysfs.c32
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c239
-rw-r--r--drivers/scsi/scsicam.c11
-rw-r--r--drivers/scsi/sd.c198
-rw-r--r--drivers/scsi/sd.h33
-rw-r--r--drivers/scsi/sd_dif.c8
-rw-r--r--drivers/scsi/sd_zbc.c236
-rw-r--r--drivers/scsi/sr.c16
-rw-r--r--drivers/scsi/sr_ioctl.c15
-rw-r--r--drivers/scsi/ufs/Kconfig26
-rw-r--r--drivers/scsi/ufs/cdns-pltfrm.c2
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210-pci.c1
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210-pltfrm.c1
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210.c2
-rw-r--r--drivers/scsi/ufs/tc-dwc-g210.h2
-rw-r--r--drivers/scsi/ufs/ti-j721e-ufs.c6
-rw-r--r--drivers/scsi/ufs/ufs-debugfs.c1
-rw-r--r--drivers/scsi/ufs/ufs-exynos.c5
-rw-r--r--drivers/scsi/ufs/ufs-exynos.h8
-rw-r--r--drivers/scsi/ufs/ufs-hisi.c2
-rw-r--r--drivers/scsi/ufs/ufs-hwmon.c1
-rw-r--r--drivers/scsi/ufs/ufs-mediatek.c31
-rw-r--r--drivers/scsi/ufs/ufs-qcom-ice.c2
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c88
-rw-r--r--drivers/scsi/ufs/ufs-qcom.h6
-rw-r--r--drivers/scsi/ufs/ufs-sysfs.c1
-rw-r--r--drivers/scsi/ufs/ufs-sysfs.h3
-rw-r--r--drivers/scsi/ufs/ufs.h35
-rw-r--r--drivers/scsi/ufs/ufs_bsg.c6
-rw-r--r--drivers/scsi/ufs/ufs_bsg.h7
-rw-r--r--drivers/scsi/ufs/ufs_quirks.h15
-rw-r--r--drivers/scsi/ufs/ufshcd-crypto.h5
-rw-r--r--drivers/scsi/ufs/ufshcd-dwc.c2
-rw-r--r--drivers/scsi/ufs/ufshcd-dwc.h2
-rw-r--r--drivers/scsi/ufs/ufshcd-pci.c21
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c38
-rw-r--r--drivers/scsi/ufs/ufshcd-priv.h298
-rw-r--r--drivers/scsi/ufs/ufshcd.c247
-rw-r--r--drivers/scsi/ufs/ufshcd.h370
-rw-r--r--drivers/scsi/ufs/ufshci.h2
-rw-r--r--drivers/scsi/ufs/ufshpb.c233
-rw-r--r--drivers/scsi/ufs/ufshpb.h16
-rw-r--r--drivers/scsi/ufs/unipro.h18
-rw-r--r--drivers/scsi/virtio_scsi.c8
-rw-r--r--drivers/scsi/vmw_pvscsi.c1
-rw-r--r--drivers/scsi/xen-scsifront.c199
-rw-r--r--drivers/scsi/zorro7xx.c2
146 files changed, 6199 insertions, 3789 deletions
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index f849e7c9d428..5e115e8b2ba4 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -121,7 +121,7 @@ enum {
#define SA_AIF_PDEV_CHANGE (1<<4)
#define SA_AIF_LDEV_CHANGE (1<<5)
#define SA_AIF_BPSTAT_CHANGE (1<<30)
-#define SA_AIF_BPCFG_CHANGE (1<<31)
+#define SA_AIF_BPCFG_CHANGE (1U<<31)
#define HBA_MAX_SG_EMBEDDED 28
#define HBA_MAX_SG_SEPARATE 90
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 5f554a3a0f62..caeebfb67149 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -317,14 +317,18 @@ enum {
};
struct aha152x_cmd_priv {
- struct scsi_pointer scsi_pointer;
+ char *ptr;
+ int this_residual;
+ struct scatterlist *buffer;
+ int status;
+ int message;
+ int sent_command;
+ int phase;
};
-static struct scsi_pointer *aha152x_scsi_pointer(struct scsi_cmnd *cmd)
+static struct aha152x_cmd_priv *aha152x_priv(struct scsi_cmnd *cmd)
{
- struct aha152x_cmd_priv *acmd = scsi_cmd_priv(cmd);
-
- return &acmd->scsi_pointer;
+ return scsi_cmd_priv(cmd);
}
MODULE_AUTHOR("Jürgen Fischer");
@@ -890,17 +894,16 @@ void aha152x_release(struct Scsi_Host *shpnt)
static int setup_expected_interrupts(struct Scsi_Host *shpnt)
{
if(CURRENT_SC) {
- struct scsi_pointer *scsi_pointer =
- aha152x_scsi_pointer(CURRENT_SC);
+ struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
- scsi_pointer->phase |= 1 << 16;
+ acp->phase |= 1 << 16;
- if (scsi_pointer->phase & selecting) {
+ if (acp->phase & selecting) {
SETPORT(SSTAT1, SELTO);
SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
SETPORT(SIMODE1, ENSELTIMO);
} else {
- SETPORT(SIMODE0, (scsi_pointer->phase & spiordy) ? ENSPIORDY : 0);
+ SETPORT(SIMODE0, (acp->phase & spiordy) ? ENSPIORDY : 0);
SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
}
} else if(STATE==seldi) {
@@ -924,17 +927,16 @@ static int setup_expected_interrupts(struct Scsi_Host *shpnt)
static int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
struct completion *complete, int phase)
{
- struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(SCpnt);
+ struct aha152x_cmd_priv *acp = aha152x_priv(SCpnt);
struct Scsi_Host *shpnt = SCpnt->device->host;
unsigned long flags;
- scsi_pointer->phase = not_issued | phase;
- scsi_pointer->Status = 0x1; /* Ilegal status by SCSI standard */
- scsi_pointer->Message = 0;
- scsi_pointer->have_data_in = 0;
- scsi_pointer->sent_command = 0;
+ acp->phase = not_issued | phase;
+ acp->status = 0x1; /* Illegal status by SCSI standard */
+ acp->message = 0;
+ acp->sent_command = 0;
- if (scsi_pointer->phase & (resetting | check_condition)) {
+ 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;
@@ -957,15 +959,15 @@ static int aha152x_internal_queue(struct scsi_cmnd *SCpnt,
SCp.phase : current state of the command */
if ((phase & resetting) || !scsi_sglist(SCpnt)) {
- scsi_pointer->ptr = NULL;
- scsi_pointer->this_residual = 0;
+ acp->ptr = NULL;
+ acp->this_residual = 0;
scsi_set_resid(SCpnt, 0);
- scsi_pointer->buffer = NULL;
+ acp->buffer = NULL;
} else {
scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
- scsi_pointer->buffer = scsi_sglist(SCpnt);
- scsi_pointer->ptr = SG_ADDRESS(scsi_pointer->buffer);
- scsi_pointer->this_residual = scsi_pointer->buffer->length;
+ acp->buffer = scsi_sglist(SCpnt);
+ acp->ptr = SG_ADDRESS(acp->buffer);
+ acp->this_residual = acp->buffer->length;
}
DO_LOCK(flags);
@@ -1015,7 +1017,7 @@ static void reset_done(struct scsi_cmnd *SCpnt)
static void aha152x_scsi_done(struct scsi_cmnd *SCpnt)
{
- if (aha152x_scsi_pointer(SCpnt)->phase & resetting)
+ if (aha152x_priv(SCpnt)->phase & resetting)
reset_done(SCpnt);
else
scsi_done(SCpnt);
@@ -1101,7 +1103,7 @@ static int aha152x_device_reset(struct scsi_cmnd * SCpnt)
DO_LOCK(flags);
- if (aha152x_scsi_pointer(SCpnt)->phase & resetted) {
+ if (aha152x_priv(SCpnt)->phase & resetted) {
HOSTDATA(shpnt)->commands--;
if (!HOSTDATA(shpnt)->commands)
SETPORT(PORTA, 0);
@@ -1395,31 +1397,30 @@ static void busfree_run(struct Scsi_Host *shpnt)
SETPORT(SSTAT1, CLRBUSFREE);
if(CURRENT_SC) {
- struct scsi_pointer *scsi_pointer =
- aha152x_scsi_pointer(CURRENT_SC);
+ struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
#if defined(AHA152X_STAT)
action++;
#endif
- scsi_pointer->phase &= ~syncneg;
+ acp->phase &= ~syncneg;
- if (scsi_pointer->phase & completed) {
+ if (acp->phase & completed) {
/* target sent COMMAND COMPLETE */
- done(shpnt, scsi_pointer->Status, DID_OK);
+ done(shpnt, acp->status, DID_OK);
- } else if (scsi_pointer->phase & aborted) {
- done(shpnt, scsi_pointer->Status, DID_ABORT);
+ } else if (acp->phase & aborted) {
+ done(shpnt, acp->status, DID_ABORT);
- } else if (scsi_pointer->phase & resetted) {
- done(shpnt, scsi_pointer->Status, DID_RESET);
+ } else if (acp->phase & resetted) {
+ done(shpnt, acp->status, DID_RESET);
- } else if (scsi_pointer->phase & disconnected) {
+ } else if (acp->phase & disconnected) {
/* target sent DISCONNECT */
#if defined(AHA152X_STAT)
HOSTDATA(shpnt)->disconnections++;
#endif
append_SC(&DISCONNECTED_SC, CURRENT_SC);
- scsi_pointer->phase |= 1 << 16;
+ acp->phase |= 1 << 16;
CURRENT_SC = NULL;
} else {
@@ -1438,24 +1439,23 @@ static void busfree_run(struct Scsi_Host *shpnt)
action++;
#endif
- if (aha152x_scsi_pointer(DONE_SC)->phase & check_condition) {
+ if (aha152x_priv(DONE_SC)->phase & check_condition) {
struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC;
struct aha152x_scdata *sc = SCDATA(cmd);
scsi_eh_restore_cmnd(cmd, &sc->ses);
- aha152x_scsi_pointer(cmd)->Status = SAM_STAT_CHECK_CONDITION;
+ aha152x_priv(cmd)->status = SAM_STAT_CHECK_CONDITION;
HOSTDATA(shpnt)->commands--;
if (!HOSTDATA(shpnt)->commands)
SETPORT(PORTA, 0); /* turn led off */
- } else if (aha152x_scsi_pointer(DONE_SC)->Status ==
- SAM_STAT_CHECK_CONDITION) {
+ } else if (aha152x_priv(DONE_SC)->status == SAM_STAT_CHECK_CONDITION) {
#if defined(AHA152X_STAT)
HOSTDATA(shpnt)->busfree_with_check_condition++;
#endif
- if(!(aha152x_scsi_pointer(DONE_SC)->phase & not_issued)) {
+ if (!(aha152x_priv(DONE_SC)->phase & not_issued)) {
struct aha152x_scdata *sc;
struct scsi_cmnd *ptr = DONE_SC;
DONE_SC=NULL;
@@ -1480,7 +1480,7 @@ static void busfree_run(struct Scsi_Host *shpnt)
if (!HOSTDATA(shpnt)->commands)
SETPORT(PORTA, 0); /* turn led off */
- if (!(aha152x_scsi_pointer(ptr)->phase & resetting)) {
+ if (!(aha152x_priv(ptr)->phase & resetting)) {
kfree(ptr->host_scribble);
ptr->host_scribble=NULL;
}
@@ -1503,13 +1503,12 @@ static void busfree_run(struct Scsi_Host *shpnt)
DO_UNLOCK(flags);
if(CURRENT_SC) {
- struct scsi_pointer *scsi_pointer =
- aha152x_scsi_pointer(CURRENT_SC);
+ struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
#if defined(AHA152X_STAT)
action++;
#endif
- scsi_pointer->phase |= selecting;
+ acp->phase |= selecting;
/* clear selection timeout */
SETPORT(SSTAT1, SELTO);
@@ -1537,13 +1536,13 @@ static void busfree_run(struct Scsi_Host *shpnt)
*/
static void seldo_run(struct Scsi_Host *shpnt)
{
- struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC);
+ struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
SETPORT(SCSISIG, 0);
SETPORT(SSTAT1, CLRBUSFREE);
SETPORT(SSTAT1, CLRPHASECHG);
- scsi_pointer->phase &= ~(selecting | not_issued);
+ acp->phase &= ~(selecting | not_issued);
SETPORT(SCSISEQ, 0);
@@ -1558,12 +1557,12 @@ static void seldo_run(struct Scsi_Host *shpnt)
ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
- if (scsi_pointer->phase & aborting) {
+ if (acp->phase & aborting) {
ADDMSGO(ABORT);
- } else if (scsi_pointer->phase & resetting) {
+ } else if (acp->phase & resetting) {
ADDMSGO(BUS_DEVICE_RESET);
} else if (SYNCNEG==0 && SYNCHRONOUS) {
- scsi_pointer->phase |= syncneg;
+ acp->phase |= syncneg;
MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8);
SYNCNEG=1; /* negotiation in progress */
}
@@ -1578,7 +1577,7 @@ static void seldo_run(struct Scsi_Host *shpnt)
*/
static void selto_run(struct Scsi_Host *shpnt)
{
- struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC);
+ struct aha152x_cmd_priv *acp;
SETPORT(SCSISEQ, 0);
SETPORT(SSTAT1, CLRSELTIMO);
@@ -1586,9 +1585,10 @@ static void selto_run(struct Scsi_Host *shpnt)
if (!CURRENT_SC)
return;
- scsi_pointer->phase &= ~selecting;
+ acp = aha152x_priv(CURRENT_SC);
+ acp->phase &= ~selecting;
- if (scsi_pointer->phase & aborted)
+ if (acp->phase & aborted)
done(shpnt, SAM_STAT_GOOD, DID_ABORT);
else if (TESTLO(SSTAT0, SELINGO))
done(shpnt, SAM_STAT_GOOD, DID_BUS_BUSY);
@@ -1616,10 +1616,9 @@ static void seldi_run(struct Scsi_Host *shpnt)
SETPORT(SSTAT1, CLRPHASECHG);
if(CURRENT_SC) {
- struct scsi_pointer *scsi_pointer =
- aha152x_scsi_pointer(CURRENT_SC);
+ struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
- if (!(scsi_pointer->phase & not_issued))
+ if (!(acp->phase & not_issued))
scmd_printk(KERN_ERR, CURRENT_SC,
"command should not have been issued yet\n");
@@ -1676,7 +1675,7 @@ static void seldi_run(struct Scsi_Host *shpnt)
static void msgi_run(struct Scsi_Host *shpnt)
{
for(;;) {
- struct scsi_pointer *scsi_pointer;
+ struct aha152x_cmd_priv *acp;
int sstat1 = GETPORT(SSTAT1);
if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT))
@@ -1714,9 +1713,9 @@ static void msgi_run(struct Scsi_Host *shpnt)
continue;
}
- scsi_pointer = aha152x_scsi_pointer(CURRENT_SC);
- scsi_pointer->Message = MSGI(0);
- scsi_pointer->phase &= ~disconnected;
+ acp = aha152x_priv(CURRENT_SC);
+ acp->message = MSGI(0);
+ acp->phase &= ~disconnected;
MSGILEN=0;
@@ -1724,8 +1723,8 @@ static void msgi_run(struct Scsi_Host *shpnt)
continue;
}
- scsi_pointer = aha152x_scsi_pointer(CURRENT_SC);
- scsi_pointer->Message = MSGI(0);
+ acp = aha152x_priv(CURRENT_SC);
+ acp->message = MSGI(0);
switch (MSGI(0)) {
case DISCONNECT:
@@ -1733,11 +1732,11 @@ static void msgi_run(struct Scsi_Host *shpnt)
scmd_printk(KERN_WARNING, CURRENT_SC,
"target was not allowed to disconnect\n");
- scsi_pointer->phase |= disconnected;
+ acp->phase |= disconnected;
break;
case COMMAND_COMPLETE:
- scsi_pointer->phase |= completed;
+ acp->phase |= completed;
break;
case MESSAGE_REJECT:
@@ -1867,11 +1866,9 @@ static void msgi_end(struct Scsi_Host *shpnt)
*/
static void msgo_init(struct Scsi_Host *shpnt)
{
- struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC);
-
if(MSGOLEN==0) {
- if ((scsi_pointer->phase & syncneg) && SYNCNEG==2 &&
- SYNCRATE==0) {
+ if ((aha152x_priv(CURRENT_SC)->phase & syncneg) &&
+ SYNCNEG == 2 && SYNCRATE == 0) {
ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
} else {
scmd_printk(KERN_INFO, CURRENT_SC,
@@ -1888,7 +1885,7 @@ static void msgo_init(struct Scsi_Host *shpnt)
*/
static void msgo_run(struct Scsi_Host *shpnt)
{
- struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC);
+ struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
while(MSGO_I<MSGOLEN) {
if (TESTLO(SSTAT0, SPIORDY))
@@ -1901,13 +1898,13 @@ static void msgo_run(struct Scsi_Host *shpnt)
if (MSGO(MSGO_I) & IDENTIFY_BASE)
- scsi_pointer->phase |= identified;
+ acp->phase |= identified;
if (MSGO(MSGO_I)==ABORT)
- scsi_pointer->phase |= aborted;
+ acp->phase |= aborted;
if (MSGO(MSGO_I)==BUS_DEVICE_RESET)
- scsi_pointer->phase |= resetted;
+ acp->phase |= resetted;
SETPORT(SCSIDAT, MSGO(MSGO_I++));
}
@@ -1936,7 +1933,7 @@ static void msgo_end(struct Scsi_Host *shpnt)
*/
static void cmd_init(struct Scsi_Host *shpnt)
{
- if (aha152x_scsi_pointer(CURRENT_SC)->sent_command) {
+ if (aha152x_priv(CURRENT_SC)->sent_command) {
scmd_printk(KERN_ERR, CURRENT_SC,
"command already sent\n");
done(shpnt, SAM_STAT_GOOD, DID_ERROR);
@@ -1967,7 +1964,7 @@ static void cmd_end(struct Scsi_Host *shpnt)
"command sent incompletely (%d/%d)\n",
CMD_I, CURRENT_SC->cmd_len);
else
- aha152x_scsi_pointer(CURRENT_SC)->sent_command++;
+ aha152x_priv(CURRENT_SC)->sent_command++;
}
/*
@@ -1979,7 +1976,7 @@ static void status_run(struct Scsi_Host *shpnt)
if (TESTLO(SSTAT0, SPIORDY))
return;
- aha152x_scsi_pointer(CURRENT_SC)->Status = GETPORT(SCSIDAT);
+ aha152x_priv(CURRENT_SC)->status = GETPORT(SCSIDAT);
}
@@ -2003,7 +2000,7 @@ static void datai_init(struct Scsi_Host *shpnt)
static void datai_run(struct Scsi_Host *shpnt)
{
- struct scsi_pointer *scsi_pointer;
+ struct aha152x_cmd_priv *acp;
unsigned long the_time;
int fifodata, data_count;
@@ -2041,36 +2038,35 @@ static void datai_run(struct Scsi_Host *shpnt)
fifodata = GETPORT(FIFOSTAT);
}
- scsi_pointer = aha152x_scsi_pointer(CURRENT_SC);
- if (scsi_pointer->this_residual > 0) {
- while (fifodata > 0 && scsi_pointer->this_residual > 0) {
- data_count = fifodata > scsi_pointer->this_residual ?
- scsi_pointer->this_residual :
- fifodata;
+ acp = aha152x_priv(CURRENT_SC);
+ if (acp->this_residual > 0) {
+ while (fifodata > 0 && acp->this_residual > 0) {
+ data_count = fifodata > acp->this_residual ?
+ acp->this_residual : fifodata;
fifodata -= data_count;
if (data_count & 1) {
SETPORT(DMACNTRL0, ENDMA|_8BIT);
- *scsi_pointer->ptr++ = GETPORT(DATAPORT);
- scsi_pointer->this_residual--;
+ *acp->ptr++ = GETPORT(DATAPORT);
+ acp->this_residual--;
DATA_LEN++;
SETPORT(DMACNTRL0, ENDMA);
}
if (data_count > 1) {
data_count >>= 1;
- insw(DATAPORT, scsi_pointer->ptr, data_count);
- scsi_pointer->ptr += 2 * data_count;
- scsi_pointer->this_residual -= 2 * data_count;
+ insw(DATAPORT, acp->ptr, data_count);
+ acp->ptr += 2 * data_count;
+ acp->this_residual -= 2 * data_count;
DATA_LEN += 2 * data_count;
}
- if (scsi_pointer->this_residual == 0 &&
- !sg_is_last(scsi_pointer->buffer)) {
+ if (acp->this_residual == 0 &&
+ !sg_is_last(acp->buffer)) {
/* advance to next buffer */
- scsi_pointer->buffer = sg_next(scsi_pointer->buffer);
- scsi_pointer->ptr = SG_ADDRESS(scsi_pointer->buffer);
- scsi_pointer->this_residual = scsi_pointer->buffer->length;
+ acp->buffer = sg_next(acp->buffer);
+ acp->ptr = SG_ADDRESS(acp->buffer);
+ acp->this_residual = acp->buffer->length;
}
}
} else if (fifodata > 0) {
@@ -2138,15 +2134,15 @@ static void datao_init(struct Scsi_Host *shpnt)
static void datao_run(struct Scsi_Host *shpnt)
{
- struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC);
+ struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
unsigned long the_time;
int data_count;
/* until phase changes or all data sent */
- while (TESTLO(DMASTAT, INTSTAT) && scsi_pointer->this_residual > 0) {
+ while (TESTLO(DMASTAT, INTSTAT) && acp->this_residual > 0) {
data_count = 128;
- if (data_count > scsi_pointer->this_residual)
- data_count = scsi_pointer->this_residual;
+ if (data_count > acp->this_residual)
+ data_count = acp->this_residual;
if(TESTLO(DMASTAT, DFIFOEMP)) {
scmd_printk(KERN_ERR, CURRENT_SC,
@@ -2157,26 +2153,25 @@ static void datao_run(struct Scsi_Host *shpnt)
if(data_count & 1) {
SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
- SETPORT(DATAPORT, *scsi_pointer->ptr++);
- scsi_pointer->this_residual--;
+ SETPORT(DATAPORT, *acp->ptr++);
+ acp->this_residual--;
CMD_INC_RESID(CURRENT_SC, -1);
SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
}
if(data_count > 1) {
data_count >>= 1;
- outsw(DATAPORT, scsi_pointer->ptr, data_count);
- scsi_pointer->ptr += 2 * data_count;
- scsi_pointer->this_residual -= 2 * data_count;
+ outsw(DATAPORT, acp->ptr, data_count);
+ acp->ptr += 2 * data_count;
+ acp->this_residual -= 2 * data_count;
CMD_INC_RESID(CURRENT_SC, -2 * data_count);
}
- if (scsi_pointer->this_residual == 0 &&
- !sg_is_last(scsi_pointer->buffer)) {
+ if (acp->this_residual == 0 && !sg_is_last(acp->buffer)) {
/* advance to next buffer */
- scsi_pointer->buffer = sg_next(scsi_pointer->buffer);
- scsi_pointer->ptr = SG_ADDRESS(scsi_pointer->buffer);
- scsi_pointer->this_residual = scsi_pointer->buffer->length;
+ acp->buffer = sg_next(acp->buffer);
+ acp->ptr = SG_ADDRESS(acp->buffer);
+ acp->this_residual = acp->buffer->length;
}
the_time=jiffies + 100*HZ;
@@ -2192,7 +2187,7 @@ static void datao_run(struct Scsi_Host *shpnt)
static void datao_end(struct Scsi_Host *shpnt)
{
- struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC);
+ struct aha152x_cmd_priv *acp = aha152x_priv(CURRENT_SC);
if(TESTLO(DMASTAT, DFIFOEMP)) {
u32 datao_cnt = GETSTCNT();
@@ -2211,10 +2206,9 @@ static void datao_end(struct Scsi_Host *shpnt)
sg = sg_next(sg);
}
- scsi_pointer->buffer = sg;
- scsi_pointer->ptr = SG_ADDRESS(scsi_pointer->buffer) + done;
- scsi_pointer->this_residual = scsi_pointer->buffer->length -
- done;
+ acp->buffer = sg;
+ acp->ptr = SG_ADDRESS(acp->buffer) + done;
+ acp->this_residual = acp->buffer->length - done;
}
SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
@@ -2229,7 +2223,6 @@ static void datao_end(struct Scsi_Host *shpnt)
*/
static int update_state(struct Scsi_Host *shpnt)
{
- struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(CURRENT_SC);
int dataphase=0;
unsigned int stat0 = GETPORT(SSTAT0);
unsigned int stat1 = GETPORT(SSTAT1);
@@ -2244,7 +2237,7 @@ static int update_state(struct Scsi_Host *shpnt)
} else if (stat0 & SELDI && PREVSTATE == busfree) {
STATE=seldi;
} else if (stat0 & SELDO && CURRENT_SC &&
- (scsi_pointer->phase & selecting)) {
+ (aha152x_priv(CURRENT_SC)->phase & selecting)) {
STATE=seldo;
} else if(stat1 & SELTO) {
STATE=selto;
@@ -2376,8 +2369,7 @@ static void is_complete(struct Scsi_Host *shpnt)
SETPORT(SXFRCTL0, CH1);
SETPORT(DMACNTRL0, 0);
if(CURRENT_SC)
- aha152x_scsi_pointer(CURRENT_SC)->phase &=
- ~spiordy;
+ aha152x_priv(CURRENT_SC)->phase &= ~spiordy;
}
/*
@@ -2399,8 +2391,7 @@ static void is_complete(struct Scsi_Host *shpnt)
SETPORT(DMACNTRL0, 0);
SETPORT(SXFRCTL0, CH1|SPIOEN);
if(CURRENT_SC)
- aha152x_scsi_pointer(CURRENT_SC)->phase |=
- spiordy;
+ aha152x_priv(CURRENT_SC)->phase |= spiordy;
}
/*
@@ -2490,7 +2481,7 @@ static void disp_enintr(struct Scsi_Host *shpnt)
*/
static void show_command(struct scsi_cmnd *ptr)
{
- const int phase = aha152x_scsi_pointer(ptr)->phase;
+ const int phase = aha152x_priv(ptr)->phase;
scsi_print_command(ptr);
scmd_printk(KERN_DEBUG, ptr,
@@ -2538,8 +2529,8 @@ static void show_queues(struct Scsi_Host *shpnt)
static void get_command(struct seq_file *m, struct scsi_cmnd * ptr)
{
- struct scsi_pointer *scsi_pointer = aha152x_scsi_pointer(ptr);
- const int phase = scsi_pointer->phase;
+ struct aha152x_cmd_priv *acp = aha152x_priv(ptr);
+ const int phase = acp->phase;
int i;
seq_printf(m, "%p: target=%d; lun=%d; cmnd=( ",
@@ -2549,8 +2540,8 @@ static void get_command(struct seq_file *m, struct scsi_cmnd * ptr)
seq_printf(m, "0x%02x ", ptr->cmnd[i]);
seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |",
- scsi_get_resid(ptr), scsi_pointer->this_residual,
- sg_nents(scsi_pointer->buffer) - 1);
+ scsi_get_resid(ptr), acp->this_residual,
+ sg_nents(acp->buffer) - 1);
if (phase & not_issued)
seq_puts(m, "not issued|");
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index cf7bba2ca68d..552ca95157da 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -302,7 +302,7 @@ static irqreturn_t aha1542_interrupt(int irq, void *dev_id)
if (flag & SCRD)
printk("SCRD ");
printk("status %02x\n", inb(STATUS(sh->io_port)));
- };
+ }
#endif
number_serviced = 0;
@@ -344,7 +344,7 @@ static irqreturn_t aha1542_interrupt(int irq, void *dev_id)
if (!number_serviced)
shost_printk(KERN_WARNING, sh, "interrupt received, but no mail.\n");
return IRQ_HANDLED;
- };
+ }
mbo = (scsi2int(mb[mbi].ccbptr) - (unsigned long)aha1542->ccb_handle) / sizeof(struct ccb);
mbistatus = mb[mbi].status;
@@ -408,7 +408,7 @@ static irqreturn_t aha1542_interrupt(int irq, void *dev_id)
*/
scsi_done(tmp_cmd);
number_serviced++;
- };
+ }
}
static int aha1542_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
@@ -534,7 +534,7 @@ static void setup_mailboxes(struct Scsi_Host *sh)
any2scsi(aha1542->mb[i].ccbptr,
aha1542->ccb_handle + i * sizeof(struct ccb));
aha1542->mb[AHA1542_MAILBOXES + i].status = 0;
- };
+ }
aha1542_intr_reset(sh->io_port); /* reset interrupts, so they don't block */
any2scsi(mb_cmd + 2, aha1542->mb_handle);
if (aha1542_out(sh->io_port, mb_cmd, 5))
@@ -549,7 +549,7 @@ static int aha1542_getconfig(struct Scsi_Host *sh)
i = inb(STATUS(sh->io_port));
if (i & DF) {
i = inb(DATA(sh->io_port));
- };
+ }
aha1542_outb(sh->io_port, CMD_RETCONF);
aha1542_in(sh->io_port, inquiry_result, 3, 0);
if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
@@ -578,7 +578,7 @@ static int aha1542_getconfig(struct Scsi_Host *sh)
default:
shost_printk(KERN_ERR, sh, "Unable to determine DMA channel.\n");
return -1;
- };
+ }
switch (inquiry_result[1]) {
case 0x40:
sh->irq = 15;
@@ -601,7 +601,7 @@ static int aha1542_getconfig(struct Scsi_Host *sh)
default:
shost_printk(KERN_ERR, sh, "Unable to determine IRQ level.\n");
return -1;
- };
+ }
sh->this_id = inquiry_result[2] & 7;
return 0;
}
@@ -636,7 +636,7 @@ static int aha1542_mbenable(struct Scsi_Host *sh)
if (aha1542_out(sh->io_port, mbenable_cmd, 3))
goto fail;
- };
+ }
while (0) {
fail:
shost_printk(KERN_ERR, sh, "Mailbox init failed\n");
@@ -654,7 +654,7 @@ static int aha1542_query(struct Scsi_Host *sh)
i = inb(STATUS(sh->io_port));
if (i & DF) {
i = inb(DATA(sh->io_port));
- };
+ }
aha1542_outb(sh->io_port, CMD_INQUIRY);
aha1542_in(sh->io_port, inquiry_result, 4, 0);
if (!wait_mask(INTRFLAGS(sh->io_port), INTRMASK, HACC, 0, 0))
@@ -673,7 +673,7 @@ static int aha1542_query(struct Scsi_Host *sh)
if (inquiry_result[0] == 0x43) {
shost_printk(KERN_INFO, sh, "Emulation mode not supported for AHA-1740 hardware, use aha1740 driver instead.\n");
return 1;
- };
+ }
/*
* Always call this - boards that do not support extended bios translation
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 679a4fd13874..793fe19993a9 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -420,8 +420,6 @@ ahd_unlock(struct ahd_softc *ahd, unsigned long *flags)
/* config registers for header type 0 devices */
#define PCIR_MAPS 0x10
-#define PCIR_SUBVEND_0 0x2c
-#define PCIR_SUBDEV_0 0x2e
/****************************** PCI-X definitions *****************************/
#define PCIXR_COMMAND 0x96
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 2f0bdb9225a4..5fad41b1ab58 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -260,8 +260,8 @@ ahd_find_pci_device(ahd_dev_softc_t pci)
vendor = ahd_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2);
device = ahd_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2);
- subvendor = ahd_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2);
- subdevice = ahd_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2);
+ subvendor = ahd_pci_read_config(pci, PCI_SUBSYSTEM_VENDOR_ID, /*bytes*/2);
+ subdevice = ahd_pci_read_config(pci, PCI_SUBSYSTEM_ID, /*bytes*/2);
full_id = ahd_compose_id(device,
vendor,
subdevice,
@@ -298,7 +298,7 @@ ahd_pci_config(struct ahd_softc *ahd, const struct ahd_pci_identity *entry)
* Record if this is an HP board.
*/
subvendor = ahd_pci_read_config(ahd->dev_softc,
- PCIR_SUBVEND_0, /*bytes*/2);
+ PCI_SUBSYSTEM_VENDOR_ID, /*bytes*/2);
if (subvendor == SUBID_HP)
ahd->flags |= AHD_HP_BOARD;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index 4782a304e93c..51d9f4de0734 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -433,8 +433,6 @@ ahc_unlock(struct ahc_softc *ahc, unsigned long *flags)
/* config registers for header type 0 devices */
#define PCIR_MAPS 0x10
-#define PCIR_SUBVEND_0 0x2c
-#define PCIR_SUBDEV_0 0x2e
typedef enum
{
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
index dab3a6d12c4d..2d4c85426dc3 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -673,8 +673,8 @@ ahc_find_pci_device(ahc_dev_softc_t pci)
vendor = ahc_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2);
device = ahc_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2);
- subvendor = ahc_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2);
- subdevice = ahc_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2);
+ subvendor = ahc_pci_read_config(pci, PCI_SUBSYSTEM_VENDOR_ID, /*bytes*/2);
+ subdevice = ahc_pci_read_config(pci, PCI_SUBSYSTEM_ID, /*bytes*/2);
full_id = ahc_compose_id(device, vendor, subdevice, subvendor);
/*
diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c
index fd1b378a263a..52db147d9979 100644
--- a/drivers/scsi/bfa/bfad_debugfs.c
+++ b/drivers/scsi/bfa/bfad_debugfs.c
@@ -371,8 +371,7 @@ bfad_debugfs_release_fwtrc(struct inode *inode, struct file *file)
if (!fw_debug)
return 0;
- if (fw_debug->debug_buffer)
- vfree(fw_debug->debug_buffer);
+ vfree(fw_debug->debug_buffer);
file->private_data = NULL;
kfree(fw_debug);
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index 8419a1a89485..c335f7a188d2 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -755,7 +755,6 @@ void
bfad_destroy_workq(struct bfad_im_s *im)
{
if (im && im->drv_workq) {
- flush_workqueue(im->drv_workq);
destroy_workqueue(im->drv_workq);
im->drv_workq = NULL;
}
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index d295867a9b46..05ddbb9bb7d8 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -273,7 +273,6 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
struct fcoe_port *port;
struct fcoe_hdr *hp;
struct bnx2fc_rport *tgt;
- struct fc_stats *stats;
u8 sof, eof;
u32 crc;
unsigned int hlen, tlen, elen;
@@ -399,10 +398,8 @@ static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp)
}
/*update tx stats */
- stats = per_cpu_ptr(lport->stats, get_cpu());
- stats->TxFrames++;
- stats->TxWords += wlen;
- put_cpu();
+ this_cpu_inc(lport->stats->TxFrames);
+ this_cpu_add(lport->stats->TxWords, wlen);
/* send down to lld */
fr_dev(fp) = lport;
@@ -512,7 +509,6 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
u32 fr_len, fr_crc;
struct fc_lport *lport;
struct fcoe_rcv_info *fr;
- struct fc_stats *stats;
struct fc_frame_header *fh;
struct fcoe_crc_eof crc_eof;
struct fc_frame *fp;
@@ -543,10 +539,8 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
skb_pull(skb, sizeof(struct fcoe_hdr));
fr_len = skb->len - sizeof(struct fcoe_crc_eof);
- stats = per_cpu_ptr(lport->stats, get_cpu());
- stats->RxFrames++;
- stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
- put_cpu();
+ this_cpu_inc(lport->stats->RxFrames);
+ this_cpu_add(lport->stats->RxWords, fr_len / FCOE_WORD_TO_BYTE);
fp = (struct fc_frame *)skb;
fc_frame_init(fp);
@@ -633,9 +627,7 @@ static void bnx2fc_recv_frame(struct sk_buff *skb)
fr_crc = le32_to_cpu(fr_crc(fp));
if (unlikely(fr_crc != ~crc32(~0, skb->data, fr_len))) {
- stats = per_cpu_ptr(lport->stats, get_cpu());
- crc_err = (stats->InvalidCRCCount++);
- put_cpu();
+ crc_err = this_cpu_inc_return(lport->stats->InvalidCRCCount);
if (crc_err < 5)
printk(KERN_WARNING PFX "dropping frame with "
"CRC error\n");
@@ -964,9 +956,7 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
mutex_unlock(&lport->lp_mutex);
fc_host_port_type(lport->host) =
FC_PORTTYPE_UNKNOWN;
- per_cpu_ptr(lport->stats,
- get_cpu())->LinkFailureCount++;
- put_cpu();
+ this_cpu_inc(lport->stats->LinkFailureCount);
fcoe_clean_pending_queue(lport);
wait_for_upload = 1;
}
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
index 0103f811cc25..776544385598 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -1169,7 +1169,7 @@ static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba,
ofld_kcqe->fcoe_conn_context_id);
interface = tgt->port->priv;
if (hba != interface->hba) {
- printk(KERN_ERR PFX "ERROR:ofld_cmpl: HBA mis-match\n");
+ printk(KERN_ERR PFX "ERROR:ofld_cmpl: HBA mismatch\n");
goto ofld_cmpl_err;
}
/*
@@ -1226,12 +1226,12 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba,
* and enable
*/
if (tgt->context_id != context_id) {
- printk(KERN_ERR PFX "context id mis-match\n");
+ printk(KERN_ERR PFX "context id mismatch\n");
return;
}
interface = tgt->port->priv;
if (hba != interface->hba) {
- printk(KERN_ERR PFX "bnx2fc-enbl_cmpl: HBA mis-match\n");
+ printk(KERN_ERR PFX "bnx2fc-enbl_cmpl: HBA mismatch\n");
goto enbl_cmpl_err;
}
if (!ofld_kcqe->completion_status)
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index 962454f2e2b1..b42a9accb832 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -472,7 +472,7 @@ struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt)
u32 free_sqes;
u32 max_sqes;
u16 xid;
- int index = get_cpu();
+ int index = raw_smp_processor_id();
max_sqes = BNX2FC_SCSI_MAX_SQES;
/*
@@ -485,7 +485,6 @@ struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt)
(tgt->num_active_ios.counter >= max_sqes) ||
(free_sqes + max_sqes <= BNX2FC_SQ_WQES_MAX)) {
spin_unlock_bh(&cmd_mgr->free_list_lock[index]);
- put_cpu();
return NULL;
}
@@ -498,7 +497,6 @@ struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt)
atomic_inc(&tgt->num_active_ios);
atomic_dec(&tgt->free_sqes);
spin_unlock_bh(&cmd_mgr->free_list_lock[index]);
- put_cpu();
INIT_LIST_HEAD(&io_req->link);
@@ -2032,7 +2030,6 @@ int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
struct bnx2fc_interface *interface = port->priv;
struct bnx2fc_hba *hba = interface->hba;
struct fc_lport *lport = port->lport;
- struct fc_stats *stats;
int task_idx, index;
u16 xid;
@@ -2045,20 +2042,18 @@ int bnx2fc_post_io_req(struct bnx2fc_rport *tgt,
io_req->data_xfer_len = scsi_bufflen(sc_cmd);
bnx2fc_priv(sc_cmd)->io_req = io_req;
- stats = per_cpu_ptr(lport->stats, get_cpu());
if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) {
io_req->io_req_flags = BNX2FC_READ;
- stats->InputRequests++;
- stats->InputBytes += io_req->data_xfer_len;
+ this_cpu_inc(lport->stats->InputRequests);
+ this_cpu_add(lport->stats->InputBytes, io_req->data_xfer_len);
} else if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) {
io_req->io_req_flags = BNX2FC_WRITE;
- stats->OutputRequests++;
- stats->OutputBytes += io_req->data_xfer_len;
+ this_cpu_inc(lport->stats->OutputRequests);
+ this_cpu_add(lport->stats->OutputBytes, io_req->data_xfer_len);
} else {
io_req->io_req_flags = 0;
- stats->ControlRequests++;
+ this_cpu_inc(lport->stats->ControlRequests);
}
- put_cpu();
xid = io_req->xid;
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 5521469ce678..6c864b093ac9 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -1977,7 +1977,7 @@ static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn)
if (nopin->cq_req_sn != qp->cqe_exp_seq_sn)
break;
- if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx))) {
+ if (unlikely(test_bit(ISCSI_CONN_FLAG_SUSPEND_RX, &conn->flags))) {
if (nopin->op_code == ISCSI_OP_NOOP_IN &&
nopin->itt == (u16) RESERVED_ITT) {
printk(KERN_ALERT "bnx2i: Unsolicited "
@@ -2398,7 +2398,7 @@ static void bnx2i_process_conn_destroy_cmpl(struct bnx2i_hba *hba,
}
if (hba != ep->hba) {
- printk(KERN_ALERT "conn destroy- error hba mis-match\n");
+ printk(KERN_ALERT "conn destroy- error hba mismatch\n");
return;
}
@@ -2432,7 +2432,7 @@ static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba,
}
if (hba != ep->hba) {
- printk(KERN_ALERT "ofld_cmpl: error hba mis-match\n");
+ printk(KERN_ALERT "ofld_cmpl: error hba mismatch\n");
return;
}
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index fe86fd61a995..15fbd09baa94 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1721,7 +1721,7 @@ static int bnx2i_tear_down_conn(struct bnx2i_hba *hba,
struct iscsi_conn *conn = ep->conn->cls_conn->dd_data;
/* Must suspend all rx queue activity for this ep */
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
+ set_bit(ISCSI_CONN_FLAG_SUSPEND_RX, &conn->flags);
}
/* CONN_DISCONNECT timeout may or may not be an issue depending
* on what transcribed in TCP layer, different targets behave
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index 8c7d4dda4cf2..4365d52c6430 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -1634,11 +1634,11 @@ void cxgbi_conn_pdu_ready(struct cxgbi_sock *csk)
log_debug(1 << CXGBI_DBG_PDU_RX,
"csk 0x%p, conn 0x%p.\n", csk, conn);
- if (unlikely(!conn || conn->suspend_rx)) {
+ if (unlikely(!conn || test_bit(ISCSI_CONN_FLAG_SUSPEND_RX, &conn->flags))) {
log_debug(1 << CXGBI_DBG_PDU_RX,
- "csk 0x%p, conn 0x%p, id %d, suspend_rx %lu!\n",
+ "csk 0x%p, conn 0x%p, id %d, conn flags 0x%lx!\n",
csk, conn, conn ? conn->id : 0xFF,
- conn ? conn->suspend_rx : 0xFF);
+ conn ? conn->flags : 0xFF);
return;
}
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 67a89715c863..670a836a6ba1 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -3585,10 +3585,19 @@ static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb,
#endif
if (dcb->target_lun != 0) {
/* Copy settings */
- struct DeviceCtlBlk *p;
- list_for_each_entry(p, &acb->dcb_list, list)
- if (p->target_id == dcb->target_id)
+ struct DeviceCtlBlk *p = NULL, *iter;
+
+ list_for_each_entry(iter, &acb->dcb_list, list)
+ if (iter->target_id == dcb->target_id) {
+ p = iter;
break;
+ }
+
+ if (!p) {
+ kfree(dcb);
+ return NULL;
+ }
+
dprintkdbg(DBG_1,
"device_alloc: <%02i-%i> copy from <%02i-%i>\n",
dcb->target_id, dcb->target_lun,
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 37d06f993b76..1d9be771f3ee 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -1172,9 +1172,8 @@ static blk_status_t alua_prep_fn(struct scsi_device *sdev, struct request *req)
case SCSI_ACCESS_STATE_OPTIMAL:
case SCSI_ACCESS_STATE_ACTIVE:
case SCSI_ACCESS_STATE_LBA:
- return BLK_STS_OK;
case SCSI_ACCESS_STATE_TRANSITIONING:
- return BLK_STS_AGAIN;
+ return BLK_STS_OK;
default:
req->rq_flags |= RQF_QUIET;
return BLK_STS_IOERR;
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 93227c04ef59..2e9155ba7408 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -1000,7 +1000,6 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
// Initializing the spinlocks
spin_lock_init(&pHba->state_lock);
- spin_lock_init(&adpt_post_wait_lock);
if(raptorFlag == 0){
printk(KERN_INFO "Adaptec I2O RAID controller"
diff --git a/drivers/scsi/elx/efct/efct_hw.c b/drivers/scsi/elx/efct/efct_hw.c
index d4bb37960a3c..5a5525054d71 100644
--- a/drivers/scsi/elx/efct/efct_hw.c
+++ b/drivers/scsi/elx/efct/efct_hw.c
@@ -1402,7 +1402,6 @@ efct_hw_command(struct efct_hw *hw, u8 *cmd, u32 opts, void *cb, void *arg)
mutex_lock(&hw->bmbx_lock);
bmbx = hw->sli.bmbx.virt;
- memset(bmbx, 0, SLI4_BMBX_SIZE);
memcpy(bmbx, cmd, SLI4_BMBX_SIZE);
if (sli_bmbx_command(&hw->sli) == 0) {
diff --git a/drivers/scsi/elx/efct/efct_io.c b/drivers/scsi/elx/efct/efct_io.c
index c3247b951a76..c612f0a48839 100644
--- a/drivers/scsi/elx/efct/efct_io.c
+++ b/drivers/scsi/elx/efct/efct_io.c
@@ -62,7 +62,6 @@ efct_io_pool_create(struct efct *efct, u32 num_sgl)
return NULL;
}
- memset(io->sgl, 0, sizeof(*io->sgl) * num_sgl);
io->sgl_allocated = num_sgl;
io->sgl_count = 0;
diff --git a/drivers/scsi/elx/efct/efct_lio.c b/drivers/scsi/elx/efct/efct_lio.c
index 8b004a5818d6..be4b5c1ee32d 100644
--- a/drivers/scsi/elx/efct/efct_lio.c
+++ b/drivers/scsi/elx/efct/efct_lio.c
@@ -370,9 +370,6 @@ static int efct_lio_get_cmd_state(struct se_cmd *cmd)
container_of(cmd, struct efct_scsi_tgt_io, cmd);
struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
- if (!io)
- return 0;
-
return io->tgt_io.state;
}
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 44ca6110213c..c2a59109857a 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -667,7 +667,7 @@ static void fcoe_netdev_features_change(struct fc_lport *lport,
if (netdev->features & NETIF_F_FSO) {
lport->seq_offload = 1;
- lport->lso_max = netdev->gso_max_size;
+ lport->lso_max = min(netdev->gso_max_size, GSO_LEGACY_MAX_SIZE);
FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n",
lport->lso_max);
} else {
@@ -1434,8 +1434,7 @@ static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
return NET_RX_SUCCESS;
err:
- per_cpu_ptr(lport->stats, get_cpu())->ErrorFrames++;
- put_cpu();
+ this_cpu_inc(lport->stats->ErrorFrames);
err2:
kfree_skb(skb);
return NET_RX_DROP;
@@ -1453,9 +1452,10 @@ static int fcoe_alloc_paged_crc_eof(struct sk_buff *skb, int tlen)
struct fcoe_percpu_s *fps;
int rc;
- fps = &get_cpu_var(fcoe_percpu);
+ local_lock(&fcoe_percpu.lock);
+ fps = this_cpu_ptr(&fcoe_percpu);
rc = fcoe_get_paged_crc_eof(skb, tlen, fps);
- put_cpu_var(fcoe_percpu);
+ local_unlock(&fcoe_percpu.lock);
return rc;
}
@@ -1474,7 +1474,6 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
struct ethhdr *eh;
struct fcoe_crc_eof *cp;
struct sk_buff *skb;
- struct fc_stats *stats;
struct fc_frame_header *fh;
unsigned int hlen; /* header length implies the version */
unsigned int tlen; /* trailer length */
@@ -1585,10 +1584,8 @@ static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
skb_shinfo(skb)->gso_size = 0;
}
/* update tx stats: regardless if LLD fails */
- stats = per_cpu_ptr(lport->stats, get_cpu());
- stats->TxFrames++;
- stats->TxWords += wlen;
- put_cpu();
+ this_cpu_inc(lport->stats->TxFrames);
+ this_cpu_add(lport->stats->TxWords, wlen);
/* send down to lld */
fr_dev(fp) = lport;
@@ -1610,7 +1607,6 @@ static inline int fcoe_filter_frames(struct fc_lport *lport,
struct fcoe_interface *fcoe;
struct fc_frame_header *fh;
struct sk_buff *skb = (struct sk_buff *)fp;
- struct fc_stats *stats;
/*
* We only check CRC if no offload is available and if it is
@@ -1640,11 +1636,8 @@ static inline int fcoe_filter_frames(struct fc_lport *lport,
return 0;
}
- stats = per_cpu_ptr(lport->stats, get_cpu());
- stats->InvalidCRCCount++;
- if (stats->InvalidCRCCount < 5)
+ if (this_cpu_inc_return(lport->stats->InvalidCRCCount) < 5)
printk(KERN_WARNING "fcoe: dropping frame with CRC error\n");
- put_cpu();
return -EINVAL;
}
@@ -1657,7 +1650,6 @@ static void fcoe_recv_frame(struct sk_buff *skb)
u32 fr_len;
struct fc_lport *lport;
struct fcoe_rcv_info *fr;
- struct fc_stats *stats;
struct fcoe_crc_eof crc_eof;
struct fc_frame *fp;
struct fcoe_hdr *hp;
@@ -1685,9 +1677,11 @@ static void fcoe_recv_frame(struct sk_buff *skb)
*/
hp = (struct fcoe_hdr *) skb_network_header(skb);
- stats = per_cpu_ptr(lport->stats, get_cpu());
if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
- if (stats->ErrorFrames < 5)
+ struct fc_stats *stats;
+
+ stats = per_cpu_ptr(lport->stats, raw_smp_processor_id());
+ if (READ_ONCE(stats->ErrorFrames) < 5)
printk(KERN_WARNING "fcoe: FCoE version "
"mismatch: The frame has "
"version %x, but the "
@@ -1700,8 +1694,8 @@ static void fcoe_recv_frame(struct sk_buff *skb)
skb_pull(skb, sizeof(struct fcoe_hdr));
fr_len = skb->len - sizeof(struct fcoe_crc_eof);
- stats->RxFrames++;
- stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
+ this_cpu_inc(lport->stats->RxFrames);
+ this_cpu_add(lport->stats->RxWords, fr_len / FCOE_WORD_TO_BYTE);
fp = (struct fc_frame *)skb;
fc_frame_init(fp);
@@ -1717,13 +1711,11 @@ static void fcoe_recv_frame(struct sk_buff *skb)
goto drop;
if (!fcoe_filter_frames(lport, fp)) {
- put_cpu();
fc_exch_recv(lport, fp);
return;
}
drop:
- stats->ErrorFrames++;
- put_cpu();
+ this_cpu_inc(lport->stats->ErrorFrames);
kfree_skb(skb);
}
@@ -1847,7 +1839,6 @@ static int fcoe_device_notification(struct notifier_block *notifier,
struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
struct fcoe_ctlr *ctlr;
struct fcoe_interface *fcoe;
- struct fc_stats *stats;
u32 link_possible = 1;
u32 mfs;
int rc = NOTIFY_OK;
@@ -1921,9 +1912,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,
break;
case FCOE_CTLR_ENABLED:
case FCOE_CTLR_UNUSED:
- stats = per_cpu_ptr(lport->stats, get_cpu());
- stats->LinkFailureCount++;
- put_cpu();
+ this_cpu_inc(lport->stats->LinkFailureCount);
fcoe_clean_pending_queue(lport);
}
}
@@ -2488,6 +2477,7 @@ static int __init fcoe_init(void)
p = per_cpu_ptr(&fcoe_percpu, cpu);
INIT_WORK(&p->work, fcoe_receive_work);
skb_queue_head_init(&p->fcoe_rx_list);
+ local_lock_init(&p->lock);
}
/* Setup link change notification */
@@ -2580,7 +2570,7 @@ static void fcoe_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
/* pre-FIP */
if (is_zero_ether_addr(mac))
fcoe_ctlr_recv_flogi(fip, lport, fp);
- if (!is_zero_ether_addr(mac))
+ else
fcoe_update_src_mac(lport, mac);
done:
fc_lport_flogi_resp(seq, fp, lport);
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 1756a0ac6f08..39e16eab47aa 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -824,22 +824,21 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
unsigned long deadline;
unsigned long sel_time = 0;
struct list_head del_list;
- struct fc_stats *stats;
INIT_LIST_HEAD(&del_list);
- stats = per_cpu_ptr(fip->lp->stats, get_cpu());
-
list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2;
if (fip->sel_fcf == fcf) {
if (time_after(jiffies, deadline)) {
- stats->MissDiscAdvCount++;
+ u64 miss_cnt;
+
+ miss_cnt = this_cpu_inc_return(fip->lp->stats->MissDiscAdvCount);
printk(KERN_INFO "libfcoe: host%d: "
"Missing Discovery Advertisement "
"for fab %16.16llx count %lld\n",
fip->lp->host->host_no, fcf->fabric_name,
- stats->MissDiscAdvCount);
+ miss_cnt);
} else if (time_after(next_timer, deadline))
next_timer = deadline;
}
@@ -855,7 +854,7 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
*/
list_del(&fcf->list);
list_add(&fcf->list, &del_list);
- stats->VLinkFailureCount++;
+ this_cpu_inc(fip->lp->stats->VLinkFailureCount);
} else {
if (time_after(next_timer, deadline))
next_timer = deadline;
@@ -864,7 +863,6 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
sel_time = fcf->time;
}
}
- put_cpu();
list_for_each_entry_safe(fcf, next, &del_list, list) {
/* Removes fcf from current list */
@@ -1142,7 +1140,6 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
struct fip_desc *desc;
struct fip_encaps *els;
struct fcoe_fcf *sel;
- struct fc_stats *stats;
enum fip_desc_type els_dtype = 0;
u8 els_op;
u8 sub;
@@ -1286,10 +1283,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
fr_dev(fp) = lport;
fr_encaps(fp) = els_dtype;
- stats = per_cpu_ptr(lport->stats, get_cpu());
- stats->RxFrames++;
- stats->RxWords += skb->len / FIP_BPW;
- put_cpu();
+ this_cpu_inc(lport->stats->RxFrames);
+ this_cpu_add(lport->stats->RxWords, skb->len / FIP_BPW);
fc_exch_recv(lport, fp);
return;
@@ -1427,9 +1422,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
ntoh24(vp->fd_fc_id));
if (vn_port && (vn_port == lport)) {
mutex_lock(&fip->ctlr_mutex);
- per_cpu_ptr(lport->stats,
- get_cpu())->VLinkFailureCount++;
- put_cpu();
+ this_cpu_inc(lport->stats->VLinkFailureCount);
fcoe_ctlr_reset(fip);
mutex_unlock(&fip->ctlr_mutex);
}
@@ -1457,8 +1450,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
* followed by physical port
*/
mutex_lock(&fip->ctlr_mutex);
- per_cpu_ptr(lport->stats, get_cpu())->VLinkFailureCount++;
- put_cpu();
+ this_cpu_inc(lport->stats->VLinkFailureCount);
fcoe_ctlr_reset(fip);
mutex_unlock(&fip->ctlr_mutex);
@@ -1969,7 +1961,7 @@ EXPORT_SYMBOL(fcoe_ctlr_recv_flogi);
*
* Returns: u64 fc world wide name
*/
-u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN],
+u64 fcoe_wwn_from_mac(unsigned char mac[ETH_ALEN],
unsigned int scheme, unsigned int port)
{
u64 wwn;
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
index 4d0e19e7c84b..62341c6353a7 100644
--- a/drivers/scsi/fcoe/fcoe_transport.c
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -183,9 +183,9 @@ void __fcoe_get_lesb(struct fc_lport *lport,
memset(lesb, 0, sizeof(*lesb));
for_each_possible_cpu(cpu) {
stats = per_cpu_ptr(lport->stats, cpu);
- lfc += stats->LinkFailureCount;
- vlfc += stats->VLinkFailureCount;
- mdac += stats->MissDiscAdvCount;
+ lfc += READ_ONCE(stats->LinkFailureCount);
+ vlfc += READ_ONCE(stats->VLinkFailureCount);
+ mdac += READ_ONCE(stats->MissDiscAdvCount);
}
lesb->lesb_link_fail = htonl(lfc);
lesb->lesb_vlink_fail = htonl(vlfc);
diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h
index aa07189fb5fb..85ec6163ddab 100644
--- a/drivers/scsi/fnic/fnic.h
+++ b/drivers/scsi/fnic/fnic.h
@@ -39,7 +39,7 @@
#define DRV_NAME "fnic"
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
-#define DRV_VERSION "1.6.0.53"
+#define DRV_VERSION "1.6.0.54"
#define PFX DRV_NAME ": "
#define DFX DRV_NAME "%d: "
diff --git a/drivers/scsi/fnic/fnic_debugfs.c b/drivers/scsi/fnic/fnic_debugfs.c
index e7326505cabb..866b4c983ace 100644
--- a/drivers/scsi/fnic/fnic_debugfs.c
+++ b/drivers/scsi/fnic/fnic_debugfs.c
@@ -86,8 +86,7 @@ void fnic_debugfs_terminate(void)
debugfs_remove(fnic_trace_debugfs_root);
fnic_trace_debugfs_root = NULL;
- if (fc_trc_flag)
- vfree(fc_trc_flag);
+ vfree(fc_trc_flag);
}
/*
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index 9161bd2fd421..51e7c344ddc3 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -612,10 +612,10 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
/* Query PCI controller on system for DMA addressing
- * limitation for the device. Try 64-bit first, and
- * fail to 32-bit.
+ * limitation for the device. Try 47-bit first, and
+ * fail to 32-bit. Cisco VIC supports 47 bits only.
*/
- err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(47));
if (err) {
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (err) {
@@ -1146,10 +1146,8 @@ static void __exit fnic_cleanup_module(void)
{
pci_unregister_driver(&fnic_driver);
destroy_workqueue(fnic_event_queue);
- if (fnic_fip_queue) {
- flush_workqueue(fnic_fip_queue);
+ if (fnic_fip_queue)
destroy_workqueue(fnic_fip_queue);
- }
kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_MAX]);
kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]);
kmem_cache_destroy(fnic_io_req_cache);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 461ef8a76c4c..764e859d0106 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -442,11 +442,12 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba,
case SAS_PROTOCOL_INTERNAL_ABORT:
hisi_sas_task_prep_abort(hisi_hba, slot);
break;
- fallthrough;
default:
return;
}
+ /* Make slot memories observable before marking as ready */
+ smp_wmb();
WRITE_ONCE(slot->ready, 1);
spin_lock(&dq->lock);
@@ -710,8 +711,6 @@ static int hisi_sas_init_device(struct domain_device *device)
struct scsi_lun lun;
int retry = HISI_SAS_DISK_RECOVER_CNT;
struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
- struct device *dev = hisi_hba->dev;
- struct sas_phy *local_phy;
switch (device->dev_type) {
case SAS_END_DEVICE:
@@ -730,30 +729,18 @@ static int hisi_sas_init_device(struct domain_device *device)
case SAS_SATA_PM_PORT:
case SAS_SATA_PENDING:
/*
- * send HARD RESET to clear previous affiliation of
- * STP target port
+ * If an expander is swapped when a SATA disk is attached then
+ * we should issue a hard reset to clear previous affiliation
+ * of STP target port, see SPL (chapter 6.19.4).
+ *
+ * However we don't need to issue a hard reset here for these
+ * reasons:
+ * a. When probing the device, libsas/libata already issues a
+ * hard reset in sas_probe_sata() -> ata_sas_async_probe().
+ * Note that in hisi_sas_debug_I_T_nexus_reset() we take care
+ * to issue a hard reset by checking the dev status (== INIT).
+ * b. When resetting the controller, this is simply unnecessary.
*/
- local_phy = sas_get_local_phy(device);
- if (!scsi_is_sas_phy_local(local_phy) &&
- !test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) {
- unsigned long deadline = ata_deadline(jiffies, 20000);
- struct sata_device *sata_dev = &device->sata_dev;
- struct ata_host *ata_host = sata_dev->ata_host;
- struct ata_port_operations *ops = ata_host->ops;
- struct ata_port *ap = sata_dev->ap;
- struct ata_link *link;
- unsigned int classes;
-
- ata_for_each_link(link, ap, EDGE)
- rc = ops->hardreset(link, &classes,
- deadline);
- }
- sas_put_local_phy(local_phy);
- if (rc) {
- dev_warn(dev, "SATA disk hardreset fail: %d\n", rc);
- return rc;
- }
-
while (retry-- > 0) {
rc = hisi_sas_softreset_ata_disk(device);
if (!rc)
@@ -769,15 +756,19 @@ static int hisi_sas_init_device(struct domain_device *device)
int hisi_sas_slave_alloc(struct scsi_device *sdev)
{
- struct domain_device *ddev;
+ struct domain_device *ddev = sdev_to_domain_dev(sdev);
+ struct hisi_sas_device *sas_dev = ddev->lldd_dev;
int rc;
rc = sas_slave_alloc(sdev);
if (rc)
return rc;
- ddev = sdev_to_domain_dev(sdev);
- return hisi_sas_init_device(ddev);
+ rc = hisi_sas_init_device(ddev);
+ if (rc)
+ return rc;
+ sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
+ return 0;
}
EXPORT_SYMBOL_GPL(hisi_sas_slave_alloc);
@@ -827,7 +818,6 @@ static int hisi_sas_dev_found(struct domain_device *device)
dev_info(dev, "dev[%d:%x] found\n",
sas_dev->device_id, sas_dev->dev_type);
- sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
return 0;
err_out:
@@ -1711,13 +1701,18 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
/* report PHY down if timed out */
if (rc == -ETIMEDOUT)
hisi_sas_phy_down(hisi_hba, sas_phy->id, 0, GFP_KERNEL);
- } else if (sas_dev->dev_status != HISI_SAS_DEV_INIT) {
- /*
- * If in init state, we rely on caller to wait for link to be
- * ready; otherwise, except phy reset is fail, delay.
- */
- if (!rc)
- msleep(2000);
+ return rc;
+ }
+
+ if (rc)
+ return rc;
+
+ /* Remote phy */
+ if (dev_is_sata(device)) {
+ rc = sas_ata_wait_after_reset(device,
+ HISI_SAS_WAIT_PHYUP_TIMEOUT);
+ } else {
+ msleep(2000);
}
return rc;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
index 79f87d7c3e68..7d819fc0395e 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c
@@ -1563,9 +1563,15 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
phy->port_id = port_id;
- /* Call pm_runtime_put_sync() with pairs in hisi_sas_phyup_pm_work() */
+ /*
+ * Call pm_runtime_get_noresume() which pairs with
+ * hisi_sas_phyup_pm_work() -> pm_runtime_put_sync().
+ * For failure call pm_runtime_put() as we are in a hardirq context.
+ */
pm_runtime_get_noresume(dev);
- hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP_PM);
+ res = hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP_PM);
+ if (!res)
+ pm_runtime_put(dev);
res = IRQ_HANDLED;
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index f69b77cbf538..8352f90d997d 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -229,10 +229,6 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
if (error)
goto fail;
- error = scsi_mq_setup_tags(shost);
- if (error)
- goto fail;
-
if (!shost->shost_gendev.parent)
shost->shost_gendev.parent = dev ? dev : &platform_bus;
if (!dma_dev)
@@ -240,6 +236,10 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
shost->dma_dev = dma_dev;
+ error = scsi_mq_setup_tags(shost);
+ if (error)
+ goto fail;
+
/*
* Increase usage count temporarily here so that calling
* scsi_autopm_put_host() will trigger runtime idle if there is
diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
index 80238e6a3c98..eee1a24f7e15 100644
--- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
+++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c
@@ -36,7 +36,7 @@
#define IBMVSCSIS_VERSION "v0.2"
-#define INITIAL_SRP_LIMIT 800
+#define INITIAL_SRP_LIMIT 1024
#define DEFAULT_MAX_SECTORS 256
#define MAX_TXU 1024 * 1024
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 104bee9b3a9d..256ec6d08c16 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3456,7 +3456,7 @@ static ssize_t ipr_read_trace(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct Scsi_Host *shost = class_to_shost(dev);
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
unsigned long lock_flags = 0;
@@ -4182,7 +4182,7 @@ static ssize_t ipr_read_async_err_log(struct file *filep, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t off, size_t count)
{
- struct device *cdev = container_of(kobj, struct device, kobj);
+ struct device *cdev = kobj_to_dev(kobj);
struct Scsi_Host *shost = class_to_shost(cdev);
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
struct ipr_hostrcb *hostrcb;
@@ -4206,7 +4206,7 @@ static ssize_t ipr_next_async_err_log(struct file *filep, struct kobject *kobj,
struct bin_attribute *bin_attr, char *buf,
loff_t off, size_t count)
{
- struct device *cdev = container_of(kobj, struct device, kobj);
+ struct device *cdev = kobj_to_dev(kobj);
struct Scsi_Host *shost = class_to_shost(cdev);
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
struct ipr_hostrcb *hostrcb;
@@ -4267,7 +4267,7 @@ static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct device *cdev = container_of(kobj, struct device, kobj);
+ struct device *cdev = kobj_to_dev(kobj);
struct Scsi_Host *shost = class_to_shost(cdev);
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
struct ipr_dump *dump;
@@ -4456,7 +4456,7 @@ static ssize_t ipr_write_dump(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
- struct device *cdev = container_of(kobj, struct device, kobj);
+ struct device *cdev = kobj_to_dev(kobj);
struct Scsi_Host *shost = class_to_shost(cdev);
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
int rc;
@@ -10092,7 +10092,6 @@ static irqreturn_t ipr_test_intr(int irq, void *devp)
{
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp;
unsigned long lock_flags = 0;
- irqreturn_t rc = IRQ_HANDLED;
dev_info(&ioa_cfg->pdev->dev, "Received IRQ : %d\n", irq);
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -10101,7 +10100,7 @@ static irqreturn_t ipr_test_intr(int irq, void *devp)
wake_up(&ioa_cfg->msi_wait_q);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
- return rc;
+ return IRQ_HANDLED;
}
/**
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index d690d9cf7eb1..35589b6af90d 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -413,7 +413,7 @@ static void sci_controller_event_completion(struct isci_host *ihost, u32 ent)
dev_warn(&ihost->pdev->dev,
"%s: SCIC Controller 0x%p received "
"event 0x%x for io request object "
- "that doesnt exist.\n",
+ "that doesn't exist.\n",
__func__,
ihost,
ent);
@@ -428,7 +428,7 @@ static void sci_controller_event_completion(struct isci_host *ihost, u32 ent)
dev_warn(&ihost->pdev->dev,
"%s: SCIC Controller 0x%p received "
"event 0x%x for remote device object "
- "that doesnt exist.\n",
+ "that doesn't exist.\n",
__func__,
ihost,
ent);
@@ -462,7 +462,7 @@ static void sci_controller_event_completion(struct isci_host *ihost, u32 ent)
} else
dev_err(&ihost->pdev->dev,
"%s: SCIC Controller 0x%p received event 0x%x "
- "for remote device object 0x%0x that doesnt "
+ "for remote device object 0x%0x that doesn't "
"exist.\n",
__func__,
ihost,
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index aa223db4cf53..1d91c457527f 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -825,10 +825,9 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport,
}
memset(ep, 0, sizeof(*ep));
- cpu = get_cpu();
+ cpu = raw_smp_processor_id();
pool = per_cpu_ptr(mp->pool, cpu);
spin_lock_bh(&pool->lock);
- put_cpu();
/* peek cache of free slot */
if (pool->left != FC_XID_UNKNOWN) {
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index bce90eb56c9c..945adca5e72f 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -143,8 +143,7 @@ static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lport, gfp_t gfp)
INIT_LIST_HEAD(&fsp->list);
spin_lock_init(&fsp->scsi_pkt_lock);
} else {
- per_cpu_ptr(lport->stats, get_cpu())->FcpPktAllocFails++;
- put_cpu();
+ this_cpu_inc(lport->stats->FcpPktAllocFails);
}
return fsp;
}
@@ -266,8 +265,7 @@ static int fc_fcp_send_abort(struct fc_fcp_pkt *fsp)
if (!fsp->seq_ptr)
return -EINVAL;
- per_cpu_ptr(fsp->lp->stats, get_cpu())->FcpPktAborts++;
- put_cpu();
+ this_cpu_inc(fsp->lp->stats->FcpPktAborts);
fsp->state |= FC_SRB_ABORT_PENDING;
rc = fc_seq_exch_abort(fsp->seq_ptr, 0);
@@ -436,8 +434,7 @@ static inline struct fc_frame *fc_fcp_frame_alloc(struct fc_lport *lport,
if (likely(fp))
return fp;
- per_cpu_ptr(lport->stats, get_cpu())->FcpFrameAllocFails++;
- put_cpu();
+ this_cpu_inc(lport->stats->FcpFrameAllocFails);
/* error case */
fc_fcp_can_queue_ramp_down(lport);
shost_printk(KERN_ERR, lport->host,
@@ -471,7 +468,6 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
{
struct scsi_cmnd *sc = fsp->cmd;
struct fc_lport *lport = fsp->lp;
- struct fc_stats *stats;
struct fc_frame_header *fh;
size_t start_offset;
size_t offset;
@@ -533,14 +529,12 @@ static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp)
if (~crc != le32_to_cpu(fr_crc(fp))) {
crc_err:
- stats = per_cpu_ptr(lport->stats, get_cpu());
- stats->ErrorFrames++;
+ this_cpu_inc(lport->stats->ErrorFrames);
/* per cpu count, not total count, but OK for limit */
- if (stats->InvalidCRCCount++ < FC_MAX_ERROR_CNT)
+ if (this_cpu_inc_return(lport->stats->InvalidCRCCount) < FC_MAX_ERROR_CNT)
printk(KERN_WARNING "libfc: CRC error on data "
"frame for port (%6.6x)\n",
lport->port_id);
- put_cpu();
/*
* Assume the frame is total garbage.
* We may have copied it over the good part
@@ -1861,7 +1855,6 @@ int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd)
struct fc_fcp_pkt *fsp;
int rval;
int rc = 0;
- struct fc_stats *stats;
rval = fc_remote_port_chkready(rport);
if (rval) {
@@ -1913,20 +1906,18 @@ int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd)
/*
* setup the data direction
*/
- stats = per_cpu_ptr(lport->stats, get_cpu());
if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) {
fsp->req_flags = FC_SRB_READ;
- stats->InputRequests++;
- stats->InputBytes += fsp->data_len;
+ this_cpu_inc(lport->stats->InputRequests);
+ this_cpu_add(lport->stats->InputBytes, fsp->data_len);
} else if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) {
fsp->req_flags = FC_SRB_WRITE;
- stats->OutputRequests++;
- stats->OutputBytes += fsp->data_len;
+ this_cpu_inc(lport->stats->OutputRequests);
+ this_cpu_add(lport->stats->OutputBytes, fsp->data_len);
} else {
fsp->req_flags = 0;
- stats->ControlRequests++;
+ this_cpu_inc(lport->stats->ControlRequests);
}
- put_cpu();
/*
* send it to the lower layer
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index 19cd4a95d354..9c02c9523c4d 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -308,21 +308,21 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost)
stats = per_cpu_ptr(lport->stats, cpu);
- fc_stats->tx_frames += stats->TxFrames;
- fc_stats->tx_words += stats->TxWords;
- fc_stats->rx_frames += stats->RxFrames;
- fc_stats->rx_words += stats->RxWords;
- fc_stats->error_frames += stats->ErrorFrames;
- fc_stats->invalid_crc_count += stats->InvalidCRCCount;
- fc_stats->fcp_input_requests += stats->InputRequests;
- fc_stats->fcp_output_requests += stats->OutputRequests;
- fc_stats->fcp_control_requests += stats->ControlRequests;
- fcp_in_bytes += stats->InputBytes;
- fcp_out_bytes += stats->OutputBytes;
- fc_stats->fcp_packet_alloc_failures += stats->FcpPktAllocFails;
- fc_stats->fcp_packet_aborts += stats->FcpPktAborts;
- fc_stats->fcp_frame_alloc_failures += stats->FcpFrameAllocFails;
- fc_stats->link_failure_count += stats->LinkFailureCount;
+ fc_stats->tx_frames += READ_ONCE(stats->TxFrames);
+ fc_stats->tx_words += READ_ONCE(stats->TxWords);
+ fc_stats->rx_frames += READ_ONCE(stats->RxFrames);
+ fc_stats->rx_words += READ_ONCE(stats->RxWords);
+ fc_stats->error_frames += READ_ONCE(stats->ErrorFrames);
+ fc_stats->invalid_crc_count += READ_ONCE(stats->InvalidCRCCount);
+ fc_stats->fcp_input_requests += READ_ONCE(stats->InputRequests);
+ fc_stats->fcp_output_requests += READ_ONCE(stats->OutputRequests);
+ fc_stats->fcp_control_requests += READ_ONCE(stats->ControlRequests);
+ fcp_in_bytes += READ_ONCE(stats->InputBytes);
+ fcp_out_bytes += READ_ONCE(stats->OutputBytes);
+ fc_stats->fcp_packet_alloc_failures += READ_ONCE(stats->FcpPktAllocFails);
+ fc_stats->fcp_packet_aborts += READ_ONCE(stats->FcpPktAborts);
+ fc_stats->fcp_frame_alloc_failures += READ_ONCE(stats->FcpFrameAllocFails);
+ fc_stats->link_failure_count += READ_ONCE(stats->LinkFailureCount);
}
fc_stats->fcp_input_megabytes = div_u64(fcp_in_bytes, 1000000);
fc_stats->fcp_output_megabytes = div_u64(fcp_out_bytes, 1000000);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index d09926e6c8a8..797abf4f5399 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -678,7 +678,8 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
struct iscsi_task *task;
itt_t itt;
- if (session->state == ISCSI_STATE_TERMINATE)
+ if (session->state == ISCSI_STATE_TERMINATE ||
+ !test_bit(ISCSI_CONN_FLAG_BOUND, &conn->flags))
return NULL;
if (opcode == ISCSI_OP_LOGIN || opcode == ISCSI_OP_TEXT) {
@@ -1392,8 +1393,8 @@ static bool iscsi_set_conn_failed(struct iscsi_conn *conn)
if (conn->stop_stage == 0)
session->state = ISCSI_STATE_FAILED;
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
+ set_bit(ISCSI_CONN_FLAG_SUSPEND_TX, &conn->flags);
+ set_bit(ISCSI_CONN_FLAG_SUSPEND_RX, &conn->flags);
return true;
}
@@ -1454,7 +1455,7 @@ static int iscsi_xmit_task(struct iscsi_conn *conn, struct iscsi_task *task,
* Do this after dropping the extra ref because if this was a requeue
* it's removed from that list and cleanup_queued_task would miss it.
*/
- if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
+ if (test_bit(ISCSI_CONN_FLAG_SUSPEND_TX, &conn->flags)) {
/*
* Save the task and ref in case we weren't cleaning up this
* task and get woken up again.
@@ -1532,7 +1533,7 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
int rc = 0;
spin_lock_bh(&conn->session->frwd_lock);
- if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
+ if (test_bit(ISCSI_CONN_FLAG_SUSPEND_TX, &conn->flags)) {
ISCSI_DBG_SESSION(conn->session, "Tx suspended!\n");
spin_unlock_bh(&conn->session->frwd_lock);
return -ENODATA;
@@ -1746,7 +1747,7 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc)
goto fault;
}
- if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) {
+ if (test_bit(ISCSI_CONN_FLAG_SUSPEND_TX, &conn->flags)) {
reason = FAILURE_SESSION_IN_RECOVERY;
sc->result = DID_REQUEUE << 16;
goto fault;
@@ -1935,7 +1936,7 @@ static void fail_scsi_tasks(struct iscsi_conn *conn, u64 lun, int error)
void iscsi_suspend_queue(struct iscsi_conn *conn)
{
spin_lock_bh(&conn->session->frwd_lock);
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+ set_bit(ISCSI_CONN_FLAG_SUSPEND_TX, &conn->flags);
spin_unlock_bh(&conn->session->frwd_lock);
}
EXPORT_SYMBOL_GPL(iscsi_suspend_queue);
@@ -1953,7 +1954,7 @@ void iscsi_suspend_tx(struct iscsi_conn *conn)
struct Scsi_Host *shost = conn->session->host;
struct iscsi_host *ihost = shost_priv(shost);
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+ set_bit(ISCSI_CONN_FLAG_SUSPEND_TX, &conn->flags);
if (ihost->workq)
flush_workqueue(ihost->workq);
}
@@ -1961,7 +1962,7 @@ EXPORT_SYMBOL_GPL(iscsi_suspend_tx);
static void iscsi_start_tx(struct iscsi_conn *conn)
{
- clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+ clear_bit(ISCSI_CONN_FLAG_SUSPEND_TX, &conn->flags);
iscsi_conn_queue_work(conn);
}
@@ -2214,6 +2215,8 @@ void iscsi_conn_unbind(struct iscsi_cls_conn *cls_conn, bool is_active)
iscsi_suspend_tx(conn);
spin_lock_bh(&session->frwd_lock);
+ clear_bit(ISCSI_CONN_FLAG_BOUND, &conn->flags);
+
if (!is_active) {
/*
* if logout timed out before userspace could even send a PDU
@@ -3045,7 +3048,6 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
if (!cls_conn)
return NULL;
conn = cls_conn->dd_data;
- memset(conn, 0, sizeof(*conn) + dd_size);
conn->dd_data = cls_conn->dd_data + sizeof(*conn);
conn->session = session;
@@ -3318,6 +3320,8 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
spin_lock_bh(&session->frwd_lock);
if (is_leading)
session->leadconn = conn;
+
+ set_bit(ISCSI_CONN_FLAG_BOUND, &conn->flags);
spin_unlock_bh(&session->frwd_lock);
/*
@@ -3330,8 +3334,8 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
/*
* Unblock xmitworker(), Login Phase will pass through.
*/
- clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
- clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+ clear_bit(ISCSI_CONN_FLAG_SUSPEND_RX, &conn->flags);
+ clear_bit(ISCSI_CONN_FLAG_SUSPEND_TX, &conn->flags);
return 0;
}
EXPORT_SYMBOL_GPL(iscsi_conn_bind);
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c
index 2e9ffe3d1a55..883005757ddb 100644
--- a/drivers/scsi/libiscsi_tcp.c
+++ b/drivers/scsi/libiscsi_tcp.c
@@ -927,7 +927,7 @@ int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb,
*/
conn->last_recv = jiffies;
- if (unlikely(conn->suspend_rx)) {
+ if (unlikely(test_bit(ISCSI_CONN_FLAG_SUSPEND_RX, &conn->flags))) {
ISCSI_DBG_TCP(conn, "Rx suspended!\n");
*status = ISCSI_TCP_SUSPENDED;
return 0;
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index d34c82e24d9a..d35c9296f738 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -358,22 +358,14 @@ static int sas_ata_printk(const char *level, const struct domain_device *ddev,
return r;
}
-static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
+int sas_ata_wait_after_reset(struct domain_device *dev, unsigned long deadline)
{
- int ret = 0, res;
- struct sas_phy *phy;
- struct ata_port *ap = link->ap;
+ struct sata_device *sata_dev = &dev->sata_dev;
int (*check_ready)(struct ata_link *link);
- struct domain_device *dev = ap->private_data;
- struct sas_internal *i = dev_to_sas_internal(dev);
-
- res = i->dft->lldd_I_T_nexus_reset(dev);
- if (res == -ENODEV)
- return res;
-
- if (res != TMF_RESP_FUNC_COMPLETE)
- sas_ata_printk(KERN_DEBUG, dev, "Unable to reset ata device?\n");
+ struct ata_port *ap = sata_dev->ap;
+ struct ata_link *link = &ap->link;
+ struct sas_phy *phy;
+ int ret;
phy = sas_get_local_phy(dev);
if (scsi_is_sas_phy_local(phy))
@@ -386,6 +378,27 @@ static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class,
if (ret && ret != -EAGAIN)
sas_ata_printk(KERN_ERR, dev, "reset failed (errno=%d)\n", ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sas_ata_wait_after_reset);
+
+static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct domain_device *dev = ap->private_data;
+ struct sas_internal *i = dev_to_sas_internal(dev);
+ int ret;
+
+ ret = i->dft->lldd_I_T_nexus_reset(dev);
+ if (ret == -ENODEV)
+ return ret;
+
+ if (ret != TMF_RESP_FUNC_COMPLETE)
+ sas_ata_printk(KERN_DEBUG, dev, "Unable to reset ata device?\n");
+
+ ret = sas_ata_wait_after_reset(dev, deadline);
+
*class = dev->sata_dev.class;
ap->cbl = ATA_CBL_SATA;
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index f0cf8ffdc5f3..da9070cdad91 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -604,6 +604,7 @@ struct lpfc_vport {
#define FC_VFI_REGISTERED 0x800000 /* VFI is registered */
#define FC_FDISC_COMPLETED 0x1000000/* FDISC completed */
#define FC_DISC_DELAYED 0x2000000/* Delay NPort discovery */
+#define FC_RSCN_MEMENTO 0x4000000/* RSCN cmd processed */
uint32_t ct_flags;
#define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */
@@ -611,6 +612,7 @@ struct lpfc_vport {
#define FC_CT_RSNN_NN 0x4 /* RSNN_NN accepted by switch */
#define FC_CT_RSPN_ID 0x8 /* RSPN_ID accepted by switch */
#define FC_CT_RFT_ID 0x10 /* RFT_ID accepted by switch */
+#define FC_CT_RPRT_DEFER 0x20 /* Defer issuing FDMI RPRT */
struct list_head fc_nodes;
@@ -713,6 +715,7 @@ struct lpfc_vport {
#define LPFC_VMID_QFPA_CMPL 0x4
#define LPFC_VMID_QOS_ENABLED 0x8
#define LPFC_VMID_TIMER_ENBLD 0x10
+#define LPFC_VMID_TYPE_PRIO 0x20
struct fc_qfpa_res *qfpa_res;
struct fc_vport *fc_vport;
@@ -738,9 +741,8 @@ struct lpfc_vport {
struct list_head rcv_buffer_list;
unsigned long rcv_buffer_time_stamp;
uint32_t vport_flag;
-#define STATIC_VPORT 1
-#define FAWWPN_SET 2
-#define FAWWPN_PARAM_CHG 4
+#define STATIC_VPORT 0x1
+#define FAWWPN_PARAM_CHG 0x2
uint16_t fdmi_num_disc;
uint32_t fdmi_hba_mask;
@@ -897,6 +899,11 @@ enum lpfc_irq_chann_mode {
NHT_MODE,
};
+enum lpfc_hba_bit_flags {
+ FABRIC_COMANDS_BLOCKED,
+ HBA_PCI_ERR,
+};
+
struct lpfc_hba {
/* SCSI interface function jump table entries */
struct lpfc_io_buf * (*lpfc_get_scsi_buf)
@@ -1020,6 +1027,7 @@ struct lpfc_hba {
#define LS_MDS_LINK_DOWN 0x8 /* MDS Diagnostics Link Down */
#define LS_MDS_LOOPBACK 0x10 /* MDS Diagnostics Link Up (Loopback) */
#define LS_CT_VEN_RPA 0x20 /* Vendor RPA sent to switch */
+#define LS_EXTERNAL_LOOPBACK 0x40 /* External loopback plug inserted */
uint32_t hba_flag; /* hba generic flags */
#define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */
@@ -1043,7 +1051,6 @@ struct lpfc_hba {
* Firmware supports Forced Link Speed
* capability
*/
-#define HBA_PCI_ERR 0x80000 /* The PCI slot is offline */
#define HBA_FLOGI_ISSUED 0x100000 /* FLOGI was issued */
#define HBA_SHORT_CMF 0x200000 /* shorter CMF timer routine */
#define HBA_CGN_DAY_WRAP 0x400000 /* HBA Congestion info day wraps */
@@ -1053,6 +1060,7 @@ struct lpfc_hba {
#define HBA_HBEAT_INP 0x4000000 /* mbox HBEAT is in progress */
#define HBA_HBEAT_TMO 0x8000000 /* HBEAT initiated after timeout */
#define HBA_FLOGI_OUTSTANDING 0x10000000 /* FLOGI is outstanding */
+#define HBA_RHBA_CMPL 0x20000000 /* RHBA FDMI command is successful */
struct completion *fw_dump_cmpl; /* cmpl event tracker for fw_dump */
uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/
@@ -1350,7 +1358,6 @@ struct lpfc_hba {
atomic_t fabric_iocb_count;
struct timer_list fabric_block_timer;
unsigned long bit_flags;
-#define FABRIC_COMANDS_BLOCKED 0
atomic_t num_rsrc_err;
atomic_t num_cmd_success;
unsigned long last_rsrc_error_time;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 9b982cc270d9..3caaa7c4af48 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2021 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -1120,12 +1120,22 @@ lpfc_link_state_show(struct device *dev, struct device_attribute *attr,
len += scnprintf(buf + len, PAGE_SIZE-len,
" Private Loop\n");
} else {
- if (vport->fc_flag & FC_FABRIC)
- len += scnprintf(buf + len, PAGE_SIZE-len,
- " Fabric\n");
- else
+ if (vport->fc_flag & FC_FABRIC) {
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ vport->port_type == LPFC_PHYSICAL_PORT &&
+ phba->sli4_hba.fawwpn_flag &
+ LPFC_FAWWPN_FABRIC)
+ len += scnprintf(buf + len,
+ PAGE_SIZE - len,
+ " Fabric FA-PWWN\n");
+ else
+ len += scnprintf(buf + len,
+ PAGE_SIZE - len,
+ " Fabric\n");
+ } else {
len += scnprintf(buf + len, PAGE_SIZE-len,
" Point-2-Point\n");
+ }
}
}
@@ -6878,17 +6888,34 @@ lpfc_get_stats(struct Scsi_Host *shost)
memset(hs, 0, sizeof (struct fc_host_statistics));
hs->tx_frames = pmb->un.varRdStatus.xmitFrameCnt;
+ hs->rx_frames = pmb->un.varRdStatus.rcvFrameCnt;
+
/*
- * The MBX_READ_STATUS returns tx_k_bytes which has to
- * converted to words
+ * The MBX_READ_STATUS returns tx_k_bytes which has to be
+ * converted to words.
+ *
+ * Check if extended byte flag is set, to know when to collect upper
+ * bits of 64 bit wide statistics counter.
*/
- hs->tx_words = (uint64_t)
- ((uint64_t)pmb->un.varRdStatus.xmitByteCnt
- * (uint64_t)256);
- hs->rx_frames = pmb->un.varRdStatus.rcvFrameCnt;
- hs->rx_words = (uint64_t)
- ((uint64_t)pmb->un.varRdStatus.rcvByteCnt
- * (uint64_t)256);
+ if (pmb->un.varRdStatus.xkb & RD_ST_XKB) {
+ hs->tx_words = (u64)
+ ((((u64)(pmb->un.varRdStatus.xmit_xkb &
+ RD_ST_XMIT_XKB_MASK) << 32) |
+ (u64)pmb->un.varRdStatus.xmitByteCnt) *
+ (u64)256);
+ hs->rx_words = (u64)
+ ((((u64)(pmb->un.varRdStatus.rcv_xkb &
+ RD_ST_RCV_XKB_MASK) << 32) |
+ (u64)pmb->un.varRdStatus.rcvByteCnt) *
+ (u64)256);
+ } else {
+ hs->tx_words = (uint64_t)
+ ((uint64_t)pmb->un.varRdStatus.xmitByteCnt
+ * (uint64_t)256);
+ hs->rx_words = (uint64_t)
+ ((uint64_t)pmb->un.varRdStatus.rcvByteCnt
+ * (uint64_t)256);
+ }
memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t));
pmb->mbxCommand = MBX_READ_LNK_STAT;
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index 8b586fa90f70..676e7d54b97a 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -310,7 +310,7 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba,
int rc = 0;
u32 ulp_status, ulp_word4, total_data_placed;
- dd_data = cmdiocbq->context1;
+ dd_data = cmdiocbq->context_un.dd_data;
/* Determine if job has been aborted */
spin_lock_irqsave(&phba->ct_ev_lock, flags);
@@ -328,10 +328,10 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba,
spin_unlock_irqrestore(&phba->hbalock, flags);
iocb = &dd_data->context_un.iocb;
- ndlp = iocb->cmdiocbq->context_un.ndlp;
+ ndlp = iocb->cmdiocbq->ndlp;
rmp = iocb->rmp;
- cmp = cmdiocbq->context2;
- bmp = cmdiocbq->context3;
+ cmp = cmdiocbq->cmd_dmabuf;
+ bmp = cmdiocbq->bpl_dmabuf;
ulp_status = get_job_ulpstatus(phba, rspiocbq);
ulp_word4 = get_job_word4(phba, rspiocbq);
total_data_placed = get_job_data_placed(phba, rspiocbq);
@@ -470,14 +470,12 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job)
cmdiocbq->num_bdes = num_entry;
cmdiocbq->vport = phba->pport;
- cmdiocbq->context2 = cmp;
- cmdiocbq->context3 = bmp;
+ cmdiocbq->cmd_dmabuf = cmp;
+ cmdiocbq->bpl_dmabuf = bmp;
cmdiocbq->cmd_flag |= LPFC_IO_LIBDFC;
cmdiocbq->cmd_cmpl = lpfc_bsg_send_mgmt_cmd_cmp;
- cmdiocbq->context1 = dd_data;
- cmdiocbq->context2 = cmp;
- cmdiocbq->context3 = bmp;
+ cmdiocbq->context_un.dd_data = dd_data;
dd_data->type = TYPE_IOCB;
dd_data->set_job = job;
@@ -495,8 +493,8 @@ lpfc_bsg_send_mgmt_cmd(struct bsg_job *job)
readl(phba->HCregaddr); /* flush */
}
- cmdiocbq->context_un.ndlp = lpfc_nlp_get(ndlp);
- if (!cmdiocbq->context_un.ndlp) {
+ cmdiocbq->ndlp = lpfc_nlp_get(ndlp);
+ if (!cmdiocbq->ndlp) {
rc = -ENODEV;
goto free_rmp;
}
@@ -573,9 +571,9 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba,
int rc = 0;
u32 ulp_status, ulp_word4, total_data_placed;
- dd_data = cmdiocbq->context1;
+ dd_data = cmdiocbq->context_un.dd_data;
ndlp = dd_data->context_un.iocb.ndlp;
- cmdiocbq->context1 = ndlp;
+ cmdiocbq->ndlp = ndlp;
/* Determine if job has been aborted */
spin_lock_irqsave(&phba->ct_ev_lock, flags);
@@ -595,7 +593,7 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba,
ulp_status = get_job_ulpstatus(phba, rspiocbq);
ulp_word4 = get_job_word4(phba, rspiocbq);
total_data_placed = get_job_data_placed(phba, rspiocbq);
- pcmd = (struct lpfc_dmabuf *)cmdiocbq->context2;
+ pcmd = cmdiocbq->cmd_dmabuf;
prsp = (struct lpfc_dmabuf *)pcmd->list.next;
/* Copy the completed job data or determine the job status if job is
@@ -711,8 +709,8 @@ lpfc_bsg_rport_els(struct bsg_job *job)
/* Transfer the request payload to allocated command dma buffer */
sg_copy_to_buffer(job->request_payload.sg_list,
job->request_payload.sg_cnt,
- ((struct lpfc_dmabuf *)cmdiocbq->context2)->virt,
- job->request_payload.payload_len);
+ cmdiocbq->cmd_dmabuf->virt,
+ cmdsize);
rpi = ndlp->nlp_rpi;
@@ -722,8 +720,8 @@ lpfc_bsg_rport_els(struct bsg_job *job)
else
cmdiocbq->iocb.ulpContext = rpi;
cmdiocbq->cmd_flag |= LPFC_IO_LIBDFC;
- cmdiocbq->context1 = dd_data;
- cmdiocbq->context_un.ndlp = ndlp;
+ cmdiocbq->context_un.dd_data = dd_data;
+ cmdiocbq->ndlp = ndlp;
cmdiocbq->cmd_cmpl = lpfc_bsg_rport_els_cmp;
dd_data->type = TYPE_IOCB;
dd_data->set_job = job;
@@ -742,12 +740,6 @@ lpfc_bsg_rport_els(struct bsg_job *job)
readl(phba->HCregaddr); /* flush */
}
- cmdiocbq->context1 = lpfc_nlp_get(ndlp);
- if (!cmdiocbq->context1) {
- rc = -EIO;
- goto linkdown_err;
- }
-
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0);
if (rc == IOCB_SUCCESS) {
spin_lock_irqsave(&phba->hbalock, flags);
@@ -917,8 +909,8 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct ulp_bde64 *bde;
dma_addr_t dma_addr;
int i;
- struct lpfc_dmabuf *bdeBuf1 = piocbq->context2;
- struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;
+ struct lpfc_dmabuf *bdeBuf1 = piocbq->cmd_dmabuf;
+ struct lpfc_dmabuf *bdeBuf2 = piocbq->bpl_dmabuf;
struct lpfc_sli_ct_request *ct_req;
struct bsg_job *job = NULL;
struct fc_bsg_reply *bsg_reply;
@@ -985,9 +977,8 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
list_for_each_entry(iocbq, &head, list) {
size = 0;
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
- bdeBuf1 = iocbq->context2;
- bdeBuf2 = iocbq->context3;
-
+ bdeBuf1 = iocbq->cmd_dmabuf;
+ bdeBuf2 = iocbq->bpl_dmabuf;
}
if (phba->sli_rev == LPFC_SLI_REV4)
bde_count = iocbq->wcqe_cmpl.word3;
@@ -1384,7 +1375,7 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba,
int rc = 0;
u32 ulp_status, ulp_word4;
- dd_data = cmdiocbq->context1;
+ dd_data = cmdiocbq->context_un.dd_data;
/* Determine if job has been aborted */
spin_lock_irqsave(&phba->ct_ev_lock, flags);
@@ -1401,8 +1392,8 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba,
spin_unlock_irqrestore(&phba->hbalock, flags);
ndlp = dd_data->context_un.iocb.ndlp;
- cmp = cmdiocbq->context2;
- bmp = cmdiocbq->context3;
+ cmp = cmdiocbq->cmd_dmabuf;
+ bmp = cmdiocbq->bpl_dmabuf;
ulp_status = get_job_ulpstatus(phba, rspiocbq);
ulp_word4 = get_job_word4(phba, rspiocbq);
@@ -1529,10 +1520,10 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct bsg_job *job, uint32_t tag,
ctiocb->cmd_flag |= LPFC_IO_LIBDFC;
ctiocb->vport = phba->pport;
- ctiocb->context1 = dd_data;
- ctiocb->context2 = cmp;
- ctiocb->context3 = bmp;
- ctiocb->context_un.ndlp = ndlp;
+ ctiocb->context_un.dd_data = dd_data;
+ ctiocb->cmd_dmabuf = cmp;
+ ctiocb->bpl_dmabuf = bmp;
+ ctiocb->ndlp = ndlp;
ctiocb->cmd_cmpl = lpfc_issue_ct_rsp_cmp;
dd_data->type = TYPE_IOCB;
@@ -2671,7 +2662,7 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi,
ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP;
ctreq->CommandResponse.bits.Size = 0;
- cmdiocbq->context3 = dmabuf;
+ cmdiocbq->bpl_dmabuf = dmabuf;
cmdiocbq->cmd_flag |= LPFC_IO_LIBDFC;
cmdiocbq->vport = phba->pport;
cmdiocbq->cmd_cmpl = NULL;
@@ -3231,7 +3222,7 @@ lpfc_bsg_diag_loopback_run(struct bsg_job *job)
cmdiocbq->cmd_flag |= LPFC_IO_LOOPBACK;
cmdiocbq->vport = phba->pport;
cmdiocbq->cmd_cmpl = NULL;
- cmdiocbq->context3 = txbmp;
+ cmdiocbq->bpl_dmabuf = txbmp;
if (phba->sli_rev < LPFC_SLI_REV4) {
lpfc_sli_prep_xmit_seq64(phba, cmdiocbq, txbmp, 0, txxri,
@@ -3384,7 +3375,7 @@ job_error:
* This is completion handler function for mailbox commands issued from
* lpfc_bsg_issue_mbox function. This function is called by the
* mailbox event handler function with no lock held. This function
- * will wake up thread waiting on the wait queue pointed by context1
+ * will wake up thread waiting on the wait queue pointed by dd_data
* of the mailbox.
**/
static void
@@ -5034,9 +5025,9 @@ lpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba,
unsigned int rsp_size;
int rc = 0;
- dd_data = cmdiocbq->context1;
- cmp = cmdiocbq->context2;
- bmp = cmdiocbq->context3;
+ dd_data = cmdiocbq->context_un.dd_data;
+ cmp = cmdiocbq->cmd_dmabuf;
+ bmp = cmdiocbq->bpl_dmabuf;
menlo = &dd_data->context_un.menlo;
rmp = menlo->rmp;
rsp = &rspiocbq->iocb;
@@ -5233,9 +5224,9 @@ lpfc_menlo_cmd(struct bsg_job *job)
/* We want the firmware to timeout before we do */
cmd->ulpTimeout = MENLO_TIMEOUT - 5;
cmdiocbq->cmd_cmpl = lpfc_bsg_menlo_cmd_cmp;
- cmdiocbq->context1 = dd_data;
- cmdiocbq->context2 = cmp;
- cmdiocbq->context3 = bmp;
+ cmdiocbq->context_un.dd_data = dd_data;
+ cmdiocbq->cmd_dmabuf = cmp;
+ cmdiocbq->bpl_dmabuf = bmp;
if (menlo_cmd->cmd == LPFC_BSG_VENDOR_MENLO_CMD) {
cmd->ulpCommand = CMD_GEN_REQUEST64_CR;
cmd->ulpPU = MENLO_PU; /* 3 */
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 96408cd6c4c8..b0775be31d5c 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -32,7 +32,9 @@ int lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
int lpfc_sli4_dump_cfg_rg23(struct lpfc_hba *, struct lpfcMboxq *);
void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
-
+int lpfc_mbox_rsrc_prep(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox);
+void lpfc_mbox_rsrc_cleanup(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox,
+ enum lpfc_mbox_ctx locked);
void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_read_topology(struct lpfc_hba *, LPFC_MBOXQ_t *, struct lpfc_dmabuf *);
void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -432,6 +434,7 @@ void lpfc_nvmet_buf_free(struct lpfc_hba *phba, void *virtp, dma_addr_t dma);
void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *);
void lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp);
+void lpfc_setup_fdmi_mask(struct lpfc_vport *vport);
int lpfc_link_reset(struct lpfc_vport *vport);
/* Function prototypes. */
@@ -670,3 +673,6 @@ struct lpfc_vmid *lpfc_get_vmid_from_hashtable(struct lpfc_vport *vport,
uint32_t hash, uint8_t *buf);
void lpfc_vmid_vport_cleanup(struct lpfc_vport *vport);
int lpfc_issue_els_qfpa(struct lpfc_vport *vport);
+
+void lpfc_sli_rpi_release(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 4b024aa03c1b..9d36b20fb878 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -118,22 +118,22 @@ lpfc_ct_unsol_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_nodelist *ndlp;
struct lpfc_dmabuf *mp, *bmp;
- ndlp = (struct lpfc_nodelist *)cmdiocb->context1;
+ ndlp = cmdiocb->ndlp;
if (ndlp)
lpfc_nlp_put(ndlp);
- mp = cmdiocb->context2;
- bmp = cmdiocb->context3;
+ mp = cmdiocb->rsp_dmabuf;
+ bmp = cmdiocb->bpl_dmabuf;
if (mp) {
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- cmdiocb->context2 = NULL;
+ cmdiocb->rsp_dmabuf = NULL;
}
if (bmp) {
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
kfree(bmp);
- cmdiocb->context3 = NULL;
+ cmdiocb->bpl_dmabuf = NULL;
}
lpfc_sli_release_iocbq(phba, cmdiocb);
@@ -232,18 +232,17 @@ lpfc_ct_reject_event(struct lpfc_nodelist *ndlp,
}
/* Save for completion so we can release these resources */
- cmdiocbq->context2 = (uint8_t *)mp;
- cmdiocbq->context3 = (uint8_t *)bmp;
+ cmdiocbq->rsp_dmabuf = mp;
+ cmdiocbq->bpl_dmabuf = bmp;
cmdiocbq->cmd_cmpl = lpfc_ct_unsol_cmpl;
tmo = (3 * phba->fc_ratov);
cmdiocbq->retry = 0;
cmdiocbq->vport = vport;
- cmdiocbq->context_un.ndlp = NULL;
cmdiocbq->drvrTimeout = tmo + LPFC_DRVR_TIMEOUT;
- cmdiocbq->context1 = lpfc_nlp_get(ndlp);
- if (!cmdiocbq->context1)
+ cmdiocbq->ndlp = lpfc_nlp_get(ndlp);
+ if (!cmdiocbq->ndlp)
goto ct_no_ndlp;
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0);
@@ -310,8 +309,8 @@ lpfc_ct_handle_mibreq(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocbq)
return;
}
- ct_req = ((struct lpfc_sli_ct_request *)
- (((struct lpfc_dmabuf *)ctiocbq->context2)->virt));
+ ct_req = (struct lpfc_sli_ct_request *)ctiocbq->cmd_dmabuf->virt;
+
mi_cmd = ct_req->CommandResponse.bits.CmdRsp;
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"6442 : MI Cmd : x%x Not Supported\n", mi_cmd);
@@ -347,14 +346,14 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
uint32_t size;
struct list_head head;
struct lpfc_sli_ct_request *ct_req;
- struct lpfc_dmabuf *bdeBuf1 = ctiocbq->context2;
- struct lpfc_dmabuf *bdeBuf2 = ctiocbq->context3;
+ struct lpfc_dmabuf *bdeBuf1 = ctiocbq->cmd_dmabuf;
+ struct lpfc_dmabuf *bdeBuf2 = ctiocbq->bpl_dmabuf;
u32 status, parameter, bde_count = 0;
struct lpfc_wcqe_complete *wcqe_cmpl = NULL;
- ctiocbq->context1 = NULL;
- ctiocbq->context2 = NULL;
- ctiocbq->context3 = NULL;
+ ctiocbq->cmd_dmabuf = NULL;
+ ctiocbq->rsp_dmabuf = NULL;
+ ctiocbq->bpl_dmabuf = NULL;
wcqe_cmpl = &ctiocbq->wcqe_cmpl;
status = get_job_ulpstatus(phba, ctiocbq);
@@ -382,12 +381,11 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (bde_count == 0)
return;
- ctiocbq->context2 = bdeBuf1;
+ ctiocbq->cmd_dmabuf = bdeBuf1;
if (bde_count == 2)
- ctiocbq->context3 = bdeBuf2;
+ ctiocbq->bpl_dmabuf = bdeBuf2;
- ct_req = ((struct lpfc_sli_ct_request *)
- (((struct lpfc_dmabuf *)ctiocbq->context2)->virt));
+ ct_req = (struct lpfc_sli_ct_request *)ctiocbq->cmd_dmabuf->virt;
if (ct_req->FsType == SLI_CT_MANAGEMENT_SERVICE &&
ct_req->FsSubType == SLI_CT_MIB_Subtypes) {
@@ -408,8 +406,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (!bde_count)
continue;
- bdeBuf1 = iocb->context2;
- iocb->context2 = NULL;
+ bdeBuf1 = iocb->cmd_dmabuf;
+ iocb->cmd_dmabuf = NULL;
if (phba->sli_rev == LPFC_SLI_REV4)
size = iocb->wqe.gen_req.bde.tus.f.bdeSize;
else
@@ -417,8 +415,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
lpfc_ct_unsol_buffer(phba, ctiocbq, bdeBuf1, size);
lpfc_in_buf_free(phba, bdeBuf1);
if (bde_count == 2) {
- bdeBuf2 = iocb->context3;
- iocb->context3 = NULL;
+ bdeBuf2 = iocb->bpl_dmabuf;
+ iocb->bpl_dmabuf = NULL;
if (phba->sli_rev == LPFC_SLI_REV4)
size = iocb->unsol_rcv_len;
else
@@ -549,24 +547,25 @@ lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
{
struct lpfc_dmabuf *buf_ptr;
- /* I/O job is complete so context is now invalid*/
- ctiocb->context_un.ndlp = NULL;
- if (ctiocb->context1) {
- buf_ptr = (struct lpfc_dmabuf *) ctiocb->context1;
+ /* IOCBQ job structure gets cleaned during release. Just release
+ * the dma buffers here.
+ */
+ if (ctiocb->cmd_dmabuf) {
+ buf_ptr = ctiocb->cmd_dmabuf;
lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
kfree(buf_ptr);
- ctiocb->context1 = NULL;
+ ctiocb->cmd_dmabuf = NULL;
}
- if (ctiocb->context2) {
- lpfc_free_ct_rsp(phba, (struct lpfc_dmabuf *) ctiocb->context2);
- ctiocb->context2 = NULL;
+ if (ctiocb->rsp_dmabuf) {
+ lpfc_free_ct_rsp(phba, ctiocb->rsp_dmabuf);
+ ctiocb->rsp_dmabuf = NULL;
}
- if (ctiocb->context3) {
- buf_ptr = (struct lpfc_dmabuf *) ctiocb->context3;
+ if (ctiocb->bpl_dmabuf) {
+ buf_ptr = ctiocb->bpl_dmabuf;
lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
kfree(buf_ptr);
- ctiocb->context3 = NULL;
+ ctiocb->bpl_dmabuf = NULL;
}
lpfc_sli_release_iocbq(phba, ctiocb);
return 0;
@@ -605,11 +604,11 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
/* Update the num_entry bde count */
geniocb->num_bdes = num_entry;
- geniocb->context3 = (uint8_t *) bmp;
+ geniocb->bpl_dmabuf = bmp;
/* Save for completion so we can release these resources */
- geniocb->context1 = (uint8_t *) inp;
- geniocb->context2 = (uint8_t *) outp;
+ geniocb->cmd_dmabuf = inp;
+ geniocb->rsp_dmabuf = outp;
geniocb->event_tag = event_tag;
@@ -635,8 +634,8 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
geniocb->drvrTimeout = tmo + LPFC_DRVR_TIMEOUT;
geniocb->vport = vport;
geniocb->retry = retry;
- geniocb->context_un.ndlp = lpfc_nlp_get(ndlp);
- if (!geniocb->context_un.ndlp)
+ geniocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!geniocb->ndlp)
goto out;
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, geniocb, 0);
@@ -926,13 +925,12 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
int rc, type;
/* First save ndlp, before we overwrite it */
- ndlp = cmdiocb->context_un.ndlp;
+ ndlp = cmdiocb->ndlp;
/* we pass cmdiocb to state machine which needs rspiocb as well */
- cmdiocb->context_un.rsp_iocb = rspiocb;
-
- inp = (struct lpfc_dmabuf *) cmdiocb->context1;
- outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+ cmdiocb->rsp_iocb = rspiocb;
+ inp = cmdiocb->cmd_dmabuf;
+ outp = cmdiocb->rsp_dmabuf;
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
"GID_FT cmpl: status:x%x/x%x rtry:%d",
@@ -962,9 +960,15 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
if (lpfc_error_lost_link(ulp_status, ulp_word4)) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
- "0226 NS query failed due to link event\n");
+ "0226 NS query failed due to link event: "
+ "ulp_status x%x ulp_word4 x%x fc_flag x%x "
+ "port_state x%x gidft_inp x%x\n",
+ ulp_status, ulp_word4, vport->fc_flag,
+ vport->port_state, vport->gidft_inp);
if (vport->fc_flag & FC_RSCN_MODE)
lpfc_els_flush_rscn(vport);
+ if (vport->gidft_inp)
+ vport->gidft_inp--;
goto out;
}
@@ -1143,12 +1147,12 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
int rc;
/* First save ndlp, before we overwrite it */
- ndlp = cmdiocb->context_un.ndlp;
+ ndlp = cmdiocb->ndlp;
/* we pass cmdiocb to state machine which needs rspiocb as well */
- cmdiocb->context_un.rsp_iocb = rspiocb;
- inp = (struct lpfc_dmabuf *)cmdiocb->context1;
- outp = (struct lpfc_dmabuf *)cmdiocb->context2;
+ cmdiocb->rsp_iocb = rspiocb;
+ inp = cmdiocb->cmd_dmabuf;
+ outp = cmdiocb->rsp_dmabuf;
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
"GID_PT cmpl: status:x%x/x%x rtry:%d",
@@ -1179,9 +1183,15 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
if (lpfc_error_lost_link(ulp_status, ulp_word4)) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
- "4166 NS query failed due to link event\n");
+ "4166 NS query failed due to link event: "
+ "ulp_status x%x ulp_word4 x%x fc_flag x%x "
+ "port_state x%x gidft_inp x%x\n",
+ ulp_status, ulp_word4, vport->fc_flag,
+ vport->port_state, vport->gidft_inp);
if (vport->fc_flag & FC_RSCN_MODE)
lpfc_els_flush_rscn(vport);
+ if (vport->gidft_inp)
+ vport->gidft_inp--;
goto out;
}
@@ -1346,8 +1356,8 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
{
struct lpfc_vport *vport = cmdiocb->vport;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1;
- struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+ struct lpfc_dmabuf *inp = cmdiocb->cmd_dmabuf;
+ struct lpfc_dmabuf *outp = cmdiocb->rsp_dmabuf;
struct lpfc_sli_ct_request *CTrsp;
int did, rc, retry;
uint8_t fbits;
@@ -1426,7 +1436,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
cmdiocb->retry, did);
if (rc == 0) {
/* success */
- free_ndlp = cmdiocb->context_un.ndlp;
+ free_ndlp = cmdiocb->ndlp;
lpfc_ct_free_iocb(phba, cmdiocb);
lpfc_nlp_put(free_ndlp);
return;
@@ -1483,7 +1493,7 @@ out:
}
iocb_free:
- free_ndlp = cmdiocb->context_un.ndlp;
+ free_ndlp = cmdiocb->ndlp;
lpfc_ct_free_iocb(phba, cmdiocb);
lpfc_nlp_put(free_ndlp);
return;
@@ -1494,8 +1504,8 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
struct lpfc_vport *vport = cmdiocb->vport;
- struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *)cmdiocb->context1;
- struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *)cmdiocb->context2;
+ struct lpfc_dmabuf *inp = cmdiocb->cmd_dmabuf;
+ struct lpfc_dmabuf *outp = cmdiocb->rsp_dmabuf;
struct lpfc_sli_ct_request *CTrsp;
int did;
struct lpfc_nodelist *ndlp = NULL;
@@ -1519,7 +1529,7 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
/* Preserve the nameserver node to release the reference. */
- ns_ndlp = cmdiocb->context_un.ndlp;
+ ns_ndlp = cmdiocb->ndlp;
if (ulp_status == IOSTAT_SUCCESS) {
/* Good status, continue checking */
@@ -1605,13 +1615,13 @@ lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
u32 ulp_word4 = get_job_word4(phba, rspiocb);
/* First save ndlp, before we overwrite it */
- ndlp = cmdiocb->context_un.ndlp;
+ ndlp = cmdiocb->ndlp;
/* we pass cmdiocb to state machine which needs rspiocb as well */
- cmdiocb->context_un.rsp_iocb = rspiocb;
+ cmdiocb->rsp_iocb = rspiocb;
- inp = (struct lpfc_dmabuf *) cmdiocb->context1;
- outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+ inp = cmdiocb->cmd_dmabuf;
+ outp = cmdiocb->rsp_dmabuf;
cmdcode = be16_to_cpu(((struct lpfc_sli_ct_request *) inp->virt)->
CommandResponse.bits.CmdRsp);
@@ -1672,8 +1682,8 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_dmabuf *outp;
struct lpfc_sli_ct_request *CTrsp;
- outp = (struct lpfc_dmabuf *) cmdiocb->context2;
- CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+ outp = cmdiocb->rsp_dmabuf;
+ CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
vport->ct_flags |= FC_CT_RFT_ID;
@@ -1693,7 +1703,7 @@ lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_dmabuf *outp;
struct lpfc_sli_ct_request *CTrsp;
- outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+ outp = cmdiocb->rsp_dmabuf;
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
@@ -1714,8 +1724,8 @@ lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_dmabuf *outp;
struct lpfc_sli_ct_request *CTrsp;
- outp = (struct lpfc_dmabuf *) cmdiocb->context2;
- CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+ outp = cmdiocb->rsp_dmabuf;
+ CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
vport->ct_flags |= FC_CT_RSPN_ID;
@@ -1735,7 +1745,7 @@ lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_dmabuf *outp;
struct lpfc_sli_ct_request *CTrsp;
- outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+ outp = cmdiocb->rsp_dmabuf;
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
@@ -1768,8 +1778,8 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_dmabuf *outp;
struct lpfc_sli_ct_request *CTrsp;
- outp = (struct lpfc_dmabuf *) cmdiocb->context2;
- CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+ outp = cmdiocb->rsp_dmabuf;
+ CTrsp = (struct lpfc_sli_ct_request *)outp->virt;
if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC))
vport->ct_flags |= FC_CT_RFF_ID;
@@ -1865,7 +1875,7 @@ lpfc_get_gidft_type(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb)
struct lpfc_dmabuf *mp;
uint32_t type;
- mp = cmdiocb->context1;
+ mp = cmdiocb->cmd_dmabuf;
if (mp == NULL)
return 0;
CtReq = (struct lpfc_sli_ct_request *)mp->virt;
@@ -2018,28 +2028,30 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
vport->ct_flags &= ~FC_CT_RFT_ID;
CtReq->CommandResponse.bits.CmdRsp =
cpu_to_be16(SLI_CTNS_RFT_ID);
- CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID);
+ CtReq->un.rft.port_id = cpu_to_be32(vport->fc_myDID);
+
+ /* Register Application Services type if vmid enabled. */
+ if (phba->cfg_vmid_app_header)
+ CtReq->un.rft.app_serv_reg =
+ cpu_to_be32(RFT_APP_SERV_REG);
/* Register FC4 FCP type if enabled. */
if (vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH ||
vport->cfg_enable_fc4_type == LPFC_ENABLE_FCP)
- CtReq->un.rft.fcpReg = 1;
+ CtReq->un.rft.fcp_reg = cpu_to_be32(RFT_FCP_REG);
- /* Register NVME type if enabled. Defined LE and swapped.
- * rsvd[0] is used as word1 because of the hard-coded
- * word0 usage in the ct_request data structure.
- */
+ /* Register NVME type if enabled. */
if (vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH ||
vport->cfg_enable_fc4_type == LPFC_ENABLE_NVME)
- CtReq->un.rft.rsvd[0] =
- cpu_to_be32(LPFC_FC4_TYPE_BITMASK);
+ CtReq->un.rft.nvme_reg = cpu_to_be32(RFT_NVME_REG);
ptr = (uint32_t *)CtReq;
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
- "6433 Issue RFT (%s %s): %08x %08x %08x %08x "
- "%08x %08x %08x %08x\n",
- CtReq->un.rft.fcpReg ? "FCP" : " ",
- CtReq->un.rft.rsvd[0] ? "NVME" : " ",
+ "6433 Issue RFT (%s %s %s): %08x %08x %08x "
+ "%08x %08x %08x %08x %08x\n",
+ CtReq->un.rft.fcp_reg ? "FCP" : " ",
+ CtReq->un.rft.nvme_reg ? "NVME" : " ",
+ CtReq->un.rft.app_serv_reg ? "APPS" : " ",
*ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3),
*(ptr + 4), *(ptr + 5),
*(ptr + 6), *(ptr + 7));
@@ -2156,6 +2168,41 @@ ns_cmd_exit:
}
/**
+ * lpfc_fdmi_rprt_defer - Check for any deferred FDMI RPRT commands
+ * @phba: Pointer to HBA context object.
+ * @mask: Initial port attributes mask
+ *
+ * This function checks to see if any vports have deferred their FDMI RPRT.
+ * A vports RPRT may be deferred if it is issued before the primary ports
+ * RHBA completes.
+ */
+static void
+lpfc_fdmi_rprt_defer(struct lpfc_hba *phba, uint32_t mask)
+{
+ struct lpfc_vport **vports;
+ struct lpfc_vport *vport;
+ struct lpfc_nodelist *ndlp;
+ int i;
+
+ phba->hba_flag |= HBA_RHBA_CMPL;
+ vports = lpfc_create_vport_work_array(phba);
+ if (vports) {
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
+ vport = vports[i];
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ continue;
+ if (vport->ct_flags & FC_CT_RPRT_DEFER) {
+ vport->ct_flags &= ~FC_CT_RPRT_DEFER;
+ vport->fdmi_port_mask = mask;
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0);
+ }
+ }
+ }
+ lpfc_destroy_vport_work_array(phba, vports);
+}
+
+/**
* lpfc_cmpl_ct_disc_fdmi - Handle a discovery FDMI completion
* @phba: Pointer to HBA context object.
* @cmdiocb: Pointer to the command IOCBQ.
@@ -2169,8 +2216,8 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
struct lpfc_vport *vport = cmdiocb->vport;
- struct lpfc_dmabuf *inp = cmdiocb->context1;
- struct lpfc_dmabuf *outp = cmdiocb->context2;
+ struct lpfc_dmabuf *inp = cmdiocb->cmd_dmabuf;
+ struct lpfc_dmabuf *outp = cmdiocb->rsp_dmabuf;
struct lpfc_sli_ct_request *CTcmd = inp->virt;
struct lpfc_sli_ct_request *CTrsp = outp->virt;
uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
@@ -2224,7 +2271,7 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
ulp_word4);
}
- free_ndlp = cmdiocb->context_un.ndlp;
+ free_ndlp = cmdiocb->ndlp;
lpfc_ct_free_iocb(phba, cmdiocb);
lpfc_nlp_put(free_ndlp);
@@ -2236,15 +2283,19 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
cmd = be16_to_cpu(fdmi_cmd);
if (fdmi_rsp == cpu_to_be16(SLI_CT_RESPONSE_FS_RJT)) {
/* FDMI rsp failed */
- lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY | LOG_ELS,
"0220 FDMI cmd failed FS_RJT Data: x%x", cmd);
/* Should we fallback to FDMI-2 / FDMI-1 ? */
switch (cmd) {
case SLI_MGMT_RHBA:
if (vport->fdmi_hba_mask == LPFC_FDMI2_HBA_ATTR) {
- /* Fallback to FDMI-1 */
+ /* Fallback to FDMI-1 for HBA attributes */
vport->fdmi_hba_mask = LPFC_FDMI1_HBA_ATTR;
+
+ /* If HBA attributes are FDMI1, so should
+ * port attributes be for consistency.
+ */
vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
/* Start over */
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
@@ -2252,6 +2303,11 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
return;
case SLI_MGMT_RPRT:
+ if (vport->port_type != LPFC_PHYSICAL_PORT) {
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ return;
+ }
if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
/* Fallback to FDMI-1 */
vport->fdmi_port_mask = LPFC_FDMI1_PORT_ATTR;
@@ -2272,9 +2328,9 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
phba->link_flag &= ~LS_CT_VEN_RPA;
if (phba->cmf_active_mode == LPFC_CFG_OFF)
return;
- lpfc_printf_log(phba, KERN_ERR,
+ lpfc_printf_log(phba, KERN_WARNING,
LOG_DISCOVERY | LOG_ELS,
- "6460 VEN FDMI RPA failure\n");
+ "6460 VEN FDMI RPA RJT\n");
return;
}
if (vport->fdmi_port_mask == LPFC_FDMI2_PORT_ATTR) {
@@ -2301,6 +2357,9 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
switch (cmd) {
case SLI_MGMT_RHBA:
+ /* Check for any RPRTs deferred till after RHBA completes */
+ lpfc_fdmi_rprt_defer(phba, vport->fdmi_port_mask);
+
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA, 0);
break;
@@ -2309,10 +2368,26 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
break;
case SLI_MGMT_DPRT:
- if (vport->port_type == LPFC_PHYSICAL_PORT)
+ if (vport->port_type == LPFC_PHYSICAL_PORT) {
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA, 0);
- else
- lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0);
+ } else {
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ return;
+
+ /* Only issue a RPRT for the vport if the RHBA
+ * for the physical port completes successfully.
+ * We may have to defer the RPRT accordingly.
+ */
+ if (phba->hba_flag & HBA_RHBA_CMPL) {
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT, 0);
+ } else {
+ lpfc_printf_vlog(vport, KERN_INFO,
+ LOG_DISCOVERY,
+ "6078 RPRT deferred\n");
+ vport->ct_flags |= FC_CT_RPRT_DEFER;
+ }
+ }
break;
case SLI_MGMT_RPA:
if (vport->port_type == LPFC_PHYSICAL_PORT &&
@@ -2327,7 +2402,8 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
break;
}
- lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_DISCOVERY | LOG_CGN_MGMT,
"6210 Issue Vendor MI FDMI %x\n",
phba->sli4_hba.pc_sli4_params.mi_ver);
@@ -2396,6 +2472,9 @@ lpfc_fdmi_change_check(struct lpfc_vport *vport)
phba->link_flag &= ~LS_CT_VEN_RPA;
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA, 0);
} else {
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ return;
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT, 0);
}
@@ -2417,6 +2496,9 @@ lpfc_fdmi_change_check(struct lpfc_vport *vport)
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA,
LPFC_FDMI_PORT_ATTR_num_disc);
} else {
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ return;
lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPRT,
LPFC_FDMI_PORT_ATTR_num_disc);
}
@@ -2830,31 +2912,59 @@ lpfc_fdmi_port_attr_support_speed(struct lpfc_vport *vport,
struct lpfc_hba *phba = vport->phba;
struct lpfc_fdmi_attr_entry *ae;
uint32_t size;
+ u32 tcfg;
+ u8 i, cnt;
ae = &ad->AttrValue;
ae->un.AttrInt = 0;
if (!(phba->hba_flag & HBA_FCOE_MODE)) {
- if (phba->lmt & LMT_256Gb)
- ae->un.AttrInt |= HBA_PORTSPEED_256GFC;
- if (phba->lmt & LMT_128Gb)
- ae->un.AttrInt |= HBA_PORTSPEED_128GFC;
- if (phba->lmt & LMT_64Gb)
- ae->un.AttrInt |= HBA_PORTSPEED_64GFC;
- if (phba->lmt & LMT_32Gb)
- ae->un.AttrInt |= HBA_PORTSPEED_32GFC;
- if (phba->lmt & LMT_16Gb)
- ae->un.AttrInt |= HBA_PORTSPEED_16GFC;
- if (phba->lmt & LMT_10Gb)
- ae->un.AttrInt |= HBA_PORTSPEED_10GFC;
- if (phba->lmt & LMT_8Gb)
- ae->un.AttrInt |= HBA_PORTSPEED_8GFC;
- if (phba->lmt & LMT_4Gb)
- ae->un.AttrInt |= HBA_PORTSPEED_4GFC;
- if (phba->lmt & LMT_2Gb)
- ae->un.AttrInt |= HBA_PORTSPEED_2GFC;
- if (phba->lmt & LMT_1Gb)
- ae->un.AttrInt |= HBA_PORTSPEED_1GFC;
+ cnt = 0;
+ if (phba->sli_rev == LPFC_SLI_REV4) {
+ tcfg = phba->sli4_hba.conf_trunk;
+ for (i = 0; i < 4; i++, tcfg >>= 1)
+ if (tcfg & 1)
+ cnt++;
+ }
+
+ if (cnt > 2) { /* 4 lane trunk group */
+ if (phba->lmt & LMT_64Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_256GFC;
+ if (phba->lmt & LMT_32Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_128GFC;
+ if (phba->lmt & LMT_16Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_64GFC;
+ } else if (cnt) { /* 2 lane trunk group */
+ if (phba->lmt & LMT_128Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_256GFC;
+ if (phba->lmt & LMT_64Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_128GFC;
+ if (phba->lmt & LMT_32Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_64GFC;
+ if (phba->lmt & LMT_16Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_32GFC;
+ } else {
+ if (phba->lmt & LMT_256Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_256GFC;
+ if (phba->lmt & LMT_128Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_128GFC;
+ if (phba->lmt & LMT_64Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_64GFC;
+ if (phba->lmt & LMT_32Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_32GFC;
+ if (phba->lmt & LMT_16Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_16GFC;
+ if (phba->lmt & LMT_10Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_10GFC;
+ if (phba->lmt & LMT_8Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_8GFC;
+ if (phba->lmt & LMT_4Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_4GFC;
+ if (phba->lmt & LMT_2Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_2GFC;
+ if (phba->lmt & LMT_1Gb)
+ ae->un.AttrInt |= HBA_PORTSPEED_1GFC;
+ }
} else {
/* FCoE links support only one speed */
switch (phba->fc_linkspeed) {
@@ -3125,6 +3235,7 @@ static int
lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport,
struct lpfc_fdmi_attr_def *ad)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_fdmi_attr_entry *ae;
uint32_t size;
@@ -3135,7 +3246,8 @@ lpfc_fdmi_port_attr_active_fc4type(struct lpfc_vport *vport,
ae->un.AttrTypes[7] = 0x01; /* Type 0x20 - CT */
/* Check to see if NVME is configured or not */
- if (vport->phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)
+ if (vport == phba->pport &&
+ phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)
ae->un.AttrTypes[6] = 0x1; /* Type 0x28 - NVME */
size = FOURBYTES + 32;
@@ -3459,8 +3571,10 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* FDMI request */
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
- "0218 FDMI Request Data: x%x x%x x%x\n",
- vport->fc_flag, vport->port_state, cmdcode);
+ "0218 FDMI Request x%x mask x%x Data: x%x x%x x%x\n",
+ cmdcode, new_mask, vport->fdmi_port_mask,
+ vport->fc_flag, vport->port_state);
+
CtReq = (struct lpfc_sli_ct_request *)mp->virt;
/* First populate the CT_IU preamble */
@@ -3529,6 +3643,12 @@ hba_out:
break;
case SLI_MGMT_RPRT:
+ if (vport->port_type != LPFC_PHYSICAL_PORT) {
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ return 0;
+ }
+ fallthrough;
case SLI_MGMT_RPA:
pab = (struct lpfc_fdmi_reg_portattr *)&CtReq->un.PortID;
if (cmdcode == SLI_MGMT_RPRT) {
@@ -3593,6 +3713,12 @@ port_out:
rsp_size = FC_MAX_NS_RSP;
fallthrough;
case SLI_MGMT_DPRT:
+ if (vport->port_type != LPFC_PHYSICAL_PORT) {
+ ndlp = lpfc_findnode_did(phba->pport, FDMI_DID);
+ if (!ndlp)
+ return 0;
+ }
+ fallthrough;
case SLI_MGMT_DPA:
pe = (struct lpfc_fdmi_port_entry *)&CtReq->un.PortID;
memcpy((uint8_t *)&pe->PortName,
@@ -3780,8 +3906,8 @@ lpfc_cmpl_ct_cmd_vmid(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
struct lpfc_vport *vport = cmdiocb->vport;
- struct lpfc_dmabuf *inp = cmdiocb->context1;
- struct lpfc_dmabuf *outp = cmdiocb->context2;
+ struct lpfc_dmabuf *inp = cmdiocb->cmd_dmabuf;
+ struct lpfc_dmabuf *outp = cmdiocb->rsp_dmabuf;
struct lpfc_sli_ct_request *ctcmd = inp->virt;
struct lpfc_sli_ct_request *ctrsp = outp->virt;
u16 rsp = ctrsp->CommandResponse.bits.CmdRsp;
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index ef6e8cd8c26a..07f9a6e61e10 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -152,7 +152,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport)
* Buffer Descriptor Entries (BDEs), allocates buffers for both command
* payload and response payload (if expected). The reference count on the
* ndlp is incremented by 1 and the reference to the ndlp is put into
- * context1 of the IOCB data structure for this IOCB to hold the ndlp
+ * ndlp of the IOCB data structure for this IOCB to hold the ndlp
* reference for the command's callback function to access later.
*
* Return code
@@ -279,8 +279,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, u8 expect_rsp,
bpl->type_size |= cpu_to_le32(ULP_BDE64_TYPE_BDE_64);
}
- elsiocb->context2 = pcmd;
- elsiocb->context3 = pbuflist;
+ elsiocb->cmd_dmabuf = pcmd;
+ elsiocb->bpl_dmabuf = pbuflist;
elsiocb->retry = retry;
elsiocb->vport = vport;
elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT;
@@ -345,7 +345,6 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
{
struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *mbox;
- struct lpfc_dmabuf *mp;
struct lpfc_nodelist *ndlp;
struct serv_parm *sp;
int rc;
@@ -395,7 +394,7 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
mbox->ctx_ndlp = lpfc_nlp_get(ndlp);
if (!mbox->ctx_ndlp) {
err = 6;
- goto fail_no_ndlp;
+ goto fail_free_mbox;
}
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
@@ -411,13 +410,8 @@ fail_issue_reg_login:
* for the failed mbox command.
*/
lpfc_nlp_put(ndlp);
-fail_no_ndlp:
- mp = (struct lpfc_dmabuf *)mbox->ctx_buf;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
fail_free_mbox:
- mempool_free(mbox, phba->mbox_mem_pool);
-
+ lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED);
fail:
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
@@ -465,45 +459,37 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport)
/* Supply CSP's only if we are fabric connect or pt-to-pt connect */
if ((vport->fc_flag & FC_FABRIC) || (vport->fc_flag & FC_PT2PT)) {
- dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
- if (!dmabuf) {
- rc = -ENOMEM;
- goto fail;
- }
- dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys);
- if (!dmabuf->virt) {
+ rc = lpfc_mbox_rsrc_prep(phba, mboxq);
+ if (rc) {
rc = -ENOMEM;
- goto fail;
+ goto fail_mbox;
}
+ dmabuf = mboxq->ctx_buf;
memcpy(dmabuf->virt, &phba->fc_fabparam,
sizeof(struct serv_parm));
}
vport->port_state = LPFC_FABRIC_CFG_LINK;
- if (dmabuf)
+ if (dmabuf) {
lpfc_reg_vfi(mboxq, vport, dmabuf->phys);
- else
+ /* lpfc_reg_vfi memsets the mailbox. Restore the ctx_buf. */
+ mboxq->ctx_buf = dmabuf;
+ } else {
lpfc_reg_vfi(mboxq, vport, 0);
+ }
mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi;
mboxq->vport = vport;
- mboxq->ctx_buf = dmabuf;
rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
rc = -ENXIO;
- goto fail;
+ goto fail_mbox;
}
return 0;
+fail_mbox:
+ lpfc_mbox_rsrc_cleanup(phba, mboxq, MBOX_THD_UNLOCKED);
fail:
- if (mboxq)
- mempool_free(mboxq, phba->mbox_mem_pool);
- if (dmabuf) {
- if (dmabuf->virt)
- lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
- kfree(dmabuf);
- }
-
lpfc_vport_set_state(vport, FC_VPORT_FAILED);
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
"0289 Issue Register VFI failed: Err %d\n", rc);
@@ -959,9 +945,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
{
struct lpfc_vport *vport = cmdiocb->vport;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- struct lpfc_nodelist *ndlp = cmdiocb->context1;
+ struct lpfc_nodelist *ndlp = cmdiocb->ndlp;
IOCB_t *irsp;
- struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
+ struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf, *prsp;
struct serv_parm *sp;
uint16_t fcf_index;
int rc;
@@ -1119,7 +1105,8 @@ stop_rr_fcf_flogi:
sp->cmn.priority_tagging, kref_read(&ndlp->kref));
if (sp->cmn.priority_tagging)
- vport->vmid_flag |= LPFC_VMID_ISSUE_QFPA;
+ vport->phba->pport->vmid_flag |= (LPFC_VMID_ISSUE_QFPA |
+ LPFC_VMID_TYPE_PRIO);
if (vport->port_state == LPFC_FLOGI) {
/*
@@ -1232,7 +1219,7 @@ lpfc_cmpl_els_link_down(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
uint32_t cmd;
u32 ulp_status, ulp_word4;
- pcmd = (uint32_t *)(((struct lpfc_dmabuf *)cmdiocb->context2)->virt);
+ pcmd = (uint32_t *)cmdiocb->cmd_dmabuf->virt;
cmd = *pcmd;
ulp_status = get_job_ulpstatus(phba, rspiocb);
@@ -1265,7 +1252,7 @@ lpfc_cmpl_els_link_down(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* out FLOGI ELS command with one outstanding fabric IOCB at a time.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the FLOGI ELS command.
*
* Return code
@@ -1295,7 +1282,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
return 1;
wqe = &elsiocb->wqe;
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
icmd = &elsiocb->iocb;
/* For FLOGI request, remainder of payload is service parameters */
@@ -1330,7 +1317,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) ==
LPFC_SLI_INTF_IF_TYPE_0) {
/* FLOGI needs to be 3 for WQE FCFI */
- ct = ((SLI4_CT_FCFI >> 1) & 1) | (SLI4_CT_FCFI & 1);
+ ct = SLI4_CT_FCFI;
bf_set(wqe_ct, &wqe->els_req.wqe_com, ct);
/* Set the fcfi to the fcfi we registered with */
@@ -1372,8 +1359,8 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
"Issue FLOGI: opt:x%x",
phba->sli3_options, 0, 0);
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
@@ -1387,6 +1374,9 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
phba->hba_flag |= (HBA_FLOGI_ISSUED | HBA_FLOGI_OUTSTANDING);
+ /* Clear external loopback plug detected flag */
+ phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
+
/* Check for a deferred FLOGI ACC condition */
if (phba->defer_flogi_acc_flag) {
/* lookup ndlp for received FLOGI */
@@ -1474,7 +1464,7 @@ lpfc_els_abort_flogi(struct lpfc_hba *phba)
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
ulp_command = get_job_cmnd(phba, iocb);
if (ulp_command == CMD_ELS_REQUEST64_CR) {
- ndlp = (struct lpfc_nodelist *)(iocb->context1);
+ ndlp = iocb->ndlp;
if (ndlp && ndlp->nlp_DID == Fabric_DID) {
if ((phba->pport->fc_flag & FC_PT2PT) &&
!(phba->pport->fc_flag & FC_PT2PT_PLOGI))
@@ -1531,11 +1521,16 @@ lpfc_initial_flogi(struct lpfc_vport *vport)
lpfc_enqueue_node(vport, ndlp);
}
+ /* Reset the Fabric flag, topology change may have happened */
+ vport->fc_flag &= ~FC_FABRIC;
if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
- /* This decrement of reference count to node shall kick off
- * the release of the node.
+ /* A node reference should be retained while registered with a
+ * transport or dev-loss-evt work is pending.
+ * Otherwise, decrement node reference to trigger release.
*/
- lpfc_nlp_put(ndlp);
+ if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD)) &&
+ !(ndlp->nlp_flag & NLP_IN_DEV_LOSS))
+ lpfc_nlp_put(ndlp);
return 0;
}
return 1;
@@ -1578,10 +1573,13 @@ lpfc_initial_fdisc(struct lpfc_vport *vport)
}
if (lpfc_issue_els_fdisc(vport, ndlp, 0)) {
- /* decrement node reference count to trigger the release of
- * the node.
+ /* A node reference should be retained while registered with a
+ * transport or dev-loss-evt work is pending.
+ * Otherwise, decrement node reference to trigger release.
*/
- lpfc_nlp_put(ndlp);
+ if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD)) &&
+ !(ndlp->nlp_flag & NLP_IN_DEV_LOSS))
+ lpfc_nlp_put(ndlp);
return 0;
}
return 1;
@@ -1888,6 +1886,7 @@ lpfc_end_rscn(struct lpfc_vport *vport)
else {
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~FC_RSCN_MODE;
+ vport->fc_flag |= FC_RSCN_MEMENTO;
spin_unlock_irq(shost->host_lock);
}
}
@@ -1910,14 +1909,14 @@ lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
struct lpfc_vport *vport = cmdiocb->vport;
- struct lpfc_nodelist *ndlp = cmdiocb->context1;
+ struct lpfc_nodelist *ndlp = cmdiocb->ndlp;
struct lpfc_node_rrq *rrq;
u32 ulp_status = get_job_ulpstatus(phba, rspiocb);
u32 ulp_word4 = get_job_word4(phba, rspiocb);
/* we pass cmdiocb to state machine which needs rspiocb as well */
rrq = cmdiocb->context_un.rrq;
- cmdiocb->context_un.rsp_iocb = rspiocb;
+ cmdiocb->rsp_iocb = rspiocb;
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
"RRQ cmpl: status:x%x/x%x did:x%x",
@@ -1983,9 +1982,10 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
int disc;
struct serv_parm *sp = NULL;
u32 ulp_status, ulp_word4, did, iotag;
+ bool release_node = false;
/* we pass cmdiocb to state machine which needs rspiocb as well */
- cmdiocb->context_un.rsp_iocb = rspiocb;
+ cmdiocb->rsp_iocb = rspiocb;
ulp_status = get_job_ulpstatus(phba, rspiocb);
ulp_word4 = get_job_word4(phba, rspiocb);
@@ -2071,23 +2071,24 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
spin_unlock_irq(&ndlp->lock);
goto out;
}
- spin_unlock_irq(&ndlp->lock);
/* No PLOGI collision and the node is not registered with the
* scsi or nvme transport. It is no longer an active node. Just
* start the device remove process.
*/
if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) {
- spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
- spin_unlock_irq(&ndlp->lock);
+ if (!(ndlp->nlp_flag & NLP_IN_DEV_LOSS))
+ release_node = true;
+ }
+ spin_unlock_irq(&ndlp->lock);
+
+ if (release_node)
lpfc_disc_state_machine(vport, ndlp, cmdiocb,
NLP_EVT_DEVICE_RM);
- }
} else {
/* Good status, call state machine */
- prsp = list_entry(((struct lpfc_dmabuf *)
- cmdiocb->context2)->list.next,
+ prsp = list_entry(cmdiocb->cmd_dmabuf->list.next,
struct lpfc_dmabuf, list);
ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp);
@@ -2132,7 +2133,7 @@ out:
out_freeiocb:
/* Release the reference on the original I/O request. */
- free_ndlp = (struct lpfc_nodelist *)cmdiocb->context1;
+ free_ndlp = cmdiocb->ndlp;
lpfc_els_free_iocb(phba, cmdiocb);
lpfc_nlp_put(free_ndlp);
@@ -2152,7 +2153,7 @@ out_freeiocb:
* the lpfc_sli_issue_iocb() routine to send out PLOGI ELS command.
*
* Note that the ndlp reference count will be incremented by 1 for holding
- * the ndlp and the reference to ndlp will be stored into the context1 field
+ * the ndlp and the reference to ndlp will be stored into the ndlp field
* of the IOCB for the completion callback function to the PLOGI ELS command.
*
* Return code
@@ -2203,7 +2204,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
ndlp->nlp_flag &= ~NLP_FCP_PRLI_RJT;
spin_unlock_irq(&ndlp->lock);
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
/* For PLOGI request, remainder of payload is service parameters */
*((uint32_t *) (pcmd)) = ELS_CMD_PLOGI;
@@ -2255,8 +2256,8 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
"Issue PLOGI: did:x%x refcnt %d",
did, kref_read(&ndlp->kref), 0);
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
@@ -2294,11 +2295,12 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
u32 loglevel;
u32 ulp_status;
u32 ulp_word4;
+ bool release_node = false;
/* we pass cmdiocb to state machine which needs rspiocb as well */
- cmdiocb->context_un.rsp_iocb = rspiocb;
+ cmdiocb->rsp_iocb = rspiocb;
- ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ ndlp = cmdiocb->ndlp;
ulp_status = get_job_ulpstatus(phba, rspiocb);
ulp_word4 = get_job_word4(phba, rspiocb);
@@ -2370,14 +2372,18 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* it is no longer an active node. Otherwise devloss
* handles the final cleanup.
*/
+ spin_lock_irq(&ndlp->lock);
if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD)) &&
!ndlp->fc4_prli_sent) {
- spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
- spin_unlock_irq(&ndlp->lock);
+ if (!(ndlp->nlp_flag & NLP_IN_DEV_LOSS))
+ release_node = true;
+ }
+ spin_unlock_irq(&ndlp->lock);
+
+ if (release_node)
lpfc_disc_state_machine(vport, ndlp, cmdiocb,
NLP_EVT_DEVICE_RM);
- }
} else {
/* Good status, call state machine. However, if another
* PRLI is outstanding, don't call the state machine
@@ -2407,7 +2413,7 @@ out:
* routine lpfc_sli_issue_iocb() to send out PRLI command.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the PRLI ELS command.
*
* Return code
@@ -2428,13 +2434,14 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
u32 local_nlp_type, elscmd;
/*
- * If we are in RSCN mode, the FC4 types supported from a
+ * If discovery was kicked off from RSCN mode,
+ * the FC4 types supported from a
* previous GFT_ID command may not be accurate. So, if we
* are a NVME Initiator, always look for the possibility of
* the remote NPort beng a NVME Target.
*/
if (phba->sli_rev == LPFC_SLI_REV4 &&
- vport->fc_flag & FC_RSCN_MODE &&
+ vport->fc_flag & (FC_RSCN_MODE | FC_RSCN_MEMENTO) &&
vport->nvmei_support)
ndlp->nlp_fc4_type |= NLP_FC4_NVME;
local_nlp_type = ndlp->nlp_fc4_type;
@@ -2481,7 +2488,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (!elsiocb)
return 1;
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
/* For PRLI request, remainder of payload is service parameters */
memset(pcmd, 0, cmdsize);
@@ -2555,33 +2562,32 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
phba->fc_stat.elsXmitPRLI++;
elsiocb->cmd_cmpl = lpfc_cmpl_els_prli;
- spin_lock_irq(&ndlp->lock);
- ndlp->nlp_flag |= NLP_PRLI_SND;
-
- /* The vport counters are used for lpfc_scan_finished, but
- * the ndlp is used to track outstanding PRLIs for different
- * FC4 types.
- */
- vport->fc_prli_sent++;
- ndlp->fc4_prli_sent++;
- spin_unlock_irq(&ndlp->lock);
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
"Issue PRLI: did:x%x refcnt %d",
ndlp->nlp_DID, kref_read(&ndlp->kref), 0);
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
- goto err;
+ return 1;
}
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
lpfc_nlp_put(ndlp);
- goto err;
+ return 1;
}
+ /* The vport counters are used for lpfc_scan_finished, but
+ * the ndlp is used to track outstanding PRLIs for different
+ * FC4 types.
+ */
+ spin_lock_irq(&ndlp->lock);
+ ndlp->nlp_flag |= NLP_PRLI_SND;
+ vport->fc_prli_sent++;
+ ndlp->fc4_prli_sent++;
+ spin_unlock_irq(&ndlp->lock);
/* The driver supports 2 FC4 types. Make sure
* a PRLI is issued for all types before exiting.
@@ -2591,12 +2597,6 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
goto send_next_prli;
else
return 0;
-
-err:
- spin_lock_irq(&ndlp->lock);
- ndlp->nlp_flag &= ~NLP_PRLI_SND;
- spin_unlock_irq(&ndlp->lock);
- return 1;
}
/**
@@ -2749,11 +2749,12 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_nodelist *ndlp;
int disc;
u32 ulp_status, ulp_word4, tmo;
+ bool release_node = false;
/* we pass cmdiocb to state machine which needs rspiocb as well */
- cmdiocb->context_un.rsp_iocb = rspiocb;
+ cmdiocb->rsp_iocb = rspiocb;
- ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ ndlp = cmdiocb->ndlp;
ulp_status = get_job_ulpstatus(phba, rspiocb);
ulp_word4 = get_job_word4(phba, rspiocb);
@@ -2815,13 +2816,17 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* transport, it is no longer an active node. Otherwise
* devloss handles the final cleanup.
*/
+ spin_lock_irq(&ndlp->lock);
if (!(ndlp->fc4_xpt_flags & (SCSI_XPT_REGD | NVME_XPT_REGD))) {
- spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
- spin_unlock_irq(&ndlp->lock);
+ if (!(ndlp->nlp_flag & NLP_IN_DEV_LOSS))
+ release_node = true;
+ }
+ spin_unlock_irq(&ndlp->lock);
+
+ if (release_node)
lpfc_disc_state_machine(vport, ndlp, cmdiocb,
NLP_EVT_DEVICE_RM);
- }
} else
/* Good status, call state machine */
lpfc_disc_state_machine(vport, ndlp, cmdiocb,
@@ -2848,7 +2853,7 @@ out:
* to issue the ADISC ELS command.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the ADISC ELS command.
*
* Return code
@@ -2872,7 +2877,7 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (!elsiocb)
return 1;
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
/* For ADISC request, remainder of payload is service parameters */
*((uint32_t *) (pcmd)) = ELS_CMD_ADISC;
@@ -2890,8 +2895,8 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag |= NLP_ADISC_SND;
spin_unlock_irq(&ndlp->lock);
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
goto err;
}
@@ -2931,7 +2936,7 @@ static void
lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
- struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_nodelist *ndlp = cmdiocb->ndlp;
struct lpfc_vport *vport = ndlp->vport;
IOCB_t *irsp;
unsigned long flags;
@@ -2942,7 +2947,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
u32 tmo;
/* we pass cmdiocb to state machine which needs rspiocb as well */
- cmdiocb->context_un.rsp_iocb = rspiocb;
+ cmdiocb->rsp_iocb = rspiocb;
ulp_status = get_job_ulpstatus(phba, rspiocb);
ulp_word4 = get_job_word4(phba, rspiocb);
@@ -2993,7 +2998,10 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
ndlp->nlp_DID, ulp_status,
ulp_word4);
+ /* Call NLP_EVT_DEVICE_RM if link is down or LOGO is aborted */
if (lpfc_error_lost_link(ulp_status, ulp_word4)) {
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_DEVICE_RM);
skip_recovery = 1;
goto out;
}
@@ -3081,7 +3089,7 @@ out:
* lpfc_sli_issue_iocb() routine to send out the LOGO ELS command.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the LOGO ELS command.
*
* Callers of this routine are expected to unregister the RPI first
@@ -3113,7 +3121,7 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (!elsiocb)
return 1;
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
pcmd += sizeof(uint32_t);
@@ -3128,8 +3136,8 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_flag |= NLP_LOGO_SND;
ndlp->nlp_flag &= ~NLP_ISSUE_LOGO;
spin_unlock_irq(&ndlp->lock);
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
goto err;
}
@@ -3207,7 +3215,7 @@ lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* Check to see if link went down during discovery */
lpfc_els_chk_latt(vport);
- free_ndlp = (struct lpfc_nodelist *)cmdiocb->context1;
+ free_ndlp = cmdiocb->ndlp;
lpfc_els_free_iocb(phba, cmdiocb);
lpfc_nlp_put(free_ndlp);
@@ -3234,7 +3242,6 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp)
struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ns_ndlp;
LPFC_MBOXQ_t *mbox;
- struct lpfc_dmabuf *mp;
if (fc_ndlp->nlp_flag & NLP_RPI_REGISTERED)
return rc;
@@ -3271,7 +3278,7 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp)
mbox->ctx_ndlp = lpfc_nlp_get(fc_ndlp);
if (!mbox->ctx_ndlp) {
rc = -ENOMEM;
- goto out_mem;
+ goto out;
}
mbox->vport = vport;
@@ -3279,21 +3286,15 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp)
if (rc == MBX_NOT_FINISHED) {
rc = -ENODEV;
lpfc_nlp_put(fc_ndlp);
- goto out_mem;
+ goto out;
}
/* Success path. Exit. */
lpfc_nlp_set_state(vport, fc_ndlp,
NLP_STE_REG_LOGIN_ISSUE);
return 0;
- out_mem:
- fc_ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
- mp = (struct lpfc_dmabuf *)mbox->ctx_buf;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
-
out:
- mempool_free(mbox, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED);
lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
"0938 %s: failed to format reg_login "
"Data: x%x x%x x%x x%x\n", __func__,
@@ -3323,7 +3324,7 @@ lpfc_cmpl_els_disc_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_dmabuf *pcmd, *prsp;
u32 *pdata;
u32 cmd;
- struct lpfc_nodelist *ndlp = cmdiocb->context1;
+ struct lpfc_nodelist *ndlp = cmdiocb->ndlp;
u32 ulp_status, ulp_word4, tmo, did, iotag;
ulp_status = get_job_ulpstatus(phba, rspiocb);
@@ -3348,7 +3349,7 @@ lpfc_cmpl_els_disc_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
"0217 ELS cmd tag x%x completes Data: x%x x%x x%x x%x\n",
iotag, ulp_status, ulp_word4, tmo, cmdiocb->retry);
- pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
+ pcmd = cmdiocb->cmd_dmabuf;
if (!pcmd)
goto out;
@@ -3371,7 +3372,6 @@ lpfc_cmpl_els_disc_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_issue_els_edc(vport, cmdiocb->retry);
break;
case ELS_CMD_RDF:
- cmdiocb->context1 = NULL; /* save ndlp refcnt */
lpfc_issue_els_rdf(vport, cmdiocb->retry);
break;
}
@@ -3439,7 +3439,7 @@ out:
* routine is invoked to send the SCR IOCB.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the SCR ELS command.
*
* Return code
@@ -3481,7 +3481,7 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry)
return 1;
}
}
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_SCR;
pcmd += sizeof(uint32_t);
@@ -3496,8 +3496,8 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry)
phba->fc_stat.elsXmitSCR++;
elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
@@ -3528,7 +3528,7 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry)
* replay the RSCN to registered recipients.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the RSCN ELS command.
*
* Return code
@@ -3578,7 +3578,7 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry)
if (!elsiocb)
return 1;
- event = ((struct lpfc_dmabuf *)elsiocb->context2)->virt;
+ event = elsiocb->cmd_dmabuf->virt;
event->rscn.rscn_cmd = ELS_RSCN;
event->rscn.rscn_page_len = sizeof(struct fc_els_rscn_page);
@@ -3593,8 +3593,8 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry)
phba->fc_stat.elsXmitRSCN++;
elsiocb->cmd_cmpl = lpfc_cmpl_els_cmd;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
@@ -3627,7 +3627,7 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry)
* lpfc_sli_issue_iocb() routine is invoked to send the FARPR ELS command.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the FARPR ELS command.
*
* Return code
@@ -3662,7 +3662,7 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
if (!elsiocb)
return 1;
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_FARPR;
pcmd += sizeof(uint32_t);
@@ -3692,8 +3692,8 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
phba->fc_stat.elsXmitFARPR++;
elsiocb->cmd_cmpl = lpfc_cmpl_els_cmd;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
@@ -3724,7 +3724,7 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
* for diagnostic functions.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the RDF ELS command.
*
* Return code
@@ -3761,8 +3761,7 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
return -ENOMEM;
/* Configure the payload for the supported FPIN events. */
- prdf = (struct lpfc_els_rdf_req *)
- (((struct lpfc_dmabuf *)elsiocb->context2)->virt);
+ prdf = (struct lpfc_els_rdf_req *)elsiocb->cmd_dmabuf->virt;
memset(prdf, 0, cmdsize);
prdf->rdf.fpin_cmd = ELS_RDF;
prdf->rdf.desc_len = cpu_to_be32(sizeof(struct lpfc_els_rdf_req) -
@@ -3783,8 +3782,8 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry)
phba->cgn_fpin_frequency = LPFC_FPIN_INIT_FREQ;
elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return -EIO;
}
@@ -3855,9 +3854,6 @@ lpfc_least_capable_settings(struct lpfc_hba *phba,
{
u32 rsp_sig_cap = 0, drv_sig_cap = 0;
u32 rsp_sig_freq_cyc = 0, rsp_sig_freq_scale = 0;
- struct lpfc_cgn_info *cp;
- u32 crc;
- u16 sig_freq;
/* Get rsp signal and frequency capabilities. */
rsp_sig_cap = be32_to_cpu(pcgd->xmt_signal_capability);
@@ -3913,25 +3909,7 @@ lpfc_least_capable_settings(struct lpfc_hba *phba,
}
}
- if (!phba->cgn_i)
- return;
-
- /* Update signal frequency in congestion info buffer */
- cp = (struct lpfc_cgn_info *)phba->cgn_i->virt;
-
- /* Frequency (in ms) Signal Warning/Signal Congestion Notifications
- * are received by the HBA
- */
- sig_freq = phba->cgn_sig_freq;
-
- if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ONLY)
- cp->cgn_warn_freq = cpu_to_le16(sig_freq);
- if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) {
- cp->cgn_alarm_freq = cpu_to_le16(sig_freq);
- cp->cgn_warn_freq = cpu_to_le16(sig_freq);
- }
- crc = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ, LPFC_CGN_CRC32_SEED);
- cp->cgn_info_crc = cpu_to_le32(crc);
+ /* We are NOT recording signal frequency in congestion info buffer */
return;
out_no_support:
@@ -3973,7 +3951,7 @@ lpfc_cmpl_els_edc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_nodelist *ndlp;
u32 ulp_status, ulp_word4, tmo, did, iotag;
- ndlp = cmdiocb->context1;
+ ndlp = cmdiocb->ndlp;
ulp_status = get_job_ulpstatus(phba, rspiocb);
ulp_word4 = get_job_word4(phba, rspiocb);
@@ -3997,7 +3975,7 @@ lpfc_cmpl_els_edc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
"4201 EDC cmd tag x%x completes Data: x%x x%x x%x\n",
iotag, ulp_status, ulp_word4, tmo);
- pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
+ pcmd = cmdiocb->cmd_dmabuf;
if (!pcmd)
goto out;
@@ -4246,7 +4224,7 @@ lpfc_issue_els_edc(struct lpfc_vport *vport, uint8_t retry)
goto try_rdf;
/* Configure the payload for the supported Diagnostics capabilities. */
- pcmd = (u8 *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt);
+ pcmd = (u8 *)elsiocb->cmd_dmabuf->virt;
memset(pcmd, 0, cmdsize);
edc_req = (struct lpfc_els_edc_req *)pcmd;
edc_req->edc.desc_len = cpu_to_be32(cgn_desc_size);
@@ -4258,15 +4236,15 @@ lpfc_issue_els_edc(struct lpfc_vport *vport, uint8_t retry)
phba->cgn_sig_freq = lpfc_fabric_cgn_frequency;
- lpfc_printf_vlog(vport, KERN_INFO, LOG_CGN_MGMT,
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT,
"4623 Xmit EDC to remote "
"NPORT x%x reg_sig x%x reg_fpin:x%x\n",
ndlp->nlp_DID, phba->cgn_reg_signal,
phba->cgn_reg_fpin);
elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return -EIO;
}
@@ -4544,8 +4522,8 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
{
struct lpfc_vport *vport = cmdiocb->vport;
union lpfc_wqe128 *irsp = &rspiocb->wqe;
- struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
- struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ struct lpfc_nodelist *ndlp = cmdiocb->ndlp;
+ struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf;
uint32_t *elscmd;
struct ls_rjt stat;
int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
@@ -4557,7 +4535,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
u32 ulp_word4 = get_job_word4(phba, rspiocb);
- /* Note: context2 may be 0 for internal driver abort
+ /* Note: cmd_dmabuf may be 0 for internal driver abort
* of delays ELS command.
*/
@@ -5068,10 +5046,10 @@ lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr)
* command IOCB data structure contains the reference to various associated
* resources, these fields must be set to NULL if the associated reference
* not present:
- * context1 - reference to ndlp
- * context2 - reference to cmd
- * context2->next - reference to rsp
- * context3 - reference to bpl
+ * cmd_dmabuf - reference to cmd.
+ * cmd_dmabuf->next - reference to rsp
+ * rsp_dmabuf - unused
+ * bpl_dmabuf - reference to bpl
*
* It first properly decrements the reference count held on ndlp for the
* IOCB completion callback function. If LPFC_DELAY_MEM_FREE flag is not
@@ -5091,19 +5069,19 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
{
struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
- /* The I/O iocb is complete. Clear the context1 data. */
- elsiocb->context1 = NULL;
+ /* The I/O iocb is complete. Clear the node and first dmbuf */
+ elsiocb->ndlp = NULL;
- /* context2 = cmd, context2->next = rsp, context3 = bpl */
- if (elsiocb->context2) {
+ /* cmd_dmabuf = cmd, cmd_dmabuf->next = rsp, bpl_dmabuf = bpl */
+ if (elsiocb->cmd_dmabuf) {
if (elsiocb->cmd_flag & LPFC_DELAY_MEM_FREE) {
/* Firmware could still be in progress of DMAing
* payload, so don't free data buffer till after
* a hbeat.
*/
elsiocb->cmd_flag &= ~LPFC_DELAY_MEM_FREE;
- buf_ptr = elsiocb->context2;
- elsiocb->context2 = NULL;
+ buf_ptr = elsiocb->cmd_dmabuf;
+ elsiocb->cmd_dmabuf = NULL;
if (buf_ptr) {
buf_ptr1 = NULL;
spin_lock_irq(&phba->hbalock);
@@ -5122,16 +5100,16 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
spin_unlock_irq(&phba->hbalock);
}
} else {
- buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
+ buf_ptr1 = elsiocb->cmd_dmabuf;
lpfc_els_free_data(phba, buf_ptr1);
- elsiocb->context2 = NULL;
+ elsiocb->cmd_dmabuf = NULL;
}
}
- if (elsiocb->context3) {
- buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
+ if (elsiocb->bpl_dmabuf) {
+ buf_ptr = elsiocb->bpl_dmabuf;
lpfc_els_free_bpl(phba, buf_ptr);
- elsiocb->context3 = NULL;
+ elsiocb->bpl_dmabuf = NULL;
}
lpfc_sli_release_iocbq(phba, elsiocb);
return 0;
@@ -5147,7 +5125,7 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
* Accept (ACC) Response ELS command. This routine is invoked to indicate
* the completion of the LOGO process. It invokes the lpfc_nlp_not_used() to
* release the ndlp if it has the last reference remaining (reference count
- * is 1). If succeeded (meaning ndlp released), it sets the IOCB context1
+ * is 1). If succeeded (meaning ndlp released), it sets the iocb ndlp
* field to NULL to inform the following lpfc_els_free_iocb() routine no
* ndlp reference count needs to be decremented. Otherwise, the ndlp
* reference use-count shall be decremented by the lpfc_els_free_iocb()
@@ -5158,7 +5136,7 @@ static void
lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
- struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_nodelist *ndlp = cmdiocb->ndlp;
struct lpfc_vport *vport = cmdiocb->vport;
u32 ulp_status, ulp_word4;
@@ -5204,7 +5182,7 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* Indicate the node has already released, should
* not reference to it from within lpfc_els_free_iocb.
*/
- cmdiocb->context1 = NULL;
+ cmdiocb->ndlp = NULL;
}
}
out:
@@ -5232,14 +5210,10 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
void
lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
- struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
+ struct lpfc_nodelist *ndlp = pmb->ctx_ndlp;
u32 mbx_flag = pmb->mbox_flag;
u32 mbx_cmd = pmb->u.mb.mbxCommand;
- pmb->ctx_buf = NULL;
- pmb->ctx_ndlp = NULL;
-
if (ndlp) {
lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE,
"0006 rpi x%x DID:%x flg:%x %d x%px "
@@ -5262,10 +5236,7 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
lpfc_drop_node(ndlp->vport, ndlp);
}
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
- return;
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
}
/**
@@ -5285,12 +5256,11 @@ static void
lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
- struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_nodelist *ndlp = cmdiocb->ndlp;
struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
IOCB_t *irsp;
LPFC_MBOXQ_t *mbox = NULL;
- struct lpfc_dmabuf *mp = NULL;
u32 ulp_status, ulp_word4, tmo, did, iotag;
if (!vport) {
@@ -5316,14 +5286,8 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* Check to see if link went down during discovery */
if (!ndlp || lpfc_els_chk_latt(vport)) {
- if (mbox) {
- mp = (struct lpfc_dmabuf *)mbox->ctx_buf;
- if (mp) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- }
- mempool_free(mbox, phba->mbox_mem_pool);
- }
+ if (mbox)
+ lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED);
goto out;
}
@@ -5354,14 +5318,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
ndlp->nlp_state,
ndlp->nlp_rpi,
ndlp->nlp_flag);
- mp = mbox->ctx_buf;
- if (mp) {
- lpfc_mbuf_free(phba, mp->virt,
- mp->phys);
- kfree(mp);
- }
- mempool_free(mbox, phba->mbox_mem_pool);
- goto out;
+ goto out_free_mbox;
}
}
@@ -5370,7 +5327,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
mbox->ctx_ndlp = lpfc_nlp_get(ndlp);
if (!mbox->ctx_ndlp)
- goto out;
+ goto out_free_mbox;
mbox->vport = vport;
if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) {
@@ -5402,12 +5359,8 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi);
}
- mp = (struct lpfc_dmabuf *)mbox->ctx_buf;
- if (mp) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- }
- mempool_free(mbox, phba->mbox_mem_pool);
+out_free_mbox:
+ lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED);
}
out:
if (ndlp && shost) {
@@ -5459,7 +5412,7 @@ out:
* mailbox command to the HBA later when callback is invoked.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the corresponding
* response ELS IOCB command.
*
@@ -5516,7 +5469,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
oldcmd->unsli3.rcvsli3.ox_id;
}
- pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t);
@@ -5551,7 +5504,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
oldcmd->unsli3.rcvsli3.ox_id;
}
- pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (u8 *)elsiocb->cmd_dmabuf->virt;
if (mbox)
elsiocb->context_un.mbox = mbox;
@@ -5629,9 +5582,9 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
oldcmd->unsli3.rcvsli3.ox_id;
}
- pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (u8 *) elsiocb->cmd_dmabuf->virt;
- memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
+ memcpy(pcmd, oldiocb->cmd_dmabuf->virt,
sizeof(uint32_t) + sizeof(PRLO));
*((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC;
els_pkt_ptr = (ELS_PKT *) pcmd;
@@ -5667,7 +5620,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
oldcmd->unsli3.rcvsli3.ox_id;
}
- pcmd = (((struct lpfc_dmabuf *)elsiocb->context2)->virt);
+ pcmd = (u8 *)elsiocb->cmd_dmabuf->virt;
rdf_resp = (struct fc_els_rdf_resp *)pcmd;
memset(rdf_resp, 0, sizeof(*rdf_resp));
rdf_resp->acc_hdr.la_cmd = ELS_LS_ACC;
@@ -5695,8 +5648,8 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
}
phba->fc_stat.elsXmitACC++;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
@@ -5733,7 +5686,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
* to issue to the HBA later.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the reject response
* ELS IOCB command.
*
@@ -5774,7 +5727,7 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id;
}
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
pcmd += sizeof(uint32_t);
@@ -5797,8 +5750,8 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
phba->fc_stat.elsXmitLSRJT++;
elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
@@ -5870,8 +5823,7 @@ lpfc_issue_els_edc_rsp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
icmd->unsli3.rcvsli3.ox_id = cmd->unsli3.rcvsli3.ox_id;
}
- pcmd = (((struct lpfc_dmabuf *)elsiocb->context2)->virt);
-
+ pcmd = elsiocb->cmd_dmabuf->virt;
memset(pcmd, 0, cmdsize);
edc_rsp = (struct lpfc_els_edc_rsp *)pcmd;
@@ -5891,8 +5843,8 @@ lpfc_issue_els_edc_rsp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp;
phba->fc_stat.elsXmitACC++;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
@@ -5927,7 +5879,7 @@ lpfc_issue_els_edc_rsp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
* and invokes the lpfc_sli_issue_iocb() routine to send out the command.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the ADISC Accept response
* ELS IOCB command.
*
@@ -5980,7 +5932,7 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
elsiocb->iotag, ulp_context,
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi);
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t);
@@ -5997,8 +5949,8 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
phba->fc_stat.elsXmitACC++;
elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
@@ -6024,7 +5976,7 @@ lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
* and invokes the lpfc_sli_issue_iocb() routine to send out the command.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the PRLI Accept response
* ELS IOCB command.
*
@@ -6054,7 +6006,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
/* Need the incoming PRLI payload to determine if the ACC is for an
* FC4 or NVME PRLI type. The PRLI type is at word 1.
*/
- req_buf = (struct lpfc_dmabuf *)oldiocb->context2;
+ req_buf = oldiocb->cmd_dmabuf;
req_payload = (((uint32_t *)req_buf->virt) + 1);
/* PRLI type payload is at byte 3 for FCP or NVME. */
@@ -6102,7 +6054,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
elsiocb->iotag, ulp_context,
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi);
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
memset(pcmd, 0, cmdsize);
*((uint32_t *)(pcmd)) = elsrspcmd;
@@ -6175,8 +6127,8 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
phba->fc_stat.elsXmitACC++;
elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
@@ -6204,7 +6156,7 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
* issue the response.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function.
*
* Return code
@@ -6255,7 +6207,7 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0132 Xmit RNID ACC response tag x%x xri x%x\n",
elsiocb->iotag, ulp_context);
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t);
@@ -6289,8 +6241,8 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
phba->fc_stat.elsXmitACC++;
elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
@@ -6325,7 +6277,7 @@ lpfc_els_clear_rrq(struct lpfc_vport *vport,
struct lpfc_node_rrq *prrq;
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) iocb->context2)->virt);
+ pcmd = (uint8_t *)iocb->cmd_dmabuf->virt;
pcmd += sizeof(uint32_t);
rrq = (struct RRQ *)pcmd;
rrq->rrq_exchg = be32_to_cpu(rrq->rrq_exchg);
@@ -6412,7 +6364,7 @@ lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data,
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"2876 Xmit ECHO ACC response tag x%x xri x%x\n",
elsiocb->iotag, ulp_context);
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t);
memcpy(pcmd, data, cmdsize - sizeof(uint32_t));
@@ -6423,8 +6375,8 @@ lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data,
phba->fc_stat.elsXmitACC++;
elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
@@ -7048,9 +7000,8 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,
elsiocb->iotag, ulp_context,
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi);
- rdp_res = (struct fc_rdp_res_frame *)
- (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ rdp_res = (struct fc_rdp_res_frame *)elsiocb->cmd_dmabuf->virt;
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
memset(pcmd, 0, sizeof(struct fc_rdp_res_frame));
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -7101,15 +7052,14 @@ lpfc_els_rdp_cmpl(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context,
elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp;
/* Now that we know the true size of the payload, update the BPL */
- bpl = (struct ulp_bde64 *)
- (((struct lpfc_dmabuf *)(elsiocb->context3))->virt);
+ bpl = (struct ulp_bde64 *)elsiocb->bpl_dmabuf->virt;
bpl->tus.f.bdeSize = len;
bpl->tus.f.bdeFlags = 0;
bpl->tus.w = le32_to_cpu(bpl->tus.w);
phba->fc_stat.elsXmitACC++;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
goto free_rdp_context;
}
@@ -7143,7 +7093,7 @@ error:
icmd->unsli3.rcvsli3.ox_id = rdp_context->ox_id;
}
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
stat = (struct ls_rjt *)(pcmd + sizeof(uint32_t));
@@ -7151,8 +7101,8 @@ error:
phba->fc_stat.elsXmitLSRJT++;
elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
goto free_rdp_context;
}
@@ -7175,7 +7125,6 @@ static int
lpfc_get_rdp_info(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context)
{
LPFC_MBOXQ_t *mbox = NULL;
- struct lpfc_dmabuf *mp;
int rc;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -7186,21 +7135,19 @@ lpfc_get_rdp_info(struct lpfc_hba *phba, struct lpfc_rdp_context *rdp_context)
}
if (lpfc_sli4_dump_page_a0(phba, mbox))
- goto prep_mbox_fail;
+ goto rdp_fail;
mbox->vport = rdp_context->ndlp->vport;
mbox->mbox_cmpl = lpfc_mbx_cmpl_rdp_page_a0;
mbox->ctx_ndlp = (struct lpfc_rdp_context *)rdp_context;
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
- mp = (struct lpfc_dmabuf *)mbox->ctx_buf;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- goto issue_mbox_fail;
+ lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED);
+ return 1;
}
return 0;
-prep_mbox_fail:
-issue_mbox_fail:
+rdp_fail:
mempool_free(mbox, phba->mbox_mem_pool);
return 1;
}
@@ -7248,7 +7195,7 @@ lpfc_els_rcv_rdp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
goto error;
}
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ pcmd = cmdiocb->cmd_dmabuf;
rdp_req = (struct fc_rdp_req_frame *) pcmd->virt;
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
@@ -7360,8 +7307,7 @@ lpfc_els_lcb_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
if (!elsiocb)
goto free_lcb_context;
- lcb_res = (struct fc_lcb_res_frame *)
- (((struct lpfc_dmabuf *)elsiocb->context2)->virt);
+ lcb_res = (struct fc_lcb_res_frame *)elsiocb->cmd_dmabuf->virt;
memset(lcb_res, 0, sizeof(struct fc_lcb_res_frame));
@@ -7376,7 +7322,7 @@ lpfc_els_lcb_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
icmd->unsli3.rcvsli3.ox_id = lcb_context->ox_id;
}
- pcmd = (uint8_t *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *)(pcmd)) = ELS_CMD_ACC;
lcb_res->lcb_sub_command = lcb_context->sub_command;
lcb_res->lcb_type = lcb_context->type;
@@ -7386,8 +7332,8 @@ lpfc_els_lcb_rsp(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp;
phba->fc_stat.elsXmitACC++;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
goto out;
}
@@ -7421,7 +7367,7 @@ error:
icmd->unsli3.rcvsli3.ox_id = lcb_context->ox_id;
}
- pcmd = (uint8_t *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *)(pcmd)) = ELS_CMD_LS_RJT;
stat = (struct ls_rjt *)(pcmd + sizeof(uint32_t));
@@ -7432,8 +7378,8 @@ error:
elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp;
phba->fc_stat.elsXmitLSRJT++;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
goto free_lcb_context;
}
@@ -7545,7 +7491,7 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
u8 state, rjt_err = 0;
struct ls_rjt stat;
- pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
+ pcmd = cmdiocb->cmd_dmabuf;
lp = (uint8_t *)pcmd->virt;
beacon = (struct fc_lcb_request_frame *)pcmd->virt;
@@ -7742,10 +7688,10 @@ return_did_out:
static int
lpfc_rscn_recovery_check(struct lpfc_vport *vport)
{
- struct lpfc_nodelist *ndlp = NULL;
+ struct lpfc_nodelist *ndlp = NULL, *n;
/* Move all affected nodes by pending RSCNs to NPR state. */
- list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+ list_for_each_entry_safe(ndlp, n, &vport->fc_nodes, nlp_listp) {
if ((ndlp->nlp_state == NLP_STE_UNUSED_NODE) ||
!lpfc_rscn_payload_check(vport, ndlp->nlp_DID))
continue;
@@ -7791,7 +7737,7 @@ lpfc_send_rscn_event(struct lpfc_vport *vport,
uint32_t payload_len;
struct lpfc_rscn_event_header *rscn_event_data;
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ pcmd = cmdiocb->cmd_dmabuf;
payload_ptr = (uint32_t *) pcmd->virt;
payload_len = be32_to_cpu(*payload_ptr & ~ELS_CMD_MASK);
@@ -7851,7 +7797,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
int rscn_id = 0, hba_id = 0;
int i, tmo;
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ pcmd = cmdiocb->cmd_dmabuf;
lp = (uint32_t *) pcmd->virt;
payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
@@ -7953,7 +7899,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
/* Get the array count after successfully have the token */
rscn_cnt = vport->fc_rscn_id_cnt;
/* If we are already processing an RSCN, save the received
- * RSCN payload buffer, cmdiocb->context2 to process later.
+ * RSCN payload buffer, cmdiocb->cmd_dmabuf to process later.
*/
if (vport->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -7972,6 +7918,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
!(vport->fc_flag & FC_RSCN_DISCOVERY)) {
vport->fc_flag |= FC_RSCN_MODE;
+ vport->fc_flag &= ~FC_RSCN_MEMENTO;
spin_unlock_irq(shost->host_lock);
if (rscn_cnt) {
cmd = vport->fc_rscn_id_list[rscn_cnt-1]->virt;
@@ -7986,10 +7933,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
} else {
vport->fc_rscn_id_list[rscn_cnt] = pcmd;
vport->fc_rscn_id_cnt++;
- /* If we zero, cmdiocb->context2, the calling
+ /* If we zero, cmdiocb->cmd_dmabuf, the calling
* routine will not try to free it.
*/
- cmdiocb->context2 = NULL;
+ cmdiocb->cmd_dmabuf = NULL;
}
/* Deferred RSCN */
lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
@@ -8021,15 +7968,16 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
spin_lock_irq(shost->host_lock);
vport->fc_flag |= FC_RSCN_MODE;
+ vport->fc_flag &= ~FC_RSCN_MEMENTO;
spin_unlock_irq(shost->host_lock);
vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd;
/* Indicate we are done walking fc_rscn_id_list on this vport */
vport->fc_rscn_flush = 0;
/*
- * If we zero, cmdiocb->context2, the calling routine will
+ * If we zero, cmdiocb->cmd_dmabuf, the calling routine will
* not try to free it.
*/
- cmdiocb->context2 = NULL;
+ cmdiocb->cmd_dmabuf = NULL;
lpfc_set_disctmo(vport);
/* Send back ACC */
lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
@@ -8153,7 +8101,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
{
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_hba *phba = vport->phba;
- struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf;
uint32_t *lp = (uint32_t *) pcmd->virt;
union lpfc_wqe128 *wqe = &cmdiocb->wqe;
struct serv_parm *sp;
@@ -8163,6 +8111,9 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
uint32_t fc_flag = 0;
uint32_t port_state = 0;
+ /* Clear external loopback plug detected flag */
+ phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
+
cmd = *lp++;
sp = (struct serv_parm *) lp;
@@ -8214,6 +8165,12 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
return 1;
}
+ /* External loopback plug insertion detected */
+ phba->link_flag |= LS_EXTERNAL_LOOPBACK;
+
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_LIBDFC,
+ "1119 External Loopback plug detected\n");
+
/* abort the flogi coming back to ourselves
* due to external loopback on the port.
*/
@@ -8320,7 +8277,7 @@ lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
RNID *rn;
struct ls_rjt stat;
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ pcmd = cmdiocb->cmd_dmabuf;
lp = (uint32_t *) pcmd->virt;
lp++;
@@ -8361,7 +8318,7 @@ lpfc_els_rcv_echo(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
{
uint8_t *pcmd;
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt);
+ pcmd = (uint8_t *)cmdiocb->cmd_dmabuf->virt;
/* skip over first word of echo command to find echo data */
pcmd += sizeof(uint32_t);
@@ -8437,7 +8394,7 @@ lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
* response to the RLS.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the RLS Accept Response
* ELS IOCB command.
*
@@ -8460,7 +8417,7 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
mb = &pmb->u.mb;
- ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
+ ndlp = pmb->ctx_ndlp;
rxid = (uint16_t)((unsigned long)(pmb->ctx_buf) & 0xffff);
oxid = (uint16_t)(((unsigned long)(pmb->ctx_buf) >> 16) & 0xffff);
pmb->ctx_buf = NULL;
@@ -8496,7 +8453,7 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
icmd->unsli3.rcvsli3.ox_id = oxid;
}
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t); /* Skip past command */
rls_rsp = (struct RLS_RSP *)pcmd;
@@ -8517,8 +8474,8 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
ndlp->nlp_rpi);
elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp;
phba->fc_stat.elsXmitACC++;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return;
}
@@ -8609,7 +8566,7 @@ reject_out:
* Value (RTV) unsolicited IOCB event.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the RTV Accept Response
* ELS IOCB command.
*
@@ -8644,7 +8601,7 @@ lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
if (!elsiocb)
return 1;
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint32_t); /* Skip past command */
@@ -8682,8 +8639,8 @@ lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
rtv_rsp->ratov, rtv_rsp->edtov, rtv_rsp->qtov);
elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp;
phba->fc_stat.elsXmitACC++;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 0;
}
@@ -8739,7 +8696,7 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (!elsiocb)
return 1;
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
/* For RRQ request, remainder of payload is Exchange IDs */
*((uint32_t *) (pcmd)) = ELS_CMD_RRQ;
@@ -8759,17 +8716,19 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
elsiocb->context_un.rrq = rrq;
elsiocb->cmd_cmpl = lpfc_cmpl_els_rrq;
- lpfc_nlp_get(ndlp);
- elsiocb->context1 = ndlp;
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp)
+ goto io_err;
ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0);
- if (ret == IOCB_ERROR)
+ if (ret == IOCB_ERROR) {
+ lpfc_nlp_put(ndlp);
goto io_err;
+ }
return 0;
io_err:
lpfc_els_free_iocb(phba, elsiocb);
- lpfc_nlp_put(ndlp);
return 1;
}
@@ -8811,7 +8770,7 @@ lpfc_send_rrq(struct lpfc_hba *phba, struct lpfc_node_rrq *rrq)
* It is to be called by the lpfc_els_rcv_rpl() routine to accept the RPL.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the RPL Accept Response
* ELS command.
*
@@ -8852,7 +8811,7 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
icmd->unsli3.rcvsli3.ox_id = get_job_rcvoxid(phba, oldiocb);
}
- pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
pcmd += sizeof(uint16_t);
*((uint16_t *)(pcmd)) = be16_to_cpu(cmdsize);
@@ -8876,8 +8835,8 @@ lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
ndlp->nlp_rpi);
elsiocb->cmd_cmpl = lpfc_cmpl_els_rsp;
phba->fc_stat.elsXmitACC++;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
@@ -8932,7 +8891,7 @@ lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
return 0;
}
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ pcmd = cmdiocb->cmd_dmabuf;
lp = (uint32_t *) pcmd->virt;
rpl = (RPL *) (lp + 1);
maxsize = be32_to_cpu(rpl->maxsize);
@@ -8984,7 +8943,7 @@ lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
uint32_t cnt, did;
did = get_job_els_rsp64_did(vport->phba, cmdiocb);
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ pcmd = cmdiocb->cmd_dmabuf;
lp = (uint32_t *) pcmd->virt;
lp++;
@@ -9054,8 +9013,8 @@ lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
uint32_t did;
did = get_job_els_rsp64_did(vport->phba, cmdiocb);
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
- lp = (uint32_t *) pcmd->virt;
+ pcmd = cmdiocb->cmd_dmabuf;
+ lp = (uint32_t *)pcmd->virt;
lp++;
/* FARP-RSP received from DID <did> */
@@ -9095,7 +9054,7 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
FAN *fp;
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0265 FAN received\n");
- lp = (uint32_t *)((struct lpfc_dmabuf *)cmdiocb->context2)->virt;
+ lp = (uint32_t *)cmdiocb->cmd_dmabuf->virt;
fp = (FAN *) ++lp;
/* FAN received; Fan does not have a reply sequence */
if ((vport == phba->pport) &&
@@ -9144,7 +9103,7 @@ lpfc_els_rcv_edc(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
int desc_cnt = 0, bytes_remain;
bool rcv_cap_desc = false;
- payload = ((struct lpfc_dmabuf *)cmdiocb->context2)->virt;
+ payload = cmdiocb->cmd_dmabuf->virt;
edc_req = (struct fc_els_edc *)payload;
bytes_remain = be32_to_cpu(edc_req->desc_len);
@@ -9329,7 +9288,7 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
if (piocb->vport != vport)
continue;
- pcmd = (struct lpfc_dmabuf *) piocb->context2;
+ pcmd = piocb->cmd_dmabuf;
if (pcmd)
els_command = *(uint32_t *) (pcmd->virt);
@@ -9584,7 +9543,7 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba,
uint32_t *pcmd;
u32 ulp_status, ulp_word4;
- ndlp = cmdiocbp->context1;
+ ndlp = cmdiocbp->ndlp;
if (!ndlp)
return;
@@ -9598,8 +9557,7 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba,
sizeof(struct lpfc_name));
memcpy(lsrjt_event.header.wwnn, &ndlp->nlp_nodename,
sizeof(struct lpfc_name));
- pcmd = (uint32_t *) (((struct lpfc_dmabuf *)
- cmdiocbp->context2)->virt);
+ pcmd = (uint32_t *)cmdiocbp->cmd_dmabuf->virt;
lsrjt_event.command = (pcmd != NULL) ? *pcmd : 0;
stat.un.ls_rjt_error_be = cpu_to_be32(ulp_word4);
lsrjt_event.reason_code = stat.un.b.lsRjtRsnCode;
@@ -9940,11 +9898,14 @@ lpfc_els_rcv_fpin_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv)
/* Take action here for an Alarm event */
if (phba->cmf_active_mode != LPFC_CFG_OFF) {
if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_ALARM) {
- /* Track of alarm cnt for cgn_info */
- atomic_inc(&phba->cgn_fabric_alarm_cnt);
/* Track of alarm cnt for SYNC_WQE */
atomic_inc(&phba->cgn_sync_alarm_cnt);
}
+ /* Track alarm cnt for cgn_info regardless
+ * of whether CMF is configured for Signals
+ * or FPINs.
+ */
+ atomic_inc(&phba->cgn_fabric_alarm_cnt);
goto cleanup;
}
break;
@@ -9952,11 +9913,14 @@ lpfc_els_rcv_fpin_cgn(struct lpfc_hba *phba, struct fc_tlv_desc *tlv)
/* Take action here for a Warning event */
if (phba->cmf_active_mode != LPFC_CFG_OFF) {
if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_WARN) {
- /* Track of warning cnt for cgn_info */
- atomic_inc(&phba->cgn_fabric_warn_cnt);
/* Track of warning cnt for SYNC_WQE */
atomic_inc(&phba->cgn_sync_warn_cnt);
}
+ /* Track warning cnt and freq for cgn_info
+ * regardless of whether CMF is configured for
+ * Signals or FPINs.
+ */
+ atomic_inc(&phba->cgn_fabric_warn_cnt);
cleanup:
/* Save frequency in ms */
phba->cgn_fpin_frequency =
@@ -9965,14 +9929,10 @@ cleanup:
if (phba->cgn_i) {
cp = (struct lpfc_cgn_info *)
phba->cgn_i->virt;
- if (phba->cgn_reg_fpin &
- LPFC_CGN_FPIN_ALARM)
- cp->cgn_alarm_freq =
- cpu_to_le16(value);
- if (phba->cgn_reg_fpin &
- LPFC_CGN_FPIN_WARN)
- cp->cgn_warn_freq =
- cpu_to_le16(value);
+ cp->cgn_alarm_freq =
+ cpu_to_le16(value);
+ cp->cgn_warn_freq =
+ cpu_to_le16(value);
crc = lpfc_cgn_calc_crc32
(cp,
LPFC_CGN_INFO_SZ,
@@ -10133,12 +10093,12 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_wcqe_complete *wcqe_cmpl = NULL;
LPFC_MBOXQ_t *mbox;
- if (!vport || !(elsiocb->context2))
+ if (!vport || !elsiocb->cmd_dmabuf)
goto dropit;
newnode = 0;
wcqe_cmpl = &elsiocb->wcqe_cmpl;
- payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt;
+ payload = elsiocb->cmd_dmabuf->virt;
if (phba->sli_rev == LPFC_SLI_REV4)
payload_len = wcqe_cmpl->total_data_placed;
else
@@ -10199,8 +10159,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
spin_unlock_irq(&ndlp->lock);
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1)
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp)
goto dropit;
elsiocb->vport = vport;
@@ -10556,8 +10516,8 @@ lsrjt:
}
/* Release the reference on this elsiocb, not the ndlp. */
- lpfc_nlp_put(elsiocb->context1);
- elsiocb->context1 = NULL;
+ lpfc_nlp_put(elsiocb->ndlp);
+ elsiocb->ndlp = NULL;
/* Special case. Driver received an unsolicited command that
* unsupportable given the driver's current state. Reset the
@@ -10611,13 +10571,13 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
u32 ulp_command, status, parameter, bde_count = 0;
IOCB_t *icmd;
struct lpfc_wcqe_complete *wcqe_cmpl = NULL;
- struct lpfc_dmabuf *bdeBuf1 = elsiocb->context2;
- struct lpfc_dmabuf *bdeBuf2 = elsiocb->context3;
+ struct lpfc_dmabuf *bdeBuf1 = elsiocb->cmd_dmabuf;
+ struct lpfc_dmabuf *bdeBuf2 = elsiocb->bpl_dmabuf;
dma_addr_t paddr;
- elsiocb->context1 = NULL;
- elsiocb->context2 = NULL;
- elsiocb->context3 = NULL;
+ elsiocb->cmd_dmabuf = NULL;
+ elsiocb->rsp_dmabuf = NULL;
+ elsiocb->bpl_dmabuf = NULL;
wcqe_cmpl = &elsiocb->wcqe_cmpl;
ulp_command = get_job_cmnd(phba, elsiocb);
@@ -10661,38 +10621,39 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/* Account for SLI2 or SLI3 and later unsolicited buffering */
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
- elsiocb->context2 = bdeBuf1;
+ elsiocb->cmd_dmabuf = bdeBuf1;
if (bde_count == 2)
- elsiocb->context3 = bdeBuf2;
+ elsiocb->bpl_dmabuf = bdeBuf2;
} else {
icmd = &elsiocb->iocb;
paddr = getPaddr(icmd->un.cont64[0].addrHigh,
icmd->un.cont64[0].addrLow);
- elsiocb->context2 = lpfc_sli_ringpostbuf_get(phba, pring,
- paddr);
+ elsiocb->cmd_dmabuf = lpfc_sli_ringpostbuf_get(phba, pring,
+ paddr);
if (bde_count == 2) {
paddr = getPaddr(icmd->un.cont64[1].addrHigh,
icmd->un.cont64[1].addrLow);
- elsiocb->context3 = lpfc_sli_ringpostbuf_get(phba,
- pring,
- paddr);
+ elsiocb->bpl_dmabuf = lpfc_sli_ringpostbuf_get(phba,
+ pring,
+ paddr);
}
}
lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
/*
* The different unsolicited event handlers would tell us
- * if they are done with "mp" by setting context2 to NULL.
+ * if they are done with "mp" by setting cmd_dmabuf to NULL.
*/
- if (elsiocb->context2) {
- lpfc_in_buf_free(phba, (struct lpfc_dmabuf *)elsiocb->context2);
- elsiocb->context2 = NULL;
+ if (elsiocb->cmd_dmabuf) {
+ lpfc_in_buf_free(phba, elsiocb->cmd_dmabuf);
+ elsiocb->cmd_dmabuf = NULL;
}
- if (elsiocb->context3) {
- lpfc_in_buf_free(phba, elsiocb->context3);
- elsiocb->context3 = NULL;
+ if (elsiocb->bpl_dmabuf) {
+ lpfc_in_buf_free(phba, elsiocb->bpl_dmabuf);
+ elsiocb->bpl_dmabuf = NULL;
}
+
}
static void
@@ -10803,7 +10764,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
+ struct lpfc_nodelist *ndlp = pmb->ctx_ndlp;
MAILBOX_t *mb = &pmb->u.mb;
int rc;
@@ -11068,11 +11029,11 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
{
struct lpfc_vport *vport = cmdiocb->vport;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_nodelist *ndlp = cmdiocb->ndlp;
struct lpfc_nodelist *np;
struct lpfc_nodelist *next_np;
struct lpfc_iocbq *piocb;
- struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
+ struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf, *prsp;
struct serv_parm *sp;
uint8_t fabric_param_changed;
u32 ulp_status, ulp_word4;
@@ -11210,7 +11171,7 @@ out:
* IOCB will be sent off HBA at any given time.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the FDISC ELS command.
*
* Return code
@@ -11255,7 +11216,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
icmd->ulpCt_l = 0;
}
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_FDISC;
pcmd += sizeof(uint32_t); /* CSP Word 1 */
memcpy(pcmd, &vport->phba->pport->fc_sparam, sizeof(struct serv_parm));
@@ -11287,8 +11248,8 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
"Issue FDISC: did:x%x",
did, 0, 0);
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1)
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp)
goto err_out;
rc = lpfc_issue_fabric_iocb(phba, elsiocb);
@@ -11332,7 +11293,7 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
u32 ulp_status, ulp_word4, did, tmo;
- ndlp = (struct lpfc_nodelist *)cmdiocb->context1;
+ ndlp = cmdiocb->ndlp;
ulp_status = get_job_ulpstatus(phba, rspiocb);
ulp_word4 = get_job_word4(phba, rspiocb);
@@ -11390,7 +11351,7 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* This routine issues a LOGO ELS command to an @ndlp off a @vport.
*
* Note that the ndlp reference count will be incremented by 1 for holding the
- * ndlp and the reference to ndlp will be stored into the context1 field of
+ * ndlp and the reference to ndlp will be stored into the ndlp field of
* the IOCB for the completion callback function to the LOGO ELS command.
*
* Return codes
@@ -11412,7 +11373,7 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
if (!elsiocb)
return 1;
- pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt;
*((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
pcmd += sizeof(uint32_t);
@@ -11429,8 +11390,8 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag |= NLP_LOGO_SND;
spin_unlock_irq(&ndlp->lock);
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(phba, elsiocb);
goto err;
}
@@ -11989,12 +11950,12 @@ lpfc_cmpl_els_qfpa(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_dmabuf *prsp = NULL;
struct lpfc_vmid_priority_range *vmid_range = NULL;
u32 *data;
- struct lpfc_dmabuf *dmabuf = cmdiocb->context2;
+ struct lpfc_dmabuf *dmabuf = cmdiocb->cmd_dmabuf;
u32 ulp_status = get_job_ulpstatus(phba, rspiocb);
u32 ulp_word4 = get_job_word4(phba, rspiocb);
u8 *pcmd, max_desc;
u32 len, i;
- struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)cmdiocb->context1;
+ struct lpfc_nodelist *ndlp = cmdiocb->ndlp;
prsp = list_get_first(&dmabuf->list, struct lpfc_dmabuf, list);
if (!prsp)
@@ -12090,15 +12051,15 @@ int lpfc_issue_els_qfpa(struct lpfc_vport *vport)
if (!elsiocb)
return -ENOMEM;
- pcmd = (u8 *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt);
+ pcmd = (u8 *)elsiocb->cmd_dmabuf->virt;
*((u32 *)(pcmd)) = ELS_CMD_QFPA;
pcmd += 4;
elsiocb->cmd_cmpl = lpfc_cmpl_els_qfpa;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(vport->phba, elsiocb);
return -ENXIO;
}
@@ -12145,7 +12106,7 @@ lpfc_vmid_uvem(struct lpfc_vport *vport,
vmid_context->nlp = ndlp;
vmid_context->instantiated = instantiated;
elsiocb->vmid_tag.vmid_context = vmid_context;
- pcmd = (u8 *)(((struct lpfc_dmabuf *)elsiocb->context2)->virt);
+ pcmd = (u8 *)elsiocb->cmd_dmabuf->virt;
if (uuid_is_null((uuid_t *)vport->lpfc_vmid_host_uuid))
memcpy(vport->lpfc_vmid_host_uuid, vmid->host_vmid,
@@ -12180,8 +12141,8 @@ lpfc_vmid_uvem(struct lpfc_vport *vport,
elsiocb->cmd_cmpl = lpfc_cmpl_els_uvem;
- elsiocb->context1 = lpfc_nlp_get(ndlp);
- if (!elsiocb->context1) {
+ elsiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!elsiocb->ndlp) {
lpfc_els_free_iocb(vport->phba, elsiocb);
goto out;
}
@@ -12207,12 +12168,12 @@ lpfc_cmpl_els_uvem(struct lpfc_hba *phba, struct lpfc_iocbq *icmdiocb,
struct lpfc_dmabuf *prsp = NULL;
struct lpfc_vmid_context *vmid_context =
icmdiocb->vmid_tag.vmid_context;
- struct lpfc_nodelist *ndlp = icmdiocb->context1;
+ struct lpfc_nodelist *ndlp = icmdiocb->ndlp;
u8 *pcmd;
u32 *data;
u32 ulp_status = get_job_ulpstatus(phba, rspiocb);
u32 ulp_word4 = get_job_word4(phba, rspiocb);
- struct lpfc_dmabuf *dmabuf = icmdiocb->context2;
+ struct lpfc_dmabuf *dmabuf = icmdiocb->cmd_dmabuf;
struct lpfc_vmid *vmid;
vmid = vmid_context->vmp;
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 0144da30e3db..fb36f26170e4 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -109,8 +109,8 @@ lpfc_rport_invalid(struct fc_rport *rport)
ndlp = rdata->pnode;
if (!rdata->pnode) {
- pr_err("**** %s: NULL ndlp on rport x%px SID x%x\n",
- __func__, rport, rport->scsi_target_id);
+ pr_info("**** %s: NULL ndlp on rport x%px SID x%x\n",
+ __func__, rport, rport->scsi_target_id);
return -EINVAL;
}
@@ -169,9 +169,10 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE,
"3181 dev_loss_callbk x%06x, rport x%px flg x%x "
- "load_flag x%x refcnt %d\n",
+ "load_flag x%x refcnt %d state %d xpt x%x\n",
ndlp->nlp_DID, ndlp->rport, ndlp->nlp_flag,
- vport->load_flag, kref_read(&ndlp->kref));
+ vport->load_flag, kref_read(&ndlp->kref),
+ ndlp->nlp_state, ndlp->fc4_xpt_flags);
/* Don't schedule a worker thread event if the vport is going down.
* The teardown process cleans up the node via lpfc_drop_node.
@@ -181,6 +182,11 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
ndlp->rport = NULL;
ndlp->fc4_xpt_flags &= ~SCSI_XPT_REGD;
+ /* clear the NLP_XPT_REGD if the node is not registered
+ * with nvme-fc
+ */
+ if (ndlp->fc4_xpt_flags == NLP_XPT_REGD)
+ ndlp->fc4_xpt_flags &= ~NLP_XPT_REGD;
/* Remove the node reference from remote_port_add now.
* The driver will not call remote_port_delete.
@@ -225,18 +231,36 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
ndlp->rport = NULL;
spin_unlock_irqrestore(&ndlp->lock, iflags);
- /* We need to hold the node by incrementing the reference
- * count until this queued work is done
- */
- evtp->evt_arg1 = lpfc_nlp_get(ndlp);
+ if (phba->worker_thread) {
+ /* We need to hold the node by incrementing the reference
+ * count until this queued work is done
+ */
+ evtp->evt_arg1 = lpfc_nlp_get(ndlp);
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ if (evtp->evt_arg1) {
+ evtp->evt = LPFC_EVT_DEV_LOSS;
+ list_add_tail(&evtp->evt_listp, &phba->work_list);
+ lpfc_worker_wake_up(phba);
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ } else {
+ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE,
+ "3188 worker thread is stopped %s x%06x, "
+ " rport x%px flg x%x load_flag x%x refcnt "
+ "%d\n", __func__, ndlp->nlp_DID,
+ ndlp->rport, ndlp->nlp_flag,
+ vport->load_flag, kref_read(&ndlp->kref));
+ if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD)) {
+ spin_lock_irqsave(&ndlp->lock, iflags);
+ /* Node is in dev loss. No further transaction. */
+ ndlp->nlp_flag &= ~NLP_IN_DEV_LOSS;
+ spin_unlock_irqrestore(&ndlp->lock, iflags);
+ lpfc_disc_state_machine(vport, ndlp, NULL,
+ NLP_EVT_DEVICE_RM);
+ }
- spin_lock_irqsave(&phba->hbalock, iflags);
- if (evtp->evt_arg1) {
- evtp->evt = LPFC_EVT_DEV_LOSS;
- list_add_tail(&evtp->evt_listp, &phba->work_list);
- lpfc_worker_wake_up(phba);
}
- spin_unlock_irqrestore(&phba->hbalock, iflags);
return;
}
@@ -503,11 +527,12 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
"0203 Devloss timeout on "
"WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x "
- "NPort x%06x Data: x%x x%x x%x\n",
+ "NPort x%06x Data: x%x x%x x%x refcnt %d\n",
*name, *(name+1), *(name+2), *(name+3),
*(name+4), *(name+5), *(name+6), *(name+7),
ndlp->nlp_DID, ndlp->nlp_flag,
- ndlp->nlp_state, ndlp->nlp_rpi);
+ ndlp->nlp_state, ndlp->nlp_rpi,
+ kref_read(&ndlp->kref));
} else {
lpfc_printf_vlog(vport, KERN_INFO, LOG_TRACE_EVENT,
"0204 Devloss timeout on "
@@ -755,18 +780,22 @@ lpfc_work_list_done(struct lpfc_hba *phba)
int free_evt;
int fcf_inuse;
uint32_t nlp_did;
+ bool hba_pci_err;
spin_lock_irq(&phba->hbalock);
while (!list_empty(&phba->work_list)) {
list_remove_head((&phba->work_list), evtp, typeof(*evtp),
evt_listp);
spin_unlock_irq(&phba->hbalock);
+ hba_pci_err = test_bit(HBA_PCI_ERR, &phba->bit_flags);
free_evt = 1;
switch (evtp->evt) {
case LPFC_EVT_ELS_RETRY:
ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
- lpfc_els_retry_delay_handler(ndlp);
- free_evt = 0; /* evt is part of ndlp */
+ if (!hba_pci_err) {
+ lpfc_els_retry_delay_handler(ndlp);
+ free_evt = 0; /* evt is part of ndlp */
+ }
/* decrement the node reference count held
* for this queued work
*/
@@ -788,8 +817,10 @@ lpfc_work_list_done(struct lpfc_hba *phba)
break;
case LPFC_EVT_RECOVER_PORT:
ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
- lpfc_sli_abts_recover_port(ndlp->vport, ndlp);
- free_evt = 0;
+ if (!hba_pci_err) {
+ lpfc_sli_abts_recover_port(ndlp->vport, ndlp);
+ free_evt = 0;
+ }
/* decrement the node reference count held for
* this queued work
*/
@@ -859,14 +890,18 @@ lpfc_work_done(struct lpfc_hba *phba)
struct lpfc_vport **vports;
struct lpfc_vport *vport;
int i;
+ bool hba_pci_err;
+ hba_pci_err = test_bit(HBA_PCI_ERR, &phba->bit_flags);
spin_lock_irq(&phba->hbalock);
ha_copy = phba->work_ha;
phba->work_ha = 0;
spin_unlock_irq(&phba->hbalock);
+ if (hba_pci_err)
+ ha_copy = 0;
/* First, try to post the next mailbox command to SLI4 device */
- if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
+ if (phba->pci_dev_grp == LPFC_PCI_DEV_OC && !hba_pci_err)
lpfc_sli4_post_async_mbox(phba);
if (ha_copy & HA_ERATT) {
@@ -886,7 +921,7 @@ lpfc_work_done(struct lpfc_hba *phba)
lpfc_handle_latt(phba);
/* Handle VMID Events */
- if (lpfc_is_vmid_enabled(phba)) {
+ if (lpfc_is_vmid_enabled(phba) && !hba_pci_err) {
if (phba->pport->work_port_events &
WORKER_CHECK_VMID_ISSUE_QFPA) {
lpfc_check_vmid_qfpa_issue(phba);
@@ -936,6 +971,8 @@ lpfc_work_done(struct lpfc_hba *phba)
work_port_events = vport->work_port_events;
vport->work_port_events &= ~work_port_events;
spin_unlock_irq(&vport->work_port_lock);
+ if (hba_pci_err)
+ continue;
if (work_port_events & WORKER_DISC_TMO)
lpfc_disc_timeout_handler(vport);
if (work_port_events & WORKER_ELS_TMO)
@@ -1146,6 +1183,7 @@ lpfc_port_link_failure(struct lpfc_vport *vport)
void
lpfc_linkdown_port(struct lpfc_vport *vport)
{
+ struct lpfc_hba *phba = vport->phba;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
if (vport->cfg_enable_fc4_type != LPFC_ENABLE_NVME)
@@ -1163,6 +1201,13 @@ lpfc_linkdown_port(struct lpfc_vport *vport)
vport->fc_flag &= ~FC_DISC_DELAYED;
spin_unlock_irq(shost->host_lock);
del_timer_sync(&vport->delayed_disc_tmo);
+
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ vport->port_type == LPFC_PHYSICAL_PORT &&
+ phba->sli4_hba.fawwpn_flag & LPFC_FAWWPN_CONFIG) {
+ /* Assume success on link up */
+ phba->sli4_hba.fawwpn_flag |= LPFC_FAWWPN_FABRIC;
+ }
}
int
@@ -1173,15 +1218,20 @@ lpfc_linkdown(struct lpfc_hba *phba)
struct lpfc_vport **vports;
LPFC_MBOXQ_t *mb;
int i;
+ int offline;
if (phba->link_state == LPFC_LINK_DOWN)
return 0;
/* Block all SCSI stack I/Os */
lpfc_scsi_dev_block(phba);
+ offline = pci_channel_offline(phba->pcidev);
phba->defer_flogi_acc_flag = false;
+ /* Clear external loopback plug detected flag */
+ phba->link_flag &= ~LS_EXTERNAL_LOOPBACK;
+
spin_lock_irq(&phba->hbalock);
phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE);
spin_unlock_irq(&phba->hbalock);
@@ -1219,7 +1269,7 @@ lpfc_linkdown(struct lpfc_hba *phba)
lpfc_destroy_vport_work_array(phba, vports);
/* Clean up any SLI3 firmware default rpi's */
- if (phba->sli_rev > LPFC_SLI_REV3)
+ if (phba->sli_rev > LPFC_SLI_REV3 || offline)
goto skip_unreg_did;
mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -1304,10 +1354,12 @@ lpfc_linkup_port(struct lpfc_vport *vport)
spin_lock_irq(shost->host_lock);
vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY |
- FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY);
+ FC_RSCN_MEMENTO | FC_RSCN_MODE |
+ FC_NLP_MORE | FC_RSCN_DISCOVERY);
vport->fc_flag |= FC_NDISC_ACTIVE;
vport->fc_ns_retry = 0;
spin_unlock_irq(shost->host_lock);
+ lpfc_setup_fdmi_mask(vport);
lpfc_linkup_cleanup_nodes(vport);
}
@@ -1339,8 +1391,8 @@ lpfc_linkup(struct lpfc_hba *phba)
phba->pport->rcv_flogi_cnt = 0;
spin_unlock_irq(shost->host_lock);
- /* reinitialize initial FLOGI flag */
- phba->hba_flag &= ~(HBA_FLOGI_ISSUED);
+ /* reinitialize initial HBA flag */
+ phba->hba_flag &= ~(HBA_FLOGI_ISSUED | HBA_RHBA_CMPL);
phba->defer_flogi_acc_flag = false;
return 0;
@@ -1419,7 +1471,6 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
LPFC_MBOXQ_t *sparam_mb;
- struct lpfc_dmabuf *sparam_mp;
u16 status = pmb->u.mb.mbxStatus;
int rc;
@@ -1468,13 +1519,8 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
sparam_mb->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
rc = lpfc_sli_issue_mbox(phba, sparam_mb, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
- sparam_mp = (struct lpfc_dmabuf *)
- sparam_mb->ctx_buf;
- lpfc_mbuf_free(phba, sparam_mp->virt,
- sparam_mp->phys);
- kfree(sparam_mp);
- sparam_mb->ctx_buf = NULL;
- mempool_free(sparam_mb, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, sparam_mb,
+ MBOX_THD_UNLOCKED);
goto sparam_out;
}
@@ -3273,7 +3319,6 @@ lpfc_start_fdiscs(struct lpfc_hba *phba)
void
lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
{
- struct lpfc_dmabuf *dmabuf = mboxq->ctx_buf;
struct lpfc_vport *vport = mboxq->vport;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
@@ -3354,12 +3399,7 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
}
out_free_mem:
- mempool_free(mboxq, phba->mbox_mem_pool);
- if (dmabuf) {
- lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys);
- kfree(dmabuf);
- }
- return;
+ lpfc_mbox_rsrc_cleanup(phba, mboxq, MBOX_THD_UNLOCKED);
}
static void
@@ -3404,9 +3444,7 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
memcpy(&phba->wwpn, &vport->fc_portname, sizeof(phba->wwnn));
}
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
/* Check if sending the FLOGI is being deferred to after we get
* up to date CSPs from MBX_READ_SPARAM.
@@ -3418,12 +3456,8 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
return;
out:
- pmb->ctx_buf = NULL;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
lpfc_issue_clear_la(phba, vport);
- mempool_free(pmb, phba->mbox_mem_pool);
- return;
}
static void
@@ -3433,7 +3467,6 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox = NULL;
struct Scsi_Host *shost;
int i;
- struct lpfc_dmabuf *mp;
int rc;
struct fcf_record *fcf_record;
uint32_t fc_flags = 0;
@@ -3561,10 +3594,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la)
sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
rc = lpfc_sli_issue_mbox(phba, sparam_mbox, MBX_NOWAIT);
if (rc == MBX_NOT_FINISHED) {
- mp = (struct lpfc_dmabuf *)sparam_mbox->ctx_buf;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(sparam_mbox, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, sparam_mbox, MBOX_THD_UNLOCKED);
goto out;
}
@@ -3840,10 +3870,7 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
}
lpfc_mbx_cmpl_read_topology_free_mbuf:
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
- return;
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
}
/*
@@ -3856,9 +3883,13 @@ void
lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
- struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
+ struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
+ /* The driver calls the state machine with the pmb pointer
+ * but wants to make sure a stale ctx_buf isn't acted on.
+ * The ctx_buf is restored later and cleaned up.
+ */
pmb->ctx_buf = NULL;
pmb->ctx_ndlp = NULL;
@@ -3895,10 +3926,9 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Call state machine */
lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
+ pmb->ctx_buf = mp;
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
/* decrement the node reference count held for this callback
* function.
*/
@@ -4065,11 +4095,15 @@ lpfc_create_static_vport(struct lpfc_hba *phba)
vport_buff = (uint8_t *) vport_info;
do {
- /* free dma buffer from previous round */
+ /* While loop iteration forces a free dma buffer from
+ * the previous loop because the mbox is reused and
+ * the dump routine is a single-use construct.
+ */
if (pmb->ctx_buf) {
mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
+ pmb->ctx_buf = NULL;
}
if (lpfc_dump_static_vport(phba, pmb, offset))
goto out;
@@ -4154,16 +4188,8 @@ lpfc_create_static_vport(struct lpfc_hba *phba)
out:
kfree(vport_info);
- if (mbx_wait_rc != MBX_TIMEOUT) {
- if (pmb->ctx_buf) {
- mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- }
- mempool_free(pmb, phba->mbox_mem_pool);
- }
-
- return;
+ if (mbx_wait_rc != MBX_TIMEOUT)
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
}
/*
@@ -4177,22 +4203,16 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
MAILBOX_t *mb = &pmb->u.mb;
- struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
- struct lpfc_nodelist *ndlp;
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
struct Scsi_Host *shost;
- ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
pmb->ctx_ndlp = NULL;
- pmb->ctx_buf = NULL;
if (mb->mbxStatus) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
"0258 Register Fabric login error: 0x%x\n",
mb->mbxStatus);
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
-
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
/* FLOGI failed, use loop map to make discovery list */
lpfc_disc_list_loopmap(vport);
@@ -4234,9 +4254,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
lpfc_do_scr_ns_plogi(phba, vport);
}
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
/* Drop the reference count from the mbox at the end after
* all the current reference to the ndlp have been done.
@@ -4330,12 +4348,10 @@ void
lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
MAILBOX_t *mb = &pmb->u.mb;
- struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
struct lpfc_vport *vport = pmb->vport;
int rc;
- pmb->ctx_buf = NULL;
pmb->ctx_ndlp = NULL;
vport->gidft_inp = 0;
@@ -4349,9 +4365,7 @@ out:
* callback function.
*/
lpfc_nlp_put(ndlp);
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
/* If the node is not registered with the scsi or nvme
* transport, remove the fabric node. The failed reg_login
@@ -4440,10 +4454,7 @@ out:
* callback function.
*/
lpfc_nlp_put(ndlp);
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
-
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
return;
}
@@ -4457,13 +4468,9 @@ lpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
MAILBOX_t *mb = &pmb->u.mb;
- struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
- struct lpfc_nodelist *ndlp;
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
- ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
pmb->ctx_ndlp = NULL;
- pmb->ctx_buf = NULL;
-
if (mb->mbxStatus) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
"0933 %s: Register FC login error: 0x%x\n",
@@ -4487,9 +4494,7 @@ lpfc_mbx_cmpl_fc_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
out:
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
/* Drop the reference count from the mbox at the end after
* all the current reference to the ndlp have been done.
@@ -4712,6 +4717,11 @@ lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
spin_lock_irqsave(&ndlp->lock, iflags);
if (!(ndlp->fc4_xpt_flags & NLP_XPT_REGD)) {
spin_unlock_irqrestore(&ndlp->lock, iflags);
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
+ "0999 %s Not regd: ndlp x%px rport x%px DID "
+ "x%x FLG x%x XPT x%x\n",
+ __func__, ndlp, ndlp->rport, ndlp->nlp_DID,
+ ndlp->nlp_flag, ndlp->fc4_xpt_flags);
return;
}
@@ -4722,6 +4732,13 @@ lpfc_nlp_unreg_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
ndlp->fc4_xpt_flags & SCSI_XPT_REGD) {
vport->phba->nport_event_cnt++;
lpfc_unregister_remote_port(ndlp);
+ } else if (!ndlp->rport) {
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
+ "1999 %s NDLP in devloss x%px DID x%x FLG x%x"
+ " XPT x%x refcnt %d\n",
+ __func__, ndlp, ndlp->nlp_DID, ndlp->nlp_flag,
+ ndlp->fc4_xpt_flags,
+ kref_read(&ndlp->kref));
}
if (ndlp->fc4_xpt_flags & NVME_XPT_REGD) {
@@ -5104,7 +5121,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba,
if (pring->ringno == LPFC_ELS_RING) {
switch (ulp_command) {
case CMD_GEN_REQUEST64_CR:
- if (iocb->context_un.ndlp == ndlp)
+ if (iocb->ndlp == ndlp)
return 1;
fallthrough;
case CMD_ELS_REQUEST64_CR:
@@ -5112,7 +5129,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba,
return 1;
fallthrough;
case CMD_XMIT_ELS_RSP64_CX:
- if (iocb->context1 == (uint8_t *) ndlp)
+ if (iocb->ndlp == ndlp)
return 1;
}
} else if (pring->ringno == LPFC_FCP_RING) {
@@ -5222,7 +5239,6 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
if (!ndlp)
return;
lpfc_issue_els_logo(vport, ndlp, 0);
- mempool_free(pmb, phba->mbox_mem_pool);
/* Check to see if there are any deferred events to process */
if ((ndlp->nlp_flag & NLP_UNREG_INP) &&
@@ -5249,6 +5265,13 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
ndlp->nlp_flag &= ~NLP_UNREG_INP;
spin_unlock_irq(&ndlp->lock);
}
+
+ /* The node has an outstanding reference for the unreg. Now
+ * that the LOGO action and cleanup are finished, release
+ * resources.
+ */
+ lpfc_nlp_put(ndlp);
+ mempool_free(pmb, phba->mbox_mem_pool);
}
/*
@@ -5371,6 +5394,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
ndlp->nlp_flag &= ~NLP_UNREG_INP;
mempool_free(mbox, phba->mbox_mem_pool);
acc_plogi = 1;
+ lpfc_nlp_put(ndlp);
}
} else {
lpfc_printf_vlog(vport, KERN_INFO,
@@ -5517,7 +5541,6 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *mb, *nextmb;
- struct lpfc_dmabuf *mp;
/* Cleanup node for NPort <nlp_DID> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
@@ -5555,16 +5578,11 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
!(mb->mbox_flag & LPFC_MBX_IMED_UNREG) &&
(ndlp == (struct lpfc_nodelist *)mb->ctx_ndlp)) {
- mp = (struct lpfc_dmabuf *)(mb->ctx_buf);
- if (mp) {
- __lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- }
list_del(&mb->list);
- mempool_free(mb, phba->mbox_mem_pool);
- /* We shall not invoke the lpfc_nlp_put to decrement
- * the ndlp reference count as we are in the process
- * of lpfc_nlp_release.
+ lpfc_mbox_rsrc_cleanup(phba, mb, MBOX_THD_LOCKED);
+
+ /* Don't invoke lpfc_nlp_put. The driver is in
+ * lpfc_nlp_release context.
*/
}
}
@@ -6046,7 +6064,7 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
*/
spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
- if (iocb->context1 != ndlp)
+ if (iocb->ndlp != ndlp)
continue;
ulp_command = get_job_cmnd(phba, iocb);
@@ -6060,7 +6078,7 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
/* Next check the txcmplq */
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
- if (iocb->context1 != ndlp)
+ if (iocb->ndlp != ndlp)
continue;
ulp_command = get_job_cmnd(phba, iocb);
@@ -6097,12 +6115,34 @@ lpfc_disc_flush_list(struct lpfc_vport *vport)
}
}
+/*
+ * lpfc_notify_xport_npr - notifies xport of node disappearance
+ * @vport: Pointer to Virtual Port object.
+ *
+ * Transitions all ndlps to NPR state. When lpfc_nlp_set_state
+ * calls lpfc_nlp_state_cleanup, the ndlp->rport is unregistered
+ * and transport notified that the node is gone.
+ * Return Code:
+ * none
+ */
+static void
+lpfc_notify_xport_npr(struct lpfc_vport *vport)
+{
+ struct lpfc_nodelist *ndlp, *next_ndlp;
+
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
+ nlp_listp) {
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ }
+}
void
lpfc_cleanup_discovery_resources(struct lpfc_vport *vport)
{
lpfc_els_flush_rscn(vport);
lpfc_els_flush_cmd(vport);
lpfc_disc_flush_list(vport);
+ if (pci_channel_offline(vport->phba->pcidev))
+ lpfc_notify_xport_npr(vport);
}
/*****************************************************************************/
@@ -6316,8 +6356,9 @@ restart_disc:
lpfc_printf_vlog(vport, KERN_ERR,
LOG_TRACE_EVENT,
"0231 RSCN timeout Data: x%x "
- "x%x\n",
- vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
+ "x%x x%x x%x\n",
+ vport->fc_ns_retry, LPFC_MAX_NS_RETRY,
+ vport->port_state, vport->gidft_inp);
/* Cleanup any outstanding ELS commands */
lpfc_els_flush_cmd(vport);
@@ -6387,11 +6428,9 @@ void
lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
MAILBOX_t *mb = &pmb->u.mb;
- struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
struct lpfc_vport *vport = pmb->vport;
- pmb->ctx_buf = NULL;
pmb->ctx_ndlp = NULL;
if (phba->sli_rev < LPFC_SLI_REV4)
@@ -6422,10 +6461,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
* function.
*/
lpfc_nlp_put(ndlp);
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
-
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index d6050f3c9efe..748c53219986 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -97,6 +97,18 @@ union CtCommandResponse {
#define FC4_FEATURE_INIT 0x2
#define FC4_FEATURE_NVME_DISC 0x4
+enum rft_word0 {
+ RFT_FCP_REG = (0x1 << 8),
+};
+
+enum rft_word1 {
+ RFT_NVME_REG = (0x1 << 8),
+};
+
+enum rft_word3 {
+ RFT_APP_SERV_REG = (0x1 << 0),
+};
+
struct lpfc_sli_ct_request {
/* Structure is in Big Endian format */
union CtRevisionId RevisionId;
@@ -131,25 +143,13 @@ struct lpfc_sli_ct_request {
uint8_t Fc4Type;
} gid_ff;
struct rft {
- uint32_t PortId; /* For RFT_ID requests */
+ __be32 port_id; /* For RFT_ID requests */
-#ifdef __BIG_ENDIAN_BITFIELD
- uint32_t rsvd0:16;
- uint32_t rsvd1:7;
- uint32_t fcpReg:1; /* Type 8 */
- uint32_t rsvd2:2;
- uint32_t ipReg:1; /* Type 5 */
- uint32_t rsvd3:5;
-#else /* __LITTLE_ENDIAN_BITFIELD */
- uint32_t rsvd0:16;
- uint32_t fcpReg:1; /* Type 8 */
- uint32_t rsvd1:7;
- uint32_t rsvd3:5;
- uint32_t ipReg:1; /* Type 5 */
- uint32_t rsvd2:2;
-#endif
-
- uint32_t rsvd[7];
+ __be32 fcp_reg; /* rsvd 31:9, fcp_reg 8, rsvd 7:0 */
+ __be32 nvme_reg; /* rsvd 31:9, nvme_reg 8, rsvd 7:0 */
+ __be32 word2;
+ __be32 app_serv_reg; /* rsvd 31:1, app_serv_reg 0 */
+ __be32 word[4];
} rft;
struct rnn {
uint32_t PortId; /* For RNN_ID requests */
@@ -511,8 +511,6 @@ struct class_parms {
uint8_t word3Reserved2; /* Fc Word 3, bit 0: 7 */
};
-#define FAPWWN_KEY_VENDOR 0x42524344 /*valid vendor version fawwpn key*/
-
struct serv_parm { /* Structure is in Big Endian format */
struct csp cmn;
struct lpfc_name portName;
@@ -2650,19 +2648,26 @@ typedef struct {
} READ_SPARM_VAR;
/* Structure for MB Command READ_STATUS (14) */
+enum read_status_word1 {
+ RD_ST_CC = 0x01,
+ RD_ST_XKB = 0x80,
+};
+
+enum read_status_word17 {
+ RD_ST_XMIT_XKB_MASK = 0x3fffff,
+};
+
+enum read_status_word18 {
+ RD_ST_RCV_XKB_MASK = 0x3fffff,
+};
typedef struct {
-#ifdef __BIG_ENDIAN_BITFIELD
- uint32_t rsvd1:31;
- uint32_t clrCounters:1;
- uint16_t activeXriCnt;
- uint16_t activeRpiCnt;
-#else /* __LITTLE_ENDIAN_BITFIELD */
- uint32_t clrCounters:1;
- uint32_t rsvd1:31;
- uint16_t activeRpiCnt;
- uint16_t activeXriCnt;
-#endif
+ u8 clear_counters; /* rsvd 7:1, cc 0 */
+ u8 rsvd5;
+ u8 rsvd6;
+ u8 xkb; /* xkb 7, rsvd 6:0 */
+
+ u32 rsvd8;
uint32_t xmitByteCnt;
uint32_t rcvByteCnt;
@@ -2674,6 +2679,14 @@ typedef struct {
uint32_t totalRespExchanges;
uint32_t rcvPbsyCnt;
uint32_t rcvFbsyCnt;
+
+ u32 drop_frame_no_rq;
+ u32 empty_rq;
+ u32 drop_frame_no_xri;
+ u32 empty_xri;
+
+ u32 xmit_xkb; /* rsvd 31:22, xmit_xkb 21:0 */
+ u32 rcv_xkb; /* rsvd 31:22, rcv_xkb 21:0 */
} READ_STATUS_VAR;
/* Structure for MB Command READ_RPI (15) */
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 02e230ed6280..8511369d2cf8 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -2893,6 +2893,9 @@ struct lpfc_mbx_read_config {
#define lpfc_mbx_rd_conf_extnts_inuse_SHIFT 31
#define lpfc_mbx_rd_conf_extnts_inuse_MASK 0x00000001
#define lpfc_mbx_rd_conf_extnts_inuse_WORD word1
+#define lpfc_mbx_rd_conf_fawwpn_SHIFT 30
+#define lpfc_mbx_rd_conf_fawwpn_MASK 0x00000001
+#define lpfc_mbx_rd_conf_fawwpn_WORD word1
#define lpfc_mbx_rd_conf_wcs_SHIFT 28 /* warning signaling */
#define lpfc_mbx_rd_conf_wcs_MASK 0x00000001
#define lpfc_mbx_rd_conf_wcs_WORD word1
@@ -4473,12 +4476,8 @@ struct wqe_common {
#define wqe_cmd_type_MASK 0x0000000f
#define wqe_cmd_type_WORD word11
#define wqe_els_id_SHIFT 4
-#define wqe_els_id_MASK 0x00000003
+#define wqe_els_id_MASK 0x00000007
#define wqe_els_id_WORD word11
-#define LPFC_ELS_ID_FLOGI 3
-#define LPFC_ELS_ID_FDISC 2
-#define LPFC_ELS_ID_LOGO 1
-#define LPFC_ELS_ID_DEFAULT 0
#define wqe_irsp_SHIFT 4
#define wqe_irsp_MASK 0x00000001
#define wqe_irsp_WORD word11
@@ -4525,6 +4524,14 @@ struct lpfc_wqe_generic{
uint32_t payload[4];
};
+enum els_request64_wqe_word11 {
+ LPFC_ELS_ID_DEFAULT,
+ LPFC_ELS_ID_LOGO,
+ LPFC_ELS_ID_FDISC,
+ LPFC_ELS_ID_FLOGI,
+ LPFC_ELS_ID_PLOGI,
+};
+
struct els_request64_wqe {
struct ulp_bde64 bde;
uint32_t payload_len;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index eed6464bd880..2bffaa681fcc 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -95,6 +95,7 @@ static void lpfc_sli4_oas_verify(struct lpfc_hba *phba);
static uint16_t lpfc_find_cpu_handle(struct lpfc_hba *, uint16_t, int);
static void lpfc_setup_bg(struct lpfc_hba *, struct Scsi_Host *);
static int lpfc_sli4_cgn_parm_chg_evt(struct lpfc_hba *);
+static void lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba);
static struct scsi_transport_template *lpfc_transport_template = NULL;
static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
@@ -349,8 +350,7 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
void
lpfc_update_vport_wwn(struct lpfc_vport *vport)
{
- uint8_t vvvl = vport->fc_sparam.cmn.valid_vendor_ver_level;
- u32 *fawwpn_key = (u32 *)&vport->fc_sparam.un.vendorVersion[0];
+ struct lpfc_hba *phba = vport->phba;
/*
* If the name is empty or there exists a soft name
@@ -369,21 +369,32 @@ lpfc_update_vport_wwn(struct lpfc_vport *vport)
*/
if (vport->fc_portname.u.wwn[0] != 0 &&
memcmp(&vport->fc_portname, &vport->fc_sparam.portName,
- sizeof(struct lpfc_name)))
+ sizeof(struct lpfc_name))) {
vport->vport_flag |= FAWWPN_PARAM_CHG;
- if (vport->fc_portname.u.wwn[0] == 0 ||
- (vvvl == 1 && cpu_to_be32(*fawwpn_key) == FAPWWN_KEY_VENDOR) ||
- vport->vport_flag & FAWWPN_SET) {
- memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
- sizeof(struct lpfc_name));
- vport->vport_flag &= ~FAWWPN_SET;
- if (vvvl == 1 && cpu_to_be32(*fawwpn_key) == FAPWWN_KEY_VENDOR)
- vport->vport_flag |= FAWWPN_SET;
+ if (phba->sli_rev == LPFC_SLI_REV4 &&
+ vport->port_type == LPFC_PHYSICAL_PORT &&
+ phba->sli4_hba.fawwpn_flag & LPFC_FAWWPN_FABRIC) {
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_SLI | LOG_DISCOVERY | LOG_ELS,
+ "2701 FA-PWWN change WWPN from %llx to "
+ "%llx: vflag x%x fawwpn_flag x%x\n",
+ wwn_to_u64(vport->fc_portname.u.wwn),
+ wwn_to_u64
+ (vport->fc_sparam.portName.u.wwn),
+ vport->vport_flag,
+ phba->sli4_hba.fawwpn_flag);
+ memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
+ }
}
+
+ if (vport->fc_portname.u.wwn[0] == 0)
+ memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
+ sizeof(struct lpfc_name));
else
memcpy(&vport->fc_sparam.portName, &vport->fc_portname,
- sizeof(struct lpfc_name));
+ sizeof(struct lpfc_name));
}
/**
@@ -442,15 +453,16 @@ lpfc_config_port_post(struct lpfc_hba *phba)
"READ_SPARM mbxStatus x%x\n",
mb->mbxCommand, mb->mbxStatus);
phba->link_state = LPFC_HBA_ERROR;
- mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
- mempool_free(pmb, phba->mbox_mem_pool);
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
return -EIO;
}
mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
+ /* This dmabuf was allocated by lpfc_read_sparam. The dmabuf is no
+ * longer needed. Prevent unintended ctx_buf access as the mbox is
+ * reused.
+ */
memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm));
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
@@ -685,8 +697,14 @@ lpfc_sli4_refresh_params(struct lpfc_hba *phba)
return rc;
}
mbx_sli4_parameters = &mqe->un.get_sli4_parameters.sli4_parameters;
- phba->sli4_hba.pc_sli4_params.mi_ver =
+
+ /* Are we forcing MI off via module parameter? */
+ if (phba->cfg_enable_mi)
+ phba->sli4_hba.pc_sli4_params.mi_ver =
bf_get(cfg_mi_ver, mbx_sli4_parameters);
+ else
+ phba->sli4_hba.pc_sli4_params.mi_ver = 0;
+
phba->sli4_hba.pc_sli4_params.cmf =
bf_get(cfg_cmf, mbx_sli4_parameters);
phba->sli4_hba.pc_sli4_params.pls =
@@ -1642,7 +1660,7 @@ lpfc_sli4_offline_eratt(struct lpfc_hba *phba)
{
spin_lock_irq(&phba->hbalock);
if (phba->link_state == LPFC_HBA_ERROR &&
- phba->hba_flag & HBA_PCI_ERR) {
+ test_bit(HBA_PCI_ERR, &phba->bit_flags)) {
spin_unlock_irq(&phba->hbalock);
return;
}
@@ -1985,6 +2003,7 @@ lpfc_handle_eratt_s4(struct lpfc_hba *phba)
if (pci_channel_offline(phba->pcidev)) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
"3166 pci channel is offline\n");
+ lpfc_sli_flush_io_rings(phba);
return;
}
@@ -2174,7 +2193,6 @@ lpfc_handle_latt(struct lpfc_hba *phba)
struct lpfc_sli *psli = &phba->sli;
LPFC_MBOXQ_t *pmb;
volatile uint32_t control;
- struct lpfc_dmabuf *mp;
int rc = 0;
pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -2183,23 +2201,17 @@ lpfc_handle_latt(struct lpfc_hba *phba)
goto lpfc_handle_latt_err_exit;
}
- mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
- if (!mp) {
+ rc = lpfc_mbox_rsrc_prep(phba, pmb);
+ if (rc) {
rc = 2;
- goto lpfc_handle_latt_free_pmb;
- }
-
- mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
- if (!mp->virt) {
- rc = 3;
- goto lpfc_handle_latt_free_mp;
+ mempool_free(pmb, phba->mbox_mem_pool);
+ goto lpfc_handle_latt_err_exit;
}
/* Cleanup any outstanding ELS commands */
lpfc_els_flush_all_cmd(phba);
-
psli->slistat.link_event++;
- lpfc_read_topology(phba, pmb, mp);
+ lpfc_read_topology(phba, pmb, (struct lpfc_dmabuf *)pmb->ctx_buf);
pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology;
pmb->vport = vport;
/* Block ELS IOCBs until we have processed this mbox command */
@@ -2220,11 +2232,7 @@ lpfc_handle_latt(struct lpfc_hba *phba)
lpfc_handle_latt_free_mbuf:
phba->sli.sli3_ring[LPFC_ELS_RING].flag &= ~LPFC_STOP_IOCB_EVENT;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
-lpfc_handle_latt_free_mp:
- kfree(mp);
-lpfc_handle_latt_free_pmb:
- mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
lpfc_handle_latt_err_exit:
/* Enable Link attention interrupts */
spin_lock_irq(&phba->hbalock);
@@ -2973,6 +2981,22 @@ lpfc_cleanup(struct lpfc_vport *vport)
NLP_EVT_DEVICE_RM);
}
+ /* This is a special case flush to return all
+ * IOs before entering this loop. There are
+ * two points in the code where a flush is
+ * avoided if the FC_UNLOADING flag is set.
+ * one is in the multipool destroy,
+ * (this prevents a crash) and the other is
+ * in the nvme abort handler, ( also prevents
+ * a crash). Both of these exceptions are
+ * cases where the slot is still accessible.
+ * The flush here is only when the pci slot
+ * is offline.
+ */
+ if (vport->load_flag & FC_UNLOADING &&
+ pci_channel_offline(phba->pcidev))
+ lpfc_sli_flush_io_rings(vport->phba);
+
/* At this point, ALL ndlp's should be gone
* because of the previous NLP_EVT_DEVICE_RM.
* Lets wait for this to happen, if needed.
@@ -2985,7 +3009,7 @@ lpfc_cleanup(struct lpfc_vport *vport)
list_for_each_entry_safe(ndlp, next_ndlp,
&vport->fc_nodes, nlp_listp) {
lpfc_printf_vlog(ndlp->vport, KERN_ERR,
- LOG_TRACE_EVENT,
+ LOG_DISCOVERY,
"0282 did:x%x ndlp:x%px "
"refcnt:%d xflags x%x nflag x%x\n",
ndlp->nlp_DID, (void *)ndlp,
@@ -3682,7 +3706,8 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action)
struct lpfc_vport **vports;
struct Scsi_Host *shost;
int i;
- int offline = 0;
+ int offline;
+ bool hba_pci_err;
if (vport->fc_flag & FC_OFFLINE_MODE)
return;
@@ -3692,6 +3717,7 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action)
lpfc_linkdown(phba);
offline = pci_channel_offline(phba->pcidev);
+ hba_pci_err = test_bit(HBA_PCI_ERR, &phba->bit_flags);
/* Issue an unreg_login to all nodes on all vports */
vports = lpfc_create_vport_work_array(phba);
@@ -3715,11 +3741,14 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action)
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
spin_unlock_irq(&ndlp->lock);
- if (offline) {
+ if (offline || hba_pci_err) {
spin_lock_irq(&ndlp->lock);
ndlp->nlp_flag &= ~(NLP_UNREG_INP |
NLP_RPI_REGISTERED);
spin_unlock_irq(&ndlp->lock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli_rpi_release(vports[i],
+ ndlp);
} else {
lpfc_unreg_rpi(vports[i], ndlp);
}
@@ -4294,9 +4323,10 @@ lpfc_sli4_io_sgl_update(struct lpfc_hba *phba)
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"6074 Current allocated XRI sgl count:%d, "
- "maximum XRI count:%d\n",
+ "maximum XRI count:%d els_xri_cnt:%d\n\n",
phba->sli4_hba.io_xri_cnt,
- phba->sli4_hba.io_xri_max);
+ phba->sli4_hba.io_xri_max,
+ els_xri_cnt);
cnt = lpfc_io_buf_flush(phba, &io_sgl_list);
@@ -4435,12 +4465,11 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc)
}
pwqeq->sli4_lxritag = lxri;
pwqeq->sli4_xritag = phba->sli4_hba.xri_ids[lxri];
- pwqeq->context1 = lpfc_ncmd;
/* Initialize local short-hand pointers. */
lpfc_ncmd->dma_sgl = lpfc_ncmd->data;
lpfc_ncmd->dma_phys_sgl = lpfc_ncmd->dma_handle;
- lpfc_ncmd->cur_iocbq.context1 = lpfc_ncmd;
+ lpfc_ncmd->cur_iocbq.io_buf = lpfc_ncmd;
spin_lock_init(&lpfc_ncmd->buf_lock);
/* add the nvme buffer to a post list */
@@ -4449,7 +4478,9 @@ lpfc_new_io_buf(struct lpfc_hba *phba, int num_to_alloc)
}
lpfc_printf_log(phba, KERN_INFO, LOG_NVME,
"6114 Allocate %d out of %d requested new NVME "
- "buffers\n", bcnt, num_to_alloc);
+ "buffers of size x%zu bytes\n", bcnt, num_to_alloc,
+ sizeof(*lpfc_ncmd));
+
/* post the list of nvme buffer sgls to port if available */
if (!list_empty(&post_nblist))
@@ -5284,7 +5315,6 @@ static void
lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
struct lpfc_acqe_link *acqe_link)
{
- struct lpfc_dmabuf *mp;
LPFC_MBOXQ_t *pmb;
MAILBOX_t *mb;
struct lpfc_mbx_read_top *la;
@@ -5301,18 +5331,13 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
"0395 The mboxq allocation failed\n");
return;
}
- mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
- if (!mp) {
+
+ rc = lpfc_mbox_rsrc_prep(phba, pmb);
+ if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
- "0396 The lpfc_dmabuf allocation failed\n");
+ "0396 mailbox allocation failed\n");
goto out_free_pmb;
}
- mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
- if (!mp->virt) {
- lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
- "0397 The mbuf allocation failed\n");
- goto out_free_dmabuf;
- }
/* Cleanup any outstanding ELS commands */
lpfc_els_flush_all_cmd(phba);
@@ -5324,7 +5349,7 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
phba->sli.slistat.link_event++;
/* Create lpfc_handle_latt mailbox command from link ACQE */
- lpfc_read_topology(phba, pmb, mp);
+ lpfc_read_topology(phba, pmb, (struct lpfc_dmabuf *)pmb->ctx_buf);
pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology;
pmb->vport = phba->pport;
@@ -5362,10 +5387,8 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
*/
if (!(phba->hba_flag & HBA_FCOE_MODE)) {
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- goto out_free_dmabuf;
- }
+ if (rc == MBX_NOT_FINISHED)
+ goto out_free_pmb;
return;
}
/*
@@ -5400,10 +5423,8 @@ lpfc_sli4_async_link_evt(struct lpfc_hba *phba,
return;
-out_free_dmabuf:
- kfree(mp);
out_free_pmb:
- mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
}
/**
@@ -5510,7 +5531,7 @@ lpfc_cgn_update_stat(struct lpfc_hba *phba, uint32_t dtag)
struct tm broken;
struct timespec64 cur_time;
u32 cnt;
- u16 value;
+ u32 value;
/* Make sure we have a congestion info buffer */
if (!phba->cgn_i)
@@ -5843,21 +5864,8 @@ lpfc_cgn_save_evt_cnt(struct lpfc_hba *phba)
/* Use the frequency found in the last rcv'ed FPIN */
value = phba->cgn_fpin_frequency;
- if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_WARN)
- cp->cgn_warn_freq = cpu_to_le16(value);
- if (phba->cgn_reg_fpin & LPFC_CGN_FPIN_ALARM)
- cp->cgn_alarm_freq = cpu_to_le16(value);
-
- /* Frequency (in ms) Signal Warning/Signal Congestion Notifications
- * are received by the HBA
- */
- value = phba->cgn_sig_freq;
-
- if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ONLY ||
- phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM)
- cp->cgn_warn_freq = cpu_to_le16(value);
- if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM)
- cp->cgn_alarm_freq = cpu_to_le16(value);
+ cp->cgn_warn_freq = cpu_to_le16(value);
+ cp->cgn_alarm_freq = cpu_to_le16(value);
lvalue = lpfc_cgn_calc_crc32(cp, LPFC_CGN_INFO_SZ,
LPFC_CGN_CRC32_SEED);
@@ -6214,7 +6222,6 @@ lpfc_update_trunk_link_status(struct lpfc_hba *phba,
static void
lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
{
- struct lpfc_dmabuf *mp;
LPFC_MBOXQ_t *pmb;
MAILBOX_t *mb;
struct lpfc_mbx_read_top *la;
@@ -6274,18 +6281,12 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
"2897 The mboxq allocation failed\n");
return;
}
- mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
- if (!mp) {
+ rc = lpfc_mbox_rsrc_prep(phba, pmb);
+ if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
- "2898 The lpfc_dmabuf allocation failed\n");
+ "2898 The mboxq prep failed\n");
goto out_free_pmb;
}
- mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
- if (!mp->virt) {
- lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
- "2899 The mbuf allocation failed\n");
- goto out_free_dmabuf;
- }
/* Cleanup any outstanding ELS commands */
lpfc_els_flush_all_cmd(phba);
@@ -6297,7 +6298,7 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
phba->sli.slistat.link_event++;
/* Create lpfc_handle_latt mailbox command from link ACQE */
- lpfc_read_topology(phba, pmb, mp);
+ lpfc_read_topology(phba, pmb, (struct lpfc_dmabuf *)pmb->ctx_buf);
pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology;
pmb->vport = phba->pport;
@@ -6341,16 +6342,12 @@ lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc)
}
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- goto out_free_dmabuf;
- }
+ if (rc == MBX_NOT_FINISHED)
+ goto out_free_pmb;
return;
-out_free_dmabuf:
- kfree(mp);
out_free_pmb:
- mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
}
/**
@@ -6542,12 +6539,15 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
case LPFC_SLI_EVENT_TYPE_MISCONF_FAWWN:
/* Misconfigured WWN. Reports that the SLI Port is configured
* to use FA-WWN, but the attached device doesn’t support it.
- * No driver action is required.
* Event Data1 - N.A, Event Data2 - N.A
+ * This event only happens on the physical port.
*/
- lpfc_log_msg(phba, KERN_WARNING, LOG_SLI,
- "2699 Misconfigured FA-WWN - Attached device does "
- "not support FA-WWN\n");
+ lpfc_log_msg(phba, KERN_WARNING, LOG_SLI | LOG_DISCOVERY,
+ "2699 Misconfigured FA-PWWN - Attached device "
+ "does not support FA-PWWN\n");
+ phba->sli4_hba.fawwpn_flag &= ~LPFC_FAWWPN_FABRIC;
+ memset(phba->pport->fc_portname.u.wwn, 0,
+ sizeof(struct lpfc_name));
break;
case LPFC_SLI_EVENT_TYPE_EEPROM_FAILURE:
/* EEPROM failure. No driver action is required */
@@ -6572,9 +6572,6 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
/* Alarm overrides warning, so check that first */
if (cgn_signal->alarm_cnt) {
if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) {
- /* Keep track of alarm cnt for cgn_info */
- atomic_add(cgn_signal->alarm_cnt,
- &phba->cgn_fabric_alarm_cnt);
/* Keep track of alarm cnt for CMF_SYNC_WQE */
atomic_add(cgn_signal->alarm_cnt,
&phba->cgn_sync_alarm_cnt);
@@ -6583,8 +6580,6 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli)
/* signal action needs to be taken */
if (phba->cgn_reg_signal == EDC_CG_SIG_WARN_ONLY ||
phba->cgn_reg_signal == EDC_CG_SIG_WARN_ALARM) {
- /* Keep track of warning cnt for cgn_info */
- atomic_add(cnt, &phba->cgn_fabric_warn_cnt);
/* Keep track of warning cnt for CMF_SYNC_WQE */
atomic_add(cnt, &phba->cgn_sync_warn_cnt);
}
@@ -8004,6 +7999,18 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
rc = lpfc_sli4_read_config(phba);
if (unlikely(rc))
goto out_free_bsmbx;
+
+ if (phba->sli4_hba.fawwpn_flag & LPFC_FAWWPN_CONFIG) {
+ /* Right now the link is down, if FA-PWWN is configured the
+ * firmware will try FLOGI before the driver gets a link up.
+ * If it fails, the driver should get a MISCONFIGURED async
+ * event which will clear this flag. The only notification
+ * the driver gets is if it fails, if it succeeds there is no
+ * notification given. Assume success.
+ */
+ phba->sli4_hba.fawwpn_flag |= LPFC_FAWWPN_FABRIC;
+ }
+
rc = lpfc_mem_alloc_active_rrq_pool_s4(phba);
if (unlikely(rc))
goto out_free_bsmbx;
@@ -8978,6 +8985,36 @@ lpfc_hba_free(struct lpfc_hba *phba)
}
/**
+ * lpfc_setup_fdmi_mask - Setup initial FDMI mask for HBA and Port attributes
+ * @vport: pointer to lpfc vport data structure.
+ *
+ * This routine is will setup initial FDMI attribute masks for
+ * FDMI2 or SmartSAN depending on module parameters. The driver will attempt
+ * to get these attributes first before falling back, the attribute
+ * fallback hierarchy is SmartSAN -> FDMI2 -> FMDI1
+ **/
+void
+lpfc_setup_fdmi_mask(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+
+ vport->load_flag |= FC_ALLOW_FDMI;
+ if (phba->cfg_enable_SmartSAN ||
+ phba->cfg_fdmi_on == LPFC_FDMI_SUPPORT) {
+ /* Setup appropriate attribute masks */
+ vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR;
+ if (phba->cfg_enable_SmartSAN)
+ vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR;
+ else
+ vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
+ }
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "6077 Setup FDMI mask: hba x%x port x%x\n",
+ vport->fdmi_hba_mask, vport->fdmi_port_mask);
+}
+
+/**
* lpfc_create_shost - Create hba physical port with associated scsi host.
* @phba: pointer to lpfc hba data structure.
*
@@ -9020,21 +9057,12 @@ lpfc_create_shost(struct lpfc_hba *phba)
/* Put reference to SCSI host to driver's device private data */
pci_set_drvdata(phba->pcidev, shost);
+ lpfc_setup_fdmi_mask(vport);
+
/*
* At this point we are fully registered with PSA. In addition,
* any initial discovery should be completed.
*/
- vport->load_flag |= FC_ALLOW_FDMI;
- if (phba->cfg_enable_SmartSAN ||
- (phba->cfg_fdmi_on == LPFC_FDMI_SUPPORT)) {
-
- /* Setup appropriate attribute masks */
- vport->fdmi_hba_mask = LPFC_FDMI2_HBA_ATTR;
- if (phba->cfg_enable_SmartSAN)
- vport->fdmi_port_mask = LPFC_FDMI2_SMART_ATTR;
- else
- vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR;
- }
return 0;
}
@@ -9807,7 +9835,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
struct lpfc_rsrc_desc_fcfcoe *desc;
char *pdesc_0;
uint16_t forced_link_speed;
- uint32_t if_type, qmin;
+ uint32_t if_type, qmin, fawwpn;
int length, i, rc = 0, rc2;
pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -9849,10 +9877,23 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
phba->sli4_hba.bbscn_params.word0 = rd_config->word8;
}
+ fawwpn = bf_get(lpfc_mbx_rd_conf_fawwpn, rd_config);
+
+ if (fawwpn) {
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_INIT | LOG_DISCOVERY,
+ "2702 READ_CONFIG: FA-PWWN is "
+ "configured on\n");
+ phba->sli4_hba.fawwpn_flag |= LPFC_FAWWPN_CONFIG;
+ } else {
+ phba->sli4_hba.fawwpn_flag = 0;
+ }
+
phba->sli4_hba.conf_trunk =
bf_get(lpfc_mbx_rd_conf_trunk, rd_config);
phba->sli4_hba.extents_in_use =
bf_get(lpfc_mbx_rd_conf_extnts_inuse, rd_config);
+
phba->sli4_hba.max_cfg_param.max_xri =
bf_get(lpfc_mbx_rd_conf_xri_count, rd_config);
/* Reduce resource usage in kdump environment */
@@ -13354,8 +13395,9 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
/* Abort all iocbs associated with the hba */
lpfc_sli_hba_iocb_abort(phba);
- /* Wait for completion of device XRI exchange busy */
- lpfc_sli4_xri_exchange_busy_wait(phba);
+ if (!pci_channel_offline(phba->pcidev))
+ /* Wait for completion of device XRI exchange busy */
+ lpfc_sli4_xri_exchange_busy_wait(phba);
/* per-phba callback de-registration for hotplug event */
if (phba->pport)
@@ -13374,15 +13416,12 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba)
/* Disable FW logging to host memory */
lpfc_ras_stop_fwlog(phba);
- /* Unset the queues shared with the hardware then release all
- * allocated resources.
- */
- lpfc_sli4_queue_unset(phba);
- lpfc_sli4_queue_destroy(phba);
-
/* Reset SLI4 HBA FCoE function */
lpfc_pci_function_reset(phba);
+ /* release all queue allocated resources. */
+ lpfc_sli4_queue_destroy(phba);
+
/* Free RAS DMA memory */
if (phba->ras_fwlog.ras_enabled)
lpfc_sli4_ras_dma_free(phba);
@@ -14262,6 +14301,7 @@ lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba)
"2711 PCI channel permanent disable for failure\n");
/* Block all SCSI devices' I/Os on the host */
lpfc_scsi_dev_block(phba);
+ lpfc_sli4_prep_dev_for_reset(phba);
/* stop all timers */
lpfc_stop_hba_timers(phba);
@@ -14810,9 +14850,6 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
/* Check if there are static vports to be created. */
lpfc_create_static_vport(phba);
- /* Enable RAS FW log support */
- lpfc_sli4_ras_setup(phba);
-
timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0);
cpuhp_state_add_instance_nocalls(lpfc_cpuhp_state, &phba->cpuhp);
@@ -15057,24 +15094,28 @@ lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba)
static void
lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba)
{
- lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
- "2826 PCI channel disable preparing for reset\n");
+ int offline = pci_channel_offline(phba->pcidev);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2826 PCI channel disable preparing for reset offline"
+ " %d\n", offline);
/* Block any management I/Os to the device */
lpfc_block_mgmt_io(phba, LPFC_MBX_NO_WAIT);
- /* Block all SCSI devices' I/Os on the host */
- lpfc_scsi_dev_block(phba);
+ /* HBA_PCI_ERR was set in io_error_detect */
+ lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT);
/* Flush all driver's outstanding I/Os as we are to reset */
lpfc_sli_flush_io_rings(phba);
+ lpfc_offline(phba);
/* stop all timers */
lpfc_stop_hba_timers(phba);
+ lpfc_sli4_queue_destroy(phba);
/* Disable interrupt and pci device */
lpfc_sli4_disable_intr(phba);
- lpfc_sli4_queue_destroy(phba);
pci_disable_device(phba->pcidev);
}
@@ -15123,6 +15164,7 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ bool hba_pci_err;
switch (state) {
case pci_channel_io_normal:
@@ -15130,17 +15172,24 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state)
lpfc_sli4_prep_dev_for_recover(phba);
return PCI_ERS_RESULT_CAN_RECOVER;
case pci_channel_io_frozen:
- phba->hba_flag |= HBA_PCI_ERR;
+ hba_pci_err = test_and_set_bit(HBA_PCI_ERR, &phba->bit_flags);
/* Fatal error, prepare for slot reset */
- lpfc_sli4_prep_dev_for_reset(phba);
+ if (!hba_pci_err)
+ lpfc_sli4_prep_dev_for_reset(phba);
+ else
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2832 Already handling PCI error "
+ "state: x%x\n", state);
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
- phba->hba_flag |= HBA_PCI_ERR;
+ set_bit(HBA_PCI_ERR, &phba->bit_flags);
/* Permanent failure, prepare for device down */
lpfc_sli4_prep_dev_for_perm_failure(phba);
return PCI_ERS_RESULT_DISCONNECT;
default:
- phba->hba_flag |= HBA_PCI_ERR;
+ hba_pci_err = test_and_set_bit(HBA_PCI_ERR, &phba->bit_flags);
+ if (!hba_pci_err)
+ lpfc_sli4_prep_dev_for_reset(phba);
/* Unknown state, prepare and request slot reset */
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
"2825 Unknown PCI error state: x%x\n", state);
@@ -15174,17 +15223,21 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev)
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
struct lpfc_sli *psli = &phba->sli;
uint32_t intr_mode;
+ bool hba_pci_err;
dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
if (pci_enable_device_mem(pdev)) {
printk(KERN_ERR "lpfc: Cannot re-enable "
- "PCI device after reset.\n");
+ "PCI device after reset.\n");
return PCI_ERS_RESULT_DISCONNECT;
}
pci_restore_state(pdev);
- phba->hba_flag &= ~HBA_PCI_ERR;
+ hba_pci_err = test_and_clear_bit(HBA_PCI_ERR, &phba->bit_flags);
+ if (!hba_pci_err)
+ dev_info(&pdev->dev,
+ "hba_pci_err was not set, recovering slot reset.\n");
/*
* As the new kernel behavior of pci_restore_state() API call clears
* device saved_state flag, need to save the restored state again.
@@ -15198,6 +15251,8 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev)
psli->sli_flag &= ~LPFC_SLI_ACTIVE;
spin_unlock_irq(&phba->hbalock);
+ /* Init cpu_map array */
+ lpfc_cpu_map_array_init(phba);
/* Configure and enable interrupt */
intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode);
if (intr_mode == LPFC_INTR_ERROR) {
@@ -15239,8 +15294,6 @@ lpfc_io_resume_s4(struct pci_dev *pdev)
*/
if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) {
/* Perform device reset */
- lpfc_offline_prep(phba, LPFC_MBX_WAIT);
- lpfc_offline(phba);
lpfc_sli_brdrestart(phba);
/* Bring the device back online */
lpfc_online(phba);
@@ -15662,34 +15715,7 @@ void lpfc_dmp_dbg(struct lpfc_hba *phba)
unsigned int temp_idx;
int i;
int j = 0;
- unsigned long rem_nsec, iflags;
- bool log_verbose = false;
- struct lpfc_vport *port_iterator;
-
- /* Don't dump messages if we explicitly set log_verbose for the
- * physical port or any vport.
- */
- if (phba->cfg_log_verbose)
- return;
-
- spin_lock_irqsave(&phba->port_list_lock, iflags);
- list_for_each_entry(port_iterator, &phba->port_list, listentry) {
- if (port_iterator->load_flag & FC_UNLOADING)
- continue;
- if (scsi_host_get(lpfc_shost_from_vport(port_iterator))) {
- if (port_iterator->cfg_log_verbose)
- log_verbose = true;
-
- scsi_host_put(lpfc_shost_from_vport(port_iterator));
-
- if (log_verbose) {
- spin_unlock_irqrestore(&phba->port_list_lock,
- iflags);
- return;
- }
- }
- }
- spin_unlock_irqrestore(&phba->port_list_lock, iflags);
+ unsigned long rem_nsec;
if (atomic_cmpxchg(&phba->dbg_log_dmping, 0, 1) != 0)
return;
diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h
index 7d480c798794..4d455da9cd69 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-2021 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2022 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. *
@@ -73,7 +73,7 @@ do { \
#define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \
do { \
{ if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '3')) { \
- if ((mask) & LOG_TRACE_EVENT) \
+ if ((mask) & LOG_TRACE_EVENT && !(vport)->cfg_log_verbose) \
lpfc_dmp_dbg((vport)->phba); \
dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \
fmt, (vport)->phba->brd_no, vport->vpi, ##arg); \
@@ -89,11 +89,11 @@ do { \
(phba)->pport->cfg_log_verbose : \
(phba)->cfg_log_verbose; \
if (((mask) & log_verbose) || (level[1] <= '3')) { \
- if ((mask) & LOG_TRACE_EVENT) \
+ if ((mask) & LOG_TRACE_EVENT && !log_verbose) \
lpfc_dmp_dbg(phba); \
dev_printk(level, &((phba)->pcidev)->dev, "%d:" \
fmt, phba->brd_no, ##arg); \
- } else if (!(phba)->cfg_log_verbose)\
+ } else if (!log_verbose)\
lpfc_dbg_print(phba, "%d:" fmt, phba->brd_no, ##arg); \
} \
} while (0)
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index e1404ab5000d..9858b1743769 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2021 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -44,6 +44,80 @@
#include "lpfc_compat.h"
/**
+ * lpfc_mbox_rsrc_prep - Prepare a mailbox with DMA buffer memory.
+ * @phba: pointer to lpfc hba data structure.
+ * @mbox: pointer to the driver internal queue element for mailbox command.
+ *
+ * A mailbox command consists of the pool memory for the command, @mbox, and
+ * one or more DMA buffers for the data transfer. This routine provides
+ * a standard framework for allocating the dma buffer and assigning to the
+ * @mbox. Callers should cleanup the mbox with a call to
+ * lpfc_mbox_rsrc_cleanup.
+ *
+ * The lpfc_mbuf_alloc routine acquires the hbalock so the caller is
+ * responsible to ensure the hbalock is released. Also note that the
+ * driver design is a single dmabuf/mbuf per mbox in the ctx_buf.
+ *
+ **/
+int
+lpfc_mbox_rsrc_prep(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
+{
+ struct lpfc_dmabuf *mp;
+
+ mp = kmalloc(sizeof(*mp), GFP_KERNEL);
+ if (!mp)
+ return -ENOMEM;
+
+ mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
+ if (!mp->virt) {
+ kfree(mp);
+ return -ENOMEM;
+ }
+
+ memset(mp->virt, 0, LPFC_BPL_SIZE);
+
+ /* Initialization only. Driver does not use a list of dmabufs. */
+ INIT_LIST_HEAD(&mp->list);
+ mbox->ctx_buf = mp;
+ return 0;
+}
+
+/**
+ * lpfc_mbox_rsrc_cleanup - Free the mailbox DMA buffer and virtual memory.
+ * @phba: pointer to lpfc hba data structure.
+ * @mbox: pointer to the driver internal queue element for mailbox command.
+ * @locked: value that indicates if the hbalock is held (1) or not (0).
+ *
+ * A mailbox command consists of the pool memory for the command, @mbox, and
+ * possibly a DMA buffer for the data transfer. This routine provides
+ * a standard framework for releasing any dma buffers and freeing all
+ * memory resources in it as well as releasing the @mbox back to the @phba pool.
+ * Callers should use this routine for cleanup for all mailboxes prepped with
+ * lpfc_mbox_rsrc_prep.
+ *
+ **/
+void
+lpfc_mbox_rsrc_cleanup(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox,
+ enum lpfc_mbox_ctx locked)
+{
+ struct lpfc_dmabuf *mp;
+
+ mp = (struct lpfc_dmabuf *)mbox->ctx_buf;
+ mbox->ctx_buf = NULL;
+
+ /* Release the generic BPL buffer memory. */
+ if (mp) {
+ if (locked == MBOX_THD_LOCKED)
+ __lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ else
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ }
+
+ mempool_free(mbox, phba->mbox_mem_pool);
+}
+
+/**
* lpfc_dump_static_vport - Dump HBA's static vport information.
* @phba: pointer to lpfc hba data structure.
* @pmb: pointer to the driver internal queue element for mailbox command.
@@ -61,6 +135,7 @@ lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb,
{
MAILBOX_t *mb;
struct lpfc_dmabuf *mp;
+ int rc;
mb = &pmb->u.mb;
@@ -79,22 +154,15 @@ lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb,
return 0;
}
- /* For SLI4 HBAs driver need to allocate memory */
- mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
- if (mp)
- mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
-
- if (!mp || !mp->virt) {
- kfree(mp);
+ rc = lpfc_mbox_rsrc_prep(phba, pmb);
+ if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "2605 lpfc_dump_static_vport: memory"
- " allocation failed\n");
+ "2605 %s: memory allocation failed\n",
+ __func__);
return 1;
}
- memset(mp->virt, 0, LPFC_BPL_SIZE);
- INIT_LIST_HEAD(&mp->list);
- /* save address for completion */
- pmb->ctx_buf = (uint8_t *)mp;
+
+ mp = pmb->ctx_buf;
mb->un.varWords[3] = putPaddrLow(mp->phys);
mb->un.varWords[4] = putPaddrHigh(mp->phys);
mb->un.varDmp.sli4_length = sizeof(struct static_vport_info);
@@ -606,26 +674,21 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
{
struct lpfc_dmabuf *mp;
MAILBOX_t *mb;
+ int rc;
- mb = &pmb->u.mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
- mb->mbxOwner = OWN_HOST;
-
/* Get a buffer to hold the HBAs Service Parameters */
-
- mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
- if (mp)
- mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
- if (!mp || !mp->virt) {
- kfree(mp);
- mb->mbxCommand = MBX_READ_SPARM64;
- /* READ_SPARAM: no buffers */
+ rc = lpfc_mbox_rsrc_prep(phba, pmb);
+ if (rc) {
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
"0301 READ_SPARAM: no buffers\n");
- return (1);
+ return 1;
}
- INIT_LIST_HEAD(&mp->list);
+
+ mp = pmb->ctx_buf;
+ mb = &pmb->u.mb;
+ mb->mbxOwner = OWN_HOST;
mb->mbxCommand = MBX_READ_SPARM64;
mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys);
@@ -633,9 +696,6 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
if (phba->sli_rev >= LPFC_SLI_REV3)
mb->un.varRdSparm.vpi = phba->vpi_ids[vpi];
- /* save address for completion */
- pmb->ctx_buf = mp;
-
return (0);
}
@@ -756,6 +816,7 @@ lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
MAILBOX_t *mb = &pmb->u.mb;
uint8_t *sparam;
struct lpfc_dmabuf *mp;
+ int rc;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
@@ -766,12 +827,10 @@ lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
mb->un.varRegLogin.vpi = phba->vpi_ids[vpi];
mb->un.varRegLogin.did = did;
mb->mbxOwner = OWN_HOST;
+
/* Get a buffer to hold NPorts Service Parameters */
- mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
- if (mp)
- mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
- if (!mp || !mp->virt) {
- kfree(mp);
+ rc = lpfc_mbox_rsrc_prep(phba, pmb);
+ if (rc) {
mb->mbxCommand = MBX_REG_LOGIN64;
/* REG_LOGIN: no buffers */
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
@@ -779,15 +838,13 @@ lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
"rpi x%x\n", vpi, did, rpi);
return 1;
}
- INIT_LIST_HEAD(&mp->list);
- sparam = mp->virt;
/* Copy param's into a new buffer */
+ mp = pmb->ctx_buf;
+ sparam = mp->virt;
memcpy(sparam, param, sizeof (struct serv_parm));
- /* save address for completion */
- pmb->ctx_buf = (uint8_t *)mp;
-
+ /* Finish initializing the mailbox. */
mb->mbxCommand = MBX_REG_LOGIN64;
mb->un.varRegLogin.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
mb->un.varRegLogin.un.sp64.addrHigh = putPaddrHigh(mp->phys);
@@ -1723,7 +1780,9 @@ lpfc_sli4_mbx_sge_get(struct lpfcMboxq *mbox, uint32_t sgentry,
* @phba: pointer to lpfc hba data structure.
* @mbox: pointer to lpfc mbox command.
*
- * This routine frees SLI4 specific mailbox command for sending IOCTL command.
+ * This routine cleans up and releases an SLI4 mailbox command that was
+ * configured using lpfc_sli4_config. It accounts for the embedded and
+ * non-embedded config types.
**/
void
lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
@@ -2277,33 +2336,24 @@ lpfc_sli4_dump_cfg_rg23(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
{
struct lpfc_dmabuf *mp = NULL;
MAILBOX_t *mb;
+ int rc;
memset(mbox, 0, sizeof(*mbox));
mb = &mbox->u.mb;
- mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
- if (mp)
- mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
-
- if (!mp || !mp->virt) {
- kfree(mp);
- /* dump config region 23 failed to allocate memory */
+ rc = lpfc_mbox_rsrc_prep(phba, mbox);
+ if (rc) {
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
- "2569 lpfc dump config region 23: memory"
- " allocation failed\n");
+ "2569 %s: memory allocation failed\n",
+ __func__);
return 1;
}
- memset(mp->virt, 0, LPFC_BPL_SIZE);
- INIT_LIST_HEAD(&mp->list);
-
- /* save address for completion */
- mbox->ctx_buf = (uint8_t *)mp;
-
mb->mbxCommand = MBX_DUMP_MEMORY;
mb->un.varDmp.type = DMP_NV_PARAMS;
mb->un.varDmp.region_id = DMP_REGION_23;
mb->un.varDmp.sli4_length = DMP_RGN23_SIZE;
+ mp = mbox->ctx_buf;
mb->un.varWords[3] = putPaddrLow(mp->phys);
mb->un.varWords[4] = putPaddrHigh(mp->phys);
return 0;
@@ -2326,7 +2376,7 @@ lpfc_mbx_cmpl_rdp_link_stat(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
rc = SUCCESS;
mbx_failed:
- lpfc_sli4_mbox_cmd_free(phba, mboxq);
+ lpfc_mbox_rsrc_cleanup(phba, mboxq, MBOX_THD_UNLOCKED);
rdp_context->cmpl(phba, rdp_context, rc);
}
@@ -2338,30 +2388,25 @@ lpfc_mbx_cmpl_rdp_page_a2(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
(struct lpfc_rdp_context *)(mbox->ctx_ndlp);
if (bf_get(lpfc_mqe_status, &mbox->u.mqe))
- goto error_mbuf_free;
+ goto error_mbox_free;
lpfc_sli_bemem_bcopy(mp->virt, &rdp_context->page_a2,
DMP_SFF_PAGE_A2_SIZE);
- /* We don't need dma buffer for link stat. */
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
-
- memset(mbox, 0, sizeof(*mbox));
lpfc_read_lnk_stat(phba, mbox);
mbox->vport = rdp_context->ndlp->vport;
+
+ /* Save the dma buffer for cleanup in the final completion. */
+ mbox->ctx_buf = mp;
mbox->mbox_cmpl = lpfc_mbx_cmpl_rdp_link_stat;
mbox->ctx_ndlp = (struct lpfc_rdp_context *)rdp_context;
if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) == MBX_NOT_FINISHED)
- goto error_cmd_free;
+ goto error_mbox_free;
return;
-error_mbuf_free:
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
-error_cmd_free:
- lpfc_sli4_mbox_cmd_free(phba, mbox);
+error_mbox_free:
+ lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED);
rdp_context->cmpl(phba, rdp_context, FAILURE);
}
@@ -2409,9 +2454,7 @@ lpfc_mbx_cmpl_rdp_page_a0(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox)
return;
error:
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- lpfc_sli4_mbox_cmd_free(phba, mbox);
+ lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED);
rdp_context->cmpl(phba, rdp_context, FAILURE);
}
@@ -2427,27 +2470,19 @@ error:
int
lpfc_sli4_dump_page_a0(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
{
+ int rc;
struct lpfc_dmabuf *mp = NULL;
memset(mbox, 0, sizeof(*mbox));
- mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
- if (mp)
- mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys);
- if (!mp || !mp->virt) {
- kfree(mp);
+ rc = lpfc_mbox_rsrc_prep(phba, mbox);
+ if (rc) {
lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
"3569 dump type 3 page 0xA0 allocation failed\n");
return 1;
}
- memset(mp->virt, 0, LPFC_BPL_SIZE);
- INIT_LIST_HEAD(&mp->list);
-
bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_DUMP_MEMORY);
- /* save address for completion */
- mbox->ctx_buf = mp;
-
bf_set(lpfc_mbx_memory_dump_type3_type,
&mbox->u.mqe.un.mem_dump_type3, DMP_LMSD);
bf_set(lpfc_mbx_memory_dump_type3_link,
@@ -2456,6 +2491,8 @@ lpfc_sli4_dump_page_a0(struct lpfc_hba *phba, struct lpfcMboxq *mbox)
&mbox->u.mqe.un.mem_dump_type3, DMP_PAGE_A0);
bf_set(lpfc_mbx_memory_dump_type3_length,
&mbox->u.mqe.un.mem_dump_type3, DMP_SFF_PAGE_A0_SIZE);
+
+ mp = mbox->ctx_buf;
mbox->u.mqe.un.mem_dump_type3.addr_lo = putPaddrLow(mp->phys);
mbox->u.mqe.un.mem_dump_type3.addr_hi = putPaddrHigh(mp->phys);
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index c4e1a07066a2..639f86635127 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -173,9 +173,9 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
void *ptr = NULL;
u32 ulp_status = get_job_ulpstatus(phba, rspiocb);
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ pcmd = cmdiocb->cmd_dmabuf;
- /* For lpfc_els_abort, context2 could be zero'ed to delay
+ /* For lpfc_els_abort, cmd_dmabuf could be zero'ed to delay
* freeing associated memory till after ABTS completes.
*/
if (pcmd) {
@@ -327,7 +327,6 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
{
struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd;
- struct lpfc_dmabuf *mp;
uint64_t nlp_portwwn = 0;
uint32_t *lp;
union lpfc_wqe128 *wqe;
@@ -343,7 +342,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
u32 remote_did;
memset(&stat, 0, sizeof (struct ls_rjt));
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ pcmd = cmdiocb->cmd_dmabuf;
lp = (uint32_t *) pcmd->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
if (wwn_to_u64(sp->portName.u.wwn) == 0) {
@@ -514,6 +513,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
lpfc_config_link(phba, link_mbox);
link_mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
link_mbox->vport = vport;
+
+ /* The default completion handling for CONFIG_LINK
+ * does not require the ndlp so no reference is needed.
+ */
link_mbox->ctx_ndlp = ndlp;
rc = lpfc_sli_issue_mbox(phba, link_mbox, MBX_NOWAIT);
@@ -592,12 +595,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
* a default RPI.
*/
if (phba->sli_rev == LPFC_SLI_REV4) {
- mp = (struct lpfc_dmabuf *)login_mbox->ctx_buf;
- if (mp) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- }
- mempool_free(login_mbox, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, login_mbox,
+ MBOX_THD_UNLOCKED);
login_mbox = NULL;
} else {
/* In order to preserve RPIs, we want to cleanup
@@ -614,9 +613,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD;
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
rc = lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
- ndlp, login_mbox);
- if (rc)
- mempool_free(login_mbox, phba->mbox_mem_pool);
+ ndlp, login_mbox);
+ if (rc && login_mbox)
+ lpfc_mbox_rsrc_cleanup(phba, login_mbox,
+ MBOX_THD_UNLOCKED);
return 1;
}
@@ -637,6 +637,9 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
*/
login_mbox->mbox_cmpl = lpfc_defer_plogi_acc;
login_mbox->ctx_ndlp = lpfc_nlp_get(ndlp);
+ if (!login_mbox->ctx_ndlp)
+ goto out;
+
login_mbox->context3 = save_iocb; /* For PLOGI ACC */
spin_lock_irq(&ndlp->lock);
@@ -645,8 +648,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
/* Start the ball rolling by issuing REG_LOGIN here */
rc = lpfc_sli_issue_mbox(phba, login_mbox, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED)
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_nlp_put(ndlp);
goto out;
+ }
lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
return 1;
@@ -710,7 +715,7 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint32_t *lp;
uint32_t cmd;
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ pcmd = cmdiocb->cmd_dmabuf;
lp = (uint32_t *) pcmd->virt;
cmd = *lp++;
@@ -918,7 +923,7 @@ lpfc_rcv_prli_support_check(struct lpfc_vport *vport,
uint32_t *payload;
uint32_t cmd;
- payload = ((struct lpfc_dmabuf *)cmdiocb->context2)->virt;
+ payload = cmdiocb->cmd_dmabuf->virt;
cmd = *payload;
if (vport->phba->nvmet_support) {
/* Must be a NVME PRLI */
@@ -955,9 +960,9 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct fc_rport *rport = ndlp->rport;
u32 roles;
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
- lp = (uint32_t *) pcmd->virt;
- npr = (PRLI *) ((uint8_t *) lp + sizeof (uint32_t));
+ pcmd = cmdiocb->cmd_dmabuf;
+ lp = (uint32_t *)pcmd->virt;
+ npr = (PRLI *)((uint8_t *)lp + sizeof(uint32_t));
if ((npr->prliType == PRLI_FCP_TYPE) ||
(npr->prliType == PRLI_NVME_TYPE)) {
@@ -1103,8 +1108,10 @@ lpfc_release_rpi(struct lpfc_hba *phba, struct lpfc_vport *vport,
ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED)
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_nlp_put(ndlp);
mempool_free(pmb, phba->mbox_mem_pool);
+ }
}
}
@@ -1218,7 +1225,7 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb = arg;
- struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf;
uint32_t *lp = (uint32_t *) pcmd->virt;
struct serv_parm *sp = (struct serv_parm *) (lp + 1);
struct ls_rjt stat;
@@ -1328,7 +1335,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
{
struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb, *rspiocb;
- struct lpfc_dmabuf *pcmd, *prsp, *mp;
+ struct lpfc_dmabuf *pcmd, *prsp;
uint32_t *lp;
uint32_t vid, flag;
struct serv_parm *sp;
@@ -1339,7 +1346,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
u32 did;
cmdiocb = (struct lpfc_iocbq *) arg;
- rspiocb = cmdiocb->context_un.rsp_iocb;
+ rspiocb = cmdiocb->rsp_iocb;
ulp_status = get_job_ulpstatus(phba, rspiocb);
@@ -1351,7 +1358,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
if (ulp_status)
goto out;
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ pcmd = cmdiocb->cmd_dmabuf;
prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
if (!prsp)
@@ -1495,11 +1502,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
* command
*/
lpfc_nlp_put(ndlp);
- mp = (struct lpfc_dmabuf *)mbox->ctx_buf;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(mbox, phba->mbox_mem_pool);
-
+ lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED);
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
"0134 PLOGI: cannot issue reg_login "
"Data: x%x x%x x%x x%x\n",
@@ -1697,7 +1700,7 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport,
u32 ulp_status;
cmdiocb = (struct lpfc_iocbq *) arg;
- rspiocb = cmdiocb->context_un.rsp_iocb;
+ rspiocb = cmdiocb->rsp_iocb;
ulp_status = get_job_ulpstatus(phba, rspiocb);
@@ -1850,7 +1853,6 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
LPFC_MBOXQ_t *mb;
LPFC_MBOXQ_t *nextmb;
- struct lpfc_dmabuf *mp;
struct lpfc_nodelist *ns_ndlp;
cmdiocb = (struct lpfc_iocbq *) arg;
@@ -1870,16 +1872,11 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) &&
(ndlp == (struct lpfc_nodelist *)mb->ctx_ndlp)) {
- mp = (struct lpfc_dmabuf *)(mb->ctx_buf);
- if (mp) {
- __lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- }
ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
lpfc_nlp_put(ndlp);
list_del(&mb->list);
phba->sli.mboxq_cnt--;
- mempool_free(mb, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, mb, MBOX_THD_LOCKED);
}
}
spin_unlock_irq(&phba->hbalock);
@@ -2152,7 +2149,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
u32 ulp_status;
cmdiocb = (struct lpfc_iocbq *) arg;
- rspiocb = cmdiocb->context_un.rsp_iocb;
+ rspiocb = cmdiocb->rsp_iocb;
ulp_status = get_job_ulpstatus(phba, rspiocb);
@@ -2772,7 +2769,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
u32 ulp_status;
cmdiocb = (struct lpfc_iocbq *) arg;
- rspiocb = cmdiocb->context_un.rsp_iocb;
+ rspiocb = cmdiocb->rsp_iocb;
ulp_status = get_job_ulpstatus(phba, rspiocb);
@@ -2791,7 +2788,7 @@ lpfc_cmpl_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
u32 ulp_status;
cmdiocb = (struct lpfc_iocbq *) arg;
- rspiocb = cmdiocb->context_un.rsp_iocb;
+ rspiocb = cmdiocb->rsp_iocb;
ulp_status = get_job_ulpstatus(phba, rspiocb);
@@ -2827,7 +2824,7 @@ lpfc_cmpl_adisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
u32 ulp_status;
cmdiocb = (struct lpfc_iocbq *) arg;
- rspiocb = cmdiocb->context_un.rsp_iocb;
+ rspiocb = cmdiocb->rsp_iocb;
ulp_status = get_job_ulpstatus(phba, rspiocb);
diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c
index 1213a299f9aa..5385f4de5523 100644
--- a/drivers/scsi/lpfc/lpfc_nvme.c
+++ b/drivers/scsi/lpfc/lpfc_nvme.c
@@ -93,6 +93,11 @@ lpfc_nvme_create_queue(struct nvme_fc_local_port *pnvme_lport,
lport = (struct lpfc_nvme_lport *)pnvme_lport->private;
vport = lport->vport;
+
+ if (!vport || vport->load_flag & FC_UNLOADING ||
+ vport->phba->hba_flag & HBA_IOQ_FLUSH)
+ return -ENODEV;
+
qhandle = kzalloc(sizeof(struct lpfc_nvme_qhandle), GFP_KERNEL);
if (qhandle == NULL)
return -ENOMEM;
@@ -267,7 +272,8 @@ lpfc_nvme_handle_lsreq(struct lpfc_hba *phba,
return -EINVAL;
remoteport = lpfc_rport->remoteport;
- if (!vport->localport)
+ if (!vport->localport ||
+ vport->phba->hba_flag & HBA_IOQ_FLUSH)
return -EINVAL;
lport = vport->localport->private;
@@ -313,8 +319,10 @@ __lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_vport *vport,
struct lpfc_nodelist *ndlp;
uint32_t status;
- pnvme_lsreq = (struct nvmefc_ls_req *)cmdwqe->context2;
- ndlp = (struct lpfc_nodelist *)cmdwqe->context1;
+ pnvme_lsreq = cmdwqe->context_un.nvme_lsreq;
+ ndlp = cmdwqe->ndlp;
+ buf_ptr = cmdwqe->bpl_dmabuf;
+
status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK;
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
@@ -324,16 +332,16 @@ __lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_vport *vport,
pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0,
cmdwqe->sli4_xritag, status,
(wcqe->parameter & 0xffff),
- cmdwqe, pnvme_lsreq, cmdwqe->context3, ndlp);
+ cmdwqe, pnvme_lsreq, cmdwqe->bpl_dmabuf,
+ ndlp);
lpfc_nvmeio_data(phba, "NVMEx LS CMPL: xri x%x stat x%x parm x%x\n",
cmdwqe->sli4_xritag, status, wcqe->parameter);
- if (cmdwqe->context3) {
- buf_ptr = (struct lpfc_dmabuf *)cmdwqe->context3;
+ if (buf_ptr) {
lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
kfree(buf_ptr);
- cmdwqe->context3 = NULL;
+ cmdwqe->bpl_dmabuf = NULL;
}
if (pnvme_lsreq->done)
pnvme_lsreq->done(pnvme_lsreq, status);
@@ -345,7 +353,7 @@ __lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_vport *vport,
cmdwqe->sli4_xritag, status);
if (ndlp) {
lpfc_nlp_put(ndlp);
- cmdwqe->context1 = NULL;
+ cmdwqe->ndlp = NULL;
}
lpfc_sli_release_iocbq(phba, cmdwqe);
}
@@ -401,19 +409,19 @@ lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
/* Initialize only 64 bytes */
memset(wqe, 0, sizeof(union lpfc_wqe));
- genwqe->context3 = (uint8_t *)bmp;
+ genwqe->bpl_dmabuf = bmp;
genwqe->cmd_flag |= LPFC_IO_NVME_LS;
/* Save for completion so we can release these resources */
- genwqe->context1 = lpfc_nlp_get(ndlp);
- if (!genwqe->context1) {
+ genwqe->ndlp = lpfc_nlp_get(ndlp);
+ if (!genwqe->ndlp) {
dev_warn(&phba->pcidev->dev,
"Warning: Failed node ref, not sending LS_REQ\n");
lpfc_sli_release_iocbq(phba, genwqe);
return 1;
}
- genwqe->context2 = (uint8_t *)pnvme_lsreq;
+ genwqe->context_un.nvme_lsreq = pnvme_lsreq;
/* Fill in payload, bp points to frame payload */
if (!tmo)
@@ -559,6 +567,8 @@ __lpfc_nvme_ls_req(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_DID, ntype, nstate);
return -ENODEV;
}
+ if (vport->phba->hba_flag & HBA_IOQ_FLUSH)
+ return -ENODEV;
if (!vport->phba->sli4_hba.nvmels_wq)
return -ENOMEM;
@@ -662,7 +672,8 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport,
return -EINVAL;
vport = lport->vport;
- if (vport->load_flag & FC_UNLOADING)
+ if (vport->load_flag & FC_UNLOADING ||
+ vport->phba->hba_flag & HBA_IOQ_FLUSH)
return -ENODEV;
atomic_inc(&lport->fc4NvmeLsRequests);
@@ -721,7 +732,7 @@ __lpfc_nvme_ls_abort(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
spin_lock_irq(&phba->hbalock);
spin_lock(&pring->ring_lock);
list_for_each_entry_safe(wqe, next_wqe, &pring->txcmplq, list) {
- if (wqe->context2 == pnvme_lsreq) {
+ if (wqe->context_un.nvme_lsreq == pnvme_lsreq) {
wqe->cmd_flag |= LPFC_DRIVER_ABORTED;
foundit = true;
break;
@@ -920,8 +931,7 @@ static void
lpfc_nvme_io_cmd_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
struct lpfc_iocbq *pwqeOut)
{
- struct lpfc_io_buf *lpfc_ncmd =
- (struct lpfc_io_buf *)pwqeIn->context1;
+ struct lpfc_io_buf *lpfc_ncmd = pwqeIn->io_buf;
struct lpfc_wcqe_complete *wcqe = &pwqeOut->wcqe_cmpl;
struct lpfc_vport *vport = pwqeIn->vport;
struct nvmefc_fcp_req *nCmd;
@@ -1391,8 +1401,8 @@ lpfc_nvme_prep_io_dma(struct lpfc_vport *vport,
if ((nseg - 1) == i)
bf_set(lpfc_sli4_sge_last, sgl, 1);
- physaddr = data_sg->dma_address;
- dma_len = data_sg->length;
+ physaddr = sg_dma_address(data_sg);
+ dma_len = sg_dma_len(data_sg);
sgl->addr_lo = cpu_to_le32(
putPaddrLow(physaddr));
sgl->addr_hi = cpu_to_le32(
@@ -1516,7 +1526,8 @@ lpfc_nvme_fcp_io_submit(struct nvme_fc_local_port *pnvme_lport,
phba = vport->phba;
- if (unlikely(vport->load_flag & FC_UNLOADING)) {
+ if ((unlikely(vport->load_flag & FC_UNLOADING)) ||
+ phba->hba_flag & HBA_IOQ_FLUSH) {
lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_IOERR,
"6124 Fail IO, Driver unload\n");
atomic_inc(&lport->xmt_fcp_err);
@@ -2169,8 +2180,7 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport,
abts_nvme = 0;
for (i = 0; i < phba->cfg_hdw_queue; i++) {
qp = &phba->sli4_hba.hdwq[i];
- if (!vport || !vport->localport ||
- !qp || !qp->io_wq)
+ if (!vport->localport || !qp || !qp->io_wq)
return;
pring = qp->io_wq->pring;
@@ -2180,8 +2190,9 @@ lpfc_nvme_lport_unreg_wait(struct lpfc_vport *vport,
abts_scsi += qp->abts_scsi_io_bufs;
abts_nvme += qp->abts_nvme_io_bufs;
}
- if (!vport || !vport->localport ||
- vport->phba->hba_flag & HBA_PCI_ERR)
+ if (!vport->localport ||
+ test_bit(HBA_PCI_ERR, &vport->phba->bit_flags) ||
+ vport->load_flag & FC_UNLOADING)
return;
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
@@ -2346,6 +2357,11 @@ lpfc_nvme_register_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
rpinfo.dev_loss_tmo = vport->cfg_devloss_tmo;
spin_lock_irq(&ndlp->lock);
+
+ /* If an oldrport exists, so does the ndlp reference. If not
+ * a new reference is needed because either the node has never
+ * been registered or it's been unregistered and getting deleted.
+ */
oldrport = lpfc_ndlp_get_nrport(ndlp);
if (oldrport) {
prev_ndlp = oldrport->ndlp;
@@ -2456,12 +2472,12 @@ lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
if (!nrport || !remoteport)
goto rescan_exit;
- /* Only rescan if we are an NVME target in the MAPPED state */
+ /* Rescan an NVME target in MAPPED state with DISCOVERY role set */
if (remoteport->port_role & FC_PORT_ROLE_NVME_DISCOVERY &&
ndlp->nlp_state == NLP_STE_MAPPED_NODE) {
nvme_fc_rescan_remoteport(remoteport);
- lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC,
"6172 NVME rescanned DID x%06x "
"port_state x%x\n",
ndlp->nlp_DID, remoteport->port_state);
@@ -2541,8 +2557,7 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
* return values is ignored. The upcall is a courtesy to the
* transport.
*/
- if (vport->load_flag & FC_UNLOADING ||
- unlikely(vport->phba->hba_flag & HBA_PCI_ERR))
+ if (vport->load_flag & FC_UNLOADING)
(void)nvme_fc_set_remoteport_devloss(remoteport, 0);
ret = nvme_fc_unregister_remoteport(remoteport);
@@ -2708,7 +2723,7 @@ lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
struct lpfc_wcqe_complete wcqe;
struct lpfc_wcqe_complete *wcqep = &wcqe;
- lpfc_ncmd = (struct lpfc_io_buf *)pwqeIn->context1;
+ lpfc_ncmd = pwqeIn->io_buf;
if (!lpfc_ncmd) {
lpfc_sli_release_iocbq(phba, pwqeIn);
return;
diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c
index 95438265fb16..c0ee0b39075d 100644
--- a/drivers/scsi/lpfc/lpfc_nvmet.c
+++ b/drivers/scsi/lpfc/lpfc_nvmet.c
@@ -295,7 +295,7 @@ void
__lpfc_nvme_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
struct lpfc_iocbq *rspwqe)
{
- struct lpfc_async_xchg_ctx *axchg = cmdwqe->context2;
+ struct lpfc_async_xchg_ctx *axchg = cmdwqe->context_un.axchg;
struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl;
struct nvmefc_ls_rsp *ls_rsp = &axchg->ls_rsp;
uint32_t status, result;
@@ -317,9 +317,9 @@ __lpfc_nvme_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
"6038 NVMEx LS rsp cmpl: %d %d oxid x%x\n",
status, result, axchg->oxid);
- lpfc_nlp_put(cmdwqe->context1);
- cmdwqe->context2 = NULL;
- cmdwqe->context3 = NULL;
+ lpfc_nlp_put(cmdwqe->ndlp);
+ cmdwqe->context_un.axchg = NULL;
+ cmdwqe->bpl_dmabuf = NULL;
lpfc_sli_release_iocbq(phba, cmdwqe);
ls_rsp->done(ls_rsp);
lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC,
@@ -728,7 +728,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
int id;
#endif
- ctxp = cmdwqe->context2;
+ ctxp = cmdwqe->context_un.axchg;
ctxp->flag &= ~LPFC_NVME_IO_INP;
rsp = &ctxp->hdlrctx.fcp_req;
@@ -903,7 +903,7 @@ __lpfc_nvme_xmt_ls_rsp(struct lpfc_async_xchg_ctx *axchg,
/* Save numBdes for bpl2sgl */
nvmewqeq->num_bdes = 1;
nvmewqeq->hba_wqidx = 0;
- nvmewqeq->context3 = &dmabuf;
+ nvmewqeq->bpl_dmabuf = &dmabuf;
dmabuf.virt = &bpl;
bpl.addrLow = nvmewqeq->wqe.xmit_sequence.bde.addrLow;
bpl.addrHigh = nvmewqeq->wqe.xmit_sequence.bde.addrHigh;
@@ -917,7 +917,7 @@ __lpfc_nvme_xmt_ls_rsp(struct lpfc_async_xchg_ctx *axchg,
*/
nvmewqeq->cmd_cmpl = xmt_ls_rsp_cmp;
- nvmewqeq->context2 = axchg;
+ nvmewqeq->context_un.axchg = axchg;
lpfc_nvmeio_data(phba, "NVMEx LS RSP: xri x%x wqidx x%x len x%x\n",
axchg->oxid, nvmewqeq->hba_wqidx, ls_rsp->rsplen);
@@ -925,7 +925,7 @@ __lpfc_nvme_xmt_ls_rsp(struct lpfc_async_xchg_ctx *axchg,
rc = lpfc_sli4_issue_wqe(phba, axchg->hdwq, nvmewqeq);
/* clear to be sure there's no reference */
- nvmewqeq->context3 = NULL;
+ nvmewqeq->bpl_dmabuf = NULL;
if (rc == WQE_SUCCESS) {
/*
@@ -942,7 +942,7 @@ __lpfc_nvme_xmt_ls_rsp(struct lpfc_async_xchg_ctx *axchg,
rc = -ENXIO;
- lpfc_nlp_put(nvmewqeq->context1);
+ lpfc_nlp_put(nvmewqeq->ndlp);
out_free_buf:
/* Give back resources */
@@ -1075,7 +1075,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
}
nvmewqeq->cmd_cmpl = lpfc_nvmet_xmt_fcp_op_cmp;
- nvmewqeq->context2 = ctxp;
+ nvmewqeq->context_un.axchg = ctxp;
nvmewqeq->cmd_flag |= LPFC_IO_NVMET;
ctxp->wqeq->hba_wqidx = rsp->hwqid;
@@ -1119,8 +1119,8 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport,
ctxp->oxid, rc);
ctxp->wqeq->hba_wqidx = 0;
- nvmewqeq->context2 = NULL;
- nvmewqeq->context3 = NULL;
+ nvmewqeq->context_un.axchg = NULL;
+ nvmewqeq->bpl_dmabuf = NULL;
rc = -EBUSY;
aerr:
return rc;
@@ -1590,7 +1590,7 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba)
/* Initialize WQE */
memset(wqe, 0, sizeof(union lpfc_wqe));
- ctx_buf->iocbq->context1 = NULL;
+ ctx_buf->iocbq->cmd_dmabuf = NULL;
spin_lock(&phba->sli4_hba.sgl_list_lock);
ctx_buf->sglq = __lpfc_sli_get_nvmet_sglq(phba, ctx_buf->iocbq);
spin_unlock(&phba->sli4_hba.sgl_list_lock);
@@ -2025,7 +2025,7 @@ lpfc_nvmet_wqfull_flush(struct lpfc_hba *phba, struct lpfc_queue *wq,
&wq->wqfull_list, list) {
if (ctxp) {
/* Checking for a specific IO to flush */
- if (nvmewqeq->context2 == ctxp) {
+ if (nvmewqeq->context_un.axchg == ctxp) {
list_del(&nvmewqeq->list);
spin_unlock_irqrestore(&pring->ring_lock,
iflags);
@@ -2071,7 +2071,7 @@ lpfc_nvmet_wqfull_process(struct lpfc_hba *phba,
list_remove_head(&wq->wqfull_list, nvmewqeq, struct lpfc_iocbq,
list);
spin_unlock_irqrestore(&pring->ring_lock, iflags);
- ctxp = (struct lpfc_async_xchg_ctx *)nvmewqeq->context2;
+ ctxp = nvmewqeq->context_un.axchg;
rc = lpfc_sli4_issue_wqe(phba, ctxp->hdwq, nvmewqeq);
spin_lock_irqsave(&pring->ring_lock, iflags);
if (rc == -EBUSY) {
@@ -2617,10 +2617,10 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba,
ctxp->wqeq = nvmewqe;
/* prevent preparing wqe with NULL ndlp reference */
- nvmewqe->context1 = lpfc_nlp_get(ndlp);
- if (nvmewqe->context1 == NULL)
+ nvmewqe->ndlp = lpfc_nlp_get(ndlp);
+ if (!nvmewqe->ndlp)
goto nvme_wqe_free_wqeq_exit;
- nvmewqe->context2 = ctxp;
+ nvmewqe->context_un.axchg = ctxp;
wqe = &nvmewqe->wqe;
memset(wqe, 0, sizeof(union lpfc_wqe));
@@ -2692,8 +2692,9 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba,
return nvmewqe;
nvme_wqe_free_wqeq_exit:
- nvmewqe->context2 = NULL;
- nvmewqe->context3 = NULL;
+ nvmewqe->context_un.axchg = NULL;
+ nvmewqe->ndlp = NULL;
+ nvmewqe->bpl_dmabuf = NULL;
lpfc_sli_release_iocbq(phba, nvmewqe);
return NULL;
}
@@ -2995,7 +2996,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba,
nvmewqe->retry = 1;
nvmewqe->vport = phba->pport;
nvmewqe->drvrTimeout = (phba->fc_ratov * 3) + LPFC_DRVR_TIMEOUT;
- nvmewqe->context1 = ndlp;
+ nvmewqe->ndlp = ndlp;
for_each_sg(rsp->sg, sgel, nsegs, i) {
physaddr = sg_dma_address(sgel);
@@ -3053,7 +3054,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
bool released = false;
struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl;
- ctxp = cmdwqe->context2;
+ ctxp = cmdwqe->context_un.axchg;
result = wcqe->parameter;
tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
@@ -3084,8 +3085,8 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
wcqe->word0, wcqe->total_data_placed,
result, wcqe->word3);
- cmdwqe->context2 = NULL;
- cmdwqe->context3 = NULL;
+ cmdwqe->rsp_dmabuf = NULL;
+ cmdwqe->bpl_dmabuf = NULL;
/*
* if transport has released ctx, then can reuse it. Otherwise,
* will be recycled by transport release call.
@@ -3123,7 +3124,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
bool released = false;
struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl;
- ctxp = cmdwqe->context2;
+ ctxp = cmdwqe->context_un.axchg;
result = wcqe->parameter;
if (!ctxp) {
@@ -3169,8 +3170,8 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
wcqe->word0, wcqe->total_data_placed,
result, wcqe->word3);
- cmdwqe->context2 = NULL;
- cmdwqe->context3 = NULL;
+ cmdwqe->rsp_dmabuf = NULL;
+ cmdwqe->bpl_dmabuf = NULL;
/*
* if transport has released ctx, then can reuse it. Otherwise,
* will be recycled by transport release call.
@@ -3203,7 +3204,7 @@ lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
uint32_t result;
struct lpfc_wcqe_complete *wcqe = &rspwqe->wcqe_cmpl;
- ctxp = cmdwqe->context2;
+ ctxp = cmdwqe->context_un.axchg;
result = wcqe->parameter;
if (phba->nvmet_support) {
@@ -3234,8 +3235,8 @@ lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe,
ctxp->oxid, ctxp->state, ctxp->entry_cnt);
}
- cmdwqe->context2 = NULL;
- cmdwqe->context3 = NULL;
+ cmdwqe->rsp_dmabuf = NULL;
+ cmdwqe->bpl_dmabuf = NULL;
lpfc_sli_release_iocbq(phba, cmdwqe);
kfree(ctxp);
}
@@ -3322,9 +3323,9 @@ lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba,
OTHER_COMMAND);
abts_wqeq->vport = phba->pport;
- abts_wqeq->context1 = ndlp;
- abts_wqeq->context2 = ctxp;
- abts_wqeq->context3 = NULL;
+ abts_wqeq->ndlp = ndlp;
+ abts_wqeq->context_un.axchg = ctxp;
+ abts_wqeq->bpl_dmabuf = NULL;
abts_wqeq->num_bdes = 0;
/* hba_wqidx should already be setup from command we are aborting */
abts_wqeq->iocb.ulpCommand = CMD_XMIT_SEQUENCE64_CR;
@@ -3477,7 +3478,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba,
abts_wqeq->hba_wqidx = ctxp->wqeq->hba_wqidx;
abts_wqeq->cmd_cmpl = lpfc_nvmet_sol_fcp_abort_cmp;
abts_wqeq->cmd_flag |= LPFC_IO_NVME;
- abts_wqeq->context2 = ctxp;
+ abts_wqeq->context_un.axchg = ctxp;
abts_wqeq->vport = phba->pport;
if (!ctxp->hdwq)
ctxp->hdwq = &phba->sli4_hba.hdwq[abts_wqeq->hba_wqidx];
@@ -3630,8 +3631,8 @@ lpfc_nvme_unsol_ls_issue_abort(struct lpfc_hba *phba,
out:
if (tgtp)
atomic_inc(&tgtp->xmt_abort_rsp_error);
- abts_wqeq->context2 = NULL;
- abts_wqeq->context3 = NULL;
+ abts_wqeq->rsp_dmabuf = NULL;
+ abts_wqeq->bpl_dmabuf = NULL;
lpfc_sli_release_iocbq(phba, abts_wqeq);
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
"6056 Failed to Issue ABTS. Status x%x\n", rc);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 3c132604fd91..3b8afa9d3056 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -433,7 +433,7 @@ lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc)
iocb->ulpClass = CLASS3;
psb->status = IOSTAT_SUCCESS;
/* Put it back into the SCSI buffer list */
- psb->cur_iocbq.context1 = psb;
+ psb->cur_iocbq.io_buf = psb;
spin_lock_init(&psb->buf_lock);
lpfc_release_scsi_buf_s3(phba, psb);
@@ -3835,7 +3835,7 @@ lpfc_update_cmf_cmpl(struct lpfc_hba *phba,
else
time = div_u64(time + 500, 1000); /* round it */
- cgs = this_cpu_ptr(phba->cmf_stat);
+ cgs = per_cpu_ptr(phba->cmf_stat, raw_smp_processor_id());
atomic64_add(size, &cgs->rcv_bytes);
atomic64_add(time, &cgs->rx_latency);
atomic_inc(&cgs->rx_io_cnt);
@@ -3879,7 +3879,7 @@ lpfc_update_cmf_cmd(struct lpfc_hba *phba, uint32_t size)
atomic_set(&phba->rx_max_read_cnt, size);
}
- cgs = this_cpu_ptr(phba->cmf_stat);
+ cgs = per_cpu_ptr(phba->cmf_stat, raw_smp_processor_id());
atomic64_add(size, &cgs->total_bytes);
return 0;
}
@@ -4082,8 +4082,7 @@ static void
lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
struct lpfc_iocbq *pwqeOut)
{
- struct lpfc_io_buf *lpfc_cmd =
- (struct lpfc_io_buf *)pwqeIn->context1;
+ struct lpfc_io_buf *lpfc_cmd = pwqeIn->io_buf;
struct lpfc_wcqe_complete *wcqe = &pwqeOut->wcqe_cmpl;
struct lpfc_vport *vport = pwqeIn->vport;
struct lpfc_rport_data *rdata;
@@ -4276,6 +4275,7 @@ lpfc_fcp_io_cmd_wqe_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn,
break;
}
if (lpfc_cmd->result == IOERR_INVALID_RPI ||
+ lpfc_cmd->result == IOERR_LINK_DOWN ||
lpfc_cmd->result == IOERR_NO_RESOURCES ||
lpfc_cmd->result == IOERR_ABORT_REQUESTED ||
lpfc_cmd->result == IOERR_RPI_SUSPENDED ||
@@ -4420,7 +4420,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
struct lpfc_iocbq *pIocbOut)
{
struct lpfc_io_buf *lpfc_cmd =
- (struct lpfc_io_buf *) pIocbIn->context1;
+ (struct lpfc_io_buf *) pIocbIn->io_buf;
struct lpfc_vport *vport = pIocbIn->vport;
struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
struct lpfc_nodelist *pnode = rdata->pnode;
@@ -4743,7 +4743,7 @@ static int lpfc_scsi_prep_cmnd_buf_s3(struct lpfc_vport *vport,
piocbq->iocb.ulpFCP2Rcvy = 0;
piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f);
- piocbq->context1 = lpfc_cmd;
+ piocbq->io_buf = lpfc_cmd;
if (!piocbq->cmd_cmpl)
piocbq->cmd_cmpl = lpfc_scsi_cmd_iocb_cmpl;
piocbq->iocb.ulpTimeout = tmo;
@@ -4855,8 +4855,7 @@ static int lpfc_scsi_prep_cmnd_buf_s4(struct lpfc_vport *vport,
bf_set(wqe_reqtag, &wqe->generic.wqe_com, pwqeq->iotag);
pwqeq->vport = vport;
- pwqeq->vport = vport;
- pwqeq->context1 = lpfc_cmd;
+ pwqeq->io_buf = lpfc_cmd;
pwqeq->hba_wqidx = lpfc_cmd->hdwq_no;
pwqeq->cmd_cmpl = lpfc_fcp_io_cmd_wqe_cmpl;
@@ -5097,8 +5096,7 @@ lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba,
struct lpfc_iocbq *cmdiocbq,
struct lpfc_iocbq *rspiocbq)
{
- struct lpfc_io_buf *lpfc_cmd =
- (struct lpfc_io_buf *) cmdiocbq->context1;
+ struct lpfc_io_buf *lpfc_cmd = cmdiocbq->io_buf;
if (lpfc_cmd)
lpfc_release_scsi_buf(phba, lpfc_cmd);
return;
@@ -5346,9 +5344,9 @@ static void lpfc_vmid_update_entry(struct lpfc_vport *vport, struct scsi_cmnd
{
u64 *lta;
- if (vport->vmid_priority_tagging)
+ if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO)
tag->cs_ctl_vmid = vmp->un.cs_ctl_vmid;
- else
+ else if (vport->phba->cfg_vmid_app_header)
tag->app_id = vmp->un.app_id;
if (cmd->sc_data_direction == DMA_TO_DEVICE)
@@ -5393,11 +5391,12 @@ static int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid, struct
scsi_cmnd * cmd, union lpfc_vmid_io_tag *tag)
{
struct lpfc_vmid *vmp = NULL;
- int hash, len, rc, i;
+ int hash, len, rc = -EPERM, i;
/* check if QFPA is complete */
- if (lpfc_vmid_is_type_priority_tag(vport) && !(vport->vmid_flag &
- LPFC_VMID_QFPA_CMPL)) {
+ if (lpfc_vmid_is_type_priority_tag(vport) &&
+ !(vport->vmid_flag & LPFC_VMID_QFPA_CMPL) &&
+ (vport->vmid_flag & LPFC_VMID_ISSUE_QFPA)) {
vport->work_port_events |= WORKER_CHECK_VMID_ISSUE_QFPA;
return -EAGAIN;
}
@@ -5471,7 +5470,7 @@ static int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid, struct
vport->vmid_inactivity_timeout ? 1 : 0;
/* if type priority tag, get next available VMID */
- if (lpfc_vmid_is_type_priority_tag(vport))
+ if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO)
lpfc_vmid_assign_cs_ctl(vport, vmp);
/* allocate the per cpu variable for holding */
@@ -5490,9 +5489,9 @@ static int lpfc_vmid_get_appid(struct lpfc_vport *vport, char *uuid, struct
write_unlock(&vport->vmid_lock);
/* complete transaction with switch */
- if (lpfc_vmid_is_type_priority_tag(vport))
+ if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO)
rc = lpfc_vmid_uvem(vport, vmp, true);
- else
+ else if (vport->phba->cfg_vmid_app_header)
rc = lpfc_vmid_cmd(vport, SLI_CTAS_RAPP_IDENT, vmp);
if (!rc) {
write_lock(&vport->vmid_lock);
@@ -5528,7 +5527,9 @@ static char *lpfc_is_command_vm_io(struct scsi_cmnd *cmd)
{
struct bio *bio = scsi_cmd_to_rq(cmd)->bio;
- return bio ? blkcg_get_fc_appid(bio) : NULL;
+ if (!IS_ENABLED(CONFIG_BLK_CGROUP_FC_APPID) || !bio)
+ return NULL;
+ return blkcg_get_fc_appid(bio);
}
/**
@@ -5864,25 +5865,25 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
if (!lpfc_cmd)
return ret;
- spin_lock_irqsave(&phba->hbalock, flags);
+ /* Guard against IO completion being called at same time */
+ spin_lock_irqsave(&lpfc_cmd->buf_lock, flags);
+
+ spin_lock(&phba->hbalock);
/* driver queued commands are in process of being flushed */
if (phba->hba_flag & HBA_IOQ_FLUSH) {
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
"3168 SCSI Layer abort requested I/O has been "
"flushed by LLD.\n");
ret = FAILED;
- goto out_unlock;
+ goto out_unlock_hba;
}
- /* Guard against IO completion being called at same time */
- spin_lock(&lpfc_cmd->buf_lock);
-
if (!lpfc_cmd->pCmd) {
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
"2873 SCSI Layer I/O Abort Request IO CMPL Status "
"x%x ID %d LUN %llu\n",
SUCCESS, cmnd->device->id, cmnd->device->lun);
- goto out_unlock_buf;
+ goto out_unlock_hba;
}
iocb = &lpfc_cmd->cur_iocbq;
@@ -5890,7 +5891,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
pring_s4 = phba->sli4_hba.hdwq[iocb->hba_wqidx].io_wq->pring;
if (!pring_s4) {
ret = FAILED;
- goto out_unlock_buf;
+ goto out_unlock_hba;
}
spin_lock(&pring_s4->ring_lock);
}
@@ -5915,7 +5916,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
goto out_unlock_ring;
}
- BUG_ON(iocb->context1 != lpfc_cmd);
+ WARN_ON(iocb->io_buf != lpfc_cmd);
/* abort issued in recovery is still in progress */
if (iocb->cmd_flag & LPFC_DRIVER_ABORTED) {
@@ -5923,19 +5924,21 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
"3389 SCSI Layer I/O Abort Request is pending\n");
if (phba->sli_rev == LPFC_SLI_REV4)
spin_unlock(&pring_s4->ring_lock);
- spin_unlock(&lpfc_cmd->buf_lock);
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_unlock(&phba->hbalock);
+ spin_unlock_irqrestore(&lpfc_cmd->buf_lock, flags);
goto wait_for_cmpl;
}
lpfc_cmd->waitq = &waitq;
- if (phba->sli_rev == LPFC_SLI_REV4)
+ if (phba->sli_rev == LPFC_SLI_REV4) {
spin_unlock(&pring_s4->ring_lock);
- else
+ ret_val = lpfc_sli4_issue_abort_iotag(phba, iocb,
+ lpfc_sli_abort_fcp_cmpl);
+ } else {
pring = &phba->sli.sli3_ring[LPFC_FCP_RING];
-
- ret_val = lpfc_sli_issue_abort_iotag(phba, pring, iocb,
- lpfc_sli_abort_fcp_cmpl);
+ ret_val = lpfc_sli_issue_abort_iotag(phba, pring, iocb,
+ lpfc_sli_abort_fcp_cmpl);
+ }
/* Make sure HBA is alive */
lpfc_issue_hb_tmo(phba);
@@ -5943,15 +5946,13 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
if (ret_val != IOCB_SUCCESS) {
/* Indicate the IO is not being aborted by the driver. */
lpfc_cmd->waitq = NULL;
- spin_unlock(&lpfc_cmd->buf_lock);
- spin_unlock_irqrestore(&phba->hbalock, flags);
ret = FAILED;
- goto out;
+ goto out_unlock_hba;
}
/* no longer need the lock after this point */
- spin_unlock(&lpfc_cmd->buf_lock);
- spin_unlock_irqrestore(&phba->hbalock, flags);
+ spin_unlock(&phba->hbalock);
+ spin_unlock_irqrestore(&lpfc_cmd->buf_lock, flags);
if (phba->cfg_poll & DISABLE_FCP_RING_INT)
lpfc_sli_handle_fast_ring_event(phba,
@@ -5986,10 +5987,9 @@ wait_for_cmpl:
out_unlock_ring:
if (phba->sli_rev == LPFC_SLI_REV4)
spin_unlock(&pring_s4->ring_lock);
-out_unlock_buf:
- spin_unlock(&lpfc_cmd->buf_lock);
-out_unlock:
- spin_unlock_irqrestore(&phba->hbalock, flags);
+out_unlock_hba:
+ spin_unlock(&phba->hbalock);
+ spin_unlock_irqrestore(&lpfc_cmd->buf_lock, flags);
out:
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
"0749 SCSI Layer I/O Abort Request Status x%x ID %d "
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 20d40957a385..6ed696c4602a 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -1254,19 +1254,19 @@ __lpfc_sli_get_els_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq)
cmnd = get_job_cmnd(phba, piocbq);
- if (piocbq->cmd_flag & LPFC_IO_FCP) {
- lpfc_cmd = (struct lpfc_io_buf *) piocbq->context1;
+ if (piocbq->cmd_flag & LPFC_IO_FCP) {
+ lpfc_cmd = piocbq->io_buf;
ndlp = lpfc_cmd->rdata->pnode;
} else if ((cmnd == CMD_GEN_REQUEST64_CR) &&
!(piocbq->cmd_flag & LPFC_IO_LIBDFC)) {
- ndlp = piocbq->context_un.ndlp;
+ ndlp = piocbq->ndlp;
} else if (piocbq->cmd_flag & LPFC_IO_LIBDFC) {
if (piocbq->cmd_flag & LPFC_IO_LOOPBACK)
ndlp = NULL;
else
- ndlp = piocbq->context_un.ndlp;
+ ndlp = piocbq->ndlp;
} else {
- ndlp = piocbq->context1;
+ ndlp = piocbq->ndlp;
}
spin_lock(&phba->sli4_hba.sgl_list_lock);
@@ -1373,7 +1373,7 @@ static void
__lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
struct lpfc_sglq *sglq;
- size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
+ size_t start_clean = offsetof(struct lpfc_iocbq, wqe);
unsigned long iflag = 0;
struct lpfc_sli_ring *pring;
@@ -1996,9 +1996,9 @@ initpath:
sync_buf->vport = phba->pport;
sync_buf->cmd_cmpl = lpfc_cmf_sync_cmpl;
- sync_buf->context1 = NULL;
- sync_buf->context2 = NULL;
- sync_buf->context3 = NULL;
+ sync_buf->cmd_dmabuf = NULL;
+ sync_buf->rsp_dmabuf = NULL;
+ sync_buf->bpl_dmabuf = NULL;
sync_buf->sli4_xritag = NO_XRI;
sync_buf->cmd_flag |= LPFC_IO_CMF;
@@ -2828,6 +2828,12 @@ __lpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
ndlp->nlp_flag &= ~NLP_UNREG_INP;
}
+void
+lpfc_sli_rpi_release(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+{
+ __lpfc_sli_rpi_release(vport, ndlp);
+}
+
/**
* lpfc_sli_def_mbox_cmpl - Default mailbox completion handler
* @phba: Pointer to HBA context object.
@@ -2842,19 +2848,11 @@ void
lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_vport *vport = pmb->vport;
- struct lpfc_dmabuf *mp;
struct lpfc_nodelist *ndlp;
struct Scsi_Host *shost;
uint16_t rpi, vpi;
int rc;
- mp = (struct lpfc_dmabuf *)(pmb->ctx_buf);
-
- if (mp) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- }
-
/*
* If a REG_LOGIN succeeded after node is destroyed or node
* is in re-discovery driver need to cleanup the RPI.
@@ -2887,8 +2885,6 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
if (pmb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
ndlp = (struct lpfc_nodelist *)pmb->ctx_ndlp;
lpfc_nlp_put(ndlp);
- pmb->ctx_buf = NULL;
- pmb->ctx_ndlp = NULL;
}
if (pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) {
@@ -2939,7 +2935,7 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
if (bf_get(lpfc_mqe_command, &pmb->u.mqe) == MBX_SLI4_CONFIG)
lpfc_sli4_mbox_cmd_free(phba, pmb);
else
- mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
}
/**
* lpfc_sli4_unreg_rpi_cmpl_clr - mailbox completion handler
@@ -3191,7 +3187,7 @@ lpfc_nvme_unsol_ls_handler(struct lpfc_hba *phba, struct lpfc_iocbq *piocb)
uint32_t oxid, sid, did, fctl, size;
int ret = 1;
- d_buf = piocb->context2;
+ d_buf = piocb->cmd_dmabuf;
nvmebuf = container_of(d_buf, struct hbq_dmabuf, dbuf);
fc_hdr = nvmebuf->hbuf.virt;
@@ -3472,9 +3468,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
if (irsp->ulpBdeCount != 0) {
- saveq->context2 = lpfc_sli_get_buff(phba, pring,
+ saveq->cmd_dmabuf = lpfc_sli_get_buff(phba, pring,
irsp->un.ulpWord[3]);
- if (!saveq->context2)
+ if (!saveq->cmd_dmabuf)
lpfc_printf_log(phba,
KERN_ERR,
LOG_SLI,
@@ -3484,9 +3480,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
irsp->un.ulpWord[3]);
}
if (irsp->ulpBdeCount == 2) {
- saveq->context3 = lpfc_sli_get_buff(phba, pring,
+ saveq->bpl_dmabuf = lpfc_sli_get_buff(phba, pring,
irsp->unsli3.sli3Words[7]);
- if (!saveq->context3)
+ if (!saveq->bpl_dmabuf)
lpfc_printf_log(phba,
KERN_ERR,
LOG_SLI,
@@ -3498,10 +3494,10 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
list_for_each_entry(iocbq, &saveq->list, list) {
irsp = &iocbq->iocb;
if (irsp->ulpBdeCount != 0) {
- iocbq->context2 = lpfc_sli_get_buff(phba,
+ iocbq->cmd_dmabuf = lpfc_sli_get_buff(phba,
pring,
irsp->un.ulpWord[3]);
- if (!iocbq->context2)
+ if (!iocbq->cmd_dmabuf)
lpfc_printf_log(phba,
KERN_ERR,
LOG_SLI,
@@ -3511,10 +3507,10 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
irsp->un.ulpWord[3]);
}
if (irsp->ulpBdeCount == 2) {
- iocbq->context3 = lpfc_sli_get_buff(phba,
+ iocbq->bpl_dmabuf = lpfc_sli_get_buff(phba,
pring,
irsp->unsli3.sli3Words[7]);
- if (!iocbq->context3)
+ if (!iocbq->bpl_dmabuf)
lpfc_printf_log(phba,
KERN_ERR,
LOG_SLI,
@@ -3528,12 +3524,12 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
} else {
paddr = getPaddr(irsp->un.cont64[0].addrHigh,
irsp->un.cont64[0].addrLow);
- saveq->context2 = lpfc_sli_ringpostbuf_get(phba, pring,
+ saveq->cmd_dmabuf = lpfc_sli_ringpostbuf_get(phba, pring,
paddr);
if (irsp->ulpBdeCount == 2) {
paddr = getPaddr(irsp->un.cont64[1].addrHigh,
irsp->un.cont64[1].addrLow);
- saveq->context3 = lpfc_sli_ringpostbuf_get(phba,
+ saveq->bpl_dmabuf = lpfc_sli_ringpostbuf_get(phba,
pring,
paddr);
}
@@ -3711,11 +3707,18 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *saveq)
{
struct lpfc_iocbq *cmdiocbp;
- int rc = 1;
unsigned long iflag;
u32 ulp_command, ulp_status, ulp_word4, ulp_context, iotag;
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_lock_irqsave(&pring->ring_lock, iflag);
+ else
+ spin_lock_irqsave(&phba->hbalock, iflag);
cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ spin_unlock_irqrestore(&pring->ring_lock, iflag);
+ else
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
ulp_command = get_job_cmnd(phba, saveq);
ulp_status = get_job_ulpstatus(phba, saveq);
@@ -3843,7 +3846,7 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
}
- return rc;
+ return 1;
}
/**
@@ -4052,10 +4055,8 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
break;
}
- spin_unlock_irqrestore(&phba->hbalock, iflag);
cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring,
&rspiocbq);
- spin_lock_irqsave(&phba->hbalock, iflag);
if (unlikely(!cmdiocbq))
break;
if (cmdiocbq->cmd_flag & LPFC_DRIVER_ABORTED)
@@ -4536,42 +4537,62 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba,
void
lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
- LIST_HEAD(completions);
+ LIST_HEAD(tx_completions);
+ LIST_HEAD(txcmplq_completions);
struct lpfc_iocbq *iocb, *next_iocb;
+ int offline;
if (pring->ringno == LPFC_ELS_RING) {
lpfc_fabric_abort_hba(phba);
}
+ offline = pci_channel_offline(phba->pcidev);
/* Error everything on txq and txcmplq
* First do the txq.
*/
if (phba->sli_rev >= LPFC_SLI_REV4) {
spin_lock_irq(&pring->ring_lock);
- list_splice_init(&pring->txq, &completions);
+ list_splice_init(&pring->txq, &tx_completions);
pring->txq_cnt = 0;
- spin_unlock_irq(&pring->ring_lock);
- spin_lock_irq(&phba->hbalock);
- /* Next issue ABTS for everything on the txcmplq */
- list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
- lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL);
- spin_unlock_irq(&phba->hbalock);
+ if (offline) {
+ list_splice_init(&pring->txcmplq,
+ &txcmplq_completions);
+ } else {
+ /* Next issue ABTS for everything on the txcmplq */
+ list_for_each_entry_safe(iocb, next_iocb,
+ &pring->txcmplq, list)
+ lpfc_sli_issue_abort_iotag(phba, pring,
+ iocb, NULL);
+ }
+ spin_unlock_irq(&pring->ring_lock);
} else {
spin_lock_irq(&phba->hbalock);
- list_splice_init(&pring->txq, &completions);
+ list_splice_init(&pring->txq, &tx_completions);
pring->txq_cnt = 0;
- /* Next issue ABTS for everything on the txcmplq */
- list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
- lpfc_sli_issue_abort_iotag(phba, pring, iocb, NULL);
+ if (offline) {
+ list_splice_init(&pring->txcmplq, &txcmplq_completions);
+ } else {
+ /* Next issue ABTS for everything on the txcmplq */
+ list_for_each_entry_safe(iocb, next_iocb,
+ &pring->txcmplq, list)
+ lpfc_sli_issue_abort_iotag(phba, pring,
+ iocb, NULL);
+ }
spin_unlock_irq(&phba->hbalock);
}
- /* Make sure HBA is alive */
- lpfc_issue_hb_tmo(phba);
+ if (offline) {
+ /* Cancel all the IOCBs from the completions list */
+ lpfc_sli_cancel_iocbs(phba, &txcmplq_completions,
+ IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED);
+ } else {
+ /* Make sure HBA is alive */
+ lpfc_issue_hb_tmo(phba);
+ }
/* Cancel all the IOCBs from the completions list */
- lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
+ lpfc_sli_cancel_iocbs(phba, &tx_completions, IOSTAT_LOCAL_REJECT,
IOERR_SLI_ABORTED);
}
@@ -4624,11 +4645,6 @@ lpfc_sli_flush_io_rings(struct lpfc_hba *phba)
struct lpfc_iocbq *piocb, *next_iocb;
spin_lock_irq(&phba->hbalock);
- if (phba->hba_flag & HBA_IOQ_FLUSH ||
- !phba->sli4_hba.hdwq) {
- spin_unlock_irq(&phba->hbalock);
- return;
- }
/* Indicate the I/O queues are flushed */
phba->hba_flag |= HBA_IOQ_FLUSH;
spin_unlock_irq(&phba->hbalock);
@@ -5248,6 +5264,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
phba->pport->stopped = 0;
phba->link_state = LPFC_INIT_START;
phba->hba_flag = 0;
+ phba->sli4_hba.fawwpn_flag = 0;
spin_unlock_irq(&phba->hbalock);
memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
@@ -5824,26 +5841,20 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba)
mboxq->mcqe.trailer);
if (rc) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
rc = -EIO;
goto out_free_mboxq;
}
data_length = mqe->un.mb_words[5];
if (data_length > DMP_RGN23_SIZE) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
rc = -EIO;
goto out_free_mboxq;
}
lpfc_parse_fcoe_conf(phba, mp->virt, data_length);
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
rc = 0;
out_free_mboxq:
- mempool_free(mboxq, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, mboxq, MBOX_THD_UNLOCKED);
return rc;
}
@@ -7967,10 +7978,6 @@ lpfc_cmf_setup(struct lpfc_hba *phba)
sli4_params = &phba->sli4_hba.pc_sli4_params;
- /* Are we forcing MI off via module parameter? */
- if (!phba->cfg_enable_mi)
- sli4_params->mi_ver = 0;
-
/* Always try to enable MI feature if we can */
if (sli4_params->mi_ver) {
lpfc_set_features(phba, mboxq, LPFC_SET_ENABLE_MI);
@@ -8516,8 +8523,9 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
}
/*
- * This memory was allocated by the lpfc_read_sparam routine. Release
- * it to the mbuf pool.
+ * This memory was allocated by the lpfc_read_sparam routine but is
+ * no longer needed. It is released and ctx_buf NULLed to prevent
+ * unintended pointer access as the mbox is reused.
*/
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
@@ -8837,6 +8845,9 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
}
mempool_free(mboxq, phba->mbox_mem_pool);
+ /* Enable RAS FW log support */
+ lpfc_sli4_ras_setup(phba);
+
phba->hba_flag |= HBA_SETUP;
return rc;
@@ -10316,8 +10327,7 @@ __lpfc_sli_issue_fcp_io_s4(struct lpfc_hba *phba, uint32_t ring_number,
struct lpfc_iocbq *piocb, uint32_t flag)
{
int rc;
- struct lpfc_io_buf *lpfc_cmd =
- (struct lpfc_io_buf *)piocb->context1;
+ struct lpfc_io_buf *lpfc_cmd = piocb->io_buf;
lpfc_prep_embed_io(phba, lpfc_cmd);
rc = lpfc_sli4_issue_wqe(phba, lpfc_cmd->hdwq, piocb);
@@ -10367,11 +10377,11 @@ lpfc_prep_embed_io(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
/* add the VMID tags as per switch response */
if (unlikely(piocb->cmd_flag & LPFC_IO_VMID)) {
- if (phba->pport->vmid_priority_tagging) {
+ if (phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) {
bf_set(wqe_ccpe, &wqe->fcp_iwrite.wqe_com, 1);
bf_set(wqe_ccp, &wqe->fcp_iwrite.wqe_com,
(piocb->vmid_tag.cs_ctl_vmid));
- } else {
+ } else if (phba->cfg_vmid_app_header) {
bf_set(wqe_appid, &wqe->fcp_iwrite.wqe_com, 1);
bf_set(wqe_wqes, &wqe->fcp_iwrite.wqe_com, 1);
wqe->words[31] = piocb->vmid_tag.app_id;
@@ -10572,6 +10582,7 @@ __lpfc_sli_prep_els_req_rsp_s4(struct lpfc_iocbq *cmdiocbq,
struct lpfc_hba *phba = vport->phba;
union lpfc_wqe128 *wqe;
struct ulp_bde64_le *bde;
+ u8 els_id;
wqe = &cmdiocbq->wqe;
memset(wqe, 0, sizeof(*wqe));
@@ -10584,7 +10595,7 @@ __lpfc_sli_prep_els_req_rsp_s4(struct lpfc_iocbq *cmdiocbq,
bde->type_size |= cpu_to_le32(ULP_BDE64_TYPE_BDE_64);
if (expect_rsp) {
- bf_set(wqe_cmnd, &wqe->els_req.wqe_com, CMD_ELS_REQUEST64_CR);
+ bf_set(wqe_cmnd, &wqe->els_req.wqe_com, CMD_ELS_REQUEST64_WQE);
/* Transfer length */
wqe->els_req.payload_len = cmd_size;
@@ -10592,6 +10603,30 @@ __lpfc_sli_prep_els_req_rsp_s4(struct lpfc_iocbq *cmdiocbq,
/* DID */
bf_set(wqe_els_did, &wqe->els_req.wqe_dest, did);
+
+ /* Word 11 - ELS_ID */
+ switch (elscmd) {
+ case ELS_CMD_PLOGI:
+ els_id = LPFC_ELS_ID_PLOGI;
+ break;
+ case ELS_CMD_FLOGI:
+ els_id = LPFC_ELS_ID_FLOGI;
+ break;
+ case ELS_CMD_LOGO:
+ els_id = LPFC_ELS_ID_LOGO;
+ break;
+ case ELS_CMD_FDISC:
+ if (!vport->fc_myDID) {
+ els_id = LPFC_ELS_ID_FDISC;
+ break;
+ }
+ fallthrough;
+ default:
+ els_id = LPFC_ELS_ID_DEFAULT;
+ break;
+ }
+
+ bf_set(wqe_els_id, &wqe->els_req.wqe_com, els_id);
} else {
/* DID */
bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest, did);
@@ -10600,7 +10635,7 @@ __lpfc_sli_prep_els_req_rsp_s4(struct lpfc_iocbq *cmdiocbq,
wqe->xmit_els_rsp.response_payload_len = cmd_size;
bf_set(wqe_cmnd, &wqe->xmit_els_rsp.wqe_com,
- CMD_XMIT_ELS_RSP64_CX);
+ CMD_XMIT_ELS_RSP64_WQE);
}
bf_set(wqe_tmo, &wqe->generic.wqe_com, tmo);
@@ -10616,7 +10651,7 @@ __lpfc_sli_prep_els_req_rsp_s4(struct lpfc_iocbq *cmdiocbq,
if (expect_rsp) {
bf_set(els_req64_sid, &wqe->els_req, vport->fc_myDID);
- /* For ELS_REQUEST64_CR, use the VPI by default */
+ /* For ELS_REQUEST64_WQE, use the VPI by default */
bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com,
phba->vpi_ids[vport->vpi]);
}
@@ -10693,10 +10728,10 @@ __lpfc_sli_prep_gen_req_s4(struct lpfc_iocbq *cmdiocbq, struct lpfc_dmabuf *bmp,
/* Words 0 - 2 */
bde = (struct ulp_bde64_le *)&cmdwqe->generic.bde;
- bde->addr_low = cpu_to_le32(putPaddrLow(bmp->phys));
- bde->addr_high = cpu_to_le32(putPaddrHigh(bmp->phys));
+ bde->addr_low = bpl->addr_low;
+ bde->addr_high = bpl->addr_high;
bde->type_size = cpu_to_le32(xmit_len);
- bde->type_size |= cpu_to_le32(ULP_BDE64_TYPE_BLP_64);
+ bde->type_size |= cpu_to_le32(ULP_BDE64_TYPE_BDE_64);
/* Word 3 */
cmdwqe->gen_req.request_payload_len = xmit_len;
@@ -10773,24 +10808,15 @@ __lpfc_sli_prep_xmit_seq64_s4(struct lpfc_iocbq *cmdiocbq,
{
union lpfc_wqe128 *wqe;
struct ulp_bde64 *bpl;
- struct ulp_bde64_le *bde;
wqe = &cmdiocbq->wqe;
memset(wqe, 0, sizeof(*wqe));
/* Words 0 - 2 */
bpl = (struct ulp_bde64 *)bmp->virt;
- if (cmdiocbq->cmd_flag & (LPFC_IO_LIBDFC | LPFC_IO_LOOPBACK)) {
- wqe->xmit_sequence.bde.addrHigh = bpl->addrHigh;
- wqe->xmit_sequence.bde.addrLow = bpl->addrLow;
- wqe->xmit_sequence.bde.tus.w = bpl->tus.w;
- } else {
- bde = (struct ulp_bde64_le *)&wqe->xmit_sequence.bde;
- bde->addr_low = cpu_to_le32(putPaddrLow(bmp->phys));
- bde->addr_high = cpu_to_le32(putPaddrHigh(bmp->phys));
- bde->type_size = cpu_to_le32(bpl->tus.f.bdeSize);
- bde->type_size |= cpu_to_le32(ULP_BDE64_TYPE_BDE_64);
- }
+ wqe->xmit_sequence.bde.addrHigh = bpl->addrHigh;
+ wqe->xmit_sequence.bde.addrLow = bpl->addrLow;
+ wqe->xmit_sequence.bde.tus.w = bpl->tus.w;
/* Word 5 */
bf_set(wqe_ls, &wqe->xmit_sequence.wge_ctl, last_seq);
@@ -10963,7 +10989,7 @@ lpfc_sli4_calc_ring(struct lpfc_hba *phba, struct lpfc_iocbq *piocb)
* be setup based on what work queue we used.
*/
if (!(piocb->cmd_flag & LPFC_USE_FCPWQIDX)) {
- lpfc_cmd = (struct lpfc_io_buf *)piocb->context1;
+ lpfc_cmd = piocb->io_buf;
piocb->hba_wqidx = lpfc_cmd->hdwq_no;
}
return phba->sli4_hba.hdwq[piocb->hba_wqidx].io_wq->pring;
@@ -10997,6 +11023,10 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
unsigned long iflags;
int rc;
+ /* If the PCI channel is in offline state, do not post iocbs. */
+ if (unlikely(pci_channel_offline(phba->pcidev)))
+ return IOCB_ERROR;
+
if (phba->sli_rev == LPFC_SLI_REV4) {
lpfc_sli_prep_wqe(phba, piocb);
@@ -12033,8 +12063,9 @@ void
lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
- struct lpfc_nodelist *ndlp = NULL;
+ struct lpfc_nodelist *ndlp = cmdiocb->ndlp;
IOCB_t *irsp;
+ LPFC_MBOXQ_t *mbox;
u32 ulp_command, ulp_status, ulp_word4, iotag;
ulp_command = get_job_cmnd(phba, cmdiocb);
@@ -12046,25 +12077,32 @@ lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
} else {
irsp = &rspiocb->iocb;
iotag = irsp->ulpIoTag;
+
+ /* It is possible a PLOGI_RJT for NPIV ports to get aborted.
+ * The MBX_REG_LOGIN64 mbox command is freed back to the
+ * mbox_mem_pool here.
+ */
+ if (cmdiocb->context_un.mbox) {
+ mbox = cmdiocb->context_un.mbox;
+ lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED);
+ cmdiocb->context_un.mbox = NULL;
+ }
}
/* ELS cmd tag <ulpIoTag> completes */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
"0139 Ignoring ELS cmd code x%x completion Data: "
- "x%x x%x x%x\n",
- ulp_command, ulp_status, ulp_word4, iotag);
-
+ "x%x x%x x%x x%px\n",
+ ulp_command, ulp_status, ulp_word4, iotag,
+ cmdiocb->ndlp);
/*
* Deref the ndlp after free_iocb. sli_release_iocb will access the ndlp
* if exchange is busy.
*/
- if (ulp_command == CMD_GEN_REQUEST64_CR) {
- ndlp = cmdiocb->context_un.ndlp;
+ if (ulp_command == CMD_GEN_REQUEST64_CR)
lpfc_ct_free_iocb(phba, cmdiocb);
- } else {
- ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ else
lpfc_els_free_iocb(phba, cmdiocb);
- }
lpfc_nlp_put(ndlp);
}
@@ -12145,7 +12183,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
} else {
iotag = cmdiocb->iocb.ulpIoTag;
if (pring->ringno == LPFC_ELS_RING) {
- ndlp = (struct lpfc_nodelist *)(cmdiocb->context1);
+ ndlp = cmdiocb->ndlp;
ulp_context = ndlp->nlp_rpi;
} else {
ulp_context = cmdiocb->iocb.ulpContext;
@@ -12154,7 +12192,8 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (phba->link_state < LPFC_LINK_UP ||
(phba->sli_rev == LPFC_SLI_REV4 &&
- phba->sli4_hba.link_state.status == LPFC_FC_LA_TYPE_LINK_DOWN))
+ phba->sli4_hba.link_state.status == LPFC_FC_LA_TYPE_LINK_DOWN) ||
+ (phba->link_flag & LS_EXTERNAL_LOOPBACK))
ia = true;
else
ia = false;
@@ -12603,7 +12642,7 @@ lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
} else {
iotag = iocbq->iocb.ulpIoTag;
if (pring->ringno == LPFC_ELS_RING) {
- ndlp = (struct lpfc_nodelist *)(iocbq->context1);
+ ndlp = iocbq->ndlp;
ulp_context = ndlp->nlp_rpi;
} else {
ulp_context = iocbq->iocb.ulpContext;
@@ -12613,7 +12652,8 @@ lpfc_sli_abort_taskmgmt(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
ndlp = lpfc_cmd->rdata->pnode;
if (lpfc_is_link_up(phba) &&
- (ndlp && ndlp->nlp_state == NLP_STE_MAPPED_NODE))
+ (ndlp && ndlp->nlp_state == NLP_STE_MAPPED_NODE) &&
+ !(phba->link_flag & LS_EXTERNAL_LOOPBACK))
ia = false;
else
ia = true;
@@ -12708,8 +12748,8 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
/* Copy the contents of the local rspiocb into the caller's buffer. */
cmdiocbq->cmd_flag |= LPFC_IO_WAKE;
- if (cmdiocbq->context2 && rspiocbq)
- memcpy((char *)cmdiocbq->context2 + offset,
+ if (cmdiocbq->rsp_iocb && rspiocbq)
+ memcpy((char *)cmdiocbq->rsp_iocb + offset,
(char *)rspiocbq + offset, sizeof(*rspiocbq) - offset);
/* Set the exchange busy flag for task management commands */
@@ -12817,13 +12857,13 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
} else
pring = &phba->sli.sli3_ring[ring_number];
/*
- * If the caller has provided a response iocbq buffer, then context2
+ * If the caller has provided a response iocbq buffer, then rsp_iocb
* is NULL or its an error.
*/
if (prspiocbq) {
- if (piocb->context2)
+ if (piocb->rsp_iocb)
return IOCB_ERROR;
- piocb->context2 = prspiocbq;
+ piocb->rsp_iocb = prspiocbq;
}
piocb->wait_cmd_cmpl = piocb->cmd_cmpl;
@@ -12907,7 +12947,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
}
if (prspiocbq)
- piocb->context2 = NULL;
+ piocb->rsp_iocb = NULL;
piocb->context_un.wait_queue = NULL;
piocb->cmd_cmpl = NULL;
@@ -15701,7 +15741,6 @@ lpfc_modify_hba_eq_delay(struct lpfc_hba *phba, uint32_t startq,
mbox->vport = phba->pport;
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->ctx_buf = NULL;
mbox->ctx_ndlp = NULL;
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
shdr = (union lpfc_sli4_cfg_shdr *) &eq_delay->header.cfg_shdr;
@@ -18076,7 +18115,6 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr)
case FC_RCTL_ELS_REP: /* extended link services reply */
case FC_RCTL_ELS4_REQ: /* FC-4 ELS request */
case FC_RCTL_ELS4_REP: /* FC-4 ELS reply */
- case FC_RCTL_BA_NOP: /* basic link service NOP */
case FC_RCTL_BA_ABTS: /* basic link service abort */
case FC_RCTL_BA_RMC: /* remove connection */
case FC_RCTL_BA_ACC: /* basic accept */
@@ -18097,6 +18135,7 @@ lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr)
fc_vft_hdr = (struct fc_vft_header *)fc_hdr;
fc_hdr = &((struct fc_frame_header *)fc_vft_hdr)[1];
return lpfc_fc_frame_check(phba, fc_hdr);
+ case FC_RCTL_BA_NOP: /* basic link service NOP */
default:
goto drop;
}
@@ -18481,11 +18520,8 @@ lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba,
struct lpfc_iocbq *cmd_iocbq,
struct lpfc_iocbq *rsp_iocbq)
{
- struct lpfc_nodelist *ndlp;
-
if (cmd_iocbq) {
- ndlp = (struct lpfc_nodelist *)cmd_iocbq->context1;
- lpfc_nlp_put(ndlp);
+ lpfc_nlp_put(cmd_iocbq->ndlp);
lpfc_sli_release_iocbq(phba, cmd_iocbq);
}
@@ -18569,8 +18605,8 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport,
/* Extract the F_CTL field from FC_HDR */
fctl = sli4_fctl_from_fc_hdr(fc_hdr);
- ctiocb->context1 = lpfc_nlp_get(ndlp);
- if (!ctiocb->context1) {
+ ctiocb->ndlp = lpfc_nlp_get(ndlp);
+ if (!ctiocb->ndlp) {
lpfc_sli_release_iocbq(phba, ctiocb);
return;
}
@@ -18646,13 +18682,11 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport,
phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
bf_set(wqe_cmnd, &icmd->generic.wqe_com, CMD_XMIT_BLS_RSP64_CX);
-
/* Xmit CT abts response on exchange <xid> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"1200 Send BLS cmd x%x on oxid x%x Data: x%x\n",
ctiocb->abort_rctl, oxid, phba->link_state);
- lpfc_sli_prep_wqe(phba, ctiocb);
rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0);
if (rc == IOCB_ERROR) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
@@ -18661,7 +18695,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_vport *vport,
ctiocb->abort_rctl, oxid,
phba->link_state);
lpfc_nlp_put(ndlp);
- ctiocb->context1 = NULL;
+ ctiocb->ndlp = NULL;
lpfc_sli_release_iocbq(phba, ctiocb);
}
}
@@ -18813,8 +18847,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
tot_len = bf_get(lpfc_rcqe_length,
&seq_dmabuf->cq_event.cqe.rcqe_cmpl);
- first_iocbq->context2 = &seq_dmabuf->dbuf;
- first_iocbq->context3 = NULL;
+ first_iocbq->cmd_dmabuf = &seq_dmabuf->dbuf;
+ first_iocbq->bpl_dmabuf = NULL;
/* Keep track of the BDE count */
first_iocbq->wcqe_cmpl.word3 = 1;
@@ -18838,8 +18872,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
lpfc_in_buf_free(vport->phba, d_buf);
continue;
}
- if (!iocbq->context3) {
- iocbq->context3 = d_buf;
+ if (!iocbq->bpl_dmabuf) {
+ iocbq->bpl_dmabuf = d_buf;
iocbq->wcqe_cmpl.word3++;
/* We need to get the size out of the right CQE */
hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
@@ -18865,8 +18899,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf)
hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
len = bf_get(lpfc_rcqe_length,
&hbq_buf->cq_event.cqe.rcqe_cmpl);
- iocbq->context2 = d_buf;
- iocbq->context3 = NULL;
+ iocbq->cmd_dmabuf = d_buf;
+ iocbq->bpl_dmabuf = NULL;
iocbq->wcqe_cmpl.word3 = 1;
if (len > LPFC_DATA_BUF_SIZE)
@@ -18911,12 +18945,14 @@ lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *vport,
if (!lpfc_complete_unsol_iocb(phba,
phba->sli4_hba.els_wq->pring,
iocbq, fc_hdr->fh_r_ctl,
- fc_hdr->fh_type))
+ fc_hdr->fh_type)) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
"2540 Ring %d handler: unexpected Rctl "
"x%x Type x%x received\n",
LPFC_ELS_RING,
fc_hdr->fh_r_ctl, fc_hdr->fh_type);
+ lpfc_in_buf_free(phba, &seq_dmabuf->dbuf);
+ }
/* Free iocb created in lpfc_prep_seq */
list_for_each_entry_safe(curr_iocb, next_iocb,
@@ -18931,7 +18967,7 @@ static void
lpfc_sli4_mds_loopback_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
- struct lpfc_dmabuf *pcmd = cmdiocb->context2;
+ struct lpfc_dmabuf *pcmd = cmdiocb->cmd_dmabuf;
if (pcmd && pcmd->virt)
dma_pool_free(phba->lpfc_drb_pool, pcmd->virt, pcmd->phys);
@@ -18982,7 +19018,7 @@ lpfc_sli4_handle_mds_loopback(struct lpfc_vport *vport,
/* copyin the payload */
memcpy(pcmd->virt, dmabuf->dbuf.virt, frame_len);
- iocbq->context2 = pcmd;
+ iocbq->cmd_dmabuf = pcmd;
iocbq->vport = vport;
iocbq->cmd_flag &= ~LPFC_FIP_ELS_ID_MASK;
iocbq->cmd_flag |= LPFC_USE_FCPWQIDX;
@@ -20301,11 +20337,7 @@ lpfc_sli4_get_config_region23(struct lpfc_hba *phba, char *rgn23_data)
}
lpfc_sli_pcimem_bcopy((char *)mp->virt, rgn23_data, data_length);
out:
- mempool_free(mboxq, phba->mbox_mem_pool);
- if (mp) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- }
+ lpfc_mbox_rsrc_cleanup(phba, mboxq, MBOX_THD_UNLOCKED);
return data_length;
}
@@ -20620,7 +20652,6 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
{
struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *mb, *nextmb;
- struct lpfc_dmabuf *mp;
struct lpfc_nodelist *ndlp;
struct lpfc_nodelist *act_mbx_ndlp = NULL;
LIST_HEAD(mbox_cmd_list);
@@ -20646,8 +20677,12 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
act_mbx_ndlp = (struct lpfc_nodelist *)mb->ctx_ndlp;
- /* Put reference count for delayed processing */
+
+ /* This reference is local to this routine. The
+ * reference is removed at routine exit.
+ */
act_mbx_ndlp = lpfc_nlp_get(act_mbx_ndlp);
+
/* Unregister the RPI when mailbox complete */
mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
}
@@ -20690,12 +20725,6 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
while (!list_empty(&mbox_cmd_list)) {
list_remove_head(&mbox_cmd_list, mb, LPFC_MBOXQ_t, list);
if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
- mp = (struct lpfc_dmabuf *)(mb->ctx_buf);
- if (mp) {
- __lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- }
- mb->ctx_buf = NULL;
ndlp = (struct lpfc_nodelist *)mb->ctx_ndlp;
mb->ctx_ndlp = NULL;
if (ndlp) {
@@ -20705,7 +20734,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
lpfc_nlp_put(ndlp);
}
}
- mempool_free(mb, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, mb, MBOX_THD_UNLOCKED);
}
/* Release the ndlp with the cleaned-up active mailbox command */
@@ -20857,8 +20886,8 @@ lpfc_wqe_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeq,
* have not been byteswapped yet so there is no
* need to swap them back.
*/
- if (pwqeq->context3)
- dmabuf = (struct lpfc_dmabuf *)pwqeq->context3;
+ if (pwqeq->bpl_dmabuf)
+ dmabuf = pwqeq->bpl_dmabuf;
else
return xritag;
@@ -21010,7 +21039,7 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp,
wq = qp->io_wq;
pring = wq->pring;
- ctxp = pwqe->context2;
+ ctxp = pwqe->context_un.axchg;
sglq = ctxp->ctxbuf->sglq;
if (pwqe->sli4_xritag == NO_XRI) {
pwqe->sli4_lxritag = sglq->sli4_lxritag;
@@ -21076,7 +21105,7 @@ lpfc_sli4_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
abtswqe = &abtsiocb->wqe;
memset(abtswqe, 0, sizeof(*abtswqe));
- if (!lpfc_is_link_up(phba))
+ if (!lpfc_is_link_up(phba) || (phba->link_flag & LS_EXTERNAL_LOOPBACK))
bf_set(abort_cmd_ia, &abtswqe->abort_cmd, 1);
bf_set(abort_cmd_criteria, &abtswqe->abort_cmd, T_XRI_TAG);
abtswqe->abort_cmd.rsrvd5 = 0;
@@ -21852,7 +21881,6 @@ lpfc_read_object(struct lpfc_hba *phba, char *rdobject, uint32_t *datap,
mbox->vport = phba->pport;
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- mbox->ctx_buf = NULL;
mbox->ctx_ndlp = NULL;
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
@@ -21889,9 +21917,12 @@ lpfc_read_object(struct lpfc_hba *phba, char *rdobject, uint32_t *datap,
}
exit:
+ /* This is an embedded SLI4 mailbox with an external buffer allocated.
+ * Free the pcmd and then cleanup with the correct routine.
+ */
lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
kfree(pcmd);
- mempool_free(mbox, phba->mbox_mem_pool);
+ lpfc_sli4_mbox_cmd_free(phba, mbox);
return byte_cnt;
}
@@ -22083,7 +22114,7 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba,
return NULL;
}
- tmp->fcp_cmnd = dma_pool_alloc(phba->lpfc_cmd_rsp_buf_pool,
+ tmp->fcp_cmnd = dma_pool_zalloc(phba->lpfc_cmd_rsp_buf_pool,
GFP_ATOMIC,
&tmp->fcp_cmd_rsp_dma_handle);
@@ -22205,8 +22236,6 @@ lpfc_sli_prep_wqe(struct lpfc_hba *phba, struct lpfc_iocbq *job)
u32 fip, abort_tag;
struct lpfc_nodelist *ndlp = NULL;
union lpfc_wqe128 *wqe = &job->wqe;
- struct lpfc_dmabuf *context2;
- u32 els_id = LPFC_ELS_ID_DEFAULT;
u8 command_type = ELS_COMMAND_NON_FIP;
fip = phba->hba_flag & HBA_FIP_SUPPORT;
@@ -22223,21 +22252,12 @@ lpfc_sli_prep_wqe(struct lpfc_hba *phba, struct lpfc_iocbq *job)
switch (cmnd) {
case CMD_ELS_REQUEST64_WQE:
- if (job->cmd_flag & LPFC_IO_LIBDFC)
- ndlp = job->context_un.ndlp;
- else
- ndlp = (struct lpfc_nodelist *)job->context1;
-
- /* CCP CCPE PV PRI in word10 were set in the memcpy */
- if (command_type == ELS_COMMAND_FIP)
- els_id = ((job->cmd_flag & LPFC_FIP_ELS_ID_MASK)
- >> LPFC_FIP_ELS_ID_SHIFT);
+ ndlp = job->ndlp;
if_type = bf_get(lpfc_sli_intf_if_type,
&phba->sli4_hba.sli_intf);
if (if_type >= LPFC_SLI_INTF_IF_TYPE_2) {
- context2 = (struct lpfc_dmabuf *)job->context2;
- pcmd = (u32 *)context2->virt;
+ pcmd = (u32 *)job->cmd_dmabuf->virt;
if (pcmd && (*pcmd == ELS_CMD_FLOGI ||
*pcmd == ELS_CMD_SCR ||
*pcmd == ELS_CMD_RDF ||
@@ -22270,7 +22290,6 @@ lpfc_sli_prep_wqe(struct lpfc_hba *phba, struct lpfc_iocbq *job)
bf_set(wqe_temp_rpi, &wqe->els_req.wqe_com,
phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]);
- bf_set(wqe_els_id, &wqe->els_req.wqe_com, els_id);
bf_set(wqe_dbde, &wqe->els_req.wqe_com, 1);
bf_set(wqe_iod, &wqe->els_req.wqe_com, LPFC_WQE_IOD_READ);
bf_set(wqe_qosd, &wqe->els_req.wqe_com, 1);
@@ -22278,7 +22297,7 @@ lpfc_sli_prep_wqe(struct lpfc_hba *phba, struct lpfc_iocbq *job)
bf_set(wqe_ebde_cnt, &wqe->els_req.wqe_com, 0);
break;
case CMD_XMIT_ELS_RSP64_WQE:
- ndlp = (struct lpfc_nodelist *)job->context1;
+ ndlp = job->ndlp;
/* word4 */
wqe->xmit_els_rsp.word4 = 0;
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 663cc90a8798..0af6860b8936 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -35,6 +35,12 @@ typedef enum _lpfc_ctx_cmd {
LPFC_CTX_HOST
} lpfc_ctx_cmd;
+/* Enumeration to describe the thread lock context. */
+enum lpfc_mbox_ctx {
+ MBOX_THD_UNLOCKED,
+ MBOX_THD_LOCKED
+};
+
union lpfc_vmid_tag {
uint32_t app_id;
uint8_t cs_ctl_vmid;
@@ -77,11 +83,15 @@ struct lpfc_iocbq {
u32 unsol_rcv_len; /* Receive len in usol path */
- uint8_t num_bdes;
- uint8_t abort_bls; /* ABTS by initiator or responder */
- u8 abort_rctl; /* ACC or RJT flag */
- uint8_t priority; /* OAS priority */
- uint8_t retry; /* retry counter for IOCB cmd - if needed */
+ /* Pack the u8's together and make them module-4. */
+ u8 num_bdes; /* Number of BDEs */
+ u8 abort_bls; /* ABTS by initiator or responder */
+ u8 abort_rctl; /* ACC or RJT flag */
+ u8 priority; /* OAS priority */
+ u8 retry; /* retry counter for IOCB cmd - if needed */
+ u8 rsvd1; /* Pad for u32 */
+ u8 rsvd2; /* Pad for u32 */
+ u8 rsvd3; /* Pad for u32 */
u32 cmd_flag;
#define LPFC_IO_LIBDFC 1 /* libdfc iocb */
@@ -116,18 +126,22 @@ struct lpfc_iocbq {
uint32_t drvrTimeout; /* driver timeout in seconds */
struct lpfc_vport *vport;/* virtual port pointer */
- void *context1; /* caller context information */
- void *context2; /* caller context information */
- void *context3; /* caller context information */
+ struct lpfc_dmabuf *cmd_dmabuf;
+ struct lpfc_dmabuf *rsp_dmabuf;
+ struct lpfc_dmabuf *bpl_dmabuf;
uint32_t event_tag; /* LA Event tag */
union {
wait_queue_head_t *wait_queue;
- struct lpfc_iocbq *rsp_iocb;
struct lpfcMboxq *mbox;
- struct lpfc_nodelist *ndlp;
struct lpfc_node_rrq *rrq;
+ struct nvmefc_ls_req *nvme_lsreq;
+ struct lpfc_async_xchg_ctx *axchg;
+ struct bsg_job_data *dd_data;
} context_un;
+ struct lpfc_io_buf *io_buf;
+ struct lpfc_iocbq *rsp_iocb;
+ struct lpfc_nodelist *ndlp;
union lpfc_vmid_tag vmid_tag;
void (*fabric_cmd_cmpl)(struct lpfc_hba *phba, struct lpfc_iocbq *cmd,
struct lpfc_iocbq *rsp);
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index e0c25699f4b8..1ddad5b170a6 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -981,6 +981,9 @@ struct lpfc_sli4_hba {
#define lpfc_conf_trunk_port3_nd_MASK 0x1
uint8_t flash_id;
uint8_t asic_rev;
+ uint16_t fawwpn_flag; /* FA-WWPN support state */
+#define LPFC_FAWWPN_CONFIG 0x1 /* FA-PWWN is configured */
+#define LPFC_FAWWPN_FABRIC 0x2 /* FA-PWWN success with Fabric */
};
enum lpfc_sge_type {
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index e52f37e5d896..4fab79ed58ed 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.2.0.0"
+#define LPFC_DRIVER_VERSION "14.2.0.3"
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index d694d0cff5a5..e7efb025ed50 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2021 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2016 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -135,12 +135,14 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
}
/*
- * Grab buffer pointer and clear context1 so we can use
- * lpfc_sli_issue_box_wait
+ * Wait for the read_sparams mailbox to complete. Driver needs
+ * this per vport to start the FDISC. If the mailbox fails,
+ * just cleanup and return an error unless the failure is a
+ * mailbox timeout. For MBX_TIMEOUT, allow the default
+ * mbox completion handler to take care of the cleanup. This
+ * is safe as the mailbox command isn't one that triggers
+ * another mailbox.
*/
- mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
- pmb->ctx_buf = NULL;
-
pmb->vport = vport;
rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
@@ -148,34 +150,29 @@ lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
"1830 Signal aborted mbxCmd x%x\n",
mb->mbxCommand);
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
if (rc != MBX_TIMEOUT)
- mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, pmb,
+ MBOX_THD_UNLOCKED);
return -EINTR;
} else {
lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT,
"1818 VPort failed init, mbxCmd x%x "
"READ_SPARM mbxStatus x%x, rc = x%x\n",
mb->mbxCommand, mb->mbxStatus, rc);
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
if (rc != MBX_TIMEOUT)
- mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_mbox_rsrc_cleanup(phba, pmb,
+ MBOX_THD_UNLOCKED);
return -EIO;
}
}
+ mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm));
memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
sizeof (struct lpfc_name));
memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
sizeof (struct lpfc_name));
-
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
-
+ lpfc_mbox_rsrc_cleanup(phba, pmb, MBOX_THD_UNLOCKED);
return 0;
}
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 070ebe352f9e..f75928f7773e 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -234,7 +234,7 @@ static void mac53c94_interrupt(int irq, void *dev_id)
++mac53c94_errors;
writeb(CMD_NOP + CMD_DMA_MODE, &regs->command);
}
- if (cmd == 0) {
+ if (!cmd) {
printk(KERN_DEBUG "53c94: interrupt with no command active?\n");
return;
}
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index a5d8cee2d510..bf491af9f0d6 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -4607,7 +4607,7 @@ static int __init megaraid_init(void)
* major number allocation.
*/
major = register_chrdev(0, "megadev_legacy", &megadev_fops);
- if (!major) {
+ if (major < 0) {
printk(KERN_WARNING
"megaraid: failed to register char device\n");
}
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 611871ef15b5..4919ea54b827 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -2560,6 +2560,9 @@ struct megasas_instance_template {
#define MEGASAS_IS_LOGICAL(sdev) \
((sdev->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1)
+#define MEGASAS_IS_LUN_VALID(sdev) \
+ (((sdev)->lun == 0) ? 1 : 0)
+
#define MEGASAS_DEV_INDEX(scp) \
(((scp->device->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + \
scp->device->id)
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 8bf72dbc33b7..c95360a3c186 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -2126,6 +2126,9 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
goto scan_target;
}
return -ENXIO;
+ } else if (!MEGASAS_IS_LUN_VALID(sdev)) {
+ sdev_printk(KERN_INFO, sdev, "%s: invalid LUN\n", __func__);
+ return -ENXIO;
}
scan_target:
@@ -2156,6 +2159,10 @@ static void megasas_slave_destroy(struct scsi_device *sdev)
instance = megasas_lookup_instance(sdev->host->host_no);
if (MEGASAS_IS_LOGICAL(sdev)) {
+ if (!MEGASAS_IS_LUN_VALID(sdev)) {
+ sdev_printk(KERN_INFO, sdev, "%s: invalid LUN\n", __func__);
+ return;
+ }
ld_tgt_id = MEGASAS_TARGET_ID(sdev);
instance->ld_tgtid_status[ld_tgt_id] = LD_TARGET_ID_DELETED;
if (megasas_dbg_lvl & LD_PD_DEBUG)
@@ -4466,8 +4473,6 @@ int megasas_alloc_cmds(struct megasas_instance *instance)
return -ENOMEM;
}
- memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) *max_cmd);
-
for (i = 0; i < max_cmd; i++) {
instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
GFP_KERNEL);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 54fde2661952..5b5885d9732b 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -2047,8 +2047,6 @@ map_cmd_status(struct fusion_context *fusion,
scmd->result = (DID_OK << 16) | ext_status;
if (ext_status == SAM_STAT_CHECK_CONDITION) {
- memset(scmd->sense_buffer, 0,
- SCSI_SENSE_BUFFERSIZE);
memcpy(scmd->sense_buffer, sense,
SCSI_SENSE_BUFFERSIZE);
}
diff --git a/drivers/scsi/mpi3mr/Kconfig b/drivers/scsi/mpi3mr/Kconfig
index f7882375e74f..8997531940c2 100644
--- a/drivers/scsi/mpi3mr/Kconfig
+++ b/drivers/scsi/mpi3mr/Kconfig
@@ -3,5 +3,6 @@
config SCSI_MPI3MR
tristate "Broadcom MPI3 Storage Controller Device Driver"
depends on PCI && SCSI
+ select BLK_DEV_BSGLIB
help
MPI3 based Storage & RAID Controllers Driver.
diff --git a/drivers/scsi/mpi3mr/Makefile b/drivers/scsi/mpi3mr/Makefile
index 7c2063e04c81..f5cdbe48c150 100644
--- a/drivers/scsi/mpi3mr/Makefile
+++ b/drivers/scsi/mpi3mr/Makefile
@@ -2,3 +2,4 @@
obj-m += mpi3mr.o
mpi3mr-y += mpi3mr_os.o \
mpi3mr_fw.o \
+ mpi3mr_app.o \
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_init.h b/drivers/scsi/mpi3mr/mpi/mpi30_init.h
index e2e8b22e9122..aac11c58cca9 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_init.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_init.h
@@ -115,57 +115,4 @@ struct mpi3_scsi_io_reply {
#define MPI3_SCSI_RSP_ARI0_MASK (0xff000000)
#define MPI3_SCSI_RSP_ARI0_SHIFT (24)
#define MPI3_SCSI_TASKTAG_UNKNOWN (0xffff)
-struct mpi3_scsi_task_mgmt_request {
- __le16 host_tag;
- u8 ioc_use_only02;
- u8 function;
- __le16 ioc_use_only04;
- u8 ioc_use_only06;
- u8 msg_flags;
- __le16 change_count;
- __le16 dev_handle;
- __le16 task_host_tag;
- u8 task_type;
- u8 reserved0f;
- __le16 task_request_queue_id;
- __le16 reserved12;
- __le32 reserved14;
- u8 lun[8];
-};
-
-#define MPI3_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x08)
-#define MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01)
-#define MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK_SET (0x02)
-#define MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03)
-#define MPI3_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05)
-#define MPI3_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06)
-#define MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07)
-#define MPI3_SCSITASKMGMT_TASKTYPE_CLEAR_ACA (0x08)
-#define MPI3_SCSITASKMGMT_TASKTYPE_QUERY_TASK_SET (0x09)
-#define MPI3_SCSITASKMGMT_TASKTYPE_QUERY_ASYNC_EVENT (0x0a)
-#define MPI3_SCSITASKMGMT_TASKTYPE_I_T_NEXUS_RESET (0x0b)
-struct mpi3_scsi_task_mgmt_reply {
- __le16 host_tag;
- u8 ioc_use_only02;
- u8 function;
- __le16 ioc_use_only04;
- u8 ioc_use_only06;
- u8 msg_flags;
- __le16 ioc_use_only08;
- __le16 ioc_status;
- __le32 ioc_log_info;
- __le32 termination_count;
- __le32 response_data;
- __le32 reserved18;
-};
-
-#define MPI3_SCSITASKMGMT_RSPCODE_TM_COMPLETE (0x00)
-#define MPI3_SCSITASKMGMT_RSPCODE_INVALID_FRAME (0x02)
-#define MPI3_SCSITASKMGMT_RSPCODE_TM_FUNCTION_NOT_SUPPORTED (0x04)
-#define MPI3_SCSITASKMGMT_RSPCODE_TM_FAILED (0x05)
-#define MPI3_SCSITASKMGMT_RSPCODE_TM_SUCCEEDED (0x08)
-#define MPI3_SCSITASKMGMT_RSPCODE_TM_INVALID_LUN (0x09)
-#define MPI3_SCSITASKMGMT_RSPCODE_TM_OVERLAPPED_TAG (0x0a)
-#define MPI3_SCSITASKMGMT_RSPCODE_IO_QUEUED_ON_IOC (0x80)
-#define MPI3_SCSITASKMGMT_RSPCODE_TM_NVME_DENIED (0x81)
#endif
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h
index 633037dc7012..214e4c65e576 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h
@@ -38,16 +38,6 @@ struct mpi3_ioc_init_request {
#define MPI3_WHOINIT_ROM_BIOS (0x02)
#define MPI3_WHOINIT_HOST_DRIVER (0x03)
#define MPI3_WHOINIT_MANUFACTURER (0x04)
-struct mpi3_driver_info_layout {
- __le32 information_length;
- u8 driver_signature[12];
- u8 os_name[16];
- u8 os_version[12];
- u8 driver_name[20];
- u8 driver_version[32];
- u8 driver_release_date[20];
- __le32 driver_capabilities;
-};
struct mpi3_ioc_facts_request {
__le16 host_tag;
@@ -647,23 +637,6 @@ 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_PEL_LOCALE_FLAGS_NON_BLOCKING_BOOT_EVENT (0x0200)
-#define MPI3_PEL_LOCALE_FLAGS_BLOCKING_BOOT_EVENT (0x0100)
-#define MPI3_PEL_LOCALE_FLAGS_PCIE (0x0080)
-#define MPI3_PEL_LOCALE_FLAGS_CONFIGURATION (0x0040)
-#define MPI3_PEL_LOCALE_FLAGS_CONTROLER (0x0020)
-#define MPI3_PEL_LOCALE_FLAGS_SAS (0x0010)
-#define MPI3_PEL_LOCALE_FLAGS_EPACK (0x0008)
-#define MPI3_PEL_LOCALE_FLAGS_ENCLOSURE (0x0004)
-#define MPI3_PEL_LOCALE_FLAGS_PD (0x0002)
-#define MPI3_PEL_LOCALE_FLAGS_VD (0x0001)
-#define MPI3_PEL_CLASS_DEBUG (0x00)
-#define MPI3_PEL_CLASS_PROGRESS (0x01)
-#define MPI3_PEL_CLASS_INFORMATIONAL (0x02)
-#define MPI3_PEL_CLASS_WARNING (0x03)
-#define MPI3_PEL_CLASS_CRITICAL (0x04)
-#define MPI3_PEL_CLASS_FATAL (0x05)
-#define MPI3_PEL_CLASS_FAULT (0x06)
#define MPI3_PEL_CLEARTYPE_CLEAR (0x00)
#define MPI3_PEL_WAITTIME_INFINITE_WAIT (0x00)
#define MPI3_PEL_ACTION_GET_SEQNUM (0x01)
diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_pci.h b/drivers/scsi/mpi3mr/mpi/mpi30_pci.h
index 77270f577f90..901dbd788940 100644
--- a/drivers/scsi/mpi3mr/mpi/mpi30_pci.h
+++ b/drivers/scsi/mpi3mr/mpi/mpi30_pci.h
@@ -5,24 +5,6 @@
*/
#ifndef MPI30_PCI_H
#define MPI30_PCI_H 1
-#ifndef MPI3_NVME_ENCAP_CMD_MAX
-#define MPI3_NVME_ENCAP_CMD_MAX (1)
-#endif
-struct mpi3_nvme_encapsulated_request {
- __le16 host_tag;
- u8 ioc_use_only02;
- u8 function;
- __le16 ioc_use_only04;
- u8 ioc_use_only06;
- u8 msg_flags;
- __le16 change_count;
- __le16 dev_handle;
- __le16 encapsulated_command_length;
- __le16 flags;
- __le32 data_length;
- __le32 reserved14[3];
- __le32 command[MPI3_NVME_ENCAP_CMD_MAX];
-};
#define MPI3_NVME_FLAGS_FORCE_ADMIN_ERR_REPLY_MASK (0x0002)
#define MPI3_NVME_FLAGS_FORCE_ADMIN_ERR_REPLY_FAIL_ONLY (0x0000)
@@ -30,16 +12,5 @@ struct mpi3_nvme_encapsulated_request {
#define MPI3_NVME_FLAGS_SUBMISSIONQ_MASK (0x0001)
#define MPI3_NVME_FLAGS_SUBMISSIONQ_IO (0x0000)
#define MPI3_NVME_FLAGS_SUBMISSIONQ_ADMIN (0x0001)
-struct mpi3_nvme_encapsulated_error_reply {
- __le16 host_tag;
- u8 ioc_use_only02;
- u8 function;
- __le16 ioc_use_only04;
- u8 ioc_use_only06;
- u8 msg_flags;
- __le16 ioc_use_only08;
- __le16 ioc_status;
- __le32 ioc_log_info;
- __le32 nvme_completion_entry[4];
-};
+
#endif
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 96c85f719af0..01cd01787b0f 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -38,6 +38,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
+#include <uapi/scsi/scsi_bsg_mpi3mr.h>
#include "mpi/mpi30_transport.h"
#include "mpi/mpi30_cnfg.h"
@@ -52,9 +53,10 @@
extern spinlock_t mrioc_list_lock;
extern struct list_head mrioc_list;
extern int prot_mask;
+extern atomic64_t event_counter;
-#define MPI3MR_DRIVER_VERSION "8.0.0.68.0"
-#define MPI3MR_DRIVER_RELDATE "10-February-2022"
+#define MPI3MR_DRIVER_VERSION "8.0.0.69.0"
+#define MPI3MR_DRIVER_RELDATE "16-March-2022"
#define MPI3MR_DRIVER_NAME "mpi3mr"
#define MPI3MR_DRIVER_LICENSE "GPL"
@@ -89,7 +91,9 @@ extern int prot_mask;
/* Reserved Host Tag definitions */
#define MPI3MR_HOSTTAG_INVALID 0xFFFF
#define MPI3MR_HOSTTAG_INITCMDS 1
-#define MPI3MR_HOSTTAG_IOCTLCMDS 2
+#define MPI3MR_HOSTTAG_BSG_CMDS 2
+#define MPI3MR_HOSTTAG_PEL_ABORT 3
+#define MPI3MR_HOSTTAG_PEL_WAIT 4
#define MPI3MR_HOSTTAG_BLK_TMS 5
#define MPI3MR_NUM_DEVRMCMD 16
@@ -120,6 +124,9 @@ extern int prot_mask;
#define MPI3MR_WATCHDOG_INTERVAL 1000 /* in milli seconds */
+#define MPI3MR_SCMD_TIMEOUT (60 * HZ)
+#define MPI3MR_EH_SCMD_TIMEOUT (60 * HZ)
+
/* Internal admin command state definitions*/
#define MPI3MR_CMD_NOTUSED 0x8000
#define MPI3MR_CMD_COMPLETE 0x0001
@@ -148,8 +155,10 @@ extern int prot_mask;
#define MPI3MR_DEFAULT_MDTS (128 * 1024)
#define MPI3MR_DEFAULT_PGSZEXP (12)
+
/* Command retry count definitions */
#define MPI3MR_DEV_RMHS_RETRY_COUNT 3
+#define MPI3MR_PEL_RETRY_COUNT 3
/* Default target device queue depth */
#define MPI3MR_DEFAULT_SDEV_QD 32
@@ -175,6 +184,57 @@ extern int prot_mask;
/* MSI Index from Reply Queue Index */
#define REPLY_QUEUE_IDX_TO_MSIX_IDX(qidx, offset) (qidx + offset)
+/*
+ * Maximum data transfer size definitions for management
+ * application commands
+ */
+#define MPI3MR_MAX_APP_XFER_SIZE (1 * 1024 * 1024)
+#define MPI3MR_MAX_APP_XFER_SEGMENTS 512
+/*
+ * 2048 sectors are for data buffers and additional 512 sectors for
+ * other buffers
+ */
+#define MPI3MR_MAX_APP_XFER_SECTORS (2048 + 512)
+
+/**
+ * struct mpi3mr_nvme_pt_sge - Structure to store SGEs for NVMe
+ * Encapsulated commands.
+ *
+ * @base_addr: Physical address
+ * @length: SGE length
+ * @rsvd: Reserved
+ * @rsvd1: Reserved
+ * @sgl_type: sgl type
+ */
+struct mpi3mr_nvme_pt_sge {
+ u64 base_addr;
+ u32 length;
+ u16 rsvd;
+ u8 rsvd1;
+ u8 sgl_type;
+};
+
+/**
+ * struct mpi3mr_buf_map - local structure to
+ * track kernel and user buffers associated with an BSG
+ * structure.
+ *
+ * @bsg_buf: BSG buffer virtual address
+ * @bsg_buf_len: BSG buffer length
+ * @kern_buf: Kernel buffer virtual address
+ * @kern_buf_len: Kernel buffer length
+ * @kern_buf_dma: Kernel buffer DMA address
+ * @data_dir: Data direction.
+ */
+struct mpi3mr_buf_map {
+ void *bsg_buf;
+ u32 bsg_buf_len;
+ void *kern_buf;
+ u32 kern_buf_len;
+ dma_addr_t kern_buf_dma;
+ u8 data_dir;
+};
+
/* IOC State definitions */
enum mpi3mr_iocstate {
MRIOC_STATE_READY = 1,
@@ -189,10 +249,10 @@ enum mpi3mr_iocstate {
enum mpi3mr_reset_reason {
MPI3MR_RESET_FROM_BRINGUP = 1,
MPI3MR_RESET_FROM_FAULT_WATCH = 2,
- MPI3MR_RESET_FROM_IOCTL = 3,
+ MPI3MR_RESET_FROM_APP = 3,
MPI3MR_RESET_FROM_EH_HOS = 4,
MPI3MR_RESET_FROM_TM_TIMEOUT = 5,
- MPI3MR_RESET_FROM_IOCTL_TIMEOUT = 6,
+ MPI3MR_RESET_FROM_APP_TIMEOUT = 6,
MPI3MR_RESET_FROM_MUR_FAILURE = 7,
MPI3MR_RESET_FROM_CTLR_CLEANUP = 8,
MPI3MR_RESET_FROM_CIACTIV_FAULT = 9,
@@ -543,6 +603,7 @@ struct mpi3mr_sdev_priv_data {
* @ioc_status: IOC status from the firmware
* @ioc_loginfo:IOC log info from the firmware
* @is_waiting: Is the command issued in block mode
+ * @is_sense: Is Sense data present
* @retry_count: Retry count for retriable commands
* @host_tag: Host tag used by the command
* @callback: Callback for non blocking commands
@@ -558,6 +619,7 @@ struct mpi3mr_drv_cmd {
u16 ioc_status;
u32 ioc_loginfo;
u8 is_waiting;
+ u8 is_sense;
u8 retry_count;
u16 host_tag;
@@ -685,6 +747,7 @@ struct scmd_priv {
* @chain_bitmap_sz: Chain buffer allocator bitmap size
* @chain_bitmap: Chain buffer allocator bitmap
* @chain_buf_lock: Chain buffer list lock
+ * @bsg_cmds: Command tracker for BSG command
* @host_tm_cmds: Command tracker for task management commands
* @dev_rmhs_cmds: Command tracker for device removal commands
* @evtack_cmds: Command tracker for event ack commands
@@ -704,16 +767,35 @@ struct scmd_priv {
* @reset_waitq: Controller reset wait queue
* @prepare_for_reset: Prepare for reset event received
* @prepare_for_reset_timeout_counter: Prepare for reset timeout
+ * @prp_list_virt: NVMe encapsulated PRP list virtual base
+ * @prp_list_dma: NVMe encapsulated PRP list DMA
+ * @prp_sz: NVME encapsulated PRP list size
* @diagsave_timeout: Diagnostic information save timeout
* @logging_level: Controller debug logging level
* @flush_io_count: I/O count to flush after reset
* @current_event: Firmware event currently in process
* @driver_info: Driver, Kernel, OS information to firmware
* @change_count: Topology change count
+ * @pel_enabled: Persistent Event Log(PEL) enabled or not
+ * @pel_abort_requested: PEL abort is requested or not
+ * @pel_class: PEL Class identifier
+ * @pel_locale: PEL Locale identifier
+ * @pel_cmds: Command tracker for PEL wait command
+ * @pel_abort_cmd: Command tracker for PEL abort command
+ * @pel_newest_seqnum: Newest PEL sequenece number
+ * @pel_seqnum_virt: PEL sequence number virtual address
+ * @pel_seqnum_dma: PEL sequence number DMA address
+ * @pel_seqnum_sz: PEL sequenece number size
* @op_reply_q_offset: Operational reply queue offset with MSIx
* @default_qcount: Total Default queues
* @active_poll_qcount: Currently active poll queue count
* @requested_poll_qcount: User requested poll queue count
+ * @bsg_dev: BSG device structure
+ * @bsg_queue: Request queue for BSG device
+ * @stop_bsgs: Stop BSG request flag
+ * @logdata_buf: Circular buffer to store log data entries
+ * @logdata_buf_idx: Index of entry in buffer to store
+ * @logdata_entry_sz: log data entry size
*/
struct mpi3mr_ioc {
struct list_head list;
@@ -820,6 +902,7 @@ struct mpi3mr_ioc {
void *chain_bitmap;
spinlock_t chain_buf_lock;
+ struct mpi3mr_drv_cmd bsg_cmds;
struct mpi3mr_drv_cmd host_tm_cmds;
struct mpi3mr_drv_cmd dev_rmhs_cmds[MPI3MR_NUM_DEVRMCMD];
struct mpi3mr_drv_cmd evtack_cmds[MPI3MR_NUM_EVTACKCMD];
@@ -842,6 +925,10 @@ struct mpi3mr_ioc {
u8 prepare_for_reset;
u16 prepare_for_reset_timeout_counter;
+ void *prp_list_virt;
+ dma_addr_t prp_list_dma;
+ u32 prp_sz;
+
u16 diagsave_timeout;
int logging_level;
u16 flush_io_count;
@@ -849,11 +936,30 @@ struct mpi3mr_ioc {
struct mpi3mr_fwevt *current_event;
struct mpi3_driver_info_layout driver_info;
u16 change_count;
- u16 op_reply_q_offset;
+ u8 pel_enabled;
+ u8 pel_abort_requested;
+ u8 pel_class;
+ u16 pel_locale;
+ struct mpi3mr_drv_cmd pel_cmds;
+ struct mpi3mr_drv_cmd pel_abort_cmd;
+
+ u32 pel_newest_seqnum;
+ void *pel_seqnum_virt;
+ dma_addr_t pel_seqnum_dma;
+ u32 pel_seqnum_sz;
+
+ u16 op_reply_q_offset;
u16 default_qcount;
u16 active_poll_qcount;
u16 requested_poll_qcount;
+
+ struct device *bsg_dev;
+ struct request_queue *bsg_queue;
+ u8 stop_bsgs;
+ u8 *logdata_buf;
+ u16 logdata_buf_idx;
+ u16 logdata_entry_sz;
};
/**
@@ -866,6 +972,7 @@ struct mpi3mr_ioc {
* @send_ack: Event acknowledgment required or not
* @process_evt: Bottomhalf processing required or not
* @evt_ctx: Event context to send in Ack
+ * @event_data_size: size of the event data in bytes
* @pending_at_sml: waiting for device add/remove API to complete
* @discard: discard this event
* @ref_count: kref count
@@ -879,6 +986,7 @@ struct mpi3mr_fwevt {
bool send_ack;
bool process_evt;
u32 evt_ctx;
+ u16 event_data_size;
bool pending_at_sml;
bool discard;
struct kref ref_count;
@@ -962,5 +1070,20 @@ void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code);
int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
struct op_reply_qinfo *op_reply_q);
int mpi3mr_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num);
-
+void mpi3mr_bsg_init(struct mpi3mr_ioc *mrioc);
+void mpi3mr_bsg_exit(struct mpi3mr_ioc *mrioc);
+int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
+ u16 handle, uint lun, u16 htag, ulong timeout,
+ struct mpi3mr_drv_cmd *drv_cmd,
+ u8 *resp_code, struct scsi_cmnd *scmd);
+struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_handle(
+ struct mpi3mr_ioc *mrioc, u16 handle);
+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,
+ u16 event_data_size);
+extern const struct attribute_group *mpi3mr_host_groups[];
+extern const struct attribute_group *mpi3mr_dev_groups[];
#endif /*MPI3MR_H_INCLUDED*/
diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c
new file mode 100644
index 000000000000..9ab1762468ad
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi3mr_app.c
@@ -0,0 +1,1864 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Broadcom MPI3 Storage Controllers
+ *
+ * Copyright (C) 2017-2022 Broadcom Inc.
+ * (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
+ *
+ */
+
+#include "mpi3mr.h"
+#include <linux/bsg-lib.h>
+#include <uapi/scsi/scsi_bsg_mpi3mr.h>
+
+/**
+ * mpi3mr_bsg_pel_abort - sends PEL abort request
+ * @mrioc: Adapter instance reference
+ *
+ * This function sends PEL abort request to the firmware through
+ * admin request queue.
+ *
+ * Return: 0 on success, -1 on failure
+ */
+static int mpi3mr_bsg_pel_abort(struct mpi3mr_ioc *mrioc)
+{
+ struct mpi3_pel_req_action_abort pel_abort_req;
+ struct mpi3_pel_reply *pel_reply;
+ int retval = 0;
+ u16 pe_log_status;
+
+ if (mrioc->reset_in_progress) {
+ dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__);
+ return -1;
+ }
+ if (mrioc->stop_bsgs) {
+ dprint_bsg_err(mrioc, "%s: bsgs are blocked\n", __func__);
+ return -1;
+ }
+
+ memset(&pel_abort_req, 0, sizeof(pel_abort_req));
+ mutex_lock(&mrioc->pel_abort_cmd.mutex);
+ if (mrioc->pel_abort_cmd.state & MPI3MR_CMD_PENDING) {
+ dprint_bsg_err(mrioc, "%s: command is in use\n", __func__);
+ mutex_unlock(&mrioc->pel_abort_cmd.mutex);
+ return -1;
+ }
+ mrioc->pel_abort_cmd.state = MPI3MR_CMD_PENDING;
+ mrioc->pel_abort_cmd.is_waiting = 1;
+ mrioc->pel_abort_cmd.callback = NULL;
+ pel_abort_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_PEL_ABORT);
+ pel_abort_req.function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG;
+ pel_abort_req.action = MPI3_PEL_ACTION_ABORT;
+ pel_abort_req.abort_host_tag = cpu_to_le16(MPI3MR_HOSTTAG_PEL_WAIT);
+
+ mrioc->pel_abort_requested = 1;
+ init_completion(&mrioc->pel_abort_cmd.done);
+ retval = mpi3mr_admin_request_post(mrioc, &pel_abort_req,
+ sizeof(pel_abort_req), 0);
+ if (retval) {
+ retval = -1;
+ dprint_bsg_err(mrioc, "%s: admin request post failed\n",
+ __func__);
+ mrioc->pel_abort_requested = 0;
+ goto out_unlock;
+ }
+
+ wait_for_completion_timeout(&mrioc->pel_abort_cmd.done,
+ (MPI3MR_INTADMCMD_TIMEOUT * HZ));
+ if (!(mrioc->pel_abort_cmd.state & MPI3MR_CMD_COMPLETE)) {
+ mrioc->pel_abort_cmd.is_waiting = 0;
+ dprint_bsg_err(mrioc, "%s: command timedout\n", __func__);
+ if (!(mrioc->pel_abort_cmd.state & MPI3MR_CMD_RESET))
+ mpi3mr_soft_reset_handler(mrioc,
+ MPI3MR_RESET_FROM_PELABORT_TIMEOUT, 1);
+ retval = -1;
+ goto out_unlock;
+ }
+ if ((mrioc->pel_abort_cmd.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+ != MPI3_IOCSTATUS_SUCCESS) {
+ dprint_bsg_err(mrioc,
+ "%s: command failed, ioc_status(0x%04x) log_info(0x%08x)\n",
+ __func__, (mrioc->pel_abort_cmd.ioc_status &
+ MPI3_IOCSTATUS_STATUS_MASK),
+ mrioc->pel_abort_cmd.ioc_loginfo);
+ retval = -1;
+ goto out_unlock;
+ }
+ if (mrioc->pel_abort_cmd.state & MPI3MR_CMD_REPLY_VALID) {
+ pel_reply = (struct mpi3_pel_reply *)mrioc->pel_abort_cmd.reply;
+ pe_log_status = le16_to_cpu(pel_reply->pe_log_status);
+ if (pe_log_status != MPI3_PEL_STATUS_SUCCESS) {
+ dprint_bsg_err(mrioc,
+ "%s: command failed, pel_status(0x%04x)\n",
+ __func__, pe_log_status);
+ retval = -1;
+ }
+ }
+
+out_unlock:
+ mrioc->pel_abort_cmd.state = MPI3MR_CMD_NOTUSED;
+ mutex_unlock(&mrioc->pel_abort_cmd.mutex);
+ return retval;
+}
+/**
+ * mpi3mr_bsg_verify_adapter - verify adapter number is valid
+ * @ioc_number: Adapter number
+ *
+ * This function returns the adapter instance pointer of given
+ * adapter number. If adapter number does not match with the
+ * driver's adapter list, driver returns NULL.
+ *
+ * Return: adapter instance reference
+ */
+static struct mpi3mr_ioc *mpi3mr_bsg_verify_adapter(int ioc_number)
+{
+ struct mpi3mr_ioc *mrioc = NULL;
+
+ spin_lock(&mrioc_list_lock);
+ list_for_each_entry(mrioc, &mrioc_list, list) {
+ if (mrioc->id == ioc_number) {
+ spin_unlock(&mrioc_list_lock);
+ return mrioc;
+ }
+ }
+ spin_unlock(&mrioc_list_lock);
+ return NULL;
+}
+
+/**
+ * mpi3mr_enable_logdata - Handler for log data enable
+ * @mrioc: Adapter instance reference
+ * @job: BSG job reference
+ *
+ * This function enables log data caching in the driver if not
+ * already enabled and return the maximum number of log data
+ * entries that can be cached in the driver.
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+static long mpi3mr_enable_logdata(struct mpi3mr_ioc *mrioc,
+ struct bsg_job *job)
+{
+ struct mpi3mr_logdata_enable logdata_enable;
+
+ if (!mrioc->logdata_buf) {
+ mrioc->logdata_entry_sz =
+ (mrioc->reply_sz - (sizeof(struct mpi3_event_notification_reply) - 4))
+ + MPI3MR_BSG_LOGDATA_ENTRY_HEADER_SZ;
+ mrioc->logdata_buf_idx = 0;
+ mrioc->logdata_buf = kcalloc(MPI3MR_BSG_LOGDATA_MAX_ENTRIES,
+ mrioc->logdata_entry_sz, GFP_KERNEL);
+
+ if (!mrioc->logdata_buf)
+ return -ENOMEM;
+ }
+
+ memset(&logdata_enable, 0, sizeof(logdata_enable));
+ logdata_enable.max_entries =
+ MPI3MR_BSG_LOGDATA_MAX_ENTRIES;
+ if (job->request_payload.payload_len >= sizeof(logdata_enable)) {
+ sg_copy_from_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ &logdata_enable, sizeof(logdata_enable));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+/**
+ * mpi3mr_get_logdata - Handler for get log data
+ * @mrioc: Adapter instance reference
+ * @job: BSG job pointer
+ * This function copies the log data entries to the user buffer
+ * when log caching is enabled in the driver.
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+static long mpi3mr_get_logdata(struct mpi3mr_ioc *mrioc,
+ struct bsg_job *job)
+{
+ u16 num_entries, sz, entry_sz = mrioc->logdata_entry_sz;
+
+ if ((!mrioc->logdata_buf) || (job->request_payload.payload_len < entry_sz))
+ return -EINVAL;
+
+ num_entries = job->request_payload.payload_len / entry_sz;
+ if (num_entries > MPI3MR_BSG_LOGDATA_MAX_ENTRIES)
+ num_entries = MPI3MR_BSG_LOGDATA_MAX_ENTRIES;
+ sz = num_entries * entry_sz;
+
+ if (job->request_payload.payload_len >= sz) {
+ sg_copy_from_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ mrioc->logdata_buf, sz);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/**
+ * mpi3mr_bsg_pel_enable - Handler for PEL enable driver
+ * @mrioc: Adapter instance reference
+ * @job: BSG job pointer
+ *
+ * This function is the handler for PEL enable driver.
+ * Validates the application given class and locale and if
+ * requires aborts the existing PEL wait request and/or issues
+ * new PEL wait request to the firmware and returns.
+ *
+ * Return: 0 on success and proper error codes on failure.
+ */
+static long mpi3mr_bsg_pel_enable(struct mpi3mr_ioc *mrioc,
+ struct bsg_job *job)
+{
+ long rval = -EINVAL;
+ struct mpi3mr_bsg_out_pel_enable pel_enable;
+ u8 issue_pel_wait;
+ u8 tmp_class;
+ u16 tmp_locale;
+
+ if (job->request_payload.payload_len != sizeof(pel_enable)) {
+ dprint_bsg_err(mrioc, "%s: invalid size argument\n",
+ __func__);
+ return rval;
+ }
+
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ &pel_enable, sizeof(pel_enable));
+
+ if (pel_enable.pel_class > MPI3_PEL_CLASS_FAULT) {
+ dprint_bsg_err(mrioc, "%s: out of range class %d sent\n",
+ __func__, pel_enable.pel_class);
+ rval = 0;
+ goto out;
+ }
+ if (!mrioc->pel_enabled)
+ issue_pel_wait = 1;
+ else {
+ if ((mrioc->pel_class <= pel_enable.pel_class) &&
+ !((mrioc->pel_locale & pel_enable.pel_locale) ^
+ pel_enable.pel_locale)) {
+ issue_pel_wait = 0;
+ rval = 0;
+ } else {
+ pel_enable.pel_locale |= mrioc->pel_locale;
+
+ if (mrioc->pel_class < pel_enable.pel_class)
+ pel_enable.pel_class = mrioc->pel_class;
+
+ rval = mpi3mr_bsg_pel_abort(mrioc);
+ if (rval) {
+ dprint_bsg_err(mrioc,
+ "%s: pel_abort failed, status(%ld)\n",
+ __func__, rval);
+ goto out;
+ }
+ issue_pel_wait = 1;
+ }
+ }
+ if (issue_pel_wait) {
+ tmp_class = mrioc->pel_class;
+ tmp_locale = mrioc->pel_locale;
+ mrioc->pel_class = pel_enable.pel_class;
+ mrioc->pel_locale = pel_enable.pel_locale;
+ mrioc->pel_enabled = 1;
+ rval = mpi3mr_pel_get_seqnum_post(mrioc, NULL);
+ if (rval) {
+ mrioc->pel_class = tmp_class;
+ mrioc->pel_locale = tmp_locale;
+ mrioc->pel_enabled = 0;
+ dprint_bsg_err(mrioc,
+ "%s: pel get sequence number failed, status(%ld)\n",
+ __func__, rval);
+ }
+ }
+
+out:
+ return rval;
+}
+/**
+ * mpi3mr_get_all_tgt_info - Get all target information
+ * @mrioc: Adapter instance reference
+ * @job: BSG job reference
+ *
+ * This function copies the driver managed target devices device
+ * handle, persistent ID, bus ID and taret ID to the user
+ * provided buffer for the specific controller. This function
+ * also provides the number of devices managed by the driver for
+ * the specific controller.
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+static long mpi3mr_get_all_tgt_info(struct mpi3mr_ioc *mrioc,
+ struct bsg_job *job)
+{
+ long rval = -EINVAL;
+ u16 num_devices = 0, i = 0, size;
+ unsigned long flags;
+ struct mpi3mr_tgt_dev *tgtdev;
+ struct mpi3mr_device_map_info *devmap_info = NULL;
+ struct mpi3mr_all_tgt_info *alltgt_info = NULL;
+ uint32_t min_entrylen = 0, kern_entrylen = 0, usr_entrylen = 0;
+
+ if (job->request_payload.payload_len < sizeof(u32)) {
+ dprint_bsg_err(mrioc, "%s: invalid size argument\n",
+ __func__);
+ return rval;
+ }
+
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
+ num_devices++;
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+
+ if ((job->request_payload.payload_len == sizeof(u32)) ||
+ list_empty(&mrioc->tgtdev_list)) {
+ sg_copy_from_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ &num_devices, sizeof(num_devices));
+ return 0;
+ }
+
+ kern_entrylen = (num_devices - 1) * sizeof(*devmap_info);
+ size = sizeof(*alltgt_info) + kern_entrylen;
+ alltgt_info = kzalloc(size, GFP_KERNEL);
+ if (!alltgt_info)
+ return -ENOMEM;
+
+ devmap_info = alltgt_info->dmi;
+ memset((u8 *)devmap_info, 0xFF, (kern_entrylen + sizeof(*devmap_info)));
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
+ if (i < num_devices) {
+ devmap_info[i].handle = tgtdev->dev_handle;
+ devmap_info[i].perst_id = tgtdev->perst_id;
+ if (tgtdev->host_exposed && tgtdev->starget) {
+ devmap_info[i].target_id = tgtdev->starget->id;
+ devmap_info[i].bus_id =
+ tgtdev->starget->channel;
+ }
+ i++;
+ }
+ }
+ num_devices = i;
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+
+ memcpy(&alltgt_info->num_devices, &num_devices, sizeof(num_devices));
+
+ usr_entrylen = (job->request_payload.payload_len - sizeof(u32)) / sizeof(*devmap_info);
+ usr_entrylen *= sizeof(*devmap_info);
+ min_entrylen = min(usr_entrylen, kern_entrylen);
+ if (min_entrylen && (!memcpy(&alltgt_info->dmi, devmap_info, min_entrylen))) {
+ dprint_bsg_err(mrioc, "%s:%d: device map info copy failed\n",
+ __func__, __LINE__);
+ rval = -EFAULT;
+ goto out;
+ }
+
+ sg_copy_from_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ alltgt_info, job->request_payload.payload_len);
+ rval = 0;
+out:
+ kfree(alltgt_info);
+ return rval;
+}
+/**
+ * mpi3mr_get_change_count - Get topology change count
+ * @mrioc: Adapter instance reference
+ * @job: BSG job reference
+ *
+ * This function copies the toplogy change count provided by the
+ * driver in events and cached in the driver to the user
+ * provided buffer for the specific controller.
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+static long mpi3mr_get_change_count(struct mpi3mr_ioc *mrioc,
+ struct bsg_job *job)
+{
+ struct mpi3mr_change_count chgcnt;
+
+ memset(&chgcnt, 0, sizeof(chgcnt));
+ chgcnt.change_count = mrioc->change_count;
+ if (job->request_payload.payload_len >= sizeof(chgcnt)) {
+ sg_copy_from_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ &chgcnt, sizeof(chgcnt));
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/**
+ * mpi3mr_bsg_adp_reset - Issue controller reset
+ * @mrioc: Adapter instance reference
+ * @job: BSG job reference
+ *
+ * This function identifies the user provided reset type and
+ * issues approporiate reset to the controller and wait for that
+ * to complete and reinitialize the controller and then returns
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+static long mpi3mr_bsg_adp_reset(struct mpi3mr_ioc *mrioc,
+ struct bsg_job *job)
+{
+ long rval = -EINVAL;
+ u8 save_snapdump;
+ struct mpi3mr_bsg_adp_reset adpreset;
+
+ if (job->request_payload.payload_len !=
+ sizeof(adpreset)) {
+ dprint_bsg_err(mrioc, "%s: invalid size argument\n",
+ __func__);
+ goto out;
+ }
+
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ &adpreset, sizeof(adpreset));
+
+ switch (adpreset.reset_type) {
+ case MPI3MR_BSG_ADPRESET_SOFT:
+ save_snapdump = 0;
+ break;
+ case MPI3MR_BSG_ADPRESET_DIAG_FAULT:
+ save_snapdump = 1;
+ break;
+ default:
+ dprint_bsg_err(mrioc, "%s: unknown reset_type(%d)\n",
+ __func__, adpreset.reset_type);
+ goto out;
+ }
+
+ rval = mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_APP,
+ save_snapdump);
+
+ if (rval)
+ dprint_bsg_err(mrioc,
+ "%s: reset handler returned error(%ld) for reset type %d\n",
+ __func__, rval, adpreset.reset_type);
+out:
+ return rval;
+}
+
+/**
+ * mpi3mr_bsg_populate_adpinfo - Get adapter info command handler
+ * @mrioc: Adapter instance reference
+ * @job: BSG job reference
+ *
+ * This function provides adapter information for the given
+ * controller
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+static long mpi3mr_bsg_populate_adpinfo(struct mpi3mr_ioc *mrioc,
+ struct bsg_job *job)
+{
+ enum mpi3mr_iocstate ioc_state;
+ struct mpi3mr_bsg_in_adpinfo adpinfo;
+
+ memset(&adpinfo, 0, sizeof(adpinfo));
+ adpinfo.adp_type = MPI3MR_BSG_ADPTYPE_AVGFAMILY;
+ adpinfo.pci_dev_id = mrioc->pdev->device;
+ adpinfo.pci_dev_hw_rev = mrioc->pdev->revision;
+ adpinfo.pci_subsys_dev_id = mrioc->pdev->subsystem_device;
+ adpinfo.pci_subsys_ven_id = mrioc->pdev->subsystem_vendor;
+ adpinfo.pci_bus = mrioc->pdev->bus->number;
+ adpinfo.pci_dev = PCI_SLOT(mrioc->pdev->devfn);
+ adpinfo.pci_func = PCI_FUNC(mrioc->pdev->devfn);
+ adpinfo.pci_seg_id = pci_domain_nr(mrioc->pdev->bus);
+ adpinfo.app_intfc_ver = MPI3MR_IOCTL_VERSION;
+
+ ioc_state = mpi3mr_get_iocstate(mrioc);
+ if (ioc_state == MRIOC_STATE_UNRECOVERABLE)
+ adpinfo.adp_state = MPI3MR_BSG_ADPSTATE_UNRECOVERABLE;
+ else if ((mrioc->reset_in_progress) || (mrioc->stop_bsgs))
+ adpinfo.adp_state = MPI3MR_BSG_ADPSTATE_IN_RESET;
+ else if (ioc_state == MRIOC_STATE_FAULT)
+ adpinfo.adp_state = MPI3MR_BSG_ADPSTATE_FAULT;
+ else
+ adpinfo.adp_state = MPI3MR_BSG_ADPSTATE_OPERATIONAL;
+
+ memcpy((u8 *)&adpinfo.driver_info, (u8 *)&mrioc->driver_info,
+ sizeof(adpinfo.driver_info));
+
+ if (job->request_payload.payload_len >= sizeof(adpinfo)) {
+ sg_copy_from_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ &adpinfo, sizeof(adpinfo));
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/**
+ * mpi3mr_bsg_process_drv_cmds - Driver Command handler
+ * @job: BSG job reference
+ *
+ * This function is the top level handler for driver commands,
+ * this does basic validation of the buffer and identifies the
+ * opcode and switches to correct sub handler.
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+static long mpi3mr_bsg_process_drv_cmds(struct bsg_job *job)
+{
+ long rval = -EINVAL;
+ struct mpi3mr_ioc *mrioc = NULL;
+ struct mpi3mr_bsg_packet *bsg_req = NULL;
+ struct mpi3mr_bsg_drv_cmd *drvrcmd = NULL;
+
+ bsg_req = job->request;
+ drvrcmd = &bsg_req->cmd.drvrcmd;
+
+ mrioc = mpi3mr_bsg_verify_adapter(drvrcmd->mrioc_id);
+ if (!mrioc)
+ return -ENODEV;
+
+ if (drvrcmd->opcode == MPI3MR_DRVBSG_OPCODE_ADPINFO) {
+ rval = mpi3mr_bsg_populate_adpinfo(mrioc, job);
+ return rval;
+ }
+
+ if (mutex_lock_interruptible(&mrioc->bsg_cmds.mutex))
+ return -ERESTARTSYS;
+
+ switch (drvrcmd->opcode) {
+ case MPI3MR_DRVBSG_OPCODE_ADPRESET:
+ rval = mpi3mr_bsg_adp_reset(mrioc, job);
+ break;
+ case MPI3MR_DRVBSG_OPCODE_ALLTGTDEVINFO:
+ rval = mpi3mr_get_all_tgt_info(mrioc, job);
+ break;
+ case MPI3MR_DRVBSG_OPCODE_GETCHGCNT:
+ rval = mpi3mr_get_change_count(mrioc, job);
+ break;
+ case MPI3MR_DRVBSG_OPCODE_LOGDATAENABLE:
+ rval = mpi3mr_enable_logdata(mrioc, job);
+ break;
+ case MPI3MR_DRVBSG_OPCODE_GETLOGDATA:
+ rval = mpi3mr_get_logdata(mrioc, job);
+ break;
+ case MPI3MR_DRVBSG_OPCODE_PELENABLE:
+ rval = mpi3mr_bsg_pel_enable(mrioc, job);
+ break;
+ case MPI3MR_DRVBSG_OPCODE_UNKNOWN:
+ default:
+ pr_err("%s: unsupported driver command opcode %d\n",
+ MPI3MR_DRIVER_NAME, drvrcmd->opcode);
+ break;
+ }
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
+ return rval;
+}
+
+/**
+ * mpi3mr_bsg_build_sgl - SGL construction for MPI commands
+ * @mpi_req: MPI request
+ * @sgl_offset: offset to start sgl in the MPI request
+ * @drv_bufs: DMA address of the buffers to be placed in sgl
+ * @bufcnt: Number of DMA buffers
+ * @is_rmc: Does the buffer list has management command buffer
+ * @is_rmr: Does the buffer list has management response buffer
+ * @num_datasges: Number of data buffers in the list
+ *
+ * This function places the DMA address of the given buffers in
+ * proper format as SGEs in the given MPI request.
+ *
+ * Return: Nothing
+ */
+static void mpi3mr_bsg_build_sgl(u8 *mpi_req, uint32_t sgl_offset,
+ struct mpi3mr_buf_map *drv_bufs, u8 bufcnt, u8 is_rmc,
+ u8 is_rmr, u8 num_datasges)
+{
+ u8 *sgl = (mpi_req + sgl_offset), count = 0;
+ struct mpi3_mgmt_passthrough_request *rmgmt_req =
+ (struct mpi3_mgmt_passthrough_request *)mpi_req;
+ struct mpi3mr_buf_map *drv_buf_iter = drv_bufs;
+ u8 sgl_flags, sgl_flags_last;
+
+ sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE |
+ MPI3_SGE_FLAGS_DLAS_SYSTEM | MPI3_SGE_FLAGS_END_OF_BUFFER;
+ sgl_flags_last = sgl_flags | MPI3_SGE_FLAGS_END_OF_LIST;
+
+ if (is_rmc) {
+ mpi3mr_add_sg_single(&rmgmt_req->command_sgl,
+ sgl_flags_last, drv_buf_iter->kern_buf_len,
+ drv_buf_iter->kern_buf_dma);
+ sgl = (u8 *)drv_buf_iter->kern_buf + drv_buf_iter->bsg_buf_len;
+ drv_buf_iter++;
+ count++;
+ if (is_rmr) {
+ mpi3mr_add_sg_single(&rmgmt_req->response_sgl,
+ sgl_flags_last, drv_buf_iter->kern_buf_len,
+ drv_buf_iter->kern_buf_dma);
+ drv_buf_iter++;
+ count++;
+ } else
+ mpi3mr_build_zero_len_sge(
+ &rmgmt_req->response_sgl);
+ }
+ if (!num_datasges) {
+ mpi3mr_build_zero_len_sge(sgl);
+ return;
+ }
+ for (; count < bufcnt; count++, drv_buf_iter++) {
+ if (drv_buf_iter->data_dir == DMA_NONE)
+ continue;
+ if (num_datasges == 1 || !is_rmc)
+ mpi3mr_add_sg_single(sgl, sgl_flags_last,
+ drv_buf_iter->kern_buf_len, drv_buf_iter->kern_buf_dma);
+ else
+ mpi3mr_add_sg_single(sgl, sgl_flags,
+ drv_buf_iter->kern_buf_len, drv_buf_iter->kern_buf_dma);
+ sgl += sizeof(struct mpi3_sge_common);
+ num_datasges--;
+ }
+}
+
+/**
+ * mpi3mr_get_nvme_data_fmt - returns the NVMe data format
+ * @nvme_encap_request: NVMe encapsulated MPI request
+ *
+ * This function returns the type of the data format specified
+ * in user provided NVMe command in NVMe encapsulated request.
+ *
+ * Return: Data format of the NVMe command (PRP/SGL etc)
+ */
+static unsigned int mpi3mr_get_nvme_data_fmt(
+ struct mpi3_nvme_encapsulated_request *nvme_encap_request)
+{
+ u8 format = 0;
+
+ format = ((nvme_encap_request->command[0] & 0xc000) >> 14);
+ return format;
+
+}
+
+/**
+ * mpi3mr_build_nvme_sgl - SGL constructor for NVME
+ * encapsulated request
+ * @mrioc: Adapter instance reference
+ * @nvme_encap_request: NVMe encapsulated MPI request
+ * @drv_bufs: DMA address of the buffers to be placed in sgl
+ * @bufcnt: Number of DMA buffers
+ *
+ * This function places the DMA address of the given buffers in
+ * proper format as SGEs in the given NVMe encapsulated request.
+ *
+ * Return: 0 on success, -1 on failure
+ */
+static int mpi3mr_build_nvme_sgl(struct mpi3mr_ioc *mrioc,
+ struct mpi3_nvme_encapsulated_request *nvme_encap_request,
+ struct mpi3mr_buf_map *drv_bufs, u8 bufcnt)
+{
+ struct mpi3mr_nvme_pt_sge *nvme_sgl;
+ u64 sgl_ptr;
+ u8 count;
+ size_t length = 0;
+ struct mpi3mr_buf_map *drv_buf_iter = drv_bufs;
+ u64 sgemod_mask = ((u64)((mrioc->facts.sge_mod_mask) <<
+ mrioc->facts.sge_mod_shift) << 32);
+ u64 sgemod_val = ((u64)(mrioc->facts.sge_mod_value) <<
+ mrioc->facts.sge_mod_shift) << 32;
+
+ /*
+ * Not all commands require a data transfer. If no data, just return
+ * without constructing any sgl.
+ */
+ for (count = 0; count < bufcnt; count++, drv_buf_iter++) {
+ if (drv_buf_iter->data_dir == DMA_NONE)
+ continue;
+ sgl_ptr = (u64)drv_buf_iter->kern_buf_dma;
+ length = drv_buf_iter->kern_buf_len;
+ break;
+ }
+ if (!length)
+ return 0;
+
+ if (sgl_ptr & sgemod_mask) {
+ dprint_bsg_err(mrioc,
+ "%s: SGL address collides with SGE modifier\n",
+ __func__);
+ return -1;
+ }
+
+ sgl_ptr &= ~sgemod_mask;
+ sgl_ptr |= sgemod_val;
+ nvme_sgl = (struct mpi3mr_nvme_pt_sge *)
+ ((u8 *)(nvme_encap_request->command) + MPI3MR_NVME_CMD_SGL_OFFSET);
+ memset(nvme_sgl, 0, sizeof(struct mpi3mr_nvme_pt_sge));
+ nvme_sgl->base_addr = sgl_ptr;
+ nvme_sgl->length = length;
+ return 0;
+}
+
+/**
+ * mpi3mr_build_nvme_prp - PRP constructor for NVME
+ * encapsulated request
+ * @mrioc: Adapter instance reference
+ * @nvme_encap_request: NVMe encapsulated MPI request
+ * @drv_bufs: DMA address of the buffers to be placed in SGL
+ * @bufcnt: Number of DMA buffers
+ *
+ * This function places the DMA address of the given buffers in
+ * proper format as PRP entries in the given NVMe encapsulated
+ * request.
+ *
+ * Return: 0 on success, -1 on failure
+ */
+static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc,
+ struct mpi3_nvme_encapsulated_request *nvme_encap_request,
+ struct mpi3mr_buf_map *drv_bufs, u8 bufcnt)
+{
+ int prp_size = MPI3MR_NVME_PRP_SIZE;
+ __le64 *prp_entry, *prp1_entry, *prp2_entry;
+ __le64 *prp_page;
+ dma_addr_t prp_entry_dma, prp_page_dma, dma_addr;
+ u32 offset, entry_len, dev_pgsz;
+ u32 page_mask_result, page_mask;
+ size_t length = 0;
+ u8 count;
+ struct mpi3mr_buf_map *drv_buf_iter = drv_bufs;
+ u64 sgemod_mask = ((u64)((mrioc->facts.sge_mod_mask) <<
+ mrioc->facts.sge_mod_shift) << 32);
+ u64 sgemod_val = ((u64)(mrioc->facts.sge_mod_value) <<
+ mrioc->facts.sge_mod_shift) << 32;
+ u16 dev_handle = nvme_encap_request->dev_handle;
+ struct mpi3mr_tgt_dev *tgtdev;
+
+ tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
+ if (!tgtdev) {
+ dprint_bsg_err(mrioc, "%s: invalid device handle 0x%04x\n",
+ __func__, dev_handle);
+ return -1;
+ }
+
+ if (tgtdev->dev_spec.pcie_inf.pgsz == 0) {
+ dprint_bsg_err(mrioc,
+ "%s: NVMe device page size is zero for handle 0x%04x\n",
+ __func__, dev_handle);
+ mpi3mr_tgtdev_put(tgtdev);
+ return -1;
+ }
+
+ dev_pgsz = 1 << (tgtdev->dev_spec.pcie_inf.pgsz);
+ mpi3mr_tgtdev_put(tgtdev);
+
+ /*
+ * Not all commands require a data transfer. If no data, just return
+ * without constructing any PRP.
+ */
+ for (count = 0; count < bufcnt; count++, drv_buf_iter++) {
+ if (drv_buf_iter->data_dir == DMA_NONE)
+ continue;
+ dma_addr = drv_buf_iter->kern_buf_dma;
+ length = drv_buf_iter->kern_buf_len;
+ break;
+ }
+
+ if (!length)
+ return 0;
+
+ mrioc->prp_sz = 0;
+ mrioc->prp_list_virt = dma_alloc_coherent(&mrioc->pdev->dev,
+ dev_pgsz, &mrioc->prp_list_dma, GFP_KERNEL);
+
+ if (!mrioc->prp_list_virt)
+ return -1;
+ mrioc->prp_sz = dev_pgsz;
+
+ /*
+ * Set pointers to PRP1 and PRP2, which are in the NVMe command.
+ * PRP1 is located at a 24 byte offset from the start of the NVMe
+ * command. Then set the current PRP entry pointer to PRP1.
+ */
+ prp1_entry = (__le64 *)((u8 *)(nvme_encap_request->command) +
+ MPI3MR_NVME_CMD_PRP1_OFFSET);
+ prp2_entry = (__le64 *)((u8 *)(nvme_encap_request->command) +
+ MPI3MR_NVME_CMD_PRP2_OFFSET);
+ prp_entry = prp1_entry;
+ /*
+ * For the PRP entries, use the specially allocated buffer of
+ * contiguous memory.
+ */
+ prp_page = (__le64 *)mrioc->prp_list_virt;
+ prp_page_dma = mrioc->prp_list_dma;
+
+ /*
+ * Check if we are within 1 entry of a page boundary we don't
+ * want our first entry to be a PRP List entry.
+ */
+ page_mask = dev_pgsz - 1;
+ page_mask_result = (uintptr_t)((u8 *)prp_page + prp_size) & page_mask;
+ if (!page_mask_result) {
+ dprint_bsg_err(mrioc, "%s: PRP page is not page aligned\n",
+ __func__);
+ goto err_out;
+ }
+
+ /*
+ * Set PRP physical pointer, which initially points to the current PRP
+ * DMA memory page.
+ */
+ prp_entry_dma = prp_page_dma;
+
+
+ /* Loop while the length is not zero. */
+ while (length) {
+ page_mask_result = (prp_entry_dma + prp_size) & page_mask;
+ if (!page_mask_result && (length > dev_pgsz)) {
+ dprint_bsg_err(mrioc,
+ "%s: single PRP page is not sufficient\n",
+ __func__);
+ goto err_out;
+ }
+
+ /* Need to handle if entry will be part of a page. */
+ offset = dma_addr & page_mask;
+ entry_len = dev_pgsz - offset;
+
+ if (prp_entry == prp1_entry) {
+ /*
+ * Must fill in the first PRP pointer (PRP1) before
+ * moving on.
+ */
+ *prp1_entry = cpu_to_le64(dma_addr);
+ if (*prp1_entry & sgemod_mask) {
+ dprint_bsg_err(mrioc,
+ "%s: PRP1 address collides with SGE modifier\n",
+ __func__);
+ goto err_out;
+ }
+ *prp1_entry &= ~sgemod_mask;
+ *prp1_entry |= sgemod_val;
+
+ /*
+ * Now point to the second PRP entry within the
+ * command (PRP2).
+ */
+ prp_entry = prp2_entry;
+ } else if (prp_entry == prp2_entry) {
+ /*
+ * Should the PRP2 entry be a PRP List pointer or just
+ * a regular PRP pointer? If there is more than one
+ * more page of data, must use a PRP List pointer.
+ */
+ if (length > dev_pgsz) {
+ /*
+ * PRP2 will contain a PRP List pointer because
+ * more PRP's are needed with this command. The
+ * list will start at the beginning of the
+ * contiguous buffer.
+ */
+ *prp2_entry = cpu_to_le64(prp_entry_dma);
+ if (*prp2_entry & sgemod_mask) {
+ dprint_bsg_err(mrioc,
+ "%s: PRP list address collides with SGE modifier\n",
+ __func__);
+ goto err_out;
+ }
+ *prp2_entry &= ~sgemod_mask;
+ *prp2_entry |= sgemod_val;
+
+ /*
+ * The next PRP Entry will be the start of the
+ * first PRP List.
+ */
+ prp_entry = prp_page;
+ continue;
+ } else {
+ /*
+ * After this, the PRP Entries are complete.
+ * This command uses 2 PRP's and no PRP list.
+ */
+ *prp2_entry = cpu_to_le64(dma_addr);
+ if (*prp2_entry & sgemod_mask) {
+ dprint_bsg_err(mrioc,
+ "%s: PRP2 collides with SGE modifier\n",
+ __func__);
+ goto err_out;
+ }
+ *prp2_entry &= ~sgemod_mask;
+ *prp2_entry |= sgemod_val;
+ }
+ } else {
+ /*
+ * Put entry in list and bump the addresses.
+ *
+ * After PRP1 and PRP2 are filled in, this will fill in
+ * all remaining PRP entries in a PRP List, one per
+ * each time through the loop.
+ */
+ *prp_entry = cpu_to_le64(dma_addr);
+ if (*prp1_entry & sgemod_mask) {
+ dprint_bsg_err(mrioc,
+ "%s: PRP address collides with SGE modifier\n",
+ __func__);
+ goto err_out;
+ }
+ *prp_entry &= ~sgemod_mask;
+ *prp_entry |= sgemod_val;
+ prp_entry++;
+ prp_entry_dma++;
+ }
+
+ /*
+ * Bump the phys address of the command's data buffer by the
+ * entry_len.
+ */
+ dma_addr += entry_len;
+
+ /* decrement length accounting for last partial page. */
+ if (entry_len > length)
+ length = 0;
+ else
+ length -= entry_len;
+ }
+ return 0;
+err_out:
+ if (mrioc->prp_list_virt) {
+ dma_free_coherent(&mrioc->pdev->dev, mrioc->prp_sz,
+ mrioc->prp_list_virt, mrioc->prp_list_dma);
+ mrioc->prp_list_virt = NULL;
+ }
+ return -1;
+}
+/**
+ * mpi3mr_bsg_process_mpt_cmds - MPI Pass through BSG handler
+ * @job: BSG job reference
+ *
+ * This function is the top level handler for MPI Pass through
+ * command, this does basic validation of the input data buffers,
+ * identifies the given buffer types and MPI command, allocates
+ * DMAable memory for user given buffers, construstcs SGL
+ * properly and passes the command to the firmware.
+ *
+ * Once the MPI command is completed the driver copies the data
+ * if any and reply, sense information to user provided buffers.
+ * If the command is timed out then issues controller reset
+ * prior to returning.
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+
+static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply_payload_rcv_len)
+{
+ long rval = -EINVAL;
+
+ struct mpi3mr_ioc *mrioc = NULL;
+ u8 *mpi_req = NULL, *sense_buff_k = NULL;
+ u8 mpi_msg_size = 0;
+ struct mpi3mr_bsg_packet *bsg_req = NULL;
+ struct mpi3mr_bsg_mptcmd *karg;
+ struct mpi3mr_buf_entry *buf_entries = NULL;
+ struct mpi3mr_buf_map *drv_bufs = NULL, *drv_buf_iter = NULL;
+ u8 count, bufcnt = 0, is_rmcb = 0, is_rmrb = 0, din_cnt = 0, dout_cnt = 0;
+ u8 invalid_be = 0, erb_offset = 0xFF, mpirep_offset = 0xFF, sg_entries = 0;
+ u8 block_io = 0, resp_code = 0, nvme_fmt = 0;
+ struct mpi3_request_header *mpi_header = NULL;
+ struct mpi3_status_reply_descriptor *status_desc;
+ struct mpi3_scsi_task_mgmt_request *tm_req;
+ u32 erbsz = MPI3MR_SENSE_BUF_SZ, tmplen;
+ u16 dev_handle;
+ struct mpi3mr_tgt_dev *tgtdev;
+ struct mpi3mr_stgt_priv_data *stgt_priv = NULL;
+ struct mpi3mr_bsg_in_reply_buf *bsg_reply_buf = NULL;
+ u32 din_size = 0, dout_size = 0;
+ u8 *din_buf = NULL, *dout_buf = NULL;
+ u8 *sgl_iter = NULL, *sgl_din_iter = NULL, *sgl_dout_iter = NULL;
+
+ bsg_req = job->request;
+ karg = (struct mpi3mr_bsg_mptcmd *)&bsg_req->cmd.mptcmd;
+
+ mrioc = mpi3mr_bsg_verify_adapter(karg->mrioc_id);
+ if (!mrioc)
+ return -ENODEV;
+
+ if (karg->timeout < MPI3MR_APP_DEFAULT_TIMEOUT)
+ karg->timeout = MPI3MR_APP_DEFAULT_TIMEOUT;
+
+ mpi_req = kzalloc(MPI3MR_ADMIN_REQ_FRAME_SZ, GFP_KERNEL);
+ if (!mpi_req)
+ return -ENOMEM;
+ mpi_header = (struct mpi3_request_header *)mpi_req;
+
+ bufcnt = karg->buf_entry_list.num_of_entries;
+ drv_bufs = kzalloc((sizeof(*drv_bufs) * bufcnt), GFP_KERNEL);
+ if (!drv_bufs) {
+ rval = -ENOMEM;
+ goto out;
+ }
+
+ dout_buf = kzalloc(job->request_payload.payload_len,
+ GFP_KERNEL);
+ if (!dout_buf) {
+ rval = -ENOMEM;
+ goto out;
+ }
+
+ din_buf = kzalloc(job->reply_payload.payload_len,
+ GFP_KERNEL);
+ if (!din_buf) {
+ rval = -ENOMEM;
+ goto out;
+ }
+
+ sg_copy_to_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ dout_buf, job->request_payload.payload_len);
+
+ buf_entries = karg->buf_entry_list.buf_entry;
+ sgl_din_iter = din_buf;
+ sgl_dout_iter = dout_buf;
+ drv_buf_iter = drv_bufs;
+
+ for (count = 0; count < bufcnt; count++, buf_entries++, drv_buf_iter++) {
+
+ if (sgl_dout_iter > (dout_buf + job->request_payload.payload_len)) {
+ dprint_bsg_err(mrioc, "%s: data_out buffer length mismatch\n",
+ __func__);
+ rval = -EINVAL;
+ goto out;
+ }
+ if (sgl_din_iter > (din_buf + job->reply_payload.payload_len)) {
+ dprint_bsg_err(mrioc, "%s: data_in buffer length mismatch\n",
+ __func__);
+ rval = -EINVAL;
+ goto out;
+ }
+
+ switch (buf_entries->buf_type) {
+ case MPI3MR_BSG_BUFTYPE_RAIDMGMT_CMD:
+ sgl_iter = sgl_dout_iter;
+ sgl_dout_iter += buf_entries->buf_len;
+ drv_buf_iter->data_dir = DMA_TO_DEVICE;
+ is_rmcb = 1;
+ if (count != 0)
+ invalid_be = 1;
+ break;
+ case MPI3MR_BSG_BUFTYPE_RAIDMGMT_RESP:
+ sgl_iter = sgl_din_iter;
+ sgl_din_iter += buf_entries->buf_len;
+ drv_buf_iter->data_dir = DMA_FROM_DEVICE;
+ is_rmrb = 1;
+ if (count != 1 || !is_rmcb)
+ invalid_be = 1;
+ break;
+ case MPI3MR_BSG_BUFTYPE_DATA_IN:
+ sgl_iter = sgl_din_iter;
+ sgl_din_iter += buf_entries->buf_len;
+ drv_buf_iter->data_dir = DMA_FROM_DEVICE;
+ din_cnt++;
+ din_size += drv_buf_iter->bsg_buf_len;
+ if ((din_cnt > 1) && !is_rmcb)
+ invalid_be = 1;
+ break;
+ case MPI3MR_BSG_BUFTYPE_DATA_OUT:
+ sgl_iter = sgl_dout_iter;
+ sgl_dout_iter += buf_entries->buf_len;
+ drv_buf_iter->data_dir = DMA_TO_DEVICE;
+ dout_cnt++;
+ dout_size += drv_buf_iter->bsg_buf_len;
+ if ((dout_cnt > 1) && !is_rmcb)
+ invalid_be = 1;
+ break;
+ case MPI3MR_BSG_BUFTYPE_MPI_REPLY:
+ sgl_iter = sgl_din_iter;
+ sgl_din_iter += buf_entries->buf_len;
+ drv_buf_iter->data_dir = DMA_NONE;
+ mpirep_offset = count;
+ break;
+ case MPI3MR_BSG_BUFTYPE_ERR_RESPONSE:
+ sgl_iter = sgl_din_iter;
+ sgl_din_iter += buf_entries->buf_len;
+ drv_buf_iter->data_dir = DMA_NONE;
+ erb_offset = count;
+ break;
+ case MPI3MR_BSG_BUFTYPE_MPI_REQUEST:
+ sgl_iter = sgl_dout_iter;
+ sgl_dout_iter += buf_entries->buf_len;
+ drv_buf_iter->data_dir = DMA_NONE;
+ mpi_msg_size = buf_entries->buf_len;
+ if ((!mpi_msg_size || (mpi_msg_size % 4)) ||
+ (mpi_msg_size > MPI3MR_ADMIN_REQ_FRAME_SZ)) {
+ dprint_bsg_err(mrioc, "%s: invalid MPI message size\n",
+ __func__);
+ rval = -EINVAL;
+ goto out;
+ }
+ memcpy(mpi_req, sgl_iter, buf_entries->buf_len);
+ break;
+ default:
+ invalid_be = 1;
+ break;
+ }
+ if (invalid_be) {
+ dprint_bsg_err(mrioc, "%s: invalid buffer entries passed\n",
+ __func__);
+ rval = -EINVAL;
+ goto out;
+ }
+
+ drv_buf_iter->bsg_buf = sgl_iter;
+ drv_buf_iter->bsg_buf_len = buf_entries->buf_len;
+
+ }
+ if (!is_rmcb && (dout_cnt || din_cnt)) {
+ sg_entries = dout_cnt + din_cnt;
+ if (((mpi_msg_size) + (sg_entries *
+ sizeof(struct mpi3_sge_common))) > MPI3MR_ADMIN_REQ_FRAME_SZ) {
+ dprint_bsg_err(mrioc,
+ "%s:%d: invalid message size passed\n",
+ __func__, __LINE__);
+ rval = -EINVAL;
+ goto out;
+ }
+ }
+ if (din_size > MPI3MR_MAX_APP_XFER_SIZE) {
+ dprint_bsg_err(mrioc,
+ "%s:%d: invalid data transfer size passed for function 0x%x din_size=%d\n",
+ __func__, __LINE__, mpi_header->function, din_size);
+ rval = -EINVAL;
+ goto out;
+ }
+ if (dout_size > MPI3MR_MAX_APP_XFER_SIZE) {
+ dprint_bsg_err(mrioc,
+ "%s:%d: invalid data transfer size passed for function 0x%x dout_size = %d\n",
+ __func__, __LINE__, mpi_header->function, dout_size);
+ rval = -EINVAL;
+ goto out;
+ }
+
+ drv_buf_iter = drv_bufs;
+ for (count = 0; count < bufcnt; count++, drv_buf_iter++) {
+ if (drv_buf_iter->data_dir == DMA_NONE)
+ continue;
+
+ drv_buf_iter->kern_buf_len = drv_buf_iter->bsg_buf_len;
+ if (is_rmcb && !count)
+ drv_buf_iter->kern_buf_len += ((dout_cnt + din_cnt) *
+ sizeof(struct mpi3_sge_common));
+
+ if (!drv_buf_iter->kern_buf_len)
+ continue;
+
+ drv_buf_iter->kern_buf = dma_alloc_coherent(&mrioc->pdev->dev,
+ drv_buf_iter->kern_buf_len, &drv_buf_iter->kern_buf_dma,
+ GFP_KERNEL);
+ if (!drv_buf_iter->kern_buf) {
+ rval = -ENOMEM;
+ goto out;
+ }
+ if (drv_buf_iter->data_dir == DMA_TO_DEVICE) {
+ tmplen = min(drv_buf_iter->kern_buf_len,
+ drv_buf_iter->bsg_buf_len);
+ memcpy(drv_buf_iter->kern_buf, drv_buf_iter->bsg_buf, tmplen);
+ }
+ }
+
+ if (erb_offset != 0xFF) {
+ sense_buff_k = kzalloc(erbsz, GFP_KERNEL);
+ if (!sense_buff_k) {
+ rval = -ENOMEM;
+ goto out;
+ }
+ }
+
+ if (mutex_lock_interruptible(&mrioc->bsg_cmds.mutex)) {
+ rval = -ERESTARTSYS;
+ goto out;
+ }
+ if (mrioc->bsg_cmds.state & MPI3MR_CMD_PENDING) {
+ rval = -EAGAIN;
+ dprint_bsg_err(mrioc, "%s: command is in use\n", __func__);
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
+ goto out;
+ }
+ if (mrioc->unrecoverable) {
+ dprint_bsg_err(mrioc, "%s: unrecoverable controller\n",
+ __func__);
+ rval = -EFAULT;
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
+ goto out;
+ }
+ if (mrioc->reset_in_progress) {
+ dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__);
+ rval = -EAGAIN;
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
+ goto out;
+ }
+ if (mrioc->stop_bsgs) {
+ dprint_bsg_err(mrioc, "%s: bsgs are blocked\n", __func__);
+ rval = -EAGAIN;
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
+ goto out;
+ }
+
+ if (mpi_header->function == MPI3_BSG_FUNCTION_NVME_ENCAPSULATED) {
+ nvme_fmt = mpi3mr_get_nvme_data_fmt(
+ (struct mpi3_nvme_encapsulated_request *)mpi_req);
+ if (nvme_fmt == MPI3MR_NVME_DATA_FORMAT_PRP) {
+ if (mpi3mr_build_nvme_prp(mrioc,
+ (struct mpi3_nvme_encapsulated_request *)mpi_req,
+ drv_bufs, bufcnt)) {
+ rval = -ENOMEM;
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
+ goto out;
+ }
+ } else if (nvme_fmt == MPI3MR_NVME_DATA_FORMAT_SGL1 ||
+ nvme_fmt == MPI3MR_NVME_DATA_FORMAT_SGL2) {
+ if (mpi3mr_build_nvme_sgl(mrioc,
+ (struct mpi3_nvme_encapsulated_request *)mpi_req,
+ drv_bufs, bufcnt)) {
+ rval = -EINVAL;
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
+ goto out;
+ }
+ } else {
+ dprint_bsg_err(mrioc,
+ "%s:invalid NVMe command format\n", __func__);
+ rval = -EINVAL;
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
+ goto out;
+ }
+ } else {
+ mpi3mr_bsg_build_sgl(mpi_req, (mpi_msg_size),
+ drv_bufs, bufcnt, is_rmcb, is_rmrb,
+ (dout_cnt + din_cnt));
+ }
+
+ if (mpi_header->function == MPI3_BSG_FUNCTION_SCSI_TASK_MGMT) {
+ tm_req = (struct mpi3_scsi_task_mgmt_request *)mpi_req;
+ if (tm_req->task_type !=
+ MPI3_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
+ dev_handle = tm_req->dev_handle;
+ block_io = 1;
+ }
+ }
+ if (block_io) {
+ tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
+ if (tgtdev && tgtdev->starget && tgtdev->starget->hostdata) {
+ stgt_priv = (struct mpi3mr_stgt_priv_data *)
+ tgtdev->starget->hostdata;
+ atomic_inc(&stgt_priv->block_io);
+ mpi3mr_tgtdev_put(tgtdev);
+ }
+ }
+
+ mrioc->bsg_cmds.state = MPI3MR_CMD_PENDING;
+ mrioc->bsg_cmds.is_waiting = 1;
+ mrioc->bsg_cmds.callback = NULL;
+ mrioc->bsg_cmds.is_sense = 0;
+ mrioc->bsg_cmds.sensebuf = sense_buff_k;
+ memset(mrioc->bsg_cmds.reply, 0, mrioc->reply_sz);
+ mpi_header->host_tag = cpu_to_le16(MPI3MR_HOSTTAG_BSG_CMDS);
+ if (mrioc->logging_level & MPI3_DEBUG_BSG_INFO) {
+ dprint_bsg_info(mrioc,
+ "%s: posting bsg request to the controller\n", __func__);
+ dprint_dump(mpi_req, MPI3MR_ADMIN_REQ_FRAME_SZ,
+ "bsg_mpi3_req");
+ if (mpi_header->function == MPI3_BSG_FUNCTION_MGMT_PASSTHROUGH) {
+ drv_buf_iter = &drv_bufs[0];
+ dprint_dump(drv_buf_iter->kern_buf,
+ drv_buf_iter->kern_buf_len, "mpi3_mgmt_req");
+ }
+ }
+
+ init_completion(&mrioc->bsg_cmds.done);
+ rval = mpi3mr_admin_request_post(mrioc, mpi_req,
+ MPI3MR_ADMIN_REQ_FRAME_SZ, 0);
+
+
+ if (rval) {
+ mrioc->bsg_cmds.is_waiting = 0;
+ dprint_bsg_err(mrioc,
+ "%s: posting bsg request is failed\n", __func__);
+ rval = -EAGAIN;
+ goto out_unlock;
+ }
+ wait_for_completion_timeout(&mrioc->bsg_cmds.done,
+ (karg->timeout * HZ));
+ if (block_io && stgt_priv)
+ atomic_dec(&stgt_priv->block_io);
+ if (!(mrioc->bsg_cmds.state & MPI3MR_CMD_COMPLETE)) {
+ mrioc->bsg_cmds.is_waiting = 0;
+ rval = -EAGAIN;
+ if (mrioc->bsg_cmds.state & MPI3MR_CMD_RESET)
+ goto out_unlock;
+ dprint_bsg_err(mrioc,
+ "%s: bsg request timedout after %d seconds\n", __func__,
+ karg->timeout);
+ if (mrioc->logging_level & MPI3_DEBUG_BSG_ERROR) {
+ dprint_dump(mpi_req, MPI3MR_ADMIN_REQ_FRAME_SZ,
+ "bsg_mpi3_req");
+ if (mpi_header->function ==
+ MPI3_BSG_FUNCTION_MGMT_PASSTHROUGH) {
+ drv_buf_iter = &drv_bufs[0];
+ dprint_dump(drv_buf_iter->kern_buf,
+ drv_buf_iter->kern_buf_len, "mpi3_mgmt_req");
+ }
+ }
+
+ if ((mpi_header->function == MPI3_BSG_FUNCTION_NVME_ENCAPSULATED) ||
+ (mpi_header->function == MPI3_BSG_FUNCTION_SCSI_IO))
+ mpi3mr_issue_tm(mrioc,
+ MPI3_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
+ mpi_header->function_dependent, 0,
+ MPI3MR_HOSTTAG_BLK_TMS, MPI3MR_RESETTM_TIMEOUT,
+ &mrioc->host_tm_cmds, &resp_code, NULL);
+ if (!(mrioc->bsg_cmds.state & MPI3MR_CMD_COMPLETE) &&
+ !(mrioc->bsg_cmds.state & MPI3MR_CMD_RESET))
+ mpi3mr_soft_reset_handler(mrioc,
+ MPI3MR_RESET_FROM_APP_TIMEOUT, 1);
+ goto out_unlock;
+ }
+ dprint_bsg_info(mrioc, "%s: bsg request is completed\n", __func__);
+
+ if (mrioc->prp_list_virt) {
+ dma_free_coherent(&mrioc->pdev->dev, mrioc->prp_sz,
+ mrioc->prp_list_virt, mrioc->prp_list_dma);
+ mrioc->prp_list_virt = NULL;
+ }
+
+ if ((mrioc->bsg_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK)
+ != MPI3_IOCSTATUS_SUCCESS) {
+ dprint_bsg_info(mrioc,
+ "%s: command failed, ioc_status(0x%04x) log_info(0x%08x)\n",
+ __func__,
+ (mrioc->bsg_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK),
+ mrioc->bsg_cmds.ioc_loginfo);
+ }
+
+ if ((mpirep_offset != 0xFF) &&
+ drv_bufs[mpirep_offset].bsg_buf_len) {
+ drv_buf_iter = &drv_bufs[mpirep_offset];
+ drv_buf_iter->kern_buf_len = (sizeof(*bsg_reply_buf) - 1 +
+ mrioc->reply_sz);
+ bsg_reply_buf = kzalloc(drv_buf_iter->kern_buf_len, GFP_KERNEL);
+
+ if (!bsg_reply_buf) {
+ rval = -ENOMEM;
+ goto out_unlock;
+ }
+ if (mrioc->bsg_cmds.state & MPI3MR_CMD_REPLY_VALID) {
+ bsg_reply_buf->mpi_reply_type =
+ MPI3MR_BSG_MPI_REPLY_BUFTYPE_ADDRESS;
+ memcpy(bsg_reply_buf->reply_buf,
+ mrioc->bsg_cmds.reply, mrioc->reply_sz);
+ } else {
+ bsg_reply_buf->mpi_reply_type =
+ MPI3MR_BSG_MPI_REPLY_BUFTYPE_STATUS;
+ status_desc = (struct mpi3_status_reply_descriptor *)
+ bsg_reply_buf->reply_buf;
+ status_desc->ioc_status = mrioc->bsg_cmds.ioc_status;
+ status_desc->ioc_log_info = mrioc->bsg_cmds.ioc_loginfo;
+ }
+ tmplen = min(drv_buf_iter->kern_buf_len,
+ drv_buf_iter->bsg_buf_len);
+ memcpy(drv_buf_iter->bsg_buf, bsg_reply_buf, tmplen);
+ }
+
+ if (erb_offset != 0xFF && mrioc->bsg_cmds.sensebuf &&
+ mrioc->bsg_cmds.is_sense) {
+ drv_buf_iter = &drv_bufs[erb_offset];
+ tmplen = min(erbsz, drv_buf_iter->bsg_buf_len);
+ memcpy(drv_buf_iter->bsg_buf, sense_buff_k, tmplen);
+ }
+
+ drv_buf_iter = drv_bufs;
+ for (count = 0; count < bufcnt; count++, drv_buf_iter++) {
+ if (drv_buf_iter->data_dir == DMA_NONE)
+ continue;
+ if (drv_buf_iter->data_dir == DMA_FROM_DEVICE) {
+ tmplen = min(drv_buf_iter->kern_buf_len,
+ drv_buf_iter->bsg_buf_len);
+ memcpy(drv_buf_iter->bsg_buf,
+ drv_buf_iter->kern_buf, tmplen);
+ }
+ }
+
+out_unlock:
+ if (din_buf) {
+ *reply_payload_rcv_len =
+ sg_copy_from_buffer(job->reply_payload.sg_list,
+ job->reply_payload.sg_cnt,
+ din_buf, job->reply_payload.payload_len);
+ }
+ mrioc->bsg_cmds.is_sense = 0;
+ mrioc->bsg_cmds.sensebuf = NULL;
+ mrioc->bsg_cmds.state = MPI3MR_CMD_NOTUSED;
+ mutex_unlock(&mrioc->bsg_cmds.mutex);
+out:
+ kfree(sense_buff_k);
+ kfree(dout_buf);
+ kfree(din_buf);
+ kfree(mpi_req);
+ if (drv_bufs) {
+ drv_buf_iter = drv_bufs;
+ for (count = 0; count < bufcnt; count++, drv_buf_iter++) {
+ if (drv_buf_iter->kern_buf && drv_buf_iter->kern_buf_dma)
+ dma_free_coherent(&mrioc->pdev->dev,
+ drv_buf_iter->kern_buf_len,
+ drv_buf_iter->kern_buf,
+ drv_buf_iter->kern_buf_dma);
+ }
+ kfree(drv_bufs);
+ }
+ kfree(bsg_reply_buf);
+ return rval;
+}
+
+/**
+ * mpi3mr_app_save_logdata - 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
+ *
+ * If log data event caching is enabled by the applicatiobns,
+ * then this function saves the log data in the circular queue
+ * and Sends async signal SIGIO to indicate there is an async
+ * event from the firmware to the event monitoring applications.
+ *
+ * Return:Nothing
+ */
+void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data,
+ u16 event_data_size)
+{
+ u32 index = mrioc->logdata_buf_idx, sz;
+ struct mpi3mr_logdata_entry *entry;
+
+ if (!(mrioc->logdata_buf))
+ return;
+
+ entry = (struct mpi3mr_logdata_entry *)
+ (mrioc->logdata_buf + (index * mrioc->logdata_entry_sz));
+ entry->valid_entry = 1;
+ sz = min(mrioc->logdata_entry_sz, event_data_size);
+ memcpy(entry->data, event_data, sz);
+ mrioc->logdata_buf_idx =
+ ((++index) % MPI3MR_BSG_LOGDATA_MAX_ENTRIES);
+ atomic64_inc(&event_counter);
+}
+
+/**
+ * mpi3mr_bsg_request - bsg request entry point
+ * @job: BSG job reference
+ *
+ * This is driver's entry point for bsg requests
+ *
+ * Return: 0 on success and proper error codes on failure
+ */
+static int mpi3mr_bsg_request(struct bsg_job *job)
+{
+ long rval = -EINVAL;
+ unsigned int reply_payload_rcv_len = 0;
+
+ struct mpi3mr_bsg_packet *bsg_req = job->request;
+
+ switch (bsg_req->cmd_type) {
+ case MPI3MR_DRV_CMD:
+ rval = mpi3mr_bsg_process_drv_cmds(job);
+ break;
+ case MPI3MR_MPT_CMD:
+ rval = mpi3mr_bsg_process_mpt_cmds(job, &reply_payload_rcv_len);
+ break;
+ default:
+ pr_err("%s: unsupported BSG command(0x%08x)\n",
+ MPI3MR_DRIVER_NAME, bsg_req->cmd_type);
+ break;
+ }
+
+ bsg_job_done(job, rval, reply_payload_rcv_len);
+
+ return 0;
+}
+
+/**
+ * mpi3mr_bsg_exit - de-registration from bsg layer
+ *
+ * This will be called during driver unload and all
+ * bsg resources allocated during load will be freed.
+ *
+ * Return:Nothing
+ */
+void mpi3mr_bsg_exit(struct mpi3mr_ioc *mrioc)
+{
+ if (!mrioc->bsg_queue)
+ return;
+
+ bsg_remove_queue(mrioc->bsg_queue);
+ mrioc->bsg_queue = NULL;
+
+ device_del(mrioc->bsg_dev);
+ put_device(mrioc->bsg_dev);
+ kfree(mrioc->bsg_dev);
+}
+
+/**
+ * mpi3mr_bsg_node_release -release bsg device node
+ * @dev: bsg device node
+ *
+ * decrements bsg dev reference count
+ *
+ * Return:Nothing
+ */
+static void mpi3mr_bsg_node_release(struct device *dev)
+{
+ put_device(dev);
+}
+
+/**
+ * mpi3mr_bsg_init - registration with bsg layer
+ *
+ * This will be called during driver load and it will
+ * register driver with bsg layer
+ *
+ * Return:Nothing
+ */
+void mpi3mr_bsg_init(struct mpi3mr_ioc *mrioc)
+{
+ mrioc->bsg_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+ if (!mrioc->bsg_dev) {
+ ioc_err(mrioc, "bsg device mem allocation failed\n");
+ return;
+ }
+
+ device_initialize(mrioc->bsg_dev);
+ dev_set_name(mrioc->bsg_dev, "mpi3mrctl%u", mrioc->id);
+
+ if (device_add(mrioc->bsg_dev)) {
+ ioc_err(mrioc, "%s: bsg device add failed\n",
+ dev_name(mrioc->bsg_dev));
+ goto err_device_add;
+ }
+
+ mrioc->bsg_dev->release = mpi3mr_bsg_node_release;
+
+ mrioc->bsg_queue = bsg_setup_queue(mrioc->bsg_dev, dev_name(mrioc->bsg_dev),
+ mpi3mr_bsg_request, NULL, 0);
+ if (IS_ERR(mrioc->bsg_queue)) {
+ ioc_err(mrioc, "%s: bsg registration failed\n",
+ dev_name(mrioc->bsg_dev));
+ goto err_setup_queue;
+ }
+
+ blk_queue_max_segments(mrioc->bsg_queue, MPI3MR_MAX_APP_XFER_SEGMENTS);
+ blk_queue_max_hw_sectors(mrioc->bsg_queue, MPI3MR_MAX_APP_XFER_SECTORS);
+
+ return;
+
+err_setup_queue:
+ device_del(mrioc->bsg_dev);
+ put_device(mrioc->bsg_dev);
+err_device_add:
+ kfree(mrioc->bsg_dev);
+}
+
+/**
+ * version_fw_show - SysFS callback for firmware version read
+ * @dev: class device
+ * @attr: Device attributes
+ * @buf: Buffer to copy
+ *
+ * Return: sysfs_emit() return after copying firmware version
+ */
+static ssize_t
+version_fw_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);
+ struct mpi3mr_compimg_ver *fwver = &mrioc->facts.fw_ver;
+
+ return sysfs_emit(buf, "%d.%d.%d.%d.%05d-%05d\n",
+ fwver->gen_major, fwver->gen_minor, fwver->ph_major,
+ fwver->ph_minor, fwver->cust_id, fwver->build_num);
+}
+static DEVICE_ATTR_RO(version_fw);
+
+/**
+ * fw_queue_depth_show - SysFS callback for firmware max cmds
+ * @dev: class device
+ * @attr: Device attributes
+ * @buf: Buffer to copy
+ *
+ * Return: sysfs_emit() return after copying firmware max commands
+ */
+static ssize_t
+fw_queue_depth_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 sysfs_emit(buf, "%d\n", mrioc->facts.max_reqs);
+}
+static DEVICE_ATTR_RO(fw_queue_depth);
+
+/**
+ * op_req_q_count_show - SysFS callback for request queue count
+ * @dev: class device
+ * @attr: Device attributes
+ * @buf: Buffer to copy
+ *
+ * Return: sysfs_emit() return after copying request queue count
+ */
+static ssize_t
+op_req_q_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 sysfs_emit(buf, "%d\n", mrioc->num_op_req_q);
+}
+static DEVICE_ATTR_RO(op_req_q_count);
+
+/**
+ * reply_queue_count_show - SysFS callback for reply queue count
+ * @dev: class device
+ * @attr: Device attributes
+ * @buf: Buffer to copy
+ *
+ * Return: sysfs_emit() return after copying reply queue count
+ */
+static ssize_t
+reply_queue_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 sysfs_emit(buf, "%d\n", mrioc->num_op_reply_q);
+}
+
+static DEVICE_ATTR_RO(reply_queue_count);
+
+/**
+ * logging_level_show - Show controller debug level
+ * @dev: class device
+ * @attr: Device attributes
+ * @buf: Buffer to copy
+ *
+ * A sysfs 'read/write' shost attribute, to show the current
+ * debug log level used by the driver for the specific
+ * controller.
+ *
+ * Return: sysfs_emit() return
+ */
+static ssize_t
+logging_level_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 sysfs_emit(buf, "%08xh\n", mrioc->logging_level);
+}
+
+/**
+ * logging_level_store- Change controller debug level
+ * @dev: class device
+ * @attr: Device attributes
+ * @buf: Buffer to copy
+ * @count: size of the buffer
+ *
+ * A sysfs 'read/write' shost attribute, to change the current
+ * debug log level used by the driver for the specific
+ * controller.
+ *
+ * Return: strlen() return
+ */
+static ssize_t
+logging_level_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct mpi3mr_ioc *mrioc = shost_priv(shost);
+ int val = 0;
+
+ if (kstrtoint(buf, 0, &val) != 0)
+ return -EINVAL;
+
+ mrioc->logging_level = val;
+ ioc_info(mrioc, "logging_level=%08xh\n", mrioc->logging_level);
+ return strlen(buf);
+}
+static DEVICE_ATTR_RW(logging_level);
+
+/**
+ * adapter_state_show - SysFS callback for adapter state show
+ * @dev: class device
+ * @attr: Device attributes
+ * @buf: Buffer to copy
+ *
+ * Return: sysfs_emit() return after copying adapter state
+ */
+static ssize_t
+adp_state_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);
+ enum mpi3mr_iocstate ioc_state;
+ uint8_t adp_state;
+
+ ioc_state = mpi3mr_get_iocstate(mrioc);
+ if (ioc_state == MRIOC_STATE_UNRECOVERABLE)
+ adp_state = MPI3MR_BSG_ADPSTATE_UNRECOVERABLE;
+ else if ((mrioc->reset_in_progress) || (mrioc->stop_bsgs))
+ adp_state = MPI3MR_BSG_ADPSTATE_IN_RESET;
+ else if (ioc_state == MRIOC_STATE_FAULT)
+ adp_state = MPI3MR_BSG_ADPSTATE_FAULT;
+ else
+ adp_state = MPI3MR_BSG_ADPSTATE_OPERATIONAL;
+
+ return sysfs_emit(buf, "%u\n", adp_state);
+}
+
+static DEVICE_ATTR_RO(adp_state);
+
+static struct attribute *mpi3mr_host_attrs[] = {
+ &dev_attr_version_fw.attr,
+ &dev_attr_fw_queue_depth.attr,
+ &dev_attr_op_req_q_count.attr,
+ &dev_attr_reply_queue_count.attr,
+ &dev_attr_logging_level.attr,
+ &dev_attr_adp_state.attr,
+ NULL,
+};
+
+static const struct attribute_group mpi3mr_host_attr_group = {
+ .attrs = mpi3mr_host_attrs
+};
+
+const struct attribute_group *mpi3mr_host_groups[] = {
+ &mpi3mr_host_attr_group,
+ NULL,
+};
+
+
+/*
+ * SCSI Device attributes under sysfs
+ */
+
+/**
+ * sas_address_show - SysFS callback for dev SASaddress display
+ * @dev: class device
+ * @attr: Device attributes
+ * @buf: Buffer to copy
+ *
+ * Return: sysfs_emit() return after copying SAS address of the
+ * specific SAS/SATA end device.
+ */
+static ssize_t
+sas_address_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct mpi3mr_sdev_priv_data *sdev_priv_data;
+ struct mpi3mr_stgt_priv_data *tgt_priv_data;
+ struct mpi3mr_tgt_dev *tgtdev;
+
+ sdev_priv_data = sdev->hostdata;
+ if (!sdev_priv_data)
+ return 0;
+
+ tgt_priv_data = sdev_priv_data->tgt_priv_data;
+ if (!tgt_priv_data)
+ return 0;
+ tgtdev = tgt_priv_data->tgt_dev;
+ if (!tgtdev || tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA)
+ return 0;
+ return sysfs_emit(buf, "0x%016llx\n",
+ (unsigned long long)tgtdev->dev_spec.sas_sata_inf.sas_address);
+}
+
+static DEVICE_ATTR_RO(sas_address);
+
+/**
+ * device_handle_show - SysFS callback for device handle display
+ * @dev: class device
+ * @attr: Device attributes
+ * @buf: Buffer to copy
+ *
+ * Return: sysfs_emit() return after copying firmware internal
+ * device handle of the specific device.
+ */
+static ssize_t
+device_handle_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct mpi3mr_sdev_priv_data *sdev_priv_data;
+ struct mpi3mr_stgt_priv_data *tgt_priv_data;
+ struct mpi3mr_tgt_dev *tgtdev;
+
+ sdev_priv_data = sdev->hostdata;
+ if (!sdev_priv_data)
+ return 0;
+
+ tgt_priv_data = sdev_priv_data->tgt_priv_data;
+ if (!tgt_priv_data)
+ return 0;
+ tgtdev = tgt_priv_data->tgt_dev;
+ if (!tgtdev)
+ return 0;
+ return sysfs_emit(buf, "0x%04x\n", tgtdev->dev_handle);
+}
+
+static DEVICE_ATTR_RO(device_handle);
+
+/**
+ * persistent_id_show - SysFS callback for persisten ID display
+ * @dev: class device
+ * @attr: Device attributes
+ * @buf: Buffer to copy
+ *
+ * Return: sysfs_emit() return after copying persistent ID of the
+ * of the specific device.
+ */
+static ssize_t
+persistent_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ struct mpi3mr_sdev_priv_data *sdev_priv_data;
+ struct mpi3mr_stgt_priv_data *tgt_priv_data;
+ struct mpi3mr_tgt_dev *tgtdev;
+
+ sdev_priv_data = sdev->hostdata;
+ if (!sdev_priv_data)
+ return 0;
+
+ tgt_priv_data = sdev_priv_data->tgt_priv_data;
+ if (!tgt_priv_data)
+ return 0;
+ tgtdev = tgt_priv_data->tgt_dev;
+ if (!tgtdev)
+ return 0;
+ return sysfs_emit(buf, "%d\n", tgtdev->perst_id);
+}
+static DEVICE_ATTR_RO(persistent_id);
+
+static struct attribute *mpi3mr_dev_attrs[] = {
+ &dev_attr_sas_address.attr,
+ &dev_attr_device_handle.attr,
+ &dev_attr_persistent_id.attr,
+ NULL,
+};
+
+static const struct attribute_group mpi3mr_dev_attr_group = {
+ .attrs = mpi3mr_dev_attrs
+};
+
+const struct attribute_group *mpi3mr_dev_groups[] = {
+ &mpi3mr_dev_attr_group,
+ NULL,
+};
diff --git a/drivers/scsi/mpi3mr/mpi3mr_debug.h b/drivers/scsi/mpi3mr/mpi3mr_debug.h
index c7982443f45a..2464c400a5a4 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_debug.h
+++ b/drivers/scsi/mpi3mr/mpi3mr_debug.h
@@ -23,8 +23,8 @@
#define MPI3_DEBUG_RESET 0x00000020
#define MPI3_DEBUG_SCSI_ERROR 0x00000040
#define MPI3_DEBUG_REPLY 0x00000080
-#define MPI3_DEBUG_IOCTL_ERROR 0x00008000
-#define MPI3_DEBUG_IOCTL_INFO 0x00010000
+#define MPI3_DEBUG_BSG_ERROR 0x00008000
+#define MPI3_DEBUG_BSG_INFO 0x00010000
#define MPI3_DEBUG_SCSI_INFO 0x00020000
#define MPI3_DEBUG 0x01000000
#define MPI3_DEBUG_SG 0x02000000
@@ -110,21 +110,46 @@
} while (0)
-#define dprint_ioctl_info(ioc, fmt, ...) \
+#define dprint_bsg_info(ioc, fmt, ...) \
do { \
- if (ioc->logging_level & MPI3_DEBUG_IOCTL_INFO) \
+ if (ioc->logging_level & MPI3_DEBUG_BSG_INFO) \
pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \
} while (0)
-#define dprint_ioctl_err(ioc, fmt, ...) \
+#define dprint_bsg_err(ioc, fmt, ...) \
do { \
- if (ioc->logging_level & MPI3_DEBUG_IOCTL_ERROR) \
+ if (ioc->logging_level & MPI3_DEBUG_BSG_ERROR) \
pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \
} while (0)
#endif /* MPT3SAS_DEBUG_H_INCLUDED */
/**
+ * dprint_dump - print contents of a memory buffer
+ * @req: Pointer to a memory buffer
+ * @sz: Memory buffer size
+ * @namestr: Name String to identify the buffer type
+ */
+static inline void
+dprint_dump(void *req, int sz, const char *name_string)
+{
+ int i;
+ __le32 *mfp = (__le32 *)req;
+
+ sz = sz/4;
+ if (name_string)
+ pr_info("%s:\n\t", name_string);
+ else
+ pr_info("request:\n\t");
+ for (i = 0; i < sz; i++) {
+ if (i && ((i % 8) == 0))
+ pr_info("\n\t");
+ pr_info("%08x ", le32_to_cpu(mfp[i]));
+ }
+ pr_info("\n");
+}
+
+/**
* dprint_dump_req - print message frame contents
* @req: pointer to message frame
* @sz: number of dwords
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index e25c02466043..f1d4ea8ba989 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -15,6 +15,8 @@ mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u32 reset_reason);
static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc);
static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
struct mpi3_ioc_facts_data *facts_data);
+static void mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_drv_cmd *drv_cmd);
static int poll_queues;
module_param(poll_queues, int, 0444);
@@ -297,8 +299,14 @@ mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
switch (host_tag) {
case MPI3MR_HOSTTAG_INITCMDS:
return &mrioc->init_cmds;
+ case MPI3MR_HOSTTAG_BSG_CMDS:
+ return &mrioc->bsg_cmds;
case MPI3MR_HOSTTAG_BLK_TMS:
return &mrioc->host_tm_cmds;
+ case MPI3MR_HOSTTAG_PEL_ABORT:
+ return &mrioc->pel_abort_cmd;
+ case MPI3MR_HOSTTAG_PEL_WAIT:
+ return &mrioc->pel_cmds;
case MPI3MR_HOSTTAG_INVALID:
if (def_reply && def_reply->function ==
MPI3_FUNCTION_EVENT_NOTIFICATION)
@@ -865,10 +873,10 @@ static const struct {
} mpi3mr_reset_reason_codes[] = {
{ MPI3MR_RESET_FROM_BRINGUP, "timeout in bringup" },
{ MPI3MR_RESET_FROM_FAULT_WATCH, "fault" },
- { MPI3MR_RESET_FROM_IOCTL, "application invocation" },
+ { MPI3MR_RESET_FROM_APP, "application invocation" },
{ MPI3MR_RESET_FROM_EH_HOS, "error handling" },
{ MPI3MR_RESET_FROM_TM_TIMEOUT, "TM timeout" },
- { MPI3MR_RESET_FROM_IOCTL_TIMEOUT, "IOCTL timeout" },
+ { MPI3MR_RESET_FROM_APP_TIMEOUT, "application command timeout" },
{ MPI3MR_RESET_FROM_MUR_FAILURE, "MUR failure" },
{ MPI3MR_RESET_FROM_CTLR_CLEANUP, "timeout in controller cleanup" },
{ MPI3MR_RESET_FROM_CIACTIV_FAULT, "component image activation fault" },
@@ -2813,6 +2821,10 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
if (!mrioc->init_cmds.reply)
goto out_failed;
+ mrioc->bsg_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
+ if (!mrioc->bsg_cmds.reply)
+ goto out_failed;
+
for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz,
GFP_KERNEL);
@@ -2831,6 +2843,14 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
if (!mrioc->host_tm_cmds.reply)
goto out_failed;
+ mrioc->pel_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
+ if (!mrioc->pel_cmds.reply)
+ goto out_failed;
+
+ mrioc->pel_abort_cmd.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
+ if (!mrioc->pel_abort_cmd.reply)
+ goto out_failed;
+
mrioc->dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8;
if (mrioc->facts.max_devhandle % 8)
mrioc->dev_handle_bitmap_sz++;
@@ -3728,6 +3748,18 @@ retry_init:
goto out_failed;
}
+ if (!mrioc->pel_seqnum_virt) {
+ dprint_init(mrioc, "allocating memory for pel_seqnum_virt\n");
+ mrioc->pel_seqnum_sz = sizeof(struct mpi3_pel_seq);
+ mrioc->pel_seqnum_virt = dma_alloc_coherent(&mrioc->pdev->dev,
+ mrioc->pel_seqnum_sz, &mrioc->pel_seqnum_dma,
+ GFP_KERNEL);
+ if (!mrioc->pel_seqnum_virt) {
+ retval = -ENOMEM;
+ goto out_failed_noretry;
+ }
+ }
+
retval = mpi3mr_enable_events(mrioc);
if (retval) {
ioc_err(mrioc, "failed to enable events %d\n",
@@ -3837,6 +3869,18 @@ retry_init:
goto out_failed;
}
+ if (!mrioc->pel_seqnum_virt) {
+ dprint_reset(mrioc, "allocating memory for pel_seqnum_virt\n");
+ mrioc->pel_seqnum_sz = sizeof(struct mpi3_pel_seq);
+ mrioc->pel_seqnum_virt = dma_alloc_coherent(&mrioc->pdev->dev,
+ mrioc->pel_seqnum_sz, &mrioc->pel_seqnum_dma,
+ GFP_KERNEL);
+ if (!mrioc->pel_seqnum_virt) {
+ retval = -ENOMEM;
+ goto out_failed_noretry;
+ }
+ }
+
if (mrioc->shost->nr_hw_queues > mrioc->num_op_reply_q) {
ioc_err(mrioc,
"cannot create minimum number of operational queues expected:%d created:%d\n",
@@ -3948,8 +3992,14 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
if (mrioc->init_cmds.reply) {
memset(mrioc->init_cmds.reply, 0, sizeof(*mrioc->init_cmds.reply));
+ memset(mrioc->bsg_cmds.reply, 0,
+ sizeof(*mrioc->bsg_cmds.reply));
memset(mrioc->host_tm_cmds.reply, 0,
sizeof(*mrioc->host_tm_cmds.reply));
+ memset(mrioc->pel_cmds.reply, 0,
+ sizeof(*mrioc->pel_cmds.reply));
+ memset(mrioc->pel_abort_cmd.reply, 0,
+ sizeof(*mrioc->pel_abort_cmd.reply));
for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
memset(mrioc->dev_rmhs_cmds[i].reply, 0,
sizeof(*mrioc->dev_rmhs_cmds[i].reply));
@@ -4050,9 +4100,18 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
kfree(mrioc->init_cmds.reply);
mrioc->init_cmds.reply = NULL;
+ kfree(mrioc->bsg_cmds.reply);
+ mrioc->bsg_cmds.reply = NULL;
+
kfree(mrioc->host_tm_cmds.reply);
mrioc->host_tm_cmds.reply = NULL;
+ kfree(mrioc->pel_cmds.reply);
+ mrioc->pel_cmds.reply = NULL;
+
+ kfree(mrioc->pel_abort_cmd.reply);
+ mrioc->pel_abort_cmd.reply = NULL;
+
for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
kfree(mrioc->evtack_cmds[i].reply);
mrioc->evtack_cmds[i].reply = NULL;
@@ -4101,6 +4160,16 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
mrioc->admin_req_base, mrioc->admin_req_dma);
mrioc->admin_req_base = NULL;
}
+
+ if (mrioc->pel_seqnum_virt) {
+ dma_free_coherent(&mrioc->pdev->dev, mrioc->pel_seqnum_sz,
+ mrioc->pel_seqnum_virt, mrioc->pel_seqnum_dma);
+ mrioc->pel_seqnum_virt = NULL;
+ }
+
+ kfree(mrioc->logdata_buf);
+ mrioc->logdata_buf = NULL;
+
}
/**
@@ -4235,6 +4304,8 @@ static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
cmdptr = &mrioc->init_cmds;
mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
+ cmdptr = &mrioc->bsg_cmds;
+ mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
cmdptr = &mrioc->host_tm_cmds;
mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
@@ -4247,6 +4318,254 @@ static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
cmdptr = &mrioc->evtack_cmds[i];
mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
}
+
+ cmdptr = &mrioc->pel_cmds;
+ mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
+
+ cmdptr = &mrioc->pel_abort_cmd;
+ mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
+
+}
+
+/**
+ * mpi3mr_pel_wait_post - Issue PEL Wait
+ * @mrioc: Adapter instance reference
+ * @drv_cmd: Internal command tracker
+ *
+ * Issue PEL Wait MPI request through admin queue and return.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_pel_wait_post(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_drv_cmd *drv_cmd)
+{
+ struct mpi3_pel_req_action_wait pel_wait;
+
+ mrioc->pel_abort_requested = false;
+
+ memset(&pel_wait, 0, sizeof(pel_wait));
+ drv_cmd->state = MPI3MR_CMD_PENDING;
+ drv_cmd->is_waiting = 0;
+ drv_cmd->callback = mpi3mr_pel_wait_complete;
+ drv_cmd->ioc_status = 0;
+ drv_cmd->ioc_loginfo = 0;
+ pel_wait.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_PEL_WAIT);
+ pel_wait.function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG;
+ pel_wait.action = MPI3_PEL_ACTION_WAIT;
+ pel_wait.starting_sequence_number = cpu_to_le32(mrioc->pel_newest_seqnum);
+ pel_wait.locale = cpu_to_le16(mrioc->pel_locale);
+ pel_wait.class = cpu_to_le16(mrioc->pel_class);
+ pel_wait.wait_time = MPI3_PEL_WAITTIME_INFINITE_WAIT;
+ dprint_bsg_info(mrioc, "sending pel_wait seqnum(%d), class(%d), locale(0x%08x)\n",
+ mrioc->pel_newest_seqnum, mrioc->pel_class, mrioc->pel_locale);
+
+ if (mpi3mr_admin_request_post(mrioc, &pel_wait, sizeof(pel_wait), 0)) {
+ dprint_bsg_err(mrioc,
+ "Issuing PELWait: Admin post failed\n");
+ drv_cmd->state = MPI3MR_CMD_NOTUSED;
+ drv_cmd->callback = NULL;
+ drv_cmd->retry_count = 0;
+ mrioc->pel_enabled = false;
+ }
+}
+
+/**
+ * mpi3mr_pel_get_seqnum_post - Issue PEL Get Sequence number
+ * @mrioc: Adapter instance reference
+ * @drv_cmd: Internal command tracker
+ *
+ * Issue PEL get sequence number MPI request through admin queue
+ * and return.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_pel_get_seqnum_post(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_drv_cmd *drv_cmd)
+{
+ struct mpi3_pel_req_action_get_sequence_numbers pel_getseq_req;
+ u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
+ int retval = 0;
+
+ memset(&pel_getseq_req, 0, sizeof(pel_getseq_req));
+ mrioc->pel_cmds.state = MPI3MR_CMD_PENDING;
+ mrioc->pel_cmds.is_waiting = 0;
+ mrioc->pel_cmds.ioc_status = 0;
+ mrioc->pel_cmds.ioc_loginfo = 0;
+ mrioc->pel_cmds.callback = mpi3mr_pel_get_seqnum_complete;
+ pel_getseq_req.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_PEL_WAIT);
+ pel_getseq_req.function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG;
+ pel_getseq_req.action = MPI3_PEL_ACTION_GET_SEQNUM;
+ mpi3mr_add_sg_single(&pel_getseq_req.sgl, sgl_flags,
+ mrioc->pel_seqnum_sz, mrioc->pel_seqnum_dma);
+
+ retval = mpi3mr_admin_request_post(mrioc, &pel_getseq_req,
+ sizeof(pel_getseq_req), 0);
+ if (retval) {
+ if (drv_cmd) {
+ drv_cmd->state = MPI3MR_CMD_NOTUSED;
+ drv_cmd->callback = NULL;
+ drv_cmd->retry_count = 0;
+ }
+ mrioc->pel_enabled = false;
+ }
+
+ return retval;
+}
+
+/**
+ * mpi3mr_pel_wait_complete - PELWait Completion callback
+ * @mrioc: Adapter instance reference
+ * @drv_cmd: Internal command tracker
+ *
+ * This is a callback handler for the PELWait request and
+ * firmware completes a PELWait request when it is aborted or a
+ * new PEL entry is available. This sends AEN to the application
+ * and if the PELwait completion is not due to PELAbort then
+ * this will send a request for new PEL Sequence number
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_drv_cmd *drv_cmd)
+{
+ struct mpi3_pel_reply *pel_reply = NULL;
+ u16 ioc_status, pe_log_status;
+ bool do_retry = false;
+
+ if (drv_cmd->state & MPI3MR_CMD_RESET)
+ goto cleanup_drv_cmd;
+
+ ioc_status = drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
+ if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+ ioc_err(mrioc, "%s: Failed ioc_status(0x%04x) Loginfo(0x%08x)\n",
+ __func__, ioc_status, drv_cmd->ioc_loginfo);
+ dprint_bsg_err(mrioc,
+ "pel_wait: failed with ioc_status(0x%04x), log_info(0x%08x)\n",
+ ioc_status, drv_cmd->ioc_loginfo);
+ do_retry = true;
+ }
+
+ if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID)
+ pel_reply = (struct mpi3_pel_reply *)drv_cmd->reply;
+
+ if (!pel_reply) {
+ dprint_bsg_err(mrioc,
+ "pel_wait: failed due to no reply\n");
+ goto out_failed;
+ }
+
+ pe_log_status = le16_to_cpu(pel_reply->pe_log_status);
+ if ((pe_log_status != MPI3_PEL_STATUS_SUCCESS) &&
+ (pe_log_status != MPI3_PEL_STATUS_ABORTED)) {
+ ioc_err(mrioc, "%s: Failed pe_log_status(0x%04x)\n",
+ __func__, pe_log_status);
+ dprint_bsg_err(mrioc,
+ "pel_wait: failed due to pel_log_status(0x%04x)\n",
+ pe_log_status);
+ do_retry = true;
+ }
+
+ if (do_retry) {
+ if (drv_cmd->retry_count < MPI3MR_PEL_RETRY_COUNT) {
+ drv_cmd->retry_count++;
+ dprint_bsg_err(mrioc, "pel_wait: retrying(%d)\n",
+ drv_cmd->retry_count);
+ mpi3mr_pel_wait_post(mrioc, drv_cmd);
+ return;
+ }
+ dprint_bsg_err(mrioc,
+ "pel_wait: failed after all retries(%d)\n",
+ drv_cmd->retry_count);
+ goto out_failed;
+ }
+ atomic64_inc(&event_counter);
+ if (!mrioc->pel_abort_requested) {
+ mrioc->pel_cmds.retry_count = 0;
+ mpi3mr_pel_get_seqnum_post(mrioc, &mrioc->pel_cmds);
+ }
+
+ return;
+out_failed:
+ mrioc->pel_enabled = false;
+cleanup_drv_cmd:
+ drv_cmd->state = MPI3MR_CMD_NOTUSED;
+ drv_cmd->callback = NULL;
+ drv_cmd->retry_count = 0;
+}
+
+/**
+ * mpi3mr_pel_get_seqnum_complete - PELGetSeqNum Completion callback
+ * @mrioc: Adapter instance reference
+ * @drv_cmd: Internal command tracker
+ *
+ * This is a callback handler for the PEL get sequence number
+ * request and a new PEL wait request will be issued to the
+ * firmware from this
+ *
+ * Return: Nothing.
+ */
+void mpi3mr_pel_get_seqnum_complete(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_drv_cmd *drv_cmd)
+{
+ struct mpi3_pel_reply *pel_reply = NULL;
+ struct mpi3_pel_seq *pel_seqnum_virt;
+ u16 ioc_status;
+ bool do_retry = false;
+
+ pel_seqnum_virt = (struct mpi3_pel_seq *)mrioc->pel_seqnum_virt;
+
+ if (drv_cmd->state & MPI3MR_CMD_RESET)
+ goto cleanup_drv_cmd;
+
+ ioc_status = drv_cmd->ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
+ if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+ dprint_bsg_err(mrioc,
+ "pel_get_seqnum: failed with ioc_status(0x%04x), log_info(0x%08x)\n",
+ ioc_status, drv_cmd->ioc_loginfo);
+ do_retry = true;
+ }
+
+ if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID)
+ pel_reply = (struct mpi3_pel_reply *)drv_cmd->reply;
+ if (!pel_reply) {
+ dprint_bsg_err(mrioc,
+ "pel_get_seqnum: failed due to no reply\n");
+ goto out_failed;
+ }
+
+ if (le16_to_cpu(pel_reply->pe_log_status) != MPI3_PEL_STATUS_SUCCESS) {
+ dprint_bsg_err(mrioc,
+ "pel_get_seqnum: failed due to pel_log_status(0x%04x)\n",
+ le16_to_cpu(pel_reply->pe_log_status));
+ do_retry = true;
+ }
+
+ if (do_retry) {
+ if (drv_cmd->retry_count < MPI3MR_PEL_RETRY_COUNT) {
+ drv_cmd->retry_count++;
+ dprint_bsg_err(mrioc,
+ "pel_get_seqnum: retrying(%d)\n",
+ drv_cmd->retry_count);
+ mpi3mr_pel_get_seqnum_post(mrioc, drv_cmd);
+ return;
+ }
+
+ dprint_bsg_err(mrioc,
+ "pel_get_seqnum: failed after all retries(%d)\n",
+ drv_cmd->retry_count);
+ goto out_failed;
+ }
+ mrioc->pel_newest_seqnum = le32_to_cpu(pel_seqnum_virt->newest) + 1;
+ drv_cmd->retry_count = 0;
+ mpi3mr_pel_wait_post(mrioc, drv_cmd);
+
+ return;
+out_failed:
+ mrioc->pel_enabled = false;
+cleanup_drv_cmd:
+ drv_cmd->state = MPI3MR_CMD_NOTUSED;
+ drv_cmd->callback = NULL;
+ drv_cmd->retry_count = 0;
}
/**
@@ -4258,7 +4577,7 @@ static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
* This is an handler for recovering controller by issuing soft
* reset are diag fault reset. This is a blocking function and
* when one reset is executed if any other resets they will be
- * blocked. All IOCTLs/IO will be blocked during the reset. If
+ * blocked. All BSG requests will be blocked during the reset. If
* controller reset is successful then the controller will be
* reinitalized, otherwise the controller will be marked as not
* recoverable
@@ -4305,6 +4624,7 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
mpi3mr_reset_rc_name(reset_reason));
mrioc->reset_in_progress = 1;
+ mrioc->stop_bsgs = 1;
mrioc->prev_reset_result = -1;
if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) &&
@@ -4369,6 +4689,12 @@ out:
if (!retval) {
mrioc->diagsave_timeout = 0;
mrioc->reset_in_progress = 0;
+ mrioc->pel_abort_requested = 0;
+ if (mrioc->pel_enabled) {
+ mrioc->pel_cmds.retry_count = 0;
+ mpi3mr_pel_wait_post(mrioc, &mrioc->pel_cmds);
+ }
+
mpi3mr_rfresh_tgtdevs(mrioc);
mrioc->ts_update_counter = 0;
spin_lock_irqsave(&mrioc->watchdog_lock, flags);
@@ -4377,6 +4703,9 @@ out:
&mrioc->watchdog_work,
msecs_to_jiffies(MPI3MR_WATCHDOG_INTERVAL));
spin_unlock_irqrestore(&mrioc->watchdog_lock, flags);
+ mrioc->stop_bsgs = 0;
+ if (mrioc->pel_enabled)
+ atomic64_inc(&event_counter);
} else {
mpi3mr_issue_reset(mrioc,
MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index f7cd70a15ea6..d8c195b7ca57 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -14,6 +14,7 @@ LIST_HEAD(mrioc_list);
DEFINE_SPINLOCK(mrioc_list_lock);
static int mrioc_ids;
static int warn_non_secure_ctlr;
+atomic64_t event_counter;
MODULE_AUTHOR(MPI3MR_DRIVER_AUTHOR);
MODULE_DESCRIPTION(MPI3MR_DRIVER_DESC);
@@ -634,7 +635,7 @@ found_tgtdev:
*
* Return: Target device reference.
*/
-static struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_handle(
+struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_handle(
struct mpi3mr_ioc *mrioc, u16 handle)
{
struct mpi3mr_tgt_dev *tgtdev;
@@ -910,9 +911,11 @@ void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc)
list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
list) {
- if ((tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) &&
- tgtdev->host_exposed) {
- mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
+ if (tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) {
+ dprint_reset(mrioc, "removing target device with perst_id(%d)\n",
+ tgtdev->perst_id);
+ if (tgtdev->host_exposed)
+ mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
mpi3mr_tgtdev_del_from_list(mrioc, tgtdev);
mpi3mr_tgtdev_put(tgtdev);
}
@@ -1416,6 +1419,23 @@ static void mpi3mr_pcietopochg_evt_bh(struct mpi3mr_ioc *mrioc,
}
/**
+ * mpi3mr_logdata_evt_bh - Log data event bottomhalf
+ * @mrioc: Adapter instance reference
+ * @fwevt: Firmware event reference
+ *
+ * Extracts the event data and calls application interfacing
+ * function to process the event further.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_logdata_evt_bh(struct mpi3mr_ioc *mrioc,
+ struct mpi3mr_fwevt *fwevt)
+{
+ mpi3mr_app_save_logdata(mrioc, fwevt->event_data,
+ fwevt->event_data_size);
+}
+
+/**
* mpi3mr_fwevt_bh - Firmware event bottomhalf handler
* @mrioc: Adapter instance reference
* @fwevt: Firmware event reference
@@ -1467,6 +1487,11 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
mpi3mr_pcietopochg_evt_bh(mrioc, fwevt);
break;
}
+ case MPI3_EVENT_LOG_DATA:
+ {
+ mpi3mr_logdata_evt_bh(mrioc, fwevt);
+ break;
+ }
default:
break;
}
@@ -2298,6 +2323,7 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
break;
}
case MPI3_EVENT_DEVICE_INFO_CHANGED:
+ case MPI3_EVENT_LOG_DATA:
{
process_evt_bh = 1;
break;
@@ -2996,7 +3022,7 @@ inline void mpi3mr_poll_pend_io_completions(struct mpi3mr_ioc *mrioc)
*
* Return: 0 on success, non-zero on errors
*/
-static int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
+int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
u16 handle, uint lun, u16 htag, ulong timeout,
struct mpi3mr_drv_cmd *drv_cmd,
u8 *resp_code, struct scsi_cmnd *scmd)
@@ -3589,6 +3615,7 @@ static int mpi3mr_scan_finished(struct Scsi_Host *shost,
mpi3mr_start_watchdog(mrioc);
mrioc->is_driver_loading = 0;
+ mrioc->stop_bsgs = 0;
return 1;
}
@@ -3700,6 +3727,10 @@ static int mpi3mr_slave_configure(struct scsi_device *sdev)
return -ENXIO;
mpi3mr_change_queue_depth(sdev, tgt_dev->q_depth);
+
+ sdev->eh_timeout = MPI3MR_EH_SCMD_TIMEOUT;
+ blk_queue_rq_timeout(sdev->request_queue, MPI3MR_SCMD_TIMEOUT);
+
switch (tgt_dev->dev_type) {
case MPI3_DEVICE_DEVFORM_PCIE:
/*The block layer hw sector size = 512*/
@@ -3971,6 +4002,12 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,
int iprio_class;
u8 is_pcie_dev = 0;
+ if (mrioc->unrecoverable) {
+ scmd->result = DID_ERROR << 16;
+ scsi_done(scmd);
+ goto out;
+ }
+
sdev_priv_data = scmd->device->hostdata;
if (!sdev_priv_data || !sdev_priv_data->tgt_priv_data) {
scmd->result = DID_NO_CONNECT << 16;
@@ -4109,6 +4146,8 @@ static struct scsi_host_template mpi3mr_driver_template = {
.max_segment_size = 0xffffffff,
.track_queue_depth = 1,
.cmd_size = sizeof(struct scmd_priv),
+ .shost_groups = mpi3mr_host_groups,
+ .sdev_groups = mpi3mr_dev_groups,
};
/**
@@ -4259,6 +4298,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mutex_init(&mrioc->reset_mutex);
mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
mpi3mr_init_drv_cmd(&mrioc->host_tm_cmds, MPI3MR_HOSTTAG_BLK_TMS);
+ mpi3mr_init_drv_cmd(&mrioc->bsg_cmds, MPI3MR_HOSTTAG_BSG_CMDS);
for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
mpi3mr_init_drv_cmd(&mrioc->dev_rmhs_cmds[i],
@@ -4271,6 +4311,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
mrioc->logging_level = logging_level;
mrioc->shost = shost;
mrioc->pdev = pdev;
+ mrioc->stop_bsgs = 1;
/* init shost parameters */
shost->max_cmd_len = MPI3MR_MAX_CDB_LENGTH;
@@ -4345,6 +4386,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
scsi_scan_host(shost);
+ mpi3mr_bsg_init(mrioc);
return retval;
addhost_failed:
@@ -4389,6 +4431,7 @@ static void mpi3mr_remove(struct pci_dev *pdev)
while (mrioc->reset_in_progress || mrioc->is_driver_loading)
ssleep(1);
+ mpi3mr_bsg_exit(mrioc);
mrioc->stop_drv_processing = 1;
mpi3mr_cleanup_fwevt_list(mrioc);
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
@@ -4563,6 +4606,12 @@ static struct pci_driver mpi3mr_pci_driver = {
#endif
};
+static ssize_t event_counter_show(struct device_driver *dd, char *buf)
+{
+ return sprintf(buf, "%llu\n", atomic64_read(&event_counter));
+}
+static DRIVER_ATTR_RO(event_counter);
+
static int __init mpi3mr_init(void)
{
int ret_val;
@@ -4571,6 +4620,16 @@ static int __init mpi3mr_init(void)
MPI3MR_DRIVER_VERSION);
ret_val = pci_register_driver(&mpi3mr_pci_driver);
+ if (ret_val) {
+ pr_err("%s failed to load due to pci register driver failure\n",
+ MPI3MR_DRIVER_NAME);
+ return ret_val;
+ }
+
+ ret_val = driver_create_file(&mpi3mr_pci_driver.driver,
+ &driver_attr_event_counter);
+ if (ret_val)
+ pci_unregister_driver(&mpi3mr_pci_driver);
return ret_val;
}
@@ -4585,6 +4644,8 @@ static void __exit mpi3mr_exit(void)
pr_info("Unloading %s version %s\n", MPI3MR_DRIVER_NAME,
MPI3MR_DRIVER_VERSION);
+ driver_remove_file(&mpi3mr_pci_driver.driver,
+ &driver_attr_event_counter);
pci_unregister_driver(&mpi3mr_pci_driver);
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index b57f1803371e..37d46ae5c61d 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -3692,10 +3692,11 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
}
for (i = 0; i < ioc->combined_reply_index_count; i++) {
- ioc->replyPostRegisterIndex[i] = (resource_size_t *)
- ((u8 __force *)&ioc->chip->Doorbell +
- MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET +
- (i * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET));
+ ioc->replyPostRegisterIndex[i] =
+ (resource_size_t __iomem *)
+ ((u8 __force *)&ioc->chip->Doorbell +
+ MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET +
+ (i * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET));
}
}
@@ -4312,7 +4313,7 @@ _base_put_smid_scsi_io_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
descriptor.SMID = cpu_to_le16(smid);
- writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+ writel(*request, &ioc->chip->AtomicRequestDescriptorPost);
}
/**
@@ -4334,7 +4335,7 @@ _base_put_smid_fast_path_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
descriptor.SMID = cpu_to_le16(smid);
- writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+ writel(*request, &ioc->chip->AtomicRequestDescriptorPost);
}
/**
@@ -4357,7 +4358,7 @@ _base_put_smid_hi_priority_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid,
descriptor.MSIxIndex = msix_task;
descriptor.SMID = cpu_to_le16(smid);
- writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+ writel(*request, &ioc->chip->AtomicRequestDescriptorPost);
}
/**
@@ -4378,7 +4379,7 @@ _base_put_smid_default_atomic(struct MPT3SAS_ADAPTER *ioc, u16 smid)
descriptor.MSIxIndex = _base_set_and_get_msix_index(ioc, smid);
descriptor.SMID = cpu_to_le16(smid);
- writel(cpu_to_le32(*request), &ioc->chip->AtomicRequestDescriptorPost);
+ writel(*request, &ioc->chip->AtomicRequestDescriptorPost);
}
/**
@@ -4752,7 +4753,7 @@ static void
_base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc)
{
int i = 0;
- char desc[16];
+ char desc[17] = {0};
u32 iounit_pg1_flags;
u32 bios_version;
@@ -5716,13 +5717,12 @@ _base_release_memory_pools(struct MPT3SAS_ADAPTER *ioc)
/**
* mpt3sas_check_same_4gb_region - checks whether all reply queues in a set are
* having same upper 32bits in their base memory address.
- * @reply_pool_start_address: Base address of a reply queue set
+ * @start_address: Base address of a reply queue set
* @pool_sz: Size of single Reply Descriptor Post Queues pool size
*
* Return: 1 if reply queues in a set have a same upper 32bits in their base
* memory address, else 0.
*/
-
static int
mpt3sas_check_same_4gb_region(dma_addr_t start_address, u32 pool_sz)
{
@@ -6894,7 +6894,7 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
/* send message 32-bits at a time */
for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
- writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
+ writel(request[i], &ioc->chip->Doorbell);
if ((_base_wait_for_doorbell_ack(ioc, 5)))
failed = 1;
}
@@ -6913,16 +6913,16 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
}
/* read the first two 16-bits, it gives the total length of the reply */
- reply[0] = le16_to_cpu(ioc->base_readl(&ioc->chip->Doorbell)
- & MPI2_DOORBELL_DATA_MASK);
+ reply[0] = ioc->base_readl(&ioc->chip->Doorbell)
+ & MPI2_DOORBELL_DATA_MASK;
writel(0, &ioc->chip->HostInterruptStatus);
if ((_base_wait_for_doorbell_int(ioc, 5))) {
ioc_err(ioc, "doorbell handshake int failed (line=%d)\n",
__LINE__);
return -EFAULT;
}
- reply[1] = le16_to_cpu(ioc->base_readl(&ioc->chip->Doorbell)
- & MPI2_DOORBELL_DATA_MASK);
+ reply[1] = ioc->base_readl(&ioc->chip->Doorbell)
+ & MPI2_DOORBELL_DATA_MASK;
writel(0, &ioc->chip->HostInterruptStatus);
for (i = 2; i < default_reply->MsgLength * 2; i++) {
@@ -6934,9 +6934,8 @@ _base_handshake_req_reply_wait(struct MPT3SAS_ADAPTER *ioc, int request_bytes,
if (i >= reply_bytes/2) /* overflow case */
ioc->base_readl(&ioc->chip->Doorbell);
else
- reply[i] = le16_to_cpu(
- ioc->base_readl(&ioc->chip->Doorbell)
- & MPI2_DOORBELL_DATA_MASK);
+ reply[i] = ioc->base_readl(&ioc->chip->Doorbell)
+ & MPI2_DOORBELL_DATA_MASK;
writel(0, &ioc->chip->HostInterruptStatus);
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index 949e98d523e2..e584cf0ffc23 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -77,8 +77,8 @@
#define MPT3SAS_DRIVER_NAME "mpt3sas"
#define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
#define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver"
-#define MPT3SAS_DRIVER_VERSION "40.100.00.00"
-#define MPT3SAS_MAJOR_VERSION 40
+#define MPT3SAS_DRIVER_VERSION "42.100.00.00"
+#define MPT3SAS_MAJOR_VERSION 42
#define MPT3SAS_MINOR_VERSION 100
#define MPT3SAS_BUILD_VERSION 0
#define MPT3SAS_RELEASE_VERSION 00
@@ -1588,7 +1588,7 @@ struct MPT3SAS_ADAPTER {
u8 combined_reply_index_count;
u8 smp_affinity_enable;
/* reply post register index */
- resource_size_t **replyPostRegisterIndex;
+ resource_size_t __iomem **replyPostRegisterIndex;
struct list_head delayed_tr_list;
struct list_head delayed_tr_volume_list;
diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c
index 0563078227de..a8dd14c91efd 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_config.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_config.c
@@ -394,10 +394,13 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
retry_count++;
if (ioc->config_cmds.smid == smid)
mpt3sas_base_free_smid(ioc, smid);
- if ((ioc->shost_recovery) || (ioc->config_cmds.status &
- MPT3_CMD_RESET) || ioc->pci_error_recovery)
+ if (ioc->config_cmds.status & MPT3_CMD_RESET)
goto retry_config;
- issue_host_reset = 1;
+ if (ioc->shost_recovery || ioc->pci_error_recovery) {
+ issue_host_reset = 0;
+ r = -EFAULT;
+ } else
+ issue_host_reset = 1;
goto free_mem;
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index d92ca140d298..84c87c2c3e7e 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -578,7 +578,7 @@ static int
_ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg,
Mpi2SCSITaskManagementRequest_t *tm_request)
{
- u8 found = 0;
+ bool found = false;
u16 smid;
u16 handle;
struct scsi_cmnd *scmd;
@@ -600,6 +600,7 @@ _ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg,
handle = le16_to_cpu(tm_request->DevHandle);
for (smid = ioc->scsiio_depth; smid && !found; smid--) {
struct scsiio_tracker *st;
+ __le16 task_mid;
scmd = mpt3sas_scsih_scsi_lookup_get(ioc, smid);
if (!scmd)
@@ -618,10 +619,10 @@ _ctl_set_task_mid(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command *karg,
* first outstanding smid will be picked up. Otherwise,
* targeted smid will be the one.
*/
- if (!tm_request->TaskMID || tm_request->TaskMID == st->smid) {
- tm_request->TaskMID = cpu_to_le16(st->smid);
- found = 1;
- }
+ task_mid = cpu_to_le16(st->smid);
+ if (!tm_request->TaskMID)
+ tm_request->TaskMID = task_mid;
+ found = tm_request->TaskMID == task_mid;
}
if (!found) {
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 00792767c620..b519f4b59d30 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -10926,20 +10926,20 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
case MPI2_EVENT_LOG_ENTRY_ADDED:
{
Mpi2EventDataLogEntryAdded_t *log_entry;
- u32 *log_code;
+ u32 log_code;
if (!ioc->is_warpdrive)
break;
log_entry = (Mpi2EventDataLogEntryAdded_t *)
mpi_reply->EventData;
- log_code = (u32 *)log_entry->LogData;
+ log_code = le32_to_cpu(*(__le32 *)log_entry->LogData);
if (le16_to_cpu(log_entry->LogEntryQualifier)
!= MPT2_WARPDRIVE_LOGENTRY)
break;
- switch (le32_to_cpu(*log_code)) {
+ switch (log_code) {
case MPT2_WARPDRIVE_LC_SSDT:
ioc_warn(ioc, "WarpDrive Warning: IO Throttling has occurred in the WarpDrive subsystem. Check WarpDrive documentation for additional details.\n");
break;
@@ -11035,6 +11035,7 @@ _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc,
{
struct _sas_port *mpt3sas_port, *next;
unsigned long flags;
+ int port_id;
/* remove sibling ports attached to this expander */
list_for_each_entry_safe(mpt3sas_port, next,
@@ -11055,6 +11056,8 @@ _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc,
mpt3sas_port->hba_port);
}
+ port_id = sas_expander->port->port_id;
+
mpt3sas_transport_port_remove(ioc, sas_expander->sas_address,
sas_expander->sas_address_parent, sas_expander->port);
@@ -11062,7 +11065,7 @@ _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc,
"expander_remove: handle(0x%04x), sas_addr(0x%016llx), port:%d\n",
sas_expander->handle, (unsigned long long)
sas_expander->sas_address,
- sas_expander->port->port_id);
+ port_id);
spin_lock_irqsave(&ioc->sas_node_lock, flags);
list_del(&sas_expander->list);
@@ -12585,20 +12588,18 @@ scsih_pci_mmio_enabled(struct pci_dev *pdev)
*/
bool scsih_ncq_prio_supp(struct scsi_device *sdev)
{
- unsigned char *buf;
+ struct scsi_vpd *vpd;
bool ncq_prio_supp = false;
- if (!scsi_device_supports_vpd(sdev))
- return ncq_prio_supp;
-
- buf = kmalloc(SCSI_VPD_PG_LEN, GFP_KERNEL);
- if (!buf)
- return ncq_prio_supp;
+ rcu_read_lock();
+ vpd = rcu_dereference(sdev->vpd_pg89);
+ if (!vpd || vpd->len < 214)
+ goto out;
- if (!scsi_get_vpd_page(sdev, 0x89, buf, SCSI_VPD_PG_LEN))
- ncq_prio_supp = (buf[213] >> 4) & 1;
+ ncq_prio_supp = (vpd->data[213] >> 4) & 1;
+out:
+ rcu_read_unlock();
- kfree(buf);
return ncq_prio_supp;
}
/*
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index 7ac63eb5ccd3..2fde496fff5f 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -647,6 +647,7 @@ static struct pci_device_id mvs_pci_table[] = {
{ PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1300), chip_1300 },
{ PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1320), chip_1320 },
{ PCI_VDEVICE(ADAPTEC2, 0x0450), chip_6440 },
+ { PCI_VDEVICE(TTI, 0x2640), chip_6440 },
{ PCI_VDEVICE(TTI, 0x2710), chip_9480 },
{ PCI_VDEVICE(TTI, 0x2720), chip_9480 },
{ PCI_VDEVICE(TTI, 0x2721), chip_9480 },
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index c4a838635893..5d7dfefd6f6c 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -192,10 +192,11 @@ struct sym53c500_data {
int fast_pio;
};
-static struct scsi_pointer *sym53c500_scsi_pointer(struct scsi_cmnd *cmd)
-{
- return scsi_cmd_priv(cmd);
-}
+struct sym53c500_cmd_priv {
+ int status;
+ int message;
+ int phase;
+};
enum Phase {
idle,
@@ -356,7 +357,7 @@ SYM53C500_intr(int irq, void *dev_id)
struct sym53c500_data *data =
(struct sym53c500_data *)dev->hostdata;
struct scsi_cmnd *curSC = data->current_SC;
- struct scsi_pointer *scsi_pointer = sym53c500_scsi_pointer(curSC);
+ struct sym53c500_cmd_priv *scp = scsi_cmd_priv(curSC);
int fast_pio = data->fast_pio;
spin_lock_irqsave(dev->host_lock, flags);
@@ -403,12 +404,11 @@ SYM53C500_intr(int irq, void *dev_id)
if (int_reg & 0x20) { /* Disconnect */
DEB(printk("SYM53C500: disconnect intr received\n"));
- if (scsi_pointer->phase != message_in) { /* Unexpected disconnect */
+ if (scp->phase != message_in) { /* Unexpected disconnect */
curSC->result = DID_NO_CONNECT << 16;
} else { /* Command complete, return status and message */
- curSC->result = (scsi_pointer->Status & 0xff) |
- ((scsi_pointer->Message & 0xff) << 8) |
- (DID_OK << 16);
+ curSC->result = (scp->status & 0xff) |
+ ((scp->message & 0xff) << 8) | (DID_OK << 16);
}
goto idle_out;
}
@@ -419,7 +419,7 @@ SYM53C500_intr(int irq, void *dev_id)
struct scatterlist *sg;
int i;
- scsi_pointer->phase = data_out;
+ scp->phase = data_out;
VDEB(printk("SYM53C500: Data-Out phase\n"));
outb(FLUSH_FIFO, port_base + CMD_REG);
LOAD_DMA_COUNT(port_base, scsi_bufflen(curSC)); /* Max transfer size */
@@ -438,7 +438,7 @@ SYM53C500_intr(int irq, void *dev_id)
struct scatterlist *sg;
int i;
- scsi_pointer->phase = data_in;
+ scp->phase = data_in;
VDEB(printk("SYM53C500: Data-In phase\n"));
outb(FLUSH_FIFO, port_base + CMD_REG);
LOAD_DMA_COUNT(port_base, scsi_bufflen(curSC)); /* Max transfer size */
@@ -453,12 +453,12 @@ SYM53C500_intr(int irq, void *dev_id)
break;
case 0x02: /* COMMAND */
- scsi_pointer->phase = command_ph;
+ scp->phase = command_ph;
printk("SYM53C500: Warning: Unknown interrupt occurred in command phase!\n");
break;
case 0x03: /* STATUS */
- scsi_pointer->phase = status_ph;
+ scp->phase = status_ph;
VDEB(printk("SYM53C500: Status phase\n"));
outb(FLUSH_FIFO, port_base + CMD_REG);
outb(INIT_CMD_COMPLETE, port_base + CMD_REG);
@@ -471,24 +471,22 @@ SYM53C500_intr(int irq, void *dev_id)
case 0x06: /* MESSAGE-OUT */
DEB(printk("SYM53C500: Message-Out phase\n"));
- scsi_pointer->phase = message_out;
+ scp->phase = message_out;
outb(SET_ATN, port_base + CMD_REG); /* Reject the message */
outb(MSG_ACCEPT, port_base + CMD_REG);
break;
case 0x07: /* MESSAGE-IN */
VDEB(printk("SYM53C500: Message-In phase\n"));
- scsi_pointer->phase = message_in;
+ scp->phase = message_in;
- scsi_pointer->Status = inb(port_base + SCSI_FIFO);
- scsi_pointer->Message = inb(port_base + SCSI_FIFO);
+ scp->status = inb(port_base + SCSI_FIFO);
+ scp->message = inb(port_base + SCSI_FIFO);
VDEB(printk("SCSI FIFO size=%d\n", inb(port_base + FIFO_FLAGS) & 0x1f));
- DEB(printk("Status = %02x Message = %02x\n",
- scsi_pointer->Status, scsi_pointer->Message));
+ DEB(printk("Status = %02x Message = %02x\n", scp->status, scp->message));
- if (scsi_pointer->Message == SAVE_POINTERS ||
- scsi_pointer->Message == DISCONNECT) {
+ if (scp->message == SAVE_POINTERS || scp->message == DISCONNECT) {
outb(SET_ATN, port_base + CMD_REG); /* Reject message */
DEB(printk("Discarding SAVE_POINTERS message\n"));
}
@@ -500,7 +498,7 @@ out:
return IRQ_HANDLED;
idle_out:
- scsi_pointer->phase = idle;
+ scp->phase = idle;
scsi_done(curSC);
goto out;
}
@@ -548,7 +546,7 @@ SYM53C500_info(struct Scsi_Host *SChost)
static int SYM53C500_queue_lck(struct scsi_cmnd *SCpnt)
{
- struct scsi_pointer *scsi_pointer = sym53c500_scsi_pointer(SCpnt);
+ struct sym53c500_cmd_priv *scp = scsi_cmd_priv(SCpnt);
int i;
int port_base = SCpnt->device->host->io_port;
struct sym53c500_data *data =
@@ -565,9 +563,9 @@ static int SYM53C500_queue_lck(struct scsi_cmnd *SCpnt)
VDEB(printk("\n"));
data->current_SC = SCpnt;
- scsi_pointer->phase = command_ph;
- scsi_pointer->Status = 0;
- scsi_pointer->Message = 0;
+ scp->phase = command_ph;
+ scp->status = 0;
+ scp->message = 0;
/* We are locked here already by the mid layer */
REG0(port_base);
@@ -682,7 +680,7 @@ static struct scsi_host_template sym53c500_driver_template = {
.this_id = 7,
.sg_tablesize = 32,
.shost_groups = SYM53C500_shost_groups,
- .cmd_size = sizeof(struct scsi_pointer),
+ .cmd_size = sizeof(struct sym53c500_cmd_priv),
};
static int SYM53C500_config_check(struct pcmcia_device *p_dev, void *priv_data)
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index f90b707c190b..01c5e8ff4cc5 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -766,6 +766,10 @@ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha)
pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity = 0x01;
pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt = 0x01;
+ /* Enable higher IQs and OQs, 32 to 63, bit 16 */
+ if (pm8001_ha->max_q_num > 32)
+ pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt |=
+ 1 << 16;
/* Disable end to end CRC checking */
pm8001_ha->main_cfg_tbl.pm80xx_tbl.crc_core_dump = (0x1 << 16);
@@ -1027,6 +1031,13 @@ static int mpi_init_check(struct pm8001_hba_info *pm8001_ha)
if (0x0000 != gst_len_mpistate)
return -EBUSY;
+ /*
+ * As per controller datasheet, after successful MPI
+ * initialization minimum 500ms delay is required before
+ * issuing commands.
+ */
+ msleep(500);
+
return 0;
}
@@ -1727,10 +1738,11 @@ static void
pm80xx_chip_interrupt_enable(struct pm8001_hba_info *pm8001_ha, u8 vec)
{
#ifdef PM8001_USE_MSIX
- u32 mask;
- mask = (u32)(1 << vec);
-
- pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_CLR, (u32)(mask & 0xFFFFFFFF));
+ if (vec < 32)
+ pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_CLR, 1U << vec);
+ else
+ pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_CLR_U,
+ 1U << (vec - 32));
return;
#endif
pm80xx_chip_intx_interrupt_enable(pm8001_ha);
@@ -1746,12 +1758,15 @@ static void
pm80xx_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha, u8 vec)
{
#ifdef PM8001_USE_MSIX
- u32 mask;
- if (vec == 0xFF)
- mask = 0xFFFFFFFF;
+ if (vec == 0xFF) {
+ /* disable all vectors 0-31, 32-63 */
+ pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, 0xFFFFFFFF);
+ pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_U, 0xFFFFFFFF);
+ } else if (vec < 32)
+ pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, 1U << vec);
else
- mask = (u32)(1 << vec);
- pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, (u32)(mask & 0xFFFFFFFF));
+ pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_U,
+ 1U << (vec - 32));
return;
#endif
pm80xx_chip_intx_interrupt_disable(pm8001_ha);
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index 928532180d32..3d5cd337a2a6 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -3182,124 +3182,6 @@ static int pmcraid_build_ioadl(
}
/**
- * pmcraid_free_sglist - Frees an allocated SG buffer list
- * @sglist: scatter/gather list pointer
- *
- * Free a DMA'able memory previously allocated with pmcraid_alloc_sglist
- *
- * Return value:
- * none
- */
-static void pmcraid_free_sglist(struct pmcraid_sglist *sglist)
-{
- sgl_free_order(sglist->scatterlist, sglist->order);
- kfree(sglist);
-}
-
-/**
- * pmcraid_alloc_sglist - Allocates memory for a SG list
- * @buflen: buffer length
- *
- * Allocates a DMA'able buffer in chunks and assembles a scatter/gather
- * list.
- *
- * Return value
- * pointer to sglist / NULL on failure
- */
-static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen)
-{
- struct pmcraid_sglist *sglist;
- int sg_size;
- int order;
-
- sg_size = buflen / (PMCRAID_MAX_IOADLS - 1);
- order = (sg_size > 0) ? get_order(sg_size) : 0;
-
- /* Allocate a scatter/gather list for the DMA */
- sglist = kzalloc(sizeof(struct pmcraid_sglist), GFP_KERNEL);
- if (sglist == NULL)
- return NULL;
-
- sglist->order = order;
- sgl_alloc_order(buflen, order, false, GFP_KERNEL | __GFP_ZERO,
- &sglist->num_sg);
-
- return sglist;
-}
-
-/**
- * pmcraid_copy_sglist - Copy user buffer to kernel buffer's SG list
- * @sglist: scatter/gather list pointer
- * @buffer: buffer pointer
- * @len: buffer length
- * @direction: data transfer direction
- *
- * Copy a user buffer into a buffer allocated by pmcraid_alloc_sglist
- *
- * Return value:
- * 0 on success / other on failure
- */
-static int pmcraid_copy_sglist(
- struct pmcraid_sglist *sglist,
- void __user *buffer,
- u32 len,
- int direction
-)
-{
- struct scatterlist *sg;
- void *kaddr;
- int bsize_elem;
- int i;
- int rc = 0;
-
- /* Determine the actual number of bytes per element */
- bsize_elem = PAGE_SIZE * (1 << sglist->order);
-
- sg = sglist->scatterlist;
-
- for (i = 0; i < (len / bsize_elem); i++, sg = sg_next(sg), buffer += bsize_elem) {
- struct page *page = sg_page(sg);
-
- kaddr = kmap(page);
- if (direction == DMA_TO_DEVICE)
- rc = copy_from_user(kaddr, buffer, bsize_elem);
- else
- rc = copy_to_user(buffer, kaddr, bsize_elem);
-
- kunmap(page);
-
- if (rc) {
- pmcraid_err("failed to copy user data into sg list\n");
- return -EFAULT;
- }
-
- sg->length = bsize_elem;
- }
-
- if (len % bsize_elem) {
- struct page *page = sg_page(sg);
-
- kaddr = kmap(page);
-
- if (direction == DMA_TO_DEVICE)
- rc = copy_from_user(kaddr, buffer, len % bsize_elem);
- else
- rc = copy_to_user(buffer, kaddr, len % bsize_elem);
-
- kunmap(page);
-
- sg->length = len % bsize_elem;
- }
-
- if (rc) {
- pmcraid_err("failed to copy user data into sg list\n");
- rc = -EFAULT;
- }
-
- return rc;
-}
-
-/**
* pmcraid_queuecommand_lck - Queue a mid-layer request
* @scsi_cmd: scsi command struct
*
@@ -3454,365 +3336,6 @@ static int pmcraid_chr_fasync(int fd, struct file *filep, int mode)
return rc;
}
-
-/**
- * pmcraid_build_passthrough_ioadls - builds SG elements for passthrough
- * commands sent over IOCTL interface
- *
- * @cmd : pointer to struct pmcraid_cmd
- * @buflen : length of the request buffer
- * @direction : data transfer direction
- *
- * Return value
- * 0 on success, non-zero error code on failure
- */
-static int pmcraid_build_passthrough_ioadls(
- struct pmcraid_cmd *cmd,
- int buflen,
- int direction
-)
-{
- struct pmcraid_sglist *sglist = NULL;
- struct scatterlist *sg = NULL;
- struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb;
- struct pmcraid_ioadl_desc *ioadl;
- int i;
-
- sglist = pmcraid_alloc_sglist(buflen);
-
- if (!sglist) {
- pmcraid_err("can't allocate memory for passthrough SGls\n");
- return -ENOMEM;
- }
-
- sglist->num_dma_sg = dma_map_sg(&cmd->drv_inst->pdev->dev,
- sglist->scatterlist,
- sglist->num_sg, direction);
-
- if (!sglist->num_dma_sg || sglist->num_dma_sg > PMCRAID_MAX_IOADLS) {
- dev_err(&cmd->drv_inst->pdev->dev,
- "Failed to map passthrough buffer!\n");
- pmcraid_free_sglist(sglist);
- return -EIO;
- }
-
- cmd->sglist = sglist;
- ioarcb->request_flags0 |= NO_LINK_DESCS;
-
- ioadl = pmcraid_init_ioadls(cmd, sglist->num_dma_sg);
-
- /* Initialize IOADL descriptor addresses */
- for_each_sg(sglist->scatterlist, sg, sglist->num_dma_sg, i) {
- ioadl[i].data_len = cpu_to_le32(sg_dma_len(sg));
- ioadl[i].address = cpu_to_le64(sg_dma_address(sg));
- ioadl[i].flags = 0;
- }
-
- /* setup the last descriptor */
- ioadl[i - 1].flags = IOADL_FLAGS_LAST_DESC;
-
- return 0;
-}
-
-
-/**
- * pmcraid_release_passthrough_ioadls - release passthrough ioadls
- *
- * @cmd: pointer to struct pmcraid_cmd for which ioadls were allocated
- * @buflen: size of the request buffer
- * @direction: data transfer direction
- *
- * Return value
- * 0 on success, non-zero error code on failure
- */
-static void pmcraid_release_passthrough_ioadls(
- struct pmcraid_cmd *cmd,
- int buflen,
- int direction
-)
-{
- struct pmcraid_sglist *sglist = cmd->sglist;
-
- if (buflen > 0) {
- dma_unmap_sg(&cmd->drv_inst->pdev->dev,
- sglist->scatterlist,
- sglist->num_sg,
- direction);
- pmcraid_free_sglist(sglist);
- cmd->sglist = NULL;
- }
-}
-
-/**
- * pmcraid_ioctl_passthrough - handling passthrough IOCTL commands
- *
- * @pinstance: pointer to adapter instance structure
- * @ioctl_cmd: ioctl code
- * @buflen: unused
- * @arg: pointer to pmcraid_passthrough_buffer user buffer
- *
- * Return value
- * 0 on success, non-zero error code on failure
- */
-static long pmcraid_ioctl_passthrough(
- struct pmcraid_instance *pinstance,
- unsigned int ioctl_cmd,
- unsigned int buflen,
- void __user *arg
-)
-{
- struct pmcraid_passthrough_ioctl_buffer *buffer;
- struct pmcraid_ioarcb *ioarcb;
- struct pmcraid_cmd *cmd;
- struct pmcraid_cmd *cancel_cmd;
- void __user *request_buffer;
- unsigned long request_offset;
- unsigned long lock_flags;
- void __user *ioasa;
- u32 ioasc;
- int request_size;
- int buffer_size;
- u8 direction;
- int rc = 0;
-
- /* If IOA reset is in progress, wait 10 secs for reset to complete */
- if (pinstance->ioa_reset_in_progress) {
- rc = wait_event_interruptible_timeout(
- pinstance->reset_wait_q,
- !pinstance->ioa_reset_in_progress,
- msecs_to_jiffies(10000));
-
- if (!rc)
- return -ETIMEDOUT;
- else if (rc < 0)
- return -ERESTARTSYS;
- }
-
- /* If adapter is not in operational state, return error */
- if (pinstance->ioa_state != IOA_STATE_OPERATIONAL) {
- pmcraid_err("IOA is not operational\n");
- return -ENOTTY;
- }
-
- buffer_size = sizeof(struct pmcraid_passthrough_ioctl_buffer);
- buffer = kmalloc(buffer_size, GFP_KERNEL);
-
- if (!buffer) {
- pmcraid_err("no memory for passthrough buffer\n");
- return -ENOMEM;
- }
-
- request_offset =
- offsetof(struct pmcraid_passthrough_ioctl_buffer, request_buffer);
-
- request_buffer = arg + request_offset;
-
- rc = copy_from_user(buffer, arg,
- sizeof(struct pmcraid_passthrough_ioctl_buffer));
-
- ioasa = arg + offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa);
-
- if (rc) {
- pmcraid_err("ioctl: can't copy passthrough buffer\n");
- rc = -EFAULT;
- goto out_free_buffer;
- }
-
- request_size = le32_to_cpu(buffer->ioarcb.data_transfer_length);
-
- if (buffer->ioarcb.request_flags0 & TRANSFER_DIR_WRITE) {
- direction = DMA_TO_DEVICE;
- } else {
- direction = DMA_FROM_DEVICE;
- }
-
- if (request_size < 0) {
- rc = -EINVAL;
- goto out_free_buffer;
- }
-
- /* check if we have any additional command parameters */
- if (le16_to_cpu(buffer->ioarcb.add_cmd_param_length)
- > PMCRAID_ADD_CMD_PARAM_LEN) {
- rc = -EINVAL;
- goto out_free_buffer;
- }
-
- cmd = pmcraid_get_free_cmd(pinstance);
-
- if (!cmd) {
- pmcraid_err("free command block is not available\n");
- rc = -ENOMEM;
- goto out_free_buffer;
- }
-
- cmd->scsi_cmd = NULL;
- ioarcb = &(cmd->ioa_cb->ioarcb);
-
- /* Copy the user-provided IOARCB stuff field by field */
- ioarcb->resource_handle = buffer->ioarcb.resource_handle;
- ioarcb->data_transfer_length = buffer->ioarcb.data_transfer_length;
- ioarcb->cmd_timeout = buffer->ioarcb.cmd_timeout;
- ioarcb->request_type = buffer->ioarcb.request_type;
- ioarcb->request_flags0 = buffer->ioarcb.request_flags0;
- ioarcb->request_flags1 = buffer->ioarcb.request_flags1;
- memcpy(ioarcb->cdb, buffer->ioarcb.cdb, PMCRAID_MAX_CDB_LEN);
-
- if (buffer->ioarcb.add_cmd_param_length) {
- ioarcb->add_cmd_param_length =
- buffer->ioarcb.add_cmd_param_length;
- ioarcb->add_cmd_param_offset =
- buffer->ioarcb.add_cmd_param_offset;
- memcpy(ioarcb->add_data.u.add_cmd_params,
- buffer->ioarcb.add_data.u.add_cmd_params,
- le16_to_cpu(buffer->ioarcb.add_cmd_param_length));
- }
-
- /* set hrrq number where the IOA should respond to. Note that all cmds
- * generated internally uses hrrq_id 0, exception to this is the cmd
- * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses
- * hrrq_id assigned here in queuecommand
- */
- ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) %
- pinstance->num_hrrq;
-
- if (request_size) {
- rc = pmcraid_build_passthrough_ioadls(cmd,
- request_size,
- direction);
- if (rc) {
- pmcraid_err("couldn't build passthrough ioadls\n");
- goto out_free_cmd;
- }
- }
-
- /* If data is being written into the device, copy the data from user
- * buffers
- */
- if (direction == DMA_TO_DEVICE && request_size > 0) {
- rc = pmcraid_copy_sglist(cmd->sglist,
- request_buffer,
- request_size,
- direction);
- if (rc) {
- pmcraid_err("failed to copy user buffer\n");
- goto out_free_sglist;
- }
- }
-
- /* passthrough ioctl is a blocking command so, put the user to sleep
- * until timeout. Note that a timeout value of 0 means, do timeout.
- */
- cmd->cmd_done = pmcraid_internal_done;
- init_completion(&cmd->wait_for_completion);
- cmd->completion_req = 1;
-
- pmcraid_info("command(%d) (CDB[0] = %x) for %x\n",
- le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2,
- cmd->ioa_cb->ioarcb.cdb[0],
- le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle));
-
- spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
- _pmcraid_fire_command(cmd);
- spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
-
- /* NOTE ! Remove the below line once abort_task is implemented
- * in firmware. This line disables ioctl command timeout handling logic
- * similar to IO command timeout handling, making ioctl commands to wait
- * until the command completion regardless of timeout value specified in
- * ioarcb
- */
- buffer->ioarcb.cmd_timeout = 0;
-
- /* If command timeout is specified put caller to wait till that time,
- * otherwise it would be blocking wait. If command gets timed out, it
- * will be aborted.
- */
- if (buffer->ioarcb.cmd_timeout == 0) {
- wait_for_completion(&cmd->wait_for_completion);
- } else if (!wait_for_completion_timeout(
- &cmd->wait_for_completion,
- msecs_to_jiffies(le16_to_cpu(buffer->ioarcb.cmd_timeout) * 1000))) {
-
- pmcraid_info("aborting cmd %d (CDB[0] = %x) due to timeout\n",
- le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2,
- cmd->ioa_cb->ioarcb.cdb[0]);
-
- spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
- cancel_cmd = pmcraid_abort_cmd(cmd);
- spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
-
- if (cancel_cmd) {
- wait_for_completion(&cancel_cmd->wait_for_completion);
- ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc);
- pmcraid_return_cmd(cancel_cmd);
-
- /* if abort task couldn't find the command i.e it got
- * completed prior to aborting, return good completion.
- * if command got aborted successfully or there was IOA
- * reset due to abort task itself getting timedout then
- * return -ETIMEDOUT
- */
- if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET ||
- PMCRAID_IOASC_SENSE_KEY(ioasc) == 0x00) {
- if (ioasc != PMCRAID_IOASC_GC_IOARCB_NOTFOUND)
- rc = -ETIMEDOUT;
- goto out_handle_response;
- }
- }
-
- /* no command block for abort task or abort task failed to abort
- * the IOARCB, then wait for 150 more seconds and initiate reset
- * sequence after timeout
- */
- if (!wait_for_completion_timeout(
- &cmd->wait_for_completion,
- msecs_to_jiffies(150 * 1000))) {
- pmcraid_reset_bringup(cmd->drv_inst);
- rc = -ETIMEDOUT;
- }
- }
-
-out_handle_response:
- /* copy entire IOASA buffer and return IOCTL success.
- * If copying IOASA to user-buffer fails, return
- * EFAULT
- */
- if (copy_to_user(ioasa, &cmd->ioa_cb->ioasa,
- sizeof(struct pmcraid_ioasa))) {
- pmcraid_err("failed to copy ioasa buffer to user\n");
- rc = -EFAULT;
- }
-
- /* If the data transfer was from device, copy the data onto user
- * buffers
- */
- else if (direction == DMA_FROM_DEVICE && request_size > 0) {
- rc = pmcraid_copy_sglist(cmd->sglist,
- request_buffer,
- request_size,
- direction);
- if (rc) {
- pmcraid_err("failed to copy user buffer\n");
- rc = -EFAULT;
- }
- }
-
-out_free_sglist:
- pmcraid_release_passthrough_ioadls(cmd, request_size, direction);
-
-out_free_cmd:
- pmcraid_return_cmd(cmd);
-
-out_free_buffer:
- kfree(buffer);
-
- return rc;
-}
-
-
-
-
/**
* pmcraid_ioctl_driver - ioctl handler for commands handled by driver itself
*
@@ -3922,20 +3445,6 @@ static long pmcraid_chr_ioctl(
switch (_IOC_TYPE(cmd)) {
- case PMCRAID_PASSTHROUGH_IOCTL:
- /* If ioctl code is to download microcode, we need to block
- * mid-layer requests.
- */
- if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE)
- scsi_block_requests(pinstance->host);
-
- retval = pmcraid_ioctl_passthrough(pinstance, cmd,
- hdr->buffer_length, argp);
-
- if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE)
- scsi_unblock_requests(pinstance->host);
- break;
-
case PMCRAID_DRIVER_IOCTL:
arg += sizeof(struct pmcraid_ioctl_header);
retval = pmcraid_ioctl_driver(pinstance, cmd,
@@ -5081,7 +4590,7 @@ static int pmcraid_init_instance(struct pci_dev *pdev, struct Scsi_Host *host,
mapped_pci_addr + chip_cfg->ioa_host_mask_clr;
pint_regs->global_interrupt_mask_reg =
mapped_pci_addr + chip_cfg->global_intr_mask;
- };
+ }
pinstance->ioa_reset_attempts = 0;
init_waitqueue_head(&pinstance->reset_wait_q);
diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h
index bbb75318f1e7..9f59930e8b4f 100644
--- a/drivers/scsi/pmcraid.h
+++ b/drivers/scsi/pmcraid.h
@@ -1023,40 +1023,15 @@ struct pmcraid_ioctl_header {
#define PMCRAID_IOCTL_SIGNATURE "PMCRAID"
/*
- * pmcraid_passthrough_ioctl_buffer - structure given as argument to
- * passthrough(or firmware handled) IOCTL commands. Note that ioarcb requires
- * 32-byte alignment so, it is necessary to pack this structure to avoid any
- * holes between ioctl_header and passthrough buffer
- *
- * .ioactl_header : ioctl header
- * .ioarcb : filled-up ioarcb buffer, driver always reads this buffer
- * .ioasa : buffer for ioasa, driver fills this with IOASA from firmware
- * .request_buffer: The I/O buffer (flat), driver reads/writes to this based on
- * the transfer directions passed in ioarcb.flags0. Contents
- * of this buffer are valid only when ioarcb.data_transfer_len
- * is not zero.
- */
-struct pmcraid_passthrough_ioctl_buffer {
- struct pmcraid_ioctl_header ioctl_header;
- struct pmcraid_ioarcb ioarcb;
- struct pmcraid_ioasa ioasa;
- u8 request_buffer[];
-} __attribute__ ((packed, aligned(PMCRAID_IOARCB_ALIGNMENT)));
-
-/*
* keys to differentiate between driver handled IOCTLs and passthrough
* IOCTLs passed to IOA. driver determines the ioctl type using macro
* _IOC_TYPE
*/
#define PMCRAID_DRIVER_IOCTL 'D'
-#define PMCRAID_PASSTHROUGH_IOCTL 'F'
#define DRV_IOCTL(n, size) \
_IOC(_IOC_READ|_IOC_WRITE, PMCRAID_DRIVER_IOCTL, (n), (size))
-#define FMW_IOCTL(n, size) \
- _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_PASSTHROUGH_IOCTL, (n), (size))
-
/*
* _ARGSIZE: macro that gives size of the argument type passed to an IOCTL cmd.
* This is to facilitate applications avoiding un-necessary memory allocations.
@@ -1069,12 +1044,4 @@ struct pmcraid_passthrough_ioctl_buffer {
#define PMCRAID_IOCTL_RESET_ADAPTER \
DRV_IOCTL(5, sizeof(struct pmcraid_ioctl_header))
-/* passthrough/firmware handled commands */
-#define PMCRAID_IOCTL_PASSTHROUGH_COMMAND \
- FMW_IOCTL(1, sizeof(struct pmcraid_passthrough_ioctl_buffer))
-
-#define PMCRAID_IOCTL_DOWNLOAD_MICROCODE \
- FMW_IOCTL(2, sizeof(struct pmcraid_passthrough_ioctl_buffer))
-
-
#endif /* _PMCRAID_H */
diff --git a/drivers/scsi/qedf/qedf_attr.c b/drivers/scsi/qedf/qedf_attr.c
index fdc66d294813..8d8c760eee43 100644
--- a/drivers/scsi/qedf/qedf_attr.c
+++ b/drivers/scsi/qedf/qedf_attr.c
@@ -131,7 +131,6 @@ qedf_sysfs_write_grcdump(struct file *filep, struct kobject *kobj,
struct qedf_ctx *qedf = NULL;
long reading;
int ret = 0;
- char msg[40];
if (off != 0)
return ret;
@@ -148,7 +147,6 @@ qedf_sysfs_write_grcdump(struct file *filep, struct kobject *kobj,
return ret;
}
- memset(msg, 0, sizeof(msg));
switch (reading) {
case 0:
memset(qedf->grcdump, 0, qedf->grcdump_size);
diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c
index 2ec1f710fd1d..e57cc22453d0 100644
--- a/drivers/scsi/qedf/qedf_io.c
+++ b/drivers/scsi/qedf/qedf_io.c
@@ -804,7 +804,6 @@ static void qedf_trace_io(struct qedf_rport *fcport, struct qedf_ioreq *io_req,
struct qedf_io_log *io_log;
struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
unsigned long flags;
- uint8_t op;
spin_lock_irqsave(&qedf->io_trace_lock, flags);
@@ -813,7 +812,7 @@ static void qedf_trace_io(struct qedf_rport *fcport, struct qedf_ioreq *io_req,
io_log->task_id = io_req->xid;
io_log->port_id = fcport->rdata->ids.port_id;
io_log->lun = sc_cmd->device->lun;
- io_log->op = op = sc_cmd->cmnd[0];
+ io_log->op = sc_cmd->cmnd[0];
io_log->lba[0] = sc_cmd->cmnd[2];
io_log->lba[1] = sc_cmd->cmnd[3];
io_log->lba[2] = sc_cmd->cmnd[4];
diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c
index 18dc68d577b6..3d6b137314f3 100644
--- a/drivers/scsi/qedf/qedf_main.c
+++ b/drivers/scsi/qedf/qedf_main.c
@@ -873,7 +873,7 @@ static int qedf_eh_device_reset(struct scsi_cmnd *sc_cmd)
bool qedf_wait_for_upload(struct qedf_ctx *qedf)
{
- struct qedf_rport *fcport = NULL;
+ struct qedf_rport *fcport;
int wait_cnt = 120;
while (wait_cnt--) {
@@ -888,7 +888,7 @@ bool qedf_wait_for_upload(struct qedf_ctx *qedf)
rcu_read_lock();
list_for_each_entry_rcu(fcport, &qedf->fcports, peers) {
- if (fcport && test_bit(QEDF_RPORT_SESSION_READY,
+ if (test_bit(QEDF_RPORT_SESSION_READY,
&fcport->flags)) {
if (fcport->rdata)
QEDF_ERR(&qedf->dbg_ctx,
@@ -899,9 +899,9 @@ bool qedf_wait_for_upload(struct qedf_ctx *qedf)
"Waiting for fcport %p.\n", fcport);
}
}
+
rcu_read_unlock();
return false;
-
}
/* Performs soft reset of qedf_ctx by simulating a link down/up */
@@ -1067,7 +1067,6 @@ static int qedf_xmit(struct fc_lport *lport, struct fc_frame *fp)
u32 crc;
unsigned int hlen, tlen, elen;
int wlen;
- struct fc_stats *stats;
struct fc_lport *tmp_lport;
struct fc_lport *vn_port = NULL;
struct qedf_rport *fcport;
@@ -1215,10 +1214,8 @@ static int qedf_xmit(struct fc_lport *lport, struct fc_frame *fp)
hp->fcoe_sof = sof;
/*update tx stats */
- stats = per_cpu_ptr(lport->stats, get_cpu());
- stats->TxFrames++;
- stats->TxWords += wlen;
- put_cpu();
+ this_cpu_inc(lport->stats->TxFrames);
+ this_cpu_add(lport->stats->TxWords, wlen);
/* Get VLAN ID from skb for printing purposes */
__vlan_hwaccel_get_tag(skb, &vlan_tci);
diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c
index 8196f89f404e..31ec429104e2 100644
--- a/drivers/scsi/qedi/qedi_iscsi.c
+++ b/drivers/scsi/qedi/qedi_iscsi.c
@@ -860,6 +860,37 @@ static int qedi_task_xmit(struct iscsi_task *task)
return qedi_iscsi_send_ioreq(task);
}
+static void qedi_offload_work(struct work_struct *work)
+{
+ struct qedi_endpoint *qedi_ep =
+ container_of(work, struct qedi_endpoint, offload_work);
+ struct qedi_ctx *qedi;
+ int wait_delay = 5 * HZ;
+ int ret;
+
+ qedi = qedi_ep->qedi;
+
+ ret = qedi_iscsi_offload_conn(qedi_ep);
+ if (ret) {
+ QEDI_ERR(&qedi->dbg_ctx,
+ "offload error: iscsi_cid=%u, qedi_ep=%p, ret=%d\n",
+ qedi_ep->iscsi_cid, qedi_ep, ret);
+ qedi_ep->state = EP_STATE_OFLDCONN_FAILED;
+ return;
+ }
+
+ ret = wait_event_interruptible_timeout(qedi_ep->tcp_ofld_wait,
+ (qedi_ep->state ==
+ EP_STATE_OFLDCONN_COMPL),
+ wait_delay);
+ if (ret <= 0 || qedi_ep->state != EP_STATE_OFLDCONN_COMPL) {
+ qedi_ep->state = EP_STATE_OFLDCONN_FAILED;
+ QEDI_ERR(&qedi->dbg_ctx,
+ "Offload conn TIMEOUT iscsi_cid=%u, qedi_ep=%p\n",
+ qedi_ep->iscsi_cid, qedi_ep);
+ }
+}
+
static struct iscsi_endpoint *
qedi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
int non_blocking)
@@ -908,6 +939,7 @@ qedi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
}
qedi_ep = ep->dd_data;
memset(qedi_ep, 0, sizeof(struct qedi_endpoint));
+ INIT_WORK(&qedi_ep->offload_work, qedi_offload_work);
qedi_ep->state = EP_STATE_IDLE;
qedi_ep->iscsi_cid = (u32)-1;
qedi_ep->qedi = qedi;
@@ -1056,12 +1088,11 @@ static void qedi_ep_disconnect(struct iscsi_endpoint *ep)
qedi_ep = ep->dd_data;
qedi = qedi_ep->qedi;
+ flush_work(&qedi_ep->offload_work);
+
if (qedi_ep->state == EP_STATE_OFLDCONN_START)
goto ep_exit_recover;
- if (qedi_ep->state != EP_STATE_OFLDCONN_NONE)
- flush_work(&qedi_ep->offload_work);
-
if (qedi_ep->conn) {
qedi_conn = qedi_ep->conn;
abrt_conn = qedi_conn->abrt_conn;
@@ -1235,37 +1266,6 @@ static int qedi_data_avail(struct qedi_ctx *qedi, u16 vlanid)
return rc;
}
-static void qedi_offload_work(struct work_struct *work)
-{
- struct qedi_endpoint *qedi_ep =
- container_of(work, struct qedi_endpoint, offload_work);
- struct qedi_ctx *qedi;
- int wait_delay = 5 * HZ;
- int ret;
-
- qedi = qedi_ep->qedi;
-
- ret = qedi_iscsi_offload_conn(qedi_ep);
- if (ret) {
- QEDI_ERR(&qedi->dbg_ctx,
- "offload error: iscsi_cid=%u, qedi_ep=%p, ret=%d\n",
- qedi_ep->iscsi_cid, qedi_ep, ret);
- qedi_ep->state = EP_STATE_OFLDCONN_FAILED;
- return;
- }
-
- ret = wait_event_interruptible_timeout(qedi_ep->tcp_ofld_wait,
- (qedi_ep->state ==
- EP_STATE_OFLDCONN_COMPL),
- wait_delay);
- if ((ret <= 0) || (qedi_ep->state != EP_STATE_OFLDCONN_COMPL)) {
- qedi_ep->state = EP_STATE_OFLDCONN_FAILED;
- QEDI_ERR(&qedi->dbg_ctx,
- "Offload conn TIMEOUT iscsi_cid=%u, qedi_ep=%p\n",
- qedi_ep->iscsi_cid, qedi_ep);
- }
-}
-
static int qedi_set_path(struct Scsi_Host *shost, struct iscsi_path *path_data)
{
struct qedi_ctx *qedi;
@@ -1381,7 +1381,6 @@ static int qedi_set_path(struct Scsi_Host *shost, struct iscsi_path *path_data)
qedi_ep->dst_addr, qedi_ep->dst_port);
}
- INIT_WORK(&qedi_ep->offload_work, qedi_offload_work);
queue_work(qedi->offload_thread, &qedi_ep->offload_work);
ret = 0;
diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c
index 0628633c7c7e..cb8145a9ac09 100644
--- a/drivers/scsi/qla2xxx/qla_edif.c
+++ b/drivers/scsi/qla2xxx/qla_edif.c
@@ -657,7 +657,6 @@ qla_edif_app_chk_sa_update(scsi_qla_host_t *vha, fc_port_t *fcport,
static int
qla_edif_app_authok(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
{
- int32_t rval = 0;
struct auth_complete_cmd appplogiok;
struct app_plogi_reply appplogireply = {0};
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
@@ -758,7 +757,7 @@ errstate_exit:
&appplogireply,
sizeof(struct app_plogi_reply));
- return rval;
+ return 0;
}
/**
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 762229d495a8..73073fb08369 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -3933,7 +3933,6 @@ qla2x00_free_device(scsi_qla_host_t *vha)
/* Flush the work queue and remove it */
if (ha->wq) {
- flush_workqueue(ha->wq);
destroy_workqueue(ha->wq);
ha->wq = NULL;
}
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 85dbf81f3204..a02235a6a8e9 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -3826,6 +3826,9 @@ int qlt_abort_cmd(struct qla_tgt_cmd *cmd)
spin_lock_irqsave(&cmd->cmd_lock, flags);
if (cmd->aborted) {
+ if (cmd->sg_mapped)
+ qlt_unmap_sg(vha, cmd);
+
spin_unlock_irqrestore(&cmd->cmd_lock, flags);
/*
* It's normal to see 2 calls in this path:
@@ -3863,8 +3866,6 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd)
BUG_ON(cmd->sg_mapped);
cmd->jiffies_at_free = get_jiffies_64();
- if (unlikely(cmd->free_sg))
- kfree(cmd->sg);
if (!sess || !sess->se_sess) {
WARN_ON(1);
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index 156b950ca7e7..de3942b8efc4 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -883,7 +883,6 @@ struct qla_tgt_cmd {
/* to save extra sess dereferences */
unsigned int conf_compl_supported:1;
unsigned int sg_mapped:1;
- unsigned int free_sg:1;
unsigned int write_data_transferred:1;
unsigned int q_full:1;
unsigned int term_exchg:1;
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 3f6cb2a5c2c2..9e849f6b0d0f 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -671,7 +671,6 @@ static void qla4xxx_create_chap_list(struct scsi_qla_host *ha)
goto exit_chap_list;
}
- memset(ha->chap_list, 0, chap_size);
memcpy(ha->chap_list, chap_flash_data, chap_size);
exit_chap_list:
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 211aace69c22..c59eac7a32f2 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -200,11 +200,11 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
/*
- * 1024 is big enough for saturating fast SCSI LUNs.
+ * 4096 is big enough for saturating fast SCSI LUNs.
*/
int scsi_device_max_queue_depth(struct scsi_device *sdev)
{
- return min_t(int, sdev->host->can_queue, 1024);
+ return min_t(int, sdev->host->can_queue, 4096);
}
/**
@@ -321,6 +321,31 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
return get_unaligned_be16(&buffer[2]) + 4;
}
+static int scsi_get_vpd_size(struct scsi_device *sdev, u8 page)
+{
+ unsigned char vpd_header[SCSI_VPD_HEADER_SIZE] __aligned(4);
+ int result;
+
+ /*
+ * Fetch the VPD page header to find out how big the page
+ * is. This is done to prevent problems on legacy devices
+ * which can not handle allocation lengths as large as
+ * potentially requested by the caller.
+ */
+ result = scsi_vpd_inquiry(sdev, vpd_header, page, sizeof(vpd_header));
+ if (result < 0)
+ return 0;
+
+ if (result < SCSI_VPD_HEADER_SIZE) {
+ dev_warn_once(&sdev->sdev_gendev,
+ "%s: short VPD page 0x%02x length: %d bytes\n",
+ __func__, page, result);
+ return 0;
+ }
+
+ return result;
+}
+
/**
* scsi_get_vpd_page - Get Vital Product Data from a SCSI device
* @sdev: The device to ask
@@ -330,47 +355,38 @@ static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer,
*
* SCSI devices may optionally supply Vital Product Data. Each 'page'
* of VPD is defined in the appropriate SCSI document (eg SPC, SBC).
- * If the device supports this VPD page, this routine returns a pointer
- * to a buffer containing the data from that page. The caller is
- * responsible for calling kfree() on this pointer when it is no longer
- * needed. If we cannot retrieve the VPD page this routine returns %NULL.
+ * If the device supports this VPD page, this routine fills @buf
+ * with the data from that page and return 0. If the VPD page is not
+ * supported or its content cannot be retrieved, -EINVAL is returned.
*/
int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
int buf_len)
{
- int i, result;
-
- if (sdev->skip_vpd_pages)
- goto fail;
-
- /* Ask for all the pages supported by this device */
- result = scsi_vpd_inquiry(sdev, buf, 0, buf_len);
- if (result < 4)
- goto fail;
+ int result, vpd_len;
- /* If the user actually wanted this page, we can skip the rest */
- if (page == 0)
- return 0;
+ if (!scsi_device_supports_vpd(sdev))
+ return -EINVAL;
- for (i = 4; i < min(result, buf_len); i++)
- if (buf[i] == page)
- goto found;
+ vpd_len = scsi_get_vpd_size(sdev, page);
+ if (vpd_len <= 0)
+ return -EINVAL;
- if (i < result && i >= buf_len)
- /* ran off the end of the buffer, give us benefit of doubt */
- goto found;
- /* The device claims it doesn't support the requested page */
- goto fail;
+ vpd_len = min(vpd_len, buf_len);
- found:
- result = scsi_vpd_inquiry(sdev, buf, page, buf_len);
+ /*
+ * Fetch the actual page. Since the appropriate size was reported
+ * by the device it is now safe to ask for something bigger.
+ */
+ memset(buf, 0, buf_len);
+ result = scsi_vpd_inquiry(sdev, buf, page, vpd_len);
if (result < 0)
- goto fail;
+ return -EINVAL;
+ else if (result > vpd_len)
+ dev_warn_once(&sdev->sdev_gendev,
+ "%s: VPD page 0x%02x result %d > %d bytes\n",
+ __func__, page, result, vpd_len);
return 0;
-
- fail:
- return -EINVAL;
}
EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
@@ -384,9 +400,17 @@ EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
static struct scsi_vpd *scsi_get_vpd_buf(struct scsi_device *sdev, u8 page)
{
struct scsi_vpd *vpd_buf;
- int vpd_len = SCSI_VPD_PG_LEN, result;
+ int vpd_len, result;
+
+ vpd_len = scsi_get_vpd_size(sdev, page);
+ if (vpd_len <= 0)
+ return NULL;
retry_pg:
+ /*
+ * Fetch the actual page. Since the appropriate size was reported
+ * by the device it is now safe to ask for something bigger.
+ */
vpd_buf = kmalloc(sizeof(*vpd_buf) + vpd_len, GFP_KERNEL);
if (!vpd_buf)
return NULL;
@@ -397,6 +421,9 @@ retry_pg:
return NULL;
}
if (result > vpd_len) {
+ dev_warn_once(&sdev->sdev_gendev,
+ "%s: VPD page 0x%02x result %d > %d bytes\n",
+ __func__, page, result, vpd_len);
vpd_len = result;
kfree(vpd_buf);
goto retry_pg;
@@ -456,6 +483,12 @@ void scsi_attach_vpd(struct scsi_device *sdev)
scsi_update_vpd_page(sdev, 0x83, &sdev->vpd_pg83);
if (vpd_buf->data[i] == 0x89)
scsi_update_vpd_page(sdev, 0x89, &sdev->vpd_pg89);
+ if (vpd_buf->data[i] == 0xb0)
+ scsi_update_vpd_page(sdev, 0xb0, &sdev->vpd_pgb0);
+ if (vpd_buf->data[i] == 0xb1)
+ scsi_update_vpd_page(sdev, 0xb1, &sdev->vpd_pgb1);
+ if (vpd_buf->data[i] == 0xb2)
+ scsi_update_vpd_page(sdev, 0xb2, &sdev->vpd_pgb2);
}
kfree(vpd_buf);
}
@@ -476,21 +509,30 @@ int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
{
unsigned char cmd[16];
struct scsi_sense_hdr sshdr;
- int result;
+ int result, request_len;
if (sdev->no_report_opcodes || sdev->scsi_level < SCSI_SPC_3)
return -EINVAL;
+ /* RSOC header + size of command we are asking about */
+ request_len = 4 + COMMAND_SIZE(opcode);
+ if (request_len > len) {
+ dev_warn_once(&sdev->sdev_gendev,
+ "%s: len %u bytes, opcode 0x%02x needs %u\n",
+ __func__, len, opcode, request_len);
+ return -EINVAL;
+ }
+
memset(cmd, 0, 16);
cmd[0] = MAINTENANCE_IN;
cmd[1] = MI_REPORT_SUPPORTED_OPERATION_CODES;
cmd[2] = 1; /* One command format */
cmd[3] = opcode;
- put_unaligned_be32(len, &cmd[6]);
+ put_unaligned_be32(request_len, &cmd[6]);
memset(buffer, 0, len);
- result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
- &sshdr, 30 * HZ, 3, NULL);
+ result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer,
+ request_len, &sshdr, 30 * HZ, 3, NULL);
if (result < 0)
return result;
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index c607755cce00..1f423f723d06 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -16,7 +16,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
#include <linux/module.h>
-
+#include <linux/align.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/jiffies.h>
@@ -32,7 +32,6 @@
#include <linux/blkdev.h>
#include <linux/crc-t10dif.h>
#include <linux/spinlock.h>
-#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/atomic.h>
#include <linux/hrtimer.h>
@@ -99,6 +98,7 @@ static const char *sdebug_version_date = "20210520";
#define WRITE_BOUNDARY_ASCQ 0x5
#define READ_INVDATA_ASCQ 0x6
#define READ_BOUNDARY_ASCQ 0x7
+#define ATTEMPT_ACCESS_GAP 0x9
#define INSUFF_ZONE_ASCQ 0xe
/* Additional Sense Code Qualifier (ASCQ) */
@@ -252,9 +252,11 @@ static const char *sdebug_version_date = "20210520";
/* Zone types (zbcr05 table 25) */
enum sdebug_z_type {
- ZBC_ZONE_TYPE_CNV = 0x1,
- ZBC_ZONE_TYPE_SWR = 0x2,
- ZBC_ZONE_TYPE_SWP = 0x3,
+ ZBC_ZTYPE_CNV = 0x1,
+ ZBC_ZTYPE_SWR = 0x2,
+ ZBC_ZTYPE_SWP = 0x3,
+ /* ZBC_ZTYPE_SOBR = 0x4, */
+ ZBC_ZTYPE_GAP = 0x5,
};
/* enumeration names taken from table 26, zbcr05 */
@@ -292,10 +294,12 @@ struct sdebug_dev_info {
/* For ZBC devices */
enum blk_zoned_model zmodel;
+ unsigned int zcap;
unsigned int zsize;
unsigned int zsize_shift;
unsigned int nr_zones;
unsigned int nr_conv_zones;
+ unsigned int nr_seq_zones;
unsigned int nr_imp_open;
unsigned int nr_exp_open;
unsigned int nr_closed;
@@ -732,9 +736,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
};
-static atomic_t sdebug_num_hosts;
-static DEFINE_MUTEX(add_host_mutex);
-
+static int sdebug_num_hosts;
static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */
static int sdebug_ato = DEF_ATO;
static int sdebug_cdb_len = DEF_CDB_LEN;
@@ -781,7 +783,6 @@ static int sdebug_uuid_ctl = DEF_UUID_CTL;
static bool sdebug_random = DEF_RANDOM;
static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
static bool sdebug_removable = DEF_REMOVABLE;
-static bool sdebug_deflect_incoming;
static bool sdebug_clustering;
static bool sdebug_host_lock = DEF_HOST_LOCK;
static bool sdebug_strict = DEF_STRICT;
@@ -833,6 +834,7 @@ static int dif_errors;
/* ZBC global data */
static bool sdeb_zbc_in_use; /* true for host-aware and host-managed disks */
+static int sdeb_zbc_zone_cap_mb;
static int sdeb_zbc_zone_size_mb;
static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES;
static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES;
@@ -1563,6 +1565,12 @@ static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr)
put_unaligned_be32(devip->max_open, &arr[12]);
else
put_unaligned_be32(0xffffffff, &arr[12]);
+ if (devip->zcap < devip->zsize) {
+ arr[19] = ZBC_CONSTANT_ZONE_START_OFFSET;
+ put_unaligned_be64(devip->zsize, &arr[20]);
+ } else {
+ arr[19] = 0;
+ }
return 0x3c;
}
@@ -2715,12 +2723,38 @@ static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip)
static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip,
unsigned long long lba)
{
- return &devip->zstate[lba >> devip->zsize_shift];
+ u32 zno = lba >> devip->zsize_shift;
+ struct sdeb_zone_state *zsp;
+
+ if (devip->zcap == devip->zsize || zno < devip->nr_conv_zones)
+ return &devip->zstate[zno];
+
+ /*
+ * If the zone capacity is less than the zone size, adjust for gap
+ * zones.
+ */
+ zno = 2 * zno - devip->nr_conv_zones;
+ WARN_ONCE(zno >= devip->nr_zones, "%u > %u\n", zno, devip->nr_zones);
+ zsp = &devip->zstate[zno];
+ if (lba >= zsp->z_start + zsp->z_size)
+ zsp++;
+ WARN_ON_ONCE(lba >= zsp->z_start + zsp->z_size);
+ return zsp;
}
static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp)
{
- return zsp->z_type == ZBC_ZONE_TYPE_CNV;
+ return zsp->z_type == ZBC_ZTYPE_CNV;
+}
+
+static inline bool zbc_zone_is_gap(struct sdeb_zone_state *zsp)
+{
+ return zsp->z_type == ZBC_ZTYPE_GAP;
+}
+
+static inline bool zbc_zone_is_seq(struct sdeb_zone_state *zsp)
+{
+ return !zbc_zone_is_conv(zsp) && !zbc_zone_is_gap(zsp);
}
static void zbc_close_zone(struct sdebug_dev_info *devip,
@@ -2728,7 +2762,7 @@ static void zbc_close_zone(struct sdebug_dev_info *devip,
{
enum sdebug_z_cond zc;
- if (zbc_zone_is_conv(zsp))
+ if (!zbc_zone_is_seq(zsp))
return;
zc = zsp->z_cond;
@@ -2766,7 +2800,7 @@ static void zbc_open_zone(struct sdebug_dev_info *devip,
{
enum sdebug_z_cond zc;
- if (zbc_zone_is_conv(zsp))
+ if (!zbc_zone_is_seq(zsp))
return;
zc = zsp->z_cond;
@@ -2798,10 +2832,10 @@ static void zbc_inc_wp(struct sdebug_dev_info *devip,
struct sdeb_zone_state *zsp = zbc_zone(devip, lba);
unsigned long long n, end, zend = zsp->z_start + zsp->z_size;
- if (zbc_zone_is_conv(zsp))
+ if (!zbc_zone_is_seq(zsp))
return;
- if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
+ if (zsp->z_type == ZBC_ZTYPE_SWR) {
zsp->z_wp += num;
if (zsp->z_wp >= zend)
zsp->z_cond = ZC5_FULL;
@@ -2846,9 +2880,7 @@ static int check_zbc_access_params(struct scsi_cmnd *scp,
if (devip->zmodel == BLK_ZONED_HA)
return 0;
/* For host-managed, reads cannot cross zone types boundaries */
- if (zsp_end != zsp &&
- zbc_zone_is_conv(zsp) &&
- !zbc_zone_is_conv(zsp_end)) {
+ if (zsp->z_type != zsp_end->z_type) {
mk_sense_buffer(scp, ILLEGAL_REQUEST,
LBA_OUT_OF_RANGE,
READ_INVDATA_ASCQ);
@@ -2857,6 +2889,13 @@ static int check_zbc_access_params(struct scsi_cmnd *scp,
return 0;
}
+ /* Writing into a gap zone is not allowed */
+ if (zbc_zone_is_gap(zsp)) {
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE,
+ ATTEMPT_ACCESS_GAP);
+ return check_condition_result;
+ }
+
/* No restrictions for writes within conventional zones */
if (zbc_zone_is_conv(zsp)) {
if (!zbc_zone_is_conv(zsp_end)) {
@@ -2868,7 +2907,7 @@ static int check_zbc_access_params(struct scsi_cmnd *scp,
return 0;
}
- if (zsp->z_type == ZBC_ZONE_TYPE_SWR) {
+ if (zsp->z_type == ZBC_ZTYPE_SWR) {
/* Writes cannot cross sequential zone boundaries */
if (zsp_end != zsp) {
mk_sense_buffer(scp, ILLEGAL_REQUEST,
@@ -4408,18 +4447,18 @@ cleanup:
#define RZONES_DESC_HD 64
-/* Report zones depending on start LBA nad reporting options */
+/* Report zones depending on start LBA and reporting options */
static int resp_report_zones(struct scsi_cmnd *scp,
struct sdebug_dev_info *devip)
{
- unsigned int i, max_zones, rep_max_zones, nrz = 0;
+ unsigned int rep_max_zones, nrz = 0;
int ret = 0;
u32 alloc_len, rep_opts, rep_len;
bool partial;
u64 lba, zs_lba;
u8 *arr = NULL, *desc;
u8 *cmd = scp->cmnd;
- struct sdeb_zone_state *zsp;
+ struct sdeb_zone_state *zsp = NULL;
struct sdeb_store_info *sip = devip2sip(devip, false);
if (!sdebug_dev_is_zoned(devip)) {
@@ -4438,9 +4477,7 @@ static int resp_report_zones(struct scsi_cmnd *scp,
return check_condition_result;
}
- max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift);
- rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD),
- max_zones);
+ rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD);
arr = kzalloc(alloc_len, GFP_ATOMIC);
if (!arr) {
@@ -4452,9 +4489,9 @@ static int resp_report_zones(struct scsi_cmnd *scp,
sdeb_read_lock(sip);
desc = arr + 64;
- for (i = 0; i < max_zones; i++) {
- lba = zs_lba + devip->zsize * i;
- if (lba > sdebug_capacity)
+ for (lba = zs_lba; lba < sdebug_capacity;
+ lba = zsp->z_start + zsp->z_size) {
+ if (WARN_ONCE(zbc_zone(devip, lba) == zsp, "lba = %llu\n", lba))
break;
zsp = zbc_zone(devip, lba);
switch (rep_opts) {
@@ -4499,9 +4536,14 @@ static int resp_report_zones(struct scsi_cmnd *scp,
if (!zsp->z_non_seq_resource)
continue;
break;
+ case 0x3e:
+ /* All zones except gap zones. */
+ if (zbc_zone_is_gap(zsp))
+ continue;
+ break;
case 0x3f:
/* Not write pointer (conventional) zones */
- if (!zbc_zone_is_conv(zsp))
+ if (zbc_zone_is_seq(zsp))
continue;
break;
default:
@@ -4530,8 +4572,13 @@ static int resp_report_zones(struct scsi_cmnd *scp,
}
/* Report header */
+ /* Zone list length. */
put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0);
+ /* Maximum LBA */
put_unaligned_be64(sdebug_capacity - 1, arr + 8);
+ /* Zone starting LBA granularity. */
+ if (devip->zcap < devip->zsize)
+ put_unaligned_be64(devip->zsize, arr + 16);
rep_len = (unsigned long)desc - (unsigned long)arr;
ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len));
@@ -4756,7 +4803,7 @@ static void zbc_rwp_zone(struct sdebug_dev_info *devip,
enum sdebug_z_cond zc;
struct sdeb_store_info *sip = devip2sip(devip, false);
- if (zbc_zone_is_conv(zsp))
+ if (!zbc_zone_is_seq(zsp))
return;
zc = zsp->z_cond;
@@ -4946,6 +4993,7 @@ static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
{
struct sdeb_zone_state *zsp;
sector_t capacity = get_sdebug_capacity();
+ sector_t conv_capacity;
sector_t zstart = 0;
unsigned int i;
@@ -4980,11 +5028,30 @@ static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
devip->zsize_shift = ilog2(devip->zsize);
devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift;
- if (sdeb_zbc_nr_conv >= devip->nr_zones) {
+ if (sdeb_zbc_zone_cap_mb == 0) {
+ devip->zcap = devip->zsize;
+ } else {
+ devip->zcap = (sdeb_zbc_zone_cap_mb * SZ_1M) >>
+ ilog2(sdebug_sector_size);
+ if (devip->zcap > devip->zsize) {
+ pr_err("Zone capacity too large\n");
+ return -EINVAL;
+ }
+ }
+
+ conv_capacity = (sector_t)sdeb_zbc_nr_conv << devip->zsize_shift;
+ if (conv_capacity >= capacity) {
pr_err("Number of conventional zones too large\n");
return -EINVAL;
}
devip->nr_conv_zones = sdeb_zbc_nr_conv;
+ devip->nr_seq_zones = ALIGN(capacity - conv_capacity, devip->zsize) >>
+ devip->zsize_shift;
+ devip->nr_zones = devip->nr_conv_zones + devip->nr_seq_zones;
+
+ /* Add gap zones if zone capacity is smaller than the zone size */
+ if (devip->zcap < devip->zsize)
+ devip->nr_zones += devip->nr_seq_zones;
if (devip->zmodel == BLK_ZONED_HM) {
/* zbc_max_open_zones can be 0, meaning "not reported" */
@@ -5005,23 +5072,29 @@ static int sdebug_device_create_zones(struct sdebug_dev_info *devip)
zsp->z_start = zstart;
if (i < devip->nr_conv_zones) {
- zsp->z_type = ZBC_ZONE_TYPE_CNV;
+ zsp->z_type = ZBC_ZTYPE_CNV;
zsp->z_cond = ZBC_NOT_WRITE_POINTER;
zsp->z_wp = (sector_t)-1;
- } else {
+ zsp->z_size =
+ min_t(u64, devip->zsize, capacity - zstart);
+ } else if ((zstart & (devip->zsize - 1)) == 0) {
if (devip->zmodel == BLK_ZONED_HM)
- zsp->z_type = ZBC_ZONE_TYPE_SWR;
+ zsp->z_type = ZBC_ZTYPE_SWR;
else
- zsp->z_type = ZBC_ZONE_TYPE_SWP;
+ zsp->z_type = ZBC_ZTYPE_SWP;
zsp->z_cond = ZC1_EMPTY;
zsp->z_wp = zsp->z_start;
+ zsp->z_size =
+ min_t(u64, devip->zcap, capacity - zstart);
+ } else {
+ zsp->z_type = ZBC_ZTYPE_GAP;
+ zsp->z_cond = ZBC_NOT_WRITE_POINTER;
+ zsp->z_wp = (sector_t)-1;
+ zsp->z_size = min_t(u64, devip->zsize - devip->zcap,
+ capacity - zstart);
}
- if (zsp->z_start + devip->zsize < capacity)
- zsp->z_size = devip->zsize;
- else
- zsp->z_size = capacity - zsp->z_start;
-
+ WARN_ON_ONCE((int)zsp->z_size <= 0);
zstart += zsp->z_size;
}
@@ -5122,10 +5195,6 @@ static int scsi_debug_slave_configure(struct scsi_device *sdp)
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
- if (smp_load_acquire(&sdebug_deflect_incoming)) {
- pr_info("Exit early due to deflect_incoming\n");
- return 1;
- }
if (devip == NULL) {
devip = find_build_dev_info(sdp);
if (devip == NULL)
@@ -5211,7 +5280,7 @@ static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
}
/* Deletes (stops) timers or work queues of all queued commands */
-static void stop_all_queued(bool done_with_no_conn)
+static void stop_all_queued(void)
{
unsigned long iflags;
int j, k;
@@ -5220,15 +5289,13 @@ static void stop_all_queued(bool done_with_no_conn)
struct sdebug_queued_cmd *sqcp;
struct sdebug_dev_info *devip;
struct sdebug_defer *sd_dp;
- struct scsi_cmnd *scp;
for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
spin_lock_irqsave(&sqp->qc_lock, iflags);
for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
if (test_bit(k, sqp->in_use_bm)) {
sqcp = &sqp->qc_arr[k];
- scp = sqcp->a_cmnd;
- if (!scp)
+ if (sqcp->a_cmnd == NULL)
continue;
devip = (struct sdebug_dev_info *)
sqcp->a_cmnd->device->hostdata;
@@ -5243,10 +5310,6 @@ static void stop_all_queued(bool done_with_no_conn)
l_defer_t = SDEB_DEFER_NONE;
spin_unlock_irqrestore(&sqp->qc_lock, iflags);
stop_qc_helper(sd_dp, l_defer_t);
- if (done_with_no_conn && l_defer_t != SDEB_DEFER_NONE) {
- scp->result = DID_NO_CONNECT << 16;
- scsi_done(scp);
- }
clear_bit(k, sqp->in_use_bm);
spin_lock_irqsave(&sqp->qc_lock, iflags);
}
@@ -5389,7 +5452,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
}
}
spin_unlock(&sdebug_host_list_lock);
- stop_all_queued(false);
+ stop_all_queued();
if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
sdev_printk(KERN_INFO, SCpnt->device,
"%s: %d device(s) found\n", __func__, k);
@@ -5449,50 +5512,13 @@ static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
}
}
-static void sdeb_block_all_queues(void)
+static void block_unblock_all_queues(bool block)
{
int j;
struct sdebug_queue *sqp;
for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
- atomic_set(&sqp->blocked, (int)true);
-}
-
-static void sdeb_unblock_all_queues(void)
-{
- int j;
- struct sdebug_queue *sqp;
-
- for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
- atomic_set(&sqp->blocked, (int)false);
-}
-
-static void
-sdeb_add_n_hosts(int num_hosts)
-{
- if (num_hosts < 1)
- return;
- do {
- bool found;
- unsigned long idx;
- struct sdeb_store_info *sip;
- bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
-
- found = false;
- if (want_phs) {
- xa_for_each_marked(per_store_ap, idx, sip, SDEB_XA_NOT_IN_USE) {
- sdeb_most_recent_idx = (int)idx;
- found = true;
- break;
- }
- if (found) /* re-use case */
- sdebug_add_host_helper((int)idx);
- else
- sdebug_do_add_host(true /* make new store */);
- } else {
- sdebug_do_add_host(false);
- }
- } while (--num_hosts);
+ atomic_set(&sqp->blocked, (int)block);
}
/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
@@ -5505,10 +5531,10 @@ static void tweak_cmnd_count(void)
modulo = abs(sdebug_every_nth);
if (modulo < 2)
return;
- sdeb_block_all_queues();
+ block_unblock_all_queues(true);
count = atomic_read(&sdebug_cmnd_count);
atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
- sdeb_unblock_all_queues();
+ block_unblock_all_queues(false);
}
static void clear_queue_stats(void)
@@ -5526,15 +5552,6 @@ static bool inject_on_this_cmd(void)
return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
}
-static int process_deflect_incoming(struct scsi_cmnd *scp)
-{
- u8 opcode = scp->cmnd[0];
-
- if (opcode == SYNCHRONIZE_CACHE || opcode == SYNCHRONIZE_CACHE_16)
- return 0;
- return DID_NO_CONNECT << 16;
-}
-
#define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */
/* Complete the processing of the thread that queued a SCSI command to this
@@ -5544,7 +5561,8 @@ static int process_deflect_incoming(struct scsi_cmnd *scp)
*/
static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
int scsi_result,
- int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *),
+ int (*pfp)(struct scsi_cmnd *,
+ struct sdebug_dev_info *),
int delta_jiff, int ndelay)
{
bool new_sd_dp;
@@ -5565,27 +5583,13 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
}
sdp = cmnd->device;
- if (delta_jiff == 0) {
- sqp = get_queue(cmnd);
- if (atomic_read(&sqp->blocked)) {
- if (smp_load_acquire(&sdebug_deflect_incoming))
- return process_deflect_incoming(cmnd);
- else
- return SCSI_MLQUEUE_HOST_BUSY;
- }
+ if (delta_jiff == 0)
goto respond_in_thread;
- }
sqp = get_queue(cmnd);
spin_lock_irqsave(&sqp->qc_lock, iflags);
if (unlikely(atomic_read(&sqp->blocked))) {
spin_unlock_irqrestore(&sqp->qc_lock, iflags);
- if (smp_load_acquire(&sdebug_deflect_incoming)) {
- scsi_result = process_deflect_incoming(cmnd);
- goto respond_in_thread;
- }
- if (sdebug_verbose)
- pr_info("blocked --> SCSI_MLQUEUE_HOST_BUSY\n");
return SCSI_MLQUEUE_HOST_BUSY;
}
num_in_q = atomic_read(&devip->num_in_q);
@@ -5774,12 +5778,8 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
respond_in_thread: /* call back to mid-layer using invocation thread */
cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
cmnd->result &= ~SDEG_RES_IMMED_MASK;
- if (cmnd->result == 0 && scsi_result != 0) {
+ if (cmnd->result == 0 && scsi_result != 0)
cmnd->result = scsi_result;
- if (sdebug_verbose)
- pr_info("respond_in_thread: tag=0x%x, scp->result=0x%x\n",
- blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)), scsi_result);
- }
scsi_done(cmnd);
return 0;
}
@@ -5856,6 +5856,7 @@ module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
module_param_named(write_same_length, sdebug_write_same_length, int,
S_IRUGO | S_IWUSR);
module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO);
+module_param_named(zone_cap_mb, sdeb_zbc_zone_cap_mb, int, S_IRUGO);
module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO);
module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO);
module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO);
@@ -5927,6 +5928,7 @@ MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique de
MODULE_PARM_DESC(wp, "Write Protect (def=0)");
MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix");
+MODULE_PARM_DESC(zone_cap_mb, "Zone capacity in MiB (def=zone size)");
MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)");
MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)");
MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)");
@@ -6064,7 +6066,7 @@ static ssize_t delay_store(struct device_driver *ddp, const char *buf,
int j, k;
struct sdebug_queue *sqp;
- sdeb_block_all_queues();
+ block_unblock_all_queues(true);
for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
++j, ++sqp) {
k = find_first_bit(sqp->in_use_bm,
@@ -6078,7 +6080,7 @@ static ssize_t delay_store(struct device_driver *ddp, const char *buf,
sdebug_jdelay = jdelay;
sdebug_ndelay = 0;
}
- sdeb_unblock_all_queues();
+ block_unblock_all_queues(false);
}
return res;
}
@@ -6104,7 +6106,7 @@ static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
int j, k;
struct sdebug_queue *sqp;
- sdeb_block_all_queues();
+ block_unblock_all_queues(true);
for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
++j, ++sqp) {
k = find_first_bit(sqp->in_use_bm,
@@ -6119,7 +6121,7 @@ static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
: DEF_JDELAY;
}
- sdeb_unblock_all_queues();
+ block_unblock_all_queues(false);
}
return res;
}
@@ -6433,7 +6435,7 @@ static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
(n <= SDEBUG_CANQUEUE) &&
(sdebug_host_max_queue == 0)) {
- sdeb_block_all_queues();
+ block_unblock_all_queues(true);
k = 0;
for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
++j, ++sqp) {
@@ -6448,7 +6450,7 @@ static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
atomic_set(&retired_max_queue, k + 1);
else
atomic_set(&retired_max_queue, 0);
- sdeb_unblock_all_queues();
+ block_unblock_all_queues(false);
return count;
}
return -EINVAL;
@@ -6537,48 +6539,43 @@ static DRIVER_ATTR_RW(virtual_gb);
static ssize_t add_host_show(struct device_driver *ddp, char *buf)
{
/* absolute number of hosts currently active is what is shown */
- return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&sdebug_num_hosts));
+ return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
}
-/*
- * Accept positive and negative values. Hex values (only positive) may be prefixed by '0x'.
- * To remove all hosts use a large negative number (e.g. -9999). The value 0 does nothing.
- * Returns -EBUSY if another add_host sysfs invocation is active.
- */
static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
size_t count)
{
+ bool found;
+ unsigned long idx;
+ struct sdeb_store_info *sip;
+ bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
int delta_hosts;
- if (count == 0 || kstrtoint(buf, 0, &delta_hosts))
+ if (sscanf(buf, "%d", &delta_hosts) != 1)
return -EINVAL;
- if (sdebug_verbose)
- pr_info("prior num_hosts=%d, num_to_add=%d\n",
- atomic_read(&sdebug_num_hosts), delta_hosts);
- if (delta_hosts == 0)
- return count;
- if (mutex_trylock(&add_host_mutex) == 0)
- return -EBUSY;
if (delta_hosts > 0) {
- sdeb_add_n_hosts(delta_hosts);
- } else if (delta_hosts < 0) {
- smp_store_release(&sdebug_deflect_incoming, true);
- sdeb_block_all_queues();
- if (delta_hosts >= atomic_read(&sdebug_num_hosts))
- stop_all_queued(true);
do {
- if (atomic_read(&sdebug_num_hosts) < 1) {
- free_all_queued();
- break;
+ found = false;
+ if (want_phs) {
+ xa_for_each_marked(per_store_ap, idx, sip,
+ SDEB_XA_NOT_IN_USE) {
+ sdeb_most_recent_idx = (int)idx;
+ found = true;
+ break;
+ }
+ if (found) /* re-use case */
+ sdebug_add_host_helper((int)idx);
+ else
+ sdebug_do_add_host(true);
+ } else {
+ sdebug_do_add_host(false);
}
+ } while (--delta_hosts);
+ } else if (delta_hosts < 0) {
+ do {
sdebug_do_remove_host(false);
} while (++delta_hosts);
- sdeb_unblock_all_queues();
- smp_store_release(&sdebug_deflect_incoming, false);
}
- mutex_unlock(&add_host_mutex);
- if (sdebug_verbose)
- pr_info("post num_hosts=%d\n", atomic_read(&sdebug_num_hosts));
return count;
}
static DRIVER_ATTR_RW(add_host);
@@ -7089,10 +7086,6 @@ static int __init scsi_debug_init(void)
sdebug_add_host = 0;
for (k = 0; k < hosts_to_add; k++) {
- if (smp_load_acquire(&sdebug_deflect_incoming)) {
- pr_info("exit early as sdebug_deflect_incoming is set\n");
- return 0;
- }
if (want_store && k == 0) {
ret = sdebug_add_host_helper(idx);
if (ret < 0) {
@@ -7110,12 +7103,8 @@ static int __init scsi_debug_init(void)
}
}
if (sdebug_verbose)
- pr_info("built %d host(s)\n", atomic_read(&sdebug_num_hosts));
+ pr_info("built %d host(s)\n", sdebug_num_hosts);
- /*
- * Even though all the hosts have been established, due to async device (LU) scanning
- * by the scsi mid-level, there may still be devices (LUs) being set up.
- */
return 0;
bus_unreg:
@@ -7131,17 +7120,12 @@ free_q_arr:
static void __exit scsi_debug_exit(void)
{
- int k;
+ int k = sdebug_num_hosts;
- /* Possible race with LUs still being set up; stop them asap */
- sdeb_block_all_queues();
- smp_store_release(&sdebug_deflect_incoming, true);
- stop_all_queued(false);
- for (k = 0; atomic_read(&sdebug_num_hosts) > 0; k++)
+ stop_all_queued();
+ for (; k; k--)
sdebug_do_remove_host(true);
free_all_queued();
- if (sdebug_verbose)
- pr_info("removed %d hosts\n", k);
driver_unregister(&sdebug_driverfs_driver);
bus_unregister(&pseudo_lld_bus);
root_device_unregister(pseudo_primary);
@@ -7311,13 +7295,13 @@ static int sdebug_add_host_helper(int per_host_idx)
sdbg_host->dev.bus = &pseudo_lld_bus;
sdbg_host->dev.parent = pseudo_primary;
sdbg_host->dev.release = &sdebug_release_adapter;
- dev_set_name(&sdbg_host->dev, "adapter%d", atomic_read(&sdebug_num_hosts));
+ dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
error = device_register(&sdbg_host->dev);
if (error)
goto clean;
- atomic_inc(&sdebug_num_hosts);
+ ++sdebug_num_hosts;
return 0;
clean:
@@ -7381,7 +7365,7 @@ static void sdebug_do_remove_host(bool the_end)
return;
device_unregister(&sdbg_host->dev);
- atomic_dec(&sdebug_num_hosts);
+ --sdebug_num_hosts;
}
static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
@@ -7389,10 +7373,10 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
int num_in_q = 0;
struct sdebug_dev_info *devip;
- sdeb_block_all_queues();
+ block_unblock_all_queues(true);
devip = (struct sdebug_dev_info *)sdev->hostdata;
if (NULL == devip) {
- sdeb_unblock_all_queues();
+ block_unblock_all_queues(false);
return -ENODEV;
}
num_in_q = atomic_read(&devip->num_in_q);
@@ -7411,7 +7395,7 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
__func__, qdepth, num_in_q);
}
- sdeb_unblock_all_queues();
+ block_unblock_all_queues(false);
return sdev->queue_depth;
}
@@ -7519,12 +7503,13 @@ static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
struct sdebug_defer *sd_dp;
sqp = sdebug_q_arr + queue_num;
- qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
- if (qc_idx >= sdebug_max_queue)
- return 0;
spin_lock_irqsave(&sqp->qc_lock, iflags);
+ qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
+ if (qc_idx >= sdebug_max_queue)
+ goto unlock;
+
for (first = true; first || qc_idx + 1 < sdebug_max_queue; ) {
if (first) {
first = false;
@@ -7589,6 +7574,7 @@ static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
break;
}
+unlock:
spin_unlock_irqrestore(&sqp->qc_lock, iflags);
if (num_entries > 0)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 8d18cc7e510e..e9db7da0c79c 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1977,7 +1977,7 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)
tag_set->nr_maps = shost->nr_maps ? : 1;
tag_set->queue_depth = shost->can_queue;
tag_set->cmd_size = cmd_size;
- tag_set->numa_node = NUMA_NO_NODE;
+ tag_set->numa_node = dev_to_node(shost->dma_dev);
tag_set->flags = BLK_MQ_F_SHOULD_MERGE;
tag_set->flags |=
BLK_ALLOC_POLICY_TO_MQ_FLAG(shost->hostt->tag_alloc_policy);
diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c
index ff89de86545d..b02af340c2d3 100644
--- a/drivers/scsi/scsi_logging.c
+++ b/drivers/scsi/scsi_logging.c
@@ -30,7 +30,7 @@ static inline const char *scmd_name(const struct scsi_cmnd *scmd)
{
struct request *rq = scsi_cmd_to_rq((struct scsi_cmnd *)scmd);
- if (!rq->q->disk)
+ if (!rq->q || !rq->q->disk)
return NULL;
return rq->q->disk->disk_name;
}
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index f4e6c68ac99e..91ac901a6682 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -223,6 +223,8 @@ static int scsi_realloc_sdev_budget_map(struct scsi_device *sdev,
int ret;
struct sbitmap sb_backup;
+ depth = min_t(unsigned int, depth, scsi_device_max_queue_depth(sdev));
+
/*
* realloc if new shift is calculated, which is caused by setting
* up one new default queue depth after calling ->slave_configure
@@ -245,6 +247,9 @@ static int scsi_realloc_sdev_budget_map(struct scsi_device *sdev,
scsi_device_max_queue_depth(sdev),
new_shift, GFP_KERNEL,
sdev->request_queue->node, false, true);
+ if (!ret)
+ sbitmap_resize(&sdev->budget_map, depth);
+
if (need_free) {
if (ret)
sdev->budget_map = sb_backup;
@@ -728,7 +733,17 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
if (pass == 1) {
if (BLIST_INQUIRY_36 & *bflags)
next_inquiry_len = 36;
- else if (sdev->inquiry_len)
+ /*
+ * LLD specified a maximum sdev->inquiry_len
+ * but device claims it has more data. Capping
+ * the length only makes sense for legacy
+ * devices. If a device supports SPC-4 (2014)
+ * or newer, assume that it is safe to ask for
+ * as much as the device says it supports.
+ */
+ else if (sdev->inquiry_len &&
+ response_len > sdev->inquiry_len &&
+ (inq_result[2] & 0x7) < 6) /* SPC-4 */
next_inquiry_len = sdev->inquiry_len;
else
next_inquiry_len = response_len;
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 226a50944c00..546a9e3cfbec 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -448,6 +448,7 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
struct list_head *this, *tmp;
struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL;
struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL;
+ struct scsi_vpd *vpd_pgb0 = NULL, *vpd_pgb1 = NULL, *vpd_pgb2 = NULL;
unsigned long flags;
struct module *mod;
@@ -490,6 +491,12 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
lockdep_is_held(&sdev->inquiry_mutex));
vpd_pg89 = rcu_replace_pointer(sdev->vpd_pg89, vpd_pg89,
lockdep_is_held(&sdev->inquiry_mutex));
+ vpd_pgb0 = rcu_replace_pointer(sdev->vpd_pgb0, vpd_pgb0,
+ lockdep_is_held(&sdev->inquiry_mutex));
+ vpd_pgb1 = rcu_replace_pointer(sdev->vpd_pgb1, vpd_pgb1,
+ lockdep_is_held(&sdev->inquiry_mutex));
+ vpd_pgb2 = rcu_replace_pointer(sdev->vpd_pgb2, vpd_pgb2,
+ lockdep_is_held(&sdev->inquiry_mutex));
mutex_unlock(&sdev->inquiry_mutex);
if (vpd_pg0)
@@ -500,6 +507,12 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
kfree_rcu(vpd_pg80, rcu);
if (vpd_pg89)
kfree_rcu(vpd_pg89, rcu);
+ if (vpd_pgb0)
+ kfree_rcu(vpd_pgb0, rcu);
+ if (vpd_pgb1)
+ kfree_rcu(vpd_pgb1, rcu);
+ if (vpd_pgb2)
+ kfree_rcu(vpd_pgb2, rcu);
kfree(sdev->inquiry);
kfree(sdev);
@@ -913,6 +926,9 @@ static struct bin_attribute dev_attr_vpd_##_page = { \
sdev_vpd_pg_attr(pg83);
sdev_vpd_pg_attr(pg80);
sdev_vpd_pg_attr(pg89);
+sdev_vpd_pg_attr(pgb0);
+sdev_vpd_pg_attr(pgb1);
+sdev_vpd_pg_attr(pgb2);
sdev_vpd_pg_attr(pg0);
static ssize_t show_inquiry(struct file *filep, struct kobject *kobj,
@@ -1250,6 +1266,15 @@ static umode_t scsi_sdev_bin_attr_is_visible(struct kobject *kobj,
if (attr == &dev_attr_vpd_pg89 && !sdev->vpd_pg89)
return 0;
+ if (attr == &dev_attr_vpd_pgb0 && !sdev->vpd_pgb0)
+ return 0;
+
+ if (attr == &dev_attr_vpd_pgb1 && !sdev->vpd_pgb1)
+ return 0;
+
+ if (attr == &dev_attr_vpd_pgb2 && !sdev->vpd_pgb2)
+ return 0;
+
return S_IRUGO;
}
@@ -1296,6 +1321,9 @@ static struct bin_attribute *scsi_sdev_bin_attrs[] = {
&dev_attr_vpd_pg83,
&dev_attr_vpd_pg80,
&dev_attr_vpd_pg89,
+ &dev_attr_vpd_pgb0,
+ &dev_attr_vpd_pgb1,
+ &dev_attr_vpd_pgb2,
&dev_attr_inquiry,
NULL
};
@@ -1384,10 +1412,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
if (IS_ENABLED(CONFIG_BLK_DEV_BSG)) {
sdev->bsg_dev = scsi_bsg_register_queue(sdev);
if (IS_ERR(sdev->bsg_dev)) {
- /*
- * We're treating error on bsg register as non-fatal, so
- * pretend nothing went wrong.
- */
error = PTR_ERR(sdev->bsg_dev);
sdev_printk(KERN_INFO, sdev,
"Failed to register bsg queue, errno=%d\n",
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 27951ea05dd4..2c0dd64159b0 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -86,6 +86,9 @@ struct iscsi_internal {
struct transport_container session_cont;
};
+static DEFINE_IDR(iscsi_ep_idr);
+static DEFINE_MUTEX(iscsi_ep_idr_mutex);
+
static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
static struct workqueue_struct *iscsi_conn_cleanup_workq;
@@ -168,6 +171,11 @@ struct device_attribute dev_attr_##_prefix##_##_name = \
static void iscsi_endpoint_release(struct device *dev)
{
struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
+
+ mutex_lock(&iscsi_ep_idr_mutex);
+ idr_remove(&iscsi_ep_idr, ep->id);
+ mutex_unlock(&iscsi_ep_idr_mutex);
+
kfree(ep);
}
@@ -180,7 +188,7 @@ static ssize_t
show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf)
{
struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
- return sysfs_emit(buf, "%llu\n", (unsigned long long) ep->id);
+ return sysfs_emit(buf, "%d\n", ep->id);
}
static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL);
@@ -193,48 +201,32 @@ static struct attribute_group iscsi_endpoint_group = {
.attrs = iscsi_endpoint_attrs,
};
-#define ISCSI_MAX_EPID -1
-
-static int iscsi_match_epid(struct device *dev, const void *data)
-{
- struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
- const uint64_t *epid = data;
-
- return *epid == ep->id;
-}
-
struct iscsi_endpoint *
iscsi_create_endpoint(int dd_size)
{
- struct device *dev;
struct iscsi_endpoint *ep;
- uint64_t id;
- int err;
-
- for (id = 1; id < ISCSI_MAX_EPID; id++) {
- dev = class_find_device(&iscsi_endpoint_class, NULL, &id,
- iscsi_match_epid);
- if (!dev)
- break;
- else
- put_device(dev);
- }
- if (id == ISCSI_MAX_EPID) {
- printk(KERN_ERR "Too many connections. Max supported %u\n",
- ISCSI_MAX_EPID - 1);
- return NULL;
- }
+ int err, id;
ep = kzalloc(sizeof(*ep) + dd_size, GFP_KERNEL);
if (!ep)
return NULL;
+ mutex_lock(&iscsi_ep_idr_mutex);
+ id = idr_alloc(&iscsi_ep_idr, ep, 0, -1, GFP_NOIO);
+ if (id < 0) {
+ mutex_unlock(&iscsi_ep_idr_mutex);
+ printk(KERN_ERR "Could not allocate endpoint ID. Error %d.\n",
+ id);
+ goto free_ep;
+ }
+ mutex_unlock(&iscsi_ep_idr_mutex);
+
ep->id = id;
ep->dev.class = &iscsi_endpoint_class;
- dev_set_name(&ep->dev, "ep-%llu", (unsigned long long) id);
+ dev_set_name(&ep->dev, "ep-%d", id);
err = device_register(&ep->dev);
if (err)
- goto free_ep;
+ goto free_id;
err = sysfs_create_group(&ep->dev.kobj, &iscsi_endpoint_group);
if (err)
@@ -248,6 +240,10 @@ unregister_dev:
device_unregister(&ep->dev);
return NULL;
+free_id:
+ mutex_lock(&iscsi_ep_idr_mutex);
+ idr_remove(&iscsi_ep_idr, id);
+ mutex_unlock(&iscsi_ep_idr_mutex);
free_ep:
kfree(ep);
return NULL;
@@ -275,14 +271,17 @@ EXPORT_SYMBOL_GPL(iscsi_put_endpoint);
*/
struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
{
- struct device *dev;
+ struct iscsi_endpoint *ep;
- dev = class_find_device(&iscsi_endpoint_class, NULL, &handle,
- iscsi_match_epid);
- if (!dev)
- return NULL;
+ mutex_lock(&iscsi_ep_idr_mutex);
+ ep = idr_find(&iscsi_ep_idr, handle);
+ if (!ep)
+ goto unlock;
- return iscsi_dev_to_endpoint(dev);
+ get_device(&ep->dev);
+unlock:
+ mutex_unlock(&iscsi_ep_idr_mutex);
+ return ep;
}
EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);
@@ -2202,10 +2201,10 @@ static void iscsi_stop_conn(struct iscsi_cls_conn *conn, int flag)
switch (flag) {
case STOP_CONN_RECOVER:
- conn->state = ISCSI_CONN_FAILED;
+ WRITE_ONCE(conn->state, ISCSI_CONN_FAILED);
break;
case STOP_CONN_TERM:
- conn->state = ISCSI_CONN_DOWN;
+ WRITE_ONCE(conn->state, ISCSI_CONN_DOWN);
break;
default:
iscsi_cls_conn_printk(KERN_ERR, conn, "invalid stop flag %d\n",
@@ -2217,6 +2216,49 @@ static void iscsi_stop_conn(struct iscsi_cls_conn *conn, int flag)
ISCSI_DBG_TRANS_CONN(conn, "Stopping conn done.\n");
}
+static void iscsi_ep_disconnect(struct iscsi_cls_conn *conn, bool is_active)
+{
+ struct iscsi_cls_session *session = iscsi_conn_to_session(conn);
+ struct iscsi_endpoint *ep;
+
+ ISCSI_DBG_TRANS_CONN(conn, "disconnect ep.\n");
+ WRITE_ONCE(conn->state, ISCSI_CONN_FAILED);
+
+ if (!conn->ep || !session->transport->ep_disconnect)
+ return;
+
+ ep = conn->ep;
+ conn->ep = NULL;
+
+ session->transport->unbind_conn(conn, is_active);
+ session->transport->ep_disconnect(ep);
+ ISCSI_DBG_TRANS_CONN(conn, "disconnect ep done.\n");
+}
+
+static void iscsi_if_disconnect_bound_ep(struct iscsi_cls_conn *conn,
+ struct iscsi_endpoint *ep,
+ bool is_active)
+{
+ /* Check if this was a conn error and the kernel took ownership */
+ spin_lock_irq(&conn->lock);
+ if (!test_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags)) {
+ spin_unlock_irq(&conn->lock);
+ iscsi_ep_disconnect(conn, is_active);
+ } else {
+ spin_unlock_irq(&conn->lock);
+ ISCSI_DBG_TRANS_CONN(conn, "flush kernel conn cleanup.\n");
+ mutex_unlock(&conn->ep_mutex);
+
+ flush_work(&conn->cleanup_work);
+ /*
+ * Userspace is now done with the EP so we can release the ref
+ * iscsi_cleanup_conn_work_fn took.
+ */
+ iscsi_put_endpoint(ep);
+ mutex_lock(&conn->ep_mutex);
+ }
+}
+
static int iscsi_if_stop_conn(struct iscsi_transport *transport,
struct iscsi_uevent *ev)
{
@@ -2238,11 +2280,24 @@ static int iscsi_if_stop_conn(struct iscsi_transport *transport,
iscsi_stop_conn(conn, flag);
} else {
/*
+ * For offload, when iscsid is restarted it won't know about
+ * existing endpoints so it can't do a ep_disconnect. We clean
+ * it up here for userspace.
+ */
+ mutex_lock(&conn->ep_mutex);
+ if (conn->ep)
+ iscsi_if_disconnect_bound_ep(conn, conn->ep, true);
+ mutex_unlock(&conn->ep_mutex);
+
+ /*
* Figure out if it was the kernel or userspace initiating this.
*/
+ spin_lock_irq(&conn->lock);
if (!test_and_set_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags)) {
+ spin_unlock_irq(&conn->lock);
iscsi_stop_conn(conn, flag);
} else {
+ spin_unlock_irq(&conn->lock);
ISCSI_DBG_TRANS_CONN(conn,
"flush kernel conn cleanup.\n");
flush_work(&conn->cleanup_work);
@@ -2251,31 +2306,14 @@ static int iscsi_if_stop_conn(struct iscsi_transport *transport,
* Only clear for recovery to avoid extra cleanup runs during
* termination.
*/
+ spin_lock_irq(&conn->lock);
clear_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags);
+ spin_unlock_irq(&conn->lock);
}
ISCSI_DBG_TRANS_CONN(conn, "iscsi if conn stop done.\n");
return 0;
}
-static void iscsi_ep_disconnect(struct iscsi_cls_conn *conn, bool is_active)
-{
- struct iscsi_cls_session *session = iscsi_conn_to_session(conn);
- struct iscsi_endpoint *ep;
-
- ISCSI_DBG_TRANS_CONN(conn, "disconnect ep.\n");
- conn->state = ISCSI_CONN_FAILED;
-
- if (!conn->ep || !session->transport->ep_disconnect)
- return;
-
- ep = conn->ep;
- conn->ep = NULL;
-
- session->transport->unbind_conn(conn, is_active);
- session->transport->ep_disconnect(ep);
- ISCSI_DBG_TRANS_CONN(conn, "disconnect ep done.\n");
-}
-
static void iscsi_cleanup_conn_work_fn(struct work_struct *work)
{
struct iscsi_cls_conn *conn = container_of(work, struct iscsi_cls_conn,
@@ -2284,18 +2322,11 @@ static void iscsi_cleanup_conn_work_fn(struct work_struct *work)
mutex_lock(&conn->ep_mutex);
/*
- * If we are not at least bound there is nothing for us to do. Userspace
- * will do a ep_disconnect call if offload is used, but will not be
- * doing a stop since there is nothing to clean up, so we have to clear
- * the cleanup bit here.
+ * Get a ref to the ep, so we don't release its ID until after
+ * userspace is done referencing it in iscsi_if_disconnect_bound_ep.
*/
- if (conn->state != ISCSI_CONN_BOUND && conn->state != ISCSI_CONN_UP) {
- ISCSI_DBG_TRANS_CONN(conn, "Got error while conn is already failed. Ignoring.\n");
- clear_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags);
- mutex_unlock(&conn->ep_mutex);
- return;
- }
-
+ if (conn->ep)
+ get_device(&conn->ep->dev);
iscsi_ep_disconnect(conn, false);
if (system_state != SYSTEM_RUNNING) {
@@ -2340,11 +2371,12 @@ iscsi_alloc_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
conn->dd_data = &conn[1];
mutex_init(&conn->ep_mutex);
+ spin_lock_init(&conn->lock);
INIT_LIST_HEAD(&conn->conn_list);
INIT_WORK(&conn->cleanup_work, iscsi_cleanup_conn_work_fn);
conn->transport = transport;
conn->cid = cid;
- conn->state = ISCSI_CONN_DOWN;
+ WRITE_ONCE(conn->state, ISCSI_CONN_DOWN);
/* this is released in the dev's release function */
if (!get_device(&session->dev))
@@ -2542,9 +2574,32 @@ void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
struct iscsi_uevent *ev;
struct iscsi_internal *priv;
int len = nlmsg_total_size(sizeof(*ev));
+ unsigned long flags;
+ int state;
- if (!test_and_set_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags))
- queue_work(iscsi_conn_cleanup_workq, &conn->cleanup_work);
+ spin_lock_irqsave(&conn->lock, flags);
+ /*
+ * Userspace will only do a stop call if we are at least bound. And, we
+ * only need to do the in kernel cleanup if in the UP state so cmds can
+ * be released to upper layers. If in other states just wait for
+ * userspace to avoid races that can leave the cleanup_work queued.
+ */
+ state = READ_ONCE(conn->state);
+ switch (state) {
+ case ISCSI_CONN_BOUND:
+ case ISCSI_CONN_UP:
+ if (!test_and_set_bit(ISCSI_CLS_CONN_BIT_CLEANUP,
+ &conn->flags)) {
+ queue_work(iscsi_conn_cleanup_workq,
+ &conn->cleanup_work);
+ }
+ break;
+ default:
+ ISCSI_DBG_TRANS_CONN(conn, "Got conn error in state %d\n",
+ state);
+ break;
+ }
+ spin_unlock_irqrestore(&conn->lock, flags);
priv = iscsi_if_transport_lookup(conn->transport);
if (!priv)
@@ -2894,7 +2949,7 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
char *data = (char*)ev + sizeof(*ev);
struct iscsi_cls_conn *conn;
struct iscsi_cls_session *session;
- int err = 0, value = 0;
+ int err = 0, value = 0, state;
if (ev->u.set_param.len > PAGE_SIZE)
return -EINVAL;
@@ -2911,8 +2966,8 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
session->recovery_tmo = value;
break;
default:
- if ((conn->state == ISCSI_CONN_BOUND) ||
- (conn->state == ISCSI_CONN_UP)) {
+ state = READ_ONCE(conn->state);
+ if (state == ISCSI_CONN_BOUND || state == ISCSI_CONN_UP) {
err = transport->set_param(conn, ev->u.set_param.param,
data, ev->u.set_param.len);
} else {
@@ -2984,16 +3039,7 @@ static int iscsi_if_ep_disconnect(struct iscsi_transport *transport,
}
mutex_lock(&conn->ep_mutex);
- /* Check if this was a conn error and the kernel took ownership */
- if (test_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags)) {
- ISCSI_DBG_TRANS_CONN(conn, "flush kernel conn cleanup.\n");
- mutex_unlock(&conn->ep_mutex);
-
- flush_work(&conn->cleanup_work);
- goto put_ep;
- }
-
- iscsi_ep_disconnect(conn, false);
+ iscsi_if_disconnect_bound_ep(conn, ep, false);
mutex_unlock(&conn->ep_mutex);
put_ep:
iscsi_put_endpoint(ep);
@@ -3696,24 +3742,17 @@ static int iscsi_if_transport_conn(struct iscsi_transport *transport,
return -EINVAL;
mutex_lock(&conn->ep_mutex);
+ spin_lock_irq(&conn->lock);
if (test_bit(ISCSI_CLS_CONN_BIT_CLEANUP, &conn->flags)) {
+ spin_unlock_irq(&conn->lock);
mutex_unlock(&conn->ep_mutex);
ev->r.retcode = -ENOTCONN;
return 0;
}
+ spin_unlock_irq(&conn->lock);
switch (nlh->nlmsg_type) {
case ISCSI_UEVENT_BIND_CONN:
- if (conn->ep) {
- /*
- * For offload boot support where iscsid is restarted
- * during the pivot root stage, the ep will be intact
- * here when the new iscsid instance starts up and
- * reconnects.
- */
- iscsi_ep_disconnect(conn, true);
- }
-
session = iscsi_session_lookup(ev->u.b_conn.sid);
if (!session) {
err = -EINVAL;
@@ -3724,7 +3763,7 @@ static int iscsi_if_transport_conn(struct iscsi_transport *transport,
ev->u.b_conn.transport_eph,
ev->u.b_conn.is_leading);
if (!ev->r.retcode)
- conn->state = ISCSI_CONN_BOUND;
+ WRITE_ONCE(conn->state, ISCSI_CONN_BOUND);
if (ev->r.retcode || !transport->ep_connect)
break;
@@ -3743,7 +3782,8 @@ static int iscsi_if_transport_conn(struct iscsi_transport *transport,
case ISCSI_UEVENT_START_CONN:
ev->r.retcode = transport->start_conn(conn);
if (!ev->r.retcode)
- conn->state = ISCSI_CONN_UP;
+ WRITE_ONCE(conn->state, ISCSI_CONN_UP);
+
break;
case ISCSI_UEVENT_SEND_PDU:
pdu_len = nlh->nlmsg_len - sizeof(*nlh) - sizeof(*ev);
@@ -4050,10 +4090,11 @@ static ssize_t show_conn_state(struct device *dev,
{
struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent);
const char *state = "unknown";
+ int conn_state = READ_ONCE(conn->state);
- if (conn->state >= 0 &&
- conn->state < ARRAY_SIZE(connection_state_names))
- state = connection_state_names[conn->state];
+ if (conn_state >= 0 &&
+ conn_state < ARRAY_SIZE(connection_state_names))
+ state = connection_state_names[conn_state];
return sysfs_emit(buf, "%s\n", state);
}
diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c
index acdc0aceca5e..e2c7d8ef205f 100644
--- a/drivers/scsi/scsicam.c
+++ b/drivers/scsi/scsicam.c
@@ -34,15 +34,14 @@ unsigned char *scsi_bios_ptable(struct block_device *dev)
{
struct address_space *mapping = bdev_whole(dev)->bd_inode->i_mapping;
unsigned char *res = NULL;
- struct page *page;
+ struct folio *folio;
- page = read_mapping_page(mapping, 0, NULL);
- if (IS_ERR(page))
+ folio = read_mapping_folio(mapping, 0, NULL);
+ if (IS_ERR(folio))
return NULL;
- if (!PageError(page))
- res = kmemdup(page_address(page) + 0x1be, 66, GFP_KERNEL);
- put_page(page);
+ res = kmemdup(folio_address(folio) + 0x1be, 66, GFP_KERNEL);
+ folio_put(folio);
return res;
}
EXPORT_SYMBOL(scsi_bios_ptable);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index a390679cf458..749316462075 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -797,7 +797,6 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
case SD_LBP_FULL:
case SD_LBP_DISABLE:
blk_queue_max_discard_sectors(q, 0);
- blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
return;
case SD_LBP_UNMAP:
@@ -830,7 +829,6 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
}
blk_queue_max_discard_sectors(q, max_blocks * (logical_block_size >> 9));
- blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
}
static blk_status_t sd_setup_unmap_cmnd(struct scsi_cmnd *cmd)
@@ -2176,40 +2174,48 @@ static int sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer
{
struct scsi_device *sdp = sdkp->device;
u8 type;
- int ret = 0;
if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) {
sdkp->protection_type = 0;
- return ret;
+ return 0;
}
type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */
- if (type > T10_PI_TYPE3_PROTECTION)
- ret = -ENODEV;
- else if (scsi_host_dif_capable(sdp->host, type))
- ret = 1;
-
- if (sdkp->first_scan || type != sdkp->protection_type)
- switch (ret) {
- case -ENODEV:
- sd_printk(KERN_ERR, sdkp, "formatted with unsupported" \
- " protection type %u. Disabling disk!\n",
- type);
- break;
- case 1:
- sd_printk(KERN_NOTICE, sdkp,
- "Enabling DIF Type %u protection\n", type);
- break;
- case 0:
- sd_printk(KERN_NOTICE, sdkp,
- "Disabling DIF Type %u protection\n", type);
- break;
- }
+ if (type > T10_PI_TYPE3_PROTECTION) {
+ sd_printk(KERN_ERR, sdkp, "formatted with unsupported" \
+ " protection type %u. Disabling disk!\n",
+ type);
+ sdkp->protection_type = 0;
+ return -ENODEV;
+ }
sdkp->protection_type = type;
- return ret;
+ return 0;
+}
+
+static void sd_config_protection(struct scsi_disk *sdkp)
+{
+ struct scsi_device *sdp = sdkp->device;
+
+ if (!sdkp->first_scan)
+ return;
+
+ sd_dif_config_host(sdkp);
+
+ if (!sdkp->protection_type)
+ return;
+
+ if (!scsi_host_dif_capable(sdp->host, sdkp->protection_type)) {
+ sd_printk(KERN_NOTICE, sdkp,
+ "Disabling DIF Type %u protection\n",
+ sdkp->protection_type);
+ sdkp->protection_type = 0;
+ }
+
+ sd_printk(KERN_NOTICE, sdkp, "Enabling DIF Type %u protection\n",
+ sdkp->protection_type);
}
static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
@@ -2843,40 +2849,37 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer)
*/
static void sd_read_block_limits(struct scsi_disk *sdkp)
{
- unsigned int sector_sz = sdkp->device->sector_size;
- const int vpd_len = 64;
- unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL);
+ struct scsi_vpd *vpd;
- if (!buffer ||
- /* Block Limits VPD */
- scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len))
- goto out;
+ rcu_read_lock();
- blk_queue_io_min(sdkp->disk->queue,
- get_unaligned_be16(&buffer[6]) * sector_sz);
+ vpd = rcu_dereference(sdkp->device->vpd_pgb0);
+ if (!vpd || vpd->len < 16)
+ goto out;
- sdkp->max_xfer_blocks = get_unaligned_be32(&buffer[8]);
- sdkp->opt_xfer_blocks = get_unaligned_be32(&buffer[12]);
+ sdkp->min_xfer_blocks = get_unaligned_be16(&vpd->data[6]);
+ sdkp->max_xfer_blocks = get_unaligned_be32(&vpd->data[8]);
+ sdkp->opt_xfer_blocks = get_unaligned_be32(&vpd->data[12]);
- if (buffer[3] == 0x3c) {
+ if (vpd->len >= 64) {
unsigned int lba_count, desc_count;
- sdkp->max_ws_blocks = (u32)get_unaligned_be64(&buffer[36]);
+ sdkp->max_ws_blocks = (u32)get_unaligned_be64(&vpd->data[36]);
if (!sdkp->lbpme)
goto out;
- lba_count = get_unaligned_be32(&buffer[20]);
- desc_count = get_unaligned_be32(&buffer[24]);
+ lba_count = get_unaligned_be32(&vpd->data[20]);
+ desc_count = get_unaligned_be32(&vpd->data[24]);
if (lba_count && desc_count)
sdkp->max_unmap_blocks = lba_count;
- sdkp->unmap_granularity = get_unaligned_be32(&buffer[28]);
+ sdkp->unmap_granularity = get_unaligned_be32(&vpd->data[28]);
- if (buffer[32] & 0x80)
+ if (vpd->data[32] & 0x80)
sdkp->unmap_alignment =
- get_unaligned_be32(&buffer[32]) & ~(1 << 31);
+ get_unaligned_be32(&vpd->data[32]) & ~(1 << 31);
if (!sdkp->lbpvpd) { /* LBP VPD page not provided */
@@ -2898,7 +2901,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
}
out:
- kfree(buffer);
+ rcu_read_unlock();
}
/**
@@ -2908,18 +2911,21 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
static void sd_read_block_characteristics(struct scsi_disk *sdkp)
{
struct request_queue *q = sdkp->disk->queue;
- unsigned char *buffer;
+ struct scsi_vpd *vpd;
u16 rot;
- const int vpd_len = 64;
+ u8 zoned;
- buffer = kmalloc(vpd_len, GFP_KERNEL);
+ rcu_read_lock();
+ vpd = rcu_dereference(sdkp->device->vpd_pgb1);
- if (!buffer ||
- /* Block Device Characteristics VPD */
- scsi_get_vpd_page(sdkp->device, 0xb1, buffer, vpd_len))
- goto out;
+ if (!vpd || vpd->len < 8) {
+ rcu_read_unlock();
+ return;
+ }
- rot = get_unaligned_be16(&buffer[4]);
+ rot = get_unaligned_be16(&vpd->data[4]);
+ zoned = (vpd->data[8] >> 4) & 3;
+ rcu_read_unlock();
if (rot == 1) {
blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
@@ -2930,7 +2936,7 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
/* Host-managed */
blk_queue_set_zoned(sdkp->disk, BLK_ZONED_HM);
} else {
- sdkp->zoned = (buffer[8] >> 4) & 3;
+ sdkp->zoned = zoned;
if (sdkp->zoned == 1) {
/* Host-aware */
blk_queue_set_zoned(sdkp->disk, BLK_ZONED_HA);
@@ -2941,7 +2947,7 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
}
if (!sdkp->first_scan)
- goto out;
+ return;
if (blk_queue_is_zoned(q)) {
sd_printk(KERN_NOTICE, sdkp, "Host-%s zoned block device\n",
@@ -2954,9 +2960,6 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
sd_printk(KERN_NOTICE, sdkp,
"Drive-managed SMR disk\n");
}
-
- out:
- kfree(buffer);
}
/**
@@ -2965,24 +2968,24 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp)
*/
static void sd_read_block_provisioning(struct scsi_disk *sdkp)
{
- unsigned char *buffer;
- const int vpd_len = 8;
+ struct scsi_vpd *vpd;
if (sdkp->lbpme == 0)
return;
- buffer = kmalloc(vpd_len, GFP_KERNEL);
+ rcu_read_lock();
+ vpd = rcu_dereference(sdkp->device->vpd_pgb2);
- if (!buffer || scsi_get_vpd_page(sdkp->device, 0xb2, buffer, vpd_len))
- goto out;
+ if (!vpd || vpd->len < 8) {
+ rcu_read_unlock();
+ return;
+ }
sdkp->lbpvpd = 1;
- sdkp->lbpu = (buffer[5] >> 7) & 1; /* UNMAP */
- sdkp->lbpws = (buffer[5] >> 6) & 1; /* WRITE SAME(16) with UNMAP */
- sdkp->lbpws10 = (buffer[5] >> 5) & 1; /* WRITE SAME(10) with UNMAP */
-
- out:
- kfree(buffer);
+ sdkp->lbpu = (vpd->data[5] >> 7) & 1; /* UNMAP */
+ sdkp->lbpws = (vpd->data[5] >> 6) & 1; /* WRITE SAME(16) w/ UNMAP */
+ sdkp->lbpws10 = (vpd->data[5] >> 5) & 1; /* WRITE SAME(10) w/ UNMAP */
+ rcu_read_unlock();
}
static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)
@@ -2996,8 +2999,7 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)
}
if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, INQUIRY) < 0) {
- /* too large values might cause issues with arcmsr */
- int vpd_buf_len = 64;
+ struct scsi_vpd *vpd;
sdev->no_report_opcodes = 1;
@@ -3005,8 +3007,11 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)
* CODES is unsupported and the device has an ATA
* Information VPD page (SAT).
*/
- if (!scsi_get_vpd_page(sdev, 0x89, buffer, vpd_buf_len))
+ rcu_read_lock();
+ vpd = rcu_dereference(sdev->vpd_pg89);
+ if (vpd)
sdev->no_write_same = 1;
+ rcu_read_unlock();
}
if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME_16) == 1)
@@ -3110,6 +3115,29 @@ out:
kfree(buffer);
}
+static bool sd_validate_min_xfer_size(struct scsi_disk *sdkp)
+{
+ struct scsi_device *sdp = sdkp->device;
+ unsigned int min_xfer_bytes =
+ logical_to_bytes(sdp, sdkp->min_xfer_blocks);
+
+ if (sdkp->min_xfer_blocks == 0)
+ return false;
+
+ 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",
+ min_xfer_bytes, sdkp->physical_block_size);
+ sdkp->min_xfer_blocks = 0;
+ return false;
+ }
+
+ sd_first_printk(KERN_INFO, sdkp, "Preferred minimum I/O size %u bytes\n",
+ min_xfer_bytes);
+ return true;
+}
+
/*
* Determine the device's preferred I/O size for reads and writes
* unless the reported value is unreasonably small, large, not a
@@ -3121,6 +3149,8 @@ static bool sd_validate_opt_xfer_size(struct scsi_disk *sdkp,
struct scsi_device *sdp = sdkp->device;
unsigned int opt_xfer_bytes =
logical_to_bytes(sdp, sdkp->opt_xfer_blocks);
+ unsigned int min_xfer_bytes =
+ logical_to_bytes(sdp, sdkp->min_xfer_blocks);
if (sdkp->opt_xfer_blocks == 0)
return false;
@@ -3149,6 +3179,15 @@ static bool sd_validate_opt_xfer_size(struct scsi_disk *sdkp,
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",
+ 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 " \
@@ -3216,6 +3255,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
sd_read_block_limits(sdkp);
sd_read_block_characteristics(sdkp);
sd_zbc_read_zones(sdkp, buffer);
+ sd_read_cpr(sdkp);
}
sd_print_capacity(sdkp, old_capacity);
@@ -3225,7 +3265,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
sd_read_app_tag_own(sdkp, buffer);
sd_read_write_same(sdkp, buffer);
sd_read_security(sdkp, buffer);
- sd_read_cpr(sdkp);
+ sd_config_protection(sdkp);
}
/*
@@ -3241,6 +3281,12 @@ static int sd_revalidate_disk(struct gendisk *disk)
dev_max = min_not_zero(dev_max, sdkp->max_xfer_blocks);
q->limits.max_dev_sectors = logical_to_sectors(sdp, dev_max);
+ if (sd_validate_min_xfer_size(sdkp))
+ blk_queue_io_min(sdkp->disk->queue,
+ logical_to_bytes(sdp, sdkp->min_xfer_blocks));
+ else
+ blk_queue_io_min(sdkp->disk->queue, 0);
+
if (sd_validate_opt_xfer_size(sdkp, dev_max)) {
q->limits.io_opt = logical_to_bytes(sdp, sdkp->opt_xfer_blocks);
rw_max = logical_to_sectors(sdp, sdkp->opt_xfer_blocks);
@@ -3475,14 +3521,10 @@ static int sd_probe(struct device *dev)
error = device_add_disk(dev, gd, NULL);
if (error) {
put_device(&sdkp->disk_dev);
+ blk_cleanup_disk(gd);
goto out;
}
- if (sdkp->capacity)
- sd_dif_config_host(sdkp);
-
- sd_revalidate_disk(gd);
-
if (sdkp->security) {
sdkp->opal_dev = init_opal_dev(sdkp, &sd_sec_submit);
if (sdkp->opal_dev)
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 0a33a4b68ffb..2abad54fd23f 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -67,6 +67,20 @@ enum {
SD_ZERO_WS10_UNMAP, /* Use WRITE SAME(10) with UNMAP */
};
+/**
+ * struct zoned_disk_info - Specific properties of a ZBC SCSI device.
+ * @nr_zones: number of zones.
+ * @zone_blocks: number of logical blocks per zone.
+ *
+ * This data structure holds the ZBC SCSI device properties that are retrieved
+ * twice: a first time before the gendisk capacity is known and a second time
+ * after the gendisk capacity is known.
+ */
+struct zoned_disk_info {
+ u32 nr_zones;
+ u32 zone_blocks;
+};
+
struct scsi_disk {
struct scsi_device *device;
@@ -78,13 +92,18 @@ struct scsi_disk {
struct gendisk *disk;
struct opal_dev *opal_dev;
#ifdef CONFIG_BLK_DEV_ZONED
- u32 nr_zones;
- u32 rev_nr_zones;
- u32 zone_blocks;
- u32 rev_zone_blocks;
+ /* Updated during revalidation before the gendisk capacity is known. */
+ struct zoned_disk_info early_zone_info;
+ /* Updated during revalidation after the gendisk capacity is known. */
+ struct zoned_disk_info zone_info;
u32 zones_optimal_open;
u32 zones_optimal_nonseq;
u32 zones_max_open;
+ /*
+ * Either zero or a power of two. If not zero it means that the offset
+ * between zone starting LBAs is constant.
+ */
+ u32 zone_starting_lba_gran;
u32 *zones_wp_offset;
spinlock_t zones_wp_offset_lock;
u32 *rev_wp_offset;
@@ -95,6 +114,7 @@ struct scsi_disk {
atomic_t openers;
sector_t capacity; /* size in logical blocks */
int max_retries;
+ u32 min_xfer_blocks;
u32 max_xfer_blocks;
u32 opt_xfer_blocks;
u32 max_ws_blocks;
@@ -222,7 +242,7 @@ static inline int sd_is_zoned(struct scsi_disk *sdkp)
#ifdef CONFIG_BLK_DEV_ZONED
void sd_zbc_release_disk(struct scsi_disk *sdkp);
-int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buffer);
+int sd_zbc_read_zones(struct scsi_disk *sdkp, u8 buf[SD_BUF_SIZE]);
int sd_zbc_revalidate_zones(struct scsi_disk *sdkp);
blk_status_t sd_zbc_setup_zone_mgmt_cmnd(struct scsi_cmnd *cmd,
unsigned char op, bool all);
@@ -238,8 +258,7 @@ blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba,
static inline void sd_zbc_release_disk(struct scsi_disk *sdkp) {}
-static inline int sd_zbc_read_zones(struct scsi_disk *sdkp,
- unsigned char *buf)
+static inline int sd_zbc_read_zones(struct scsi_disk *sdkp, u8 buf[SD_BUF_SIZE])
{
return 0;
}
diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c
index 349950616adc..968993ee6d5d 100644
--- a/drivers/scsi/sd_dif.c
+++ b/drivers/scsi/sd_dif.c
@@ -59,8 +59,6 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
bi.profile = &t10_pi_type1_crc;
bi.tuple_size = sizeof(struct t10_pi_tuple);
- sd_printk(KERN_NOTICE, sdkp,
- "Enabling DIX %s protection\n", bi.profile->name);
if (dif && type) {
bi.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
@@ -72,11 +70,11 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
bi.tag_size = sizeof(u16) + sizeof(u32);
else
bi.tag_size = sizeof(u16);
-
- sd_printk(KERN_NOTICE, sdkp, "DIF application tag size %u\n",
- bi.tag_size);
}
+ sd_printk(KERN_NOTICE, sdkp,
+ "Enabling DIX %s, application tag size %u bytes\n",
+ bi.profile->name, bi.tag_size);
out:
blk_integrity_register(disk, &bi);
}
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index 7f466280993b..5b9fad70aa88 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -20,6 +20,12 @@
#include "sd.h"
+/**
+ * sd_zbc_get_zone_wp_offset - Get zone write pointer offset.
+ * @zone: Zone for which to return the write pointer offset.
+ *
+ * Return: offset of the write pointer from the start of the zone.
+ */
static unsigned int sd_zbc_get_zone_wp_offset(struct blk_zone *zone)
{
if (zone->type == ZBC_ZONE_TYPE_CONV)
@@ -44,13 +50,37 @@ static unsigned int sd_zbc_get_zone_wp_offset(struct blk_zone *zone)
}
}
-static int sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf,
+/* Whether or not a SCSI zone descriptor describes a gap zone. */
+static bool sd_zbc_is_gap_zone(const u8 buf[64])
+{
+ return (buf[0] & 0xf) == ZBC_ZONE_TYPE_GAP;
+}
+
+/**
+ * sd_zbc_parse_report - Parse a SCSI zone descriptor
+ * @sdkp: SCSI disk pointer.
+ * @buf: SCSI zone descriptor.
+ * @idx: Index of the zone relative to the first zone reported by the current
+ * sd_zbc_report_zones() call.
+ * @cb: Callback function pointer.
+ * @data: Second argument passed to @cb.
+ *
+ * Return: Value returned by @cb.
+ *
+ * Convert a SCSI zone descriptor into struct blk_zone format. Additionally,
+ * call @cb(blk_zone, @data).
+ */
+static int sd_zbc_parse_report(struct scsi_disk *sdkp, const u8 buf[64],
unsigned int idx, report_zones_cb cb, void *data)
{
struct scsi_device *sdp = sdkp->device;
struct blk_zone zone = { 0 };
+ sector_t start_lba, gran;
int ret;
+ if (WARN_ON_ONCE(sd_zbc_is_gap_zone(buf)))
+ return -EINVAL;
+
zone.type = buf[0] & 0x0f;
zone.cond = (buf[1] >> 4) & 0xf;
if (buf[1] & 0x01)
@@ -58,9 +88,27 @@ static int sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf,
if (buf[1] & 0x02)
zone.non_seq = 1;
- zone.len = logical_to_sectors(sdp, get_unaligned_be64(&buf[8]));
- zone.capacity = zone.len;
- zone.start = logical_to_sectors(sdp, get_unaligned_be64(&buf[16]));
+ start_lba = get_unaligned_be64(&buf[16]);
+ zone.start = logical_to_sectors(sdp, start_lba);
+ zone.capacity = logical_to_sectors(sdp, get_unaligned_be64(&buf[8]));
+ zone.len = zone.capacity;
+ if (sdkp->zone_starting_lba_gran) {
+ gran = logical_to_sectors(sdp, sdkp->zone_starting_lba_gran);
+ if (zone.len > gran) {
+ sd_printk(KERN_ERR, sdkp,
+ "Invalid zone at LBA %llu with capacity %llu and length %llu; granularity = %llu\n",
+ start_lba,
+ sectors_to_logical(sdp, zone.capacity),
+ sectors_to_logical(sdp, zone.len),
+ sectors_to_logical(sdp, gran));
+ return -EINVAL;
+ }
+ /*
+ * Use the starting LBA granularity instead of the zone length
+ * obtained from the REPORT ZONES command.
+ */
+ zone.len = gran;
+ }
if (zone.cond == ZBC_ZONE_COND_FULL)
zone.wp = zone.start + zone.len;
else
@@ -161,7 +209,7 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp,
* sure that the allocated buffer can always be mapped by limiting the
* number of pages allocated to the HBA max segments limit.
*/
- nr_zones = min(nr_zones, sdkp->nr_zones);
+ nr_zones = min(nr_zones, sdkp->zone_info.nr_zones);
bufsize = roundup((nr_zones + 1) * 64, SECTOR_SIZE);
bufsize = min_t(size_t, bufsize,
queue_max_hw_sectors(q) << SECTOR_SHIFT);
@@ -186,16 +234,28 @@ static void *sd_zbc_alloc_report_buffer(struct scsi_disk *sdkp,
*/
static inline sector_t sd_zbc_zone_sectors(struct scsi_disk *sdkp)
{
- return logical_to_sectors(sdkp->device, sdkp->zone_blocks);
+ return logical_to_sectors(sdkp->device, sdkp->zone_info.zone_blocks);
}
+/**
+ * sd_zbc_report_zones - SCSI .report_zones() callback.
+ * @disk: Disk to report zones for.
+ * @sector: Start sector.
+ * @nr_zones: Maximum number of zones to report.
+ * @cb: Callback function called to report zone information.
+ * @data: Second argument passed to @cb.
+ *
+ * Called by the block layer to iterate over zone information. See also the
+ * disk->fops->report_zones() calls in block/blk-zoned.c.
+ */
int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
unsigned int nr_zones, report_zones_cb cb, void *data)
{
struct scsi_disk *sdkp = scsi_disk(disk);
- sector_t capacity = logical_to_sectors(sdkp->device, sdkp->capacity);
+ sector_t lba = sectors_to_logical(sdkp->device, sector);
unsigned int nr, i;
unsigned char *buf;
+ u64 zone_length, start_lba;
size_t offset, buflen = 0;
int zone_idx = 0;
int ret;
@@ -204,7 +264,7 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
/* Not a zoned device */
return -EOPNOTSUPP;
- if (!capacity)
+ if (!sdkp->capacity)
/* Device gone or invalid */
return -ENODEV;
@@ -212,9 +272,8 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
if (!buf)
return -ENOMEM;
- while (zone_idx < nr_zones && sector < capacity) {
- ret = sd_zbc_do_report_zones(sdkp, buf, buflen,
- sectors_to_logical(sdkp->device, sector), true);
+ while (zone_idx < nr_zones && lba < sdkp->capacity) {
+ ret = sd_zbc_do_report_zones(sdkp, buf, buflen, lba, true);
if (ret)
goto out;
@@ -225,14 +284,36 @@ int sd_zbc_report_zones(struct gendisk *disk, sector_t sector,
for (i = 0; i < nr && zone_idx < nr_zones; i++) {
offset += 64;
+ start_lba = get_unaligned_be64(&buf[offset + 16]);
+ zone_length = get_unaligned_be64(&buf[offset + 8]);
+ if ((zone_idx == 0 &&
+ (lba < start_lba ||
+ lba >= start_lba + zone_length)) ||
+ (zone_idx > 0 && start_lba != lba) ||
+ start_lba + zone_length < start_lba) {
+ sd_printk(KERN_ERR, sdkp,
+ "Zone %d at LBA %llu is invalid: %llu + %llu\n",
+ zone_idx, lba, start_lba, zone_length);
+ ret = -EINVAL;
+ goto out;
+ }
+ lba = start_lba + zone_length;
+ if (sd_zbc_is_gap_zone(&buf[offset])) {
+ if (sdkp->zone_starting_lba_gran)
+ continue;
+ sd_printk(KERN_ERR, sdkp,
+ "Gap zone without constant LBA offsets\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
ret = sd_zbc_parse_report(sdkp, buf + offset, zone_idx,
cb, data);
if (ret)
goto out;
+
zone_idx++;
}
-
- sector += sd_zbc_zone_sectors(sdkp) * i;
}
ret = zone_idx;
@@ -276,6 +357,10 @@ static int sd_zbc_update_wp_offset_cb(struct blk_zone *zone, unsigned int idx,
return 0;
}
+/*
+ * An attempt to append a zone triggered an invalid write pointer error.
+ * Reread the write pointer of the zone(s) in which the append failed.
+ */
static void sd_zbc_update_wp_offset_workfn(struct work_struct *work)
{
struct scsi_disk *sdkp;
@@ -286,14 +371,14 @@ static void sd_zbc_update_wp_offset_workfn(struct work_struct *work)
sdkp = container_of(work, struct scsi_disk, zone_wp_offset_work);
spin_lock_irqsave(&sdkp->zones_wp_offset_lock, flags);
- for (zno = 0; zno < sdkp->nr_zones; zno++) {
+ for (zno = 0; zno < sdkp->zone_info.nr_zones; zno++) {
if (sdkp->zones_wp_offset[zno] != SD_ZBC_UPDATING_WP_OFST)
continue;
spin_unlock_irqrestore(&sdkp->zones_wp_offset_lock, flags);
ret = sd_zbc_do_report_zones(sdkp, sdkp->zone_wp_update_buf,
SD_BUF_SIZE,
- zno * sdkp->zone_blocks, true);
+ zno * sdkp->zone_info.zone_blocks, true);
spin_lock_irqsave(&sdkp->zones_wp_offset_lock, flags);
if (!ret)
sd_zbc_parse_report(sdkp, sdkp->zone_wp_update_buf + 64,
@@ -360,7 +445,7 @@ blk_status_t sd_zbc_prepare_zone_append(struct scsi_cmnd *cmd, sector_t *lba,
break;
default:
wp_offset = sectors_to_logical(sdkp->device, wp_offset);
- if (wp_offset + nr_blocks > sdkp->zone_blocks) {
+ if (wp_offset + nr_blocks > sdkp->zone_info.zone_blocks) {
ret = BLK_STS_IOERR;
break;
}
@@ -489,7 +574,7 @@ static unsigned int sd_zbc_zone_wp_update(struct scsi_cmnd *cmd,
break;
case REQ_OP_ZONE_RESET_ALL:
memset(sdkp->zones_wp_offset, 0,
- sdkp->nr_zones * sizeof(unsigned int));
+ sdkp->zone_info.nr_zones * sizeof(unsigned int));
break;
default:
break;
@@ -545,6 +630,7 @@ unsigned int sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes,
static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp,
unsigned char *buf)
{
+ u64 zone_starting_lba_gran;
if (scsi_get_vpd_page(sdkp->device, 0xb6, buf, 64)) {
sd_printk(KERN_NOTICE, sdkp,
@@ -558,12 +644,36 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp,
sdkp->zones_optimal_open = get_unaligned_be32(&buf[8]);
sdkp->zones_optimal_nonseq = get_unaligned_be32(&buf[12]);
sdkp->zones_max_open = 0;
- } else {
- /* Host-managed */
- sdkp->urswrz = buf[4] & 1;
- sdkp->zones_optimal_open = 0;
- sdkp->zones_optimal_nonseq = 0;
- sdkp->zones_max_open = get_unaligned_be32(&buf[16]);
+ return 0;
+ }
+
+ /* Host-managed */
+ sdkp->urswrz = buf[4] & 1;
+ sdkp->zones_optimal_open = 0;
+ sdkp->zones_optimal_nonseq = 0;
+ sdkp->zones_max_open = get_unaligned_be32(&buf[16]);
+ /* Check zone alignment method */
+ switch (buf[23] & 0xf) {
+ case 0:
+ case ZBC_CONSTANT_ZONE_LENGTH:
+ /* Use zone length */
+ break;
+ case ZBC_CONSTANT_ZONE_START_OFFSET:
+ zone_starting_lba_gran = get_unaligned_be64(&buf[24]);
+ if (zone_starting_lba_gran == 0 ||
+ !is_power_of_2(zone_starting_lba_gran) ||
+ logical_to_sectors(sdkp->device, zone_starting_lba_gran) >
+ UINT_MAX) {
+ sd_printk(KERN_ERR, sdkp,
+ "Invalid zone starting LBA granularity %llu\n",
+ zone_starting_lba_gran);
+ return -ENODEV;
+ }
+ sdkp->zone_starting_lba_gran = zone_starting_lba_gran;
+ break;
+ default:
+ sd_printk(KERN_ERR, sdkp, "Invalid zone alignment method\n");
+ return -ENODEV;
}
/*
@@ -585,7 +695,7 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp,
* sd_zbc_check_capacity - Check the device capacity
* @sdkp: Target disk
* @buf: command buffer
- * @zblocks: zone size in number of blocks
+ * @zblocks: zone size in logical blocks
*
* Get the device zone size and check that the device capacity as reported
* by READ CAPACITY matches the max_lba value (plus one) of the report zones
@@ -619,14 +729,25 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf,
}
}
- /* Get the size of the first reported zone */
- rec = buf + 64;
- zone_blocks = get_unaligned_be64(&rec[8]);
- if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) {
- if (sdkp->first_scan)
- sd_printk(KERN_NOTICE, sdkp,
- "Zone size too large\n");
- return -EFBIG;
+ if (sdkp->zone_starting_lba_gran == 0) {
+ /* Get the size of the first reported zone */
+ rec = buf + 64;
+ zone_blocks = get_unaligned_be64(&rec[8]);
+ if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) {
+ if (sdkp->first_scan)
+ sd_printk(KERN_NOTICE, sdkp,
+ "Zone size too large\n");
+ return -EFBIG;
+ }
+ } else {
+ zone_blocks = sdkp->zone_starting_lba_gran;
+ }
+
+ if (!is_power_of_2(zone_blocks)) {
+ sd_printk(KERN_ERR, sdkp,
+ "Zone size %llu is not a power of two.\n",
+ zone_blocks);
+ return -EINVAL;
}
*zblocks = zone_blocks;
@@ -639,16 +760,16 @@ static void sd_zbc_print_zones(struct scsi_disk *sdkp)
if (!sd_is_zoned(sdkp) || !sdkp->capacity)
return;
- if (sdkp->capacity & (sdkp->zone_blocks - 1))
+ if (sdkp->capacity & (sdkp->zone_info.zone_blocks - 1))
sd_printk(KERN_NOTICE, sdkp,
"%u zones of %u logical blocks + 1 runt zone\n",
- sdkp->nr_zones - 1,
- sdkp->zone_blocks);
+ sdkp->zone_info.nr_zones - 1,
+ sdkp->zone_info.zone_blocks);
else
sd_printk(KERN_NOTICE, sdkp,
"%u zones of %u logical blocks\n",
- sdkp->nr_zones,
- sdkp->zone_blocks);
+ sdkp->zone_info.nr_zones,
+ sdkp->zone_info.zone_blocks);
}
static int sd_zbc_init_disk(struct scsi_disk *sdkp)
@@ -675,10 +796,8 @@ static void sd_zbc_clear_zone_info(struct scsi_disk *sdkp)
kfree(sdkp->zone_wp_update_buf);
sdkp->zone_wp_update_buf = NULL;
- sdkp->nr_zones = 0;
- sdkp->rev_nr_zones = 0;
- sdkp->zone_blocks = 0;
- sdkp->rev_zone_blocks = 0;
+ sdkp->early_zone_info = (struct zoned_disk_info){ };
+ sdkp->zone_info = (struct zoned_disk_info){ };
mutex_unlock(&sdkp->rev_mutex);
}
@@ -696,12 +815,17 @@ static void sd_zbc_revalidate_zones_cb(struct gendisk *disk)
swap(sdkp->zones_wp_offset, sdkp->rev_wp_offset);
}
+/*
+ * Call blk_revalidate_disk_zones() if any of the zoned disk properties have
+ * changed that make it necessary to call that function. Called by
+ * sd_revalidate_disk() after the gendisk capacity has been set.
+ */
int sd_zbc_revalidate_zones(struct scsi_disk *sdkp)
{
struct gendisk *disk = sdkp->disk;
struct request_queue *q = disk->queue;
- u32 zone_blocks = sdkp->rev_zone_blocks;
- unsigned int nr_zones = sdkp->rev_nr_zones;
+ u32 zone_blocks = sdkp->early_zone_info.zone_blocks;
+ unsigned int nr_zones = sdkp->early_zone_info.nr_zones;
u32 max_append;
int ret = 0;
unsigned int flags;
@@ -732,14 +856,14 @@ int sd_zbc_revalidate_zones(struct scsi_disk *sdkp)
*/
mutex_lock(&sdkp->rev_mutex);
- if (sdkp->zone_blocks == zone_blocks &&
- sdkp->nr_zones == nr_zones &&
+ if (sdkp->zone_info.zone_blocks == zone_blocks &&
+ sdkp->zone_info.nr_zones == nr_zones &&
disk->queue->nr_zones == nr_zones)
goto unlock;
flags = memalloc_noio_save();
- sdkp->zone_blocks = zone_blocks;
- sdkp->nr_zones = nr_zones;
+ sdkp->zone_info.zone_blocks = zone_blocks;
+ sdkp->zone_info.nr_zones = nr_zones;
sdkp->rev_wp_offset = kvcalloc(nr_zones, sizeof(u32), GFP_KERNEL);
if (!sdkp->rev_wp_offset) {
ret = -ENOMEM;
@@ -754,8 +878,7 @@ int sd_zbc_revalidate_zones(struct scsi_disk *sdkp)
sdkp->rev_wp_offset = NULL;
if (ret) {
- sdkp->zone_blocks = 0;
- sdkp->nr_zones = 0;
+ sdkp->zone_info = (struct zoned_disk_info){ };
sdkp->capacity = 0;
goto unlock;
}
@@ -774,7 +897,16 @@ unlock:
return ret;
}
-int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
+/**
+ * sd_zbc_read_zones - Read zone information and update the request queue
+ * @sdkp: SCSI disk pointer.
+ * @buf: 512 byte buffer used for storing SCSI command output.
+ *
+ * Read zone information and update the request queue zone characteristics and
+ * also the zoned device information in *sdkp. Called by sd_revalidate_disk()
+ * before the gendisk capacity has been set.
+ */
+int sd_zbc_read_zones(struct scsi_disk *sdkp, u8 buf[SD_BUF_SIZE])
{
struct gendisk *disk = sdkp->disk;
struct request_queue *q = disk->queue;
@@ -832,8 +964,8 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
if (blk_queue_zoned_model(q) == BLK_ZONED_HM)
blk_queue_zone_write_granularity(q, sdkp->physical_block_size);
- sdkp->rev_nr_zones = nr_zones;
- sdkp->rev_zone_blocks = zone_blocks;
+ sdkp->early_zone_info.nr_zones = nr_zones;
+ sdkp->early_zone_info.zone_blocks = zone_blocks;
return 0;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 5ba9df334968..32d3b8274f14 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -113,7 +113,7 @@ static int sr_open(struct cdrom_device_info *, int);
static void sr_release(struct cdrom_device_info *);
static void get_sectorsize(struct scsi_cd *);
-static void get_capabilities(struct scsi_cd *);
+static int get_capabilities(struct scsi_cd *);
static unsigned int sr_check_events(struct cdrom_device_info *cdi,
unsigned int clearing, int slot);
@@ -535,7 +535,7 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
scsi_autopm_get_device(sdev);
- if (ret != CDROMCLOSETRAY && ret != CDROMEJECT) {
+ if (cmd != CDROMCLOSETRAY && cmd != CDROMEJECT) {
ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, arg);
if (ret != -ENOSYS)
goto put;
@@ -669,8 +669,9 @@ static int sr_probe(struct device *dev)
sdev->sector_size = 2048; /* A guess, just in case */
- /* FIXME: need to handle a get_capabilities failure properly ?? */
- get_capabilities(cd);
+ error = -ENOMEM;
+ if (get_capabilities(cd))
+ goto fail_minor;
sr_vendor_init(cd);
set_capacity(disk, cd->capacity);
@@ -794,7 +795,7 @@ static void get_sectorsize(struct scsi_cd *cd)
return;
}
-static void get_capabilities(struct scsi_cd *cd)
+static int get_capabilities(struct scsi_cd *cd)
{
unsigned char *buffer;
struct scsi_mode_data data;
@@ -819,7 +820,7 @@ static void get_capabilities(struct scsi_cd *cd)
buffer = kmalloc(512, GFP_KERNEL);
if (!buffer) {
sr_printk(KERN_ERR, cd, "out of memory.\n");
- return;
+ return -ENOMEM;
}
/* eat unit attentions */
@@ -839,7 +840,7 @@ static void get_capabilities(struct scsi_cd *cd)
CDC_MRW | CDC_MRW_W | CDC_RAM);
kfree(buffer);
sr_printk(KERN_INFO, cd, "scsi-1 drive");
- return;
+ return 0;
}
n = data.header_length + data.block_descriptor_length;
@@ -898,6 +899,7 @@ static void get_capabilities(struct scsi_cd *cd)
}
kfree(buffer);
+ return 0;
}
/*
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index ddd00efc4882..fbdb5124d7f7 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -41,7 +41,7 @@ static int sr_read_tochdr(struct cdrom_device_info *cdi,
int result;
unsigned char *buffer;
- buffer = kmalloc(32, GFP_KERNEL);
+ buffer = kzalloc(32, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
@@ -55,10 +55,13 @@ static int sr_read_tochdr(struct cdrom_device_info *cdi,
cgc.data_direction = DMA_FROM_DEVICE;
result = sr_do_ioctl(cd, &cgc);
+ if (result)
+ goto err;
tochdr->cdth_trk0 = buffer[2];
tochdr->cdth_trk1 = buffer[3];
+err:
kfree(buffer);
return result;
}
@@ -71,7 +74,7 @@ static int sr_read_tocentry(struct cdrom_device_info *cdi,
int result;
unsigned char *buffer;
- buffer = kmalloc(32, GFP_KERNEL);
+ buffer = kzalloc(32, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
@@ -86,6 +89,8 @@ static int sr_read_tocentry(struct cdrom_device_info *cdi,
cgc.data_direction = DMA_FROM_DEVICE;
result = sr_do_ioctl(cd, &cgc);
+ if (result)
+ goto err;
tocentry->cdte_ctrl = buffer[5] & 0xf;
tocentry->cdte_adr = buffer[5] >> 4;
@@ -98,6 +103,7 @@ static int sr_read_tocentry(struct cdrom_device_info *cdi,
tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
+ buffer[10]) << 8) + buffer[11];
+err:
kfree(buffer);
return result;
}
@@ -384,7 +390,7 @@ int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
{
Scsi_CD *cd = cdi->handle;
struct packet_command cgc;
- char *buffer = kmalloc(32, GFP_KERNEL);
+ char *buffer = kzalloc(32, GFP_KERNEL);
int result;
if (!buffer)
@@ -400,10 +406,13 @@ int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
cgc.data_direction = DMA_FROM_DEVICE;
cgc.timeout = IOCTL_TIMEOUT;
result = sr_do_ioctl(cd, &cgc);
+ if (result)
+ goto err;
memcpy(mcn->medium_catalog_number, buffer + 9, 13);
mcn->medium_catalog_number[13] = 0;
+err:
kfree(buffer);
return result;
}
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index 9fe27b01904e..393b9a01da36 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -1,36 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0+
#
# Kernel configuration file for the UFS Host Controller
#
-# This code is based on drivers/scsi/ufs/Kconfig
# Copyright (C) 2011-2013 Samsung India Software Operations
#
# Authors:
# Santosh Yaraganavi <santosh.sy@samsung.com>
# Vinayak Holikatti <h.vinayak@samsung.com>
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-# See the COPYING file in the top-level directory or visit
-# <http://www.gnu.org/licenses/gpl-2.0.html>
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# This program is provided "AS IS" and "WITH ALL FAULTS" and
-# without warranty of any kind. You are solely responsible for
-# determining the appropriateness of using and distributing
-# the program and assume all risks associated with your exercise
-# of rights with respect to the program, including but not limited
-# to infringement of third party rights, the risks and costs of
-# program errors, damage to or loss of data, programs or equipment,
-# and unavailability or interruption of operations. Under no
-# circumstances will the contributor of this Program be liable for
-# any damages of any kind arising from your use or distribution of
-# this program.
config SCSI_UFSHCD
tristate "Universal Flash Storage Controller Driver Core"
diff --git a/drivers/scsi/ufs/cdns-pltfrm.c b/drivers/scsi/ufs/cdns-pltfrm.c
index 7da8be2f35c4..e05c0ae64eea 100644
--- a/drivers/scsi/ufs/cdns-pltfrm.c
+++ b/drivers/scsi/ufs/cdns-pltfrm.c
@@ -9,6 +9,7 @@
*
*/
+#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -340,4 +341,3 @@ module_platform_driver(cdns_ufs_pltfrm_driver);
MODULE_AUTHOR("Jan Kotas <jank@cadence.com>");
MODULE_DESCRIPTION("Cadence UFS host controller platform driver");
MODULE_LICENSE("GPL v2");
-MODULE_VERSION(UFSHCD_DRIVER_VERSION);
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pci.c b/drivers/scsi/ufs/tc-dwc-g210-pci.c
index 7b08e2e07cc5..e635c211c783 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pci.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pci.c
@@ -11,6 +11,7 @@
#include "ufshcd-dwc.h"
#include "tc-dwc-g210.h"
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
diff --git a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c
index 783ec43efa78..f15a84d0c176 100644
--- a/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c
+++ b/drivers/scsi/ufs/tc-dwc-g210-pltfrm.c
@@ -12,6 +12,7 @@
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/delay.h>
+#include <linux/pm_runtime.h>
#include "ufshcd-pltfrm.h"
#include "ufshcd-dwc.h"
diff --git a/drivers/scsi/ufs/tc-dwc-g210.c b/drivers/scsi/ufs/tc-dwc-g210.c
index f954a68f6b4c..7ef67c9fc5b8 100644
--- a/drivers/scsi/ufs/tc-dwc-g210.c
+++ b/drivers/scsi/ufs/tc-dwc-g210.c
@@ -7,6 +7,8 @@
* Authors: Joao Pinto <jpinto@synopsys.com>
*/
+#include <linux/module.h>
+
#include "ufshcd.h"
#include "unipro.h"
diff --git a/drivers/scsi/ufs/tc-dwc-g210.h b/drivers/scsi/ufs/tc-dwc-g210.h
index 5a506da03f4a..f7154012f5c7 100644
--- a/drivers/scsi/ufs/tc-dwc-g210.h
+++ b/drivers/scsi/ufs/tc-dwc-g210.h
@@ -10,6 +10,8 @@
#ifndef _TC_DWC_G210_H
#define _TC_DWC_G210_H
+struct ufs_hba;
+
int tc_dwc_g210_config_40_bit(struct ufs_hba *hba);
int tc_dwc_g210_config_20_bit(struct ufs_hba *hba);
diff --git a/drivers/scsi/ufs/ti-j721e-ufs.c b/drivers/scsi/ufs/ti-j721e-ufs.c
index eafe0db98d54..122d650d0810 100644
--- a/drivers/scsi/ufs/ti-j721e-ufs.c
+++ b/drivers/scsi/ufs/ti-j721e-ufs.c
@@ -29,11 +29,9 @@ static int ti_j721e_ufs_probe(struct platform_device *pdev)
return PTR_ERR(regbase);
pm_runtime_enable(dev);
- ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
- pm_runtime_put_noidle(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
goto disable_pm;
- }
/* Select MPHY refclk frequency */
clk = devm_clk_get(dev, NULL);
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index 4a0bbcf1757a..c10a8f09682b 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -5,6 +5,7 @@
#include "ufs-debugfs.h"
#include "ufshcd.h"
+#include "ufshcd-priv.h"
static struct dentry *ufs_debugfs_root;
diff --git a/drivers/scsi/ufs/ufs-exynos.c b/drivers/scsi/ufs/ufs-exynos.c
index 474a4a064a68..ddb2d42605c5 100644
--- a/drivers/scsi/ufs/ufs-exynos.c
+++ b/drivers/scsi/ufs/ufs-exynos.c
@@ -9,6 +9,7 @@
*/
#include <linux/clk.h>
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -704,7 +705,7 @@ static void exynos_ufs_establish_connt(struct exynos_ufs *ufs)
/* local unipro attributes */
ufshcd_dme_set(hba, UIC_ARG_MIB(N_DEVICEID), DEV_ID);
- ufshcd_dme_set(hba, UIC_ARG_MIB(N_DEVICEID_VALID), TRUE);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(N_DEVICEID_VALID), true);
ufshcd_dme_set(hba, UIC_ARG_MIB(T_PEERDEVICEID), PEER_DEV_ID);
ufshcd_dme_set(hba, UIC_ARG_MIB(T_PEERCPORTID), PEER_CPORT_ID);
ufshcd_dme_set(hba, UIC_ARG_MIB(T_CPORTFLAGS), CPORT_DEF_FLAGS);
@@ -1028,7 +1029,7 @@ static int exynos_ufs_post_link(struct ufs_hba *hba)
if (ufs->opts & EXYNOS_UFS_OPT_SKIP_CONNECTION_ESTAB)
ufshcd_dme_set(hba,
- UIC_ARG_MIB(T_DBG_SKIP_INIT_HIBERN8_EXIT), TRUE);
+ UIC_ARG_MIB(T_DBG_SKIP_INIT_HIBERN8_EXIT), true);
if (attr->pa_granularity) {
exynos_ufs_enable_dbg_mode(hba);
diff --git a/drivers/scsi/ufs/ufs-exynos.h b/drivers/scsi/ufs/ufs-exynos.h
index 1c33e5466082..0b0a3d530ca6 100644
--- a/drivers/scsi/ufs/ufs-exynos.h
+++ b/drivers/scsi/ufs/ufs-exynos.h
@@ -248,22 +248,22 @@ long exynos_ufs_calc_time_cntr(struct exynos_ufs *, long);
static inline void exynos_ufs_enable_ov_tm(struct ufs_hba *hba)
{
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_OV_TM), TRUE);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_OV_TM), true);
}
static inline void exynos_ufs_disable_ov_tm(struct ufs_hba *hba)
{
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_OV_TM), FALSE);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_OV_TM), false);
}
static inline void exynos_ufs_enable_dbg_mode(struct ufs_hba *hba)
{
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_MODE), TRUE);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_MODE), true);
}
static inline void exynos_ufs_disable_dbg_mode(struct ufs_hba *hba)
{
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_MODE), FALSE);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_DBG_MODE), false);
}
#endif /* _UFS_EXYNOS_H_ */
diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c
index ab1a7ebd89b1..7046143063ee 100644
--- a/drivers/scsi/ufs/ufs-hisi.c
+++ b/drivers/scsi/ufs/ufs-hisi.c
@@ -7,6 +7,8 @@
*/
#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/scsi/ufs/ufs-hwmon.c b/drivers/scsi/ufs/ufs-hwmon.c
index 74855491dc8f..c38d9d98a86d 100644
--- a/drivers/scsi/ufs/ufs-hwmon.c
+++ b/drivers/scsi/ufs/ufs-hwmon.c
@@ -8,6 +8,7 @@
#include <linux/units.h>
#include "ufshcd.h"
+#include "ufshcd-priv.h"
struct ufs_hwmon_data {
struct ufs_hba *hba;
diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
index 86a938075f30..083d6bd4d561 100644
--- a/drivers/scsi/ufs/ufs-mediatek.c
+++ b/drivers/scsi/ufs/ufs-mediatek.c
@@ -8,6 +8,9 @@
#include <linux/arm-smccc.h>
#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
@@ -19,7 +22,6 @@
#include <linux/soc/mediatek/mtk_sip_svc.h>
#include "ufshcd.h"
-#include "ufshcd-crypto.h"
#include "ufshcd-pltfrm.h"
#include "ufs_quirks.h"
#include "unipro.h"
@@ -44,12 +46,14 @@
#define ufs_mtk_device_reset_ctrl(high, res) \
ufs_mtk_smc(UFS_MTK_SIP_DEVICE_RESET, high, res)
-static struct ufs_dev_fix ufs_mtk_dev_fixups[] = {
- UFS_FIX(UFS_VENDOR_MICRON, UFS_ANY_MODEL,
- UFS_DEVICE_QUIRK_DELAY_AFTER_LPM),
- UFS_FIX(UFS_VENDOR_SKHYNIX, "H9HQ21AFAMZDAR",
- UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES),
- END_FIX
+static const struct ufs_dev_quirk ufs_mtk_dev_fixups[] = {
+ { .wmanufacturerid = UFS_VENDOR_MICRON,
+ .model = UFS_ANY_MODEL,
+ .quirk = UFS_DEVICE_QUIRK_DELAY_AFTER_LPM },
+ { .wmanufacturerid = UFS_VENDOR_SKHYNIX,
+ .model = "H9HQ21AFAMZDAR",
+ .quirk = UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES },
+ {}
};
static const struct of_device_id ufs_mtk_of_match[] = {
@@ -169,7 +173,6 @@ static int ufs_mtk_hce_enable_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status)
{
struct ufs_mtk_host *host = ufshcd_get_variant(hba);
- unsigned long flags;
if (status == PRE_CHANGE) {
if (host->unipro_lpm) {
@@ -183,12 +186,8 @@ static int ufs_mtk_hce_enable_notify(struct ufs_hba *hba,
ufs_mtk_crypto_enable(hba);
if (host->caps & UFS_MTK_CAP_DISABLE_AH8) {
- spin_lock_irqsave(hba->host->host_lock, flags);
ufshcd_writel(hba, 0,
REG_AUTO_HIBERNATE_IDLE_TIMER);
- spin_unlock_irqrestore(hba->host->host_lock,
- flags);
-
hba->capabilities &= ~MASK_AUTO_HIBERN8_SUPPORT;
hba->ahit = 0;
}
@@ -860,7 +859,6 @@ static int ufs_mtk_pre_link(struct ufs_hba *hba)
static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
{
- unsigned long flags;
u32 ah_ms;
if (ufshcd_is_clkgating_allowed(hba)) {
@@ -869,9 +867,7 @@ static void ufs_mtk_setup_clk_gating(struct ufs_hba *hba)
hba->ahit);
else
ah_ms = 10;
- spin_lock_irqsave(hba->host->host_lock, flags);
- hba->clk_gating.delay_ms = ah_ms + 5;
- spin_unlock_irqrestore(hba->host->host_lock, flags);
+ ufshcd_clkgate_delay_set(hba->dev, ah_ms + 5);
}
}
@@ -992,13 +988,10 @@ static void ufs_mtk_vreg_set_lpm(struct ufs_hba *hba, bool lpm)
static void ufs_mtk_auto_hibern8_disable(struct ufs_hba *hba)
{
- unsigned long flags;
int ret;
/* disable auto-hibern8 */
- spin_lock_irqsave(hba->host->host_lock, flags);
ufshcd_writel(hba, 0, REG_AUTO_HIBERNATE_IDLE_TIMER);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
/* wait host return to idle state when auto-hibern8 off */
ufs_mtk_wait_idle_state(hba, 5);
diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
index bbb0ad7590ec..745e48ec598f 100644
--- a/drivers/scsi/ufs/ufs-qcom-ice.c
+++ b/drivers/scsi/ufs/ufs-qcom-ice.c
@@ -6,10 +6,10 @@
* Copyright 2019 Google LLC
*/
+#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/qcom_scm.h>
-#include "ufshcd-crypto.h"
#include "ufs-qcom.h"
#define AES_256_XTS_KEY_SIZE 64
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 0d2e950d0865..4dcb232facaa 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -5,6 +5,9 @@
#include <linux/acpi.h>
#include <linux/time.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
@@ -18,6 +21,7 @@
#include "ufs-qcom.h"
#include "ufshci.h"
#include "ufs_quirks.h"
+
#define UFS_QCOM_DEFAULT_DBG_PRINT_EN \
(UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
@@ -299,8 +303,7 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
int ret = 0;
- bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B)
- ? true : false;
+ bool is_rate_B = UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B;
/* Reset UFS Host Controller and PHY */
ret = ufs_qcom_host_reset(hba);
@@ -641,12 +644,7 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
return err;
}
- err = ufs_qcom_ice_resume(host);
- if (err)
- return err;
-
- hba->is_sys_suspended = false;
- return 0;
+ return ufs_qcom_ice_resume(host);
}
static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable)
@@ -687,8 +685,11 @@ static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable)
writel_relaxed(temp, host->dev_ref_clk_ctrl_mmio);
- /* ensure that ref_clk is enabled/disabled before we return */
- wmb();
+ /*
+ * Make sure the write to ref_clk reaches the destination and
+ * not stored in a Write Buffer (WB).
+ */
+ readl(host->dev_ref_clk_ctrl_mmio);
/*
* If we call hibern8 exit after this, we need to make sure that
@@ -873,6 +874,7 @@ static void ufs_qcom_set_caps(struct ufs_hba *hba)
hba->caps |= UFSHCD_CAP_WB_EN;
hba->caps |= UFSHCD_CAP_CRYPTO;
hba->caps |= UFSHCD_CAP_AGGR_POWER_COLLAPSE;
+ hba->caps |= UFSHCD_CAP_RPM_AUTOSUSPEND;
if (host->hw_ver.major >= 0x2) {
host->caps = UFS_QCOM_CAP_QUNIPRO |
@@ -957,18 +959,6 @@ static const struct reset_control_ops ufs_qcom_reset_ops = {
.deassert = ufs_qcom_reset_deassert,
};
-#define ANDROID_BOOT_DEV_MAX 30
-static char android_boot_dev[ANDROID_BOOT_DEV_MAX];
-
-#ifndef MODULE
-static int __init get_android_boot_dev(char *str)
-{
- strlcpy(android_boot_dev, str, ANDROID_BOOT_DEV_MAX);
- return 1;
-}
-__setup("androidboot.bootdevice=", get_android_boot_dev);
-#endif
-
/**
* ufs_qcom_init - bind phy with controller
* @hba: host controller instance
@@ -988,9 +978,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)
struct resource *res;
struct ufs_clk_info *clki;
- if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev)))
- return -ENODEV;
-
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
if (!host) {
err = -ENOMEM;
@@ -1002,13 +989,12 @@ static int ufs_qcom_init(struct ufs_hba *hba)
host->hba = hba;
ufshcd_set_variant(hba, host);
- /* Setup the reset control of HCI */
- host->core_reset = devm_reset_control_get(hba->dev, "rst");
+ /* Setup the optional reset control of HCI */
+ host->core_reset = devm_reset_control_get_optional(hba->dev, "rst");
if (IS_ERR(host->core_reset)) {
- err = PTR_ERR(host->core_reset);
- dev_warn(dev, "Failed to get reset control %d\n", err);
- host->core_reset = NULL;
- err = 0;
+ err = dev_err_probe(dev, PTR_ERR(host->core_reset),
+ "Failed to get reset control\n");
+ goto out_variant_clear;
}
/* Fire up the reset controller. Failure here is non-fatal. */
@@ -1022,28 +1008,10 @@ static int ufs_qcom_init(struct ufs_hba *hba)
err = 0;
}
- /*
- * voting/devoting device ref_clk source is time consuming hence
- * skip devoting it during aggressive clock gating. This clock
- * will still be gated off during runtime suspend.
- */
- host->generic_phy = devm_phy_get(dev, "ufsphy");
-
- if (host->generic_phy == ERR_PTR(-EPROBE_DEFER)) {
- /*
- * UFS driver might be probed before the phy driver does.
- * In that case we would like to return EPROBE_DEFER code.
- */
- err = -EPROBE_DEFER;
- dev_warn(dev, "%s: required phy device. hasn't probed yet. err = %d\n",
- __func__, err);
- goto out_variant_clear;
- } else if (IS_ERR(host->generic_phy)) {
- if (has_acpi_companion(dev)) {
- host->generic_phy = NULL;
- } else {
- err = PTR_ERR(host->generic_phy);
- dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
+ if (!has_acpi_companion(dev)) {
+ host->generic_phy = devm_phy_get(dev, "ufsphy");
+ if (IS_ERR(host->generic_phy)) {
+ err = dev_err_probe(dev, PTR_ERR(host->generic_phy), "Failed to get PHY\n");
goto out_variant_clear;
}
}
@@ -1464,23 +1432,17 @@ static int ufs_qcom_device_reset(struct ufs_hba *hba)
#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
static void ufs_qcom_config_scaling_param(struct ufs_hba *hba,
- struct devfreq_dev_profile *p,
- void *data)
+ struct devfreq_dev_profile *p,
+ struct devfreq_simple_ondemand_data *d)
{
- static struct devfreq_simple_ondemand_data *d;
-
- if (!data)
- return;
-
- d = (struct devfreq_simple_ondemand_data *)data;
p->polling_ms = 60;
d->upthreshold = 70;
d->downdifferential = 5;
}
#else
static void ufs_qcom_config_scaling_param(struct ufs_hba *hba,
- struct devfreq_dev_profile *p,
- void *data)
+ struct devfreq_dev_profile *p,
+ struct devfreq_simple_ondemand_data *data)
{
}
#endif
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 8208e3a3ef59..771bc95d02c7 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -7,6 +7,7 @@
#include <linux/reset-controller.h>
#include <linux/reset.h>
+#include "ufshcd.h"
#define MAX_UFS_QCOM_HOSTS 1
#define MAX_U32 (~(u32)0)
@@ -239,10 +240,7 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host);
static inline bool ufs_qcom_cap_qunipro(struct ufs_qcom_host *host)
{
- if (host->caps & UFS_QCOM_CAP_QUNIPRO)
- return true;
- else
- return false;
+ return host->caps & UFS_QCOM_CAP_QUNIPRO;
}
/* ufs-qcom-ice.c */
diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index 5c405ff7b6ea..8a3c6442f291 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -8,6 +8,7 @@
#include "ufs.h"
#include "ufs-sysfs.h"
+#include "ufshcd-priv.h"
static const char *ufshcd_uic_link_state_to_string(
enum uic_link_state state)
diff --git a/drivers/scsi/ufs/ufs-sysfs.h b/drivers/scsi/ufs/ufs-sysfs.h
index 0f4e750a6748..8d94af3b8077 100644
--- a/drivers/scsi/ufs/ufs-sysfs.h
+++ b/drivers/scsi/ufs/ufs-sysfs.h
@@ -7,11 +7,12 @@
#include <linux/sysfs.h>
-#include "ufshcd.h"
+struct device;
void ufs_sysfs_add_nodes(struct device *dev);
void ufs_sysfs_remove_nodes(struct device *dev);
extern const struct attribute_group ufs_sysfs_unit_descriptor_group;
extern const struct attribute_group ufs_sysfs_lun_attributes_group;
+
#endif
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 4a00c24a3209..1bba3fead2ce 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -415,11 +415,6 @@ enum ufs_ref_clk_freq {
REF_CLK_FREQ_INVAL = -1,
};
-struct ufs_ref_clk {
- unsigned long freq_hz;
- enum ufs_ref_clk_freq val;
-};
-
/* Query response result code */
enum {
QUERY_RESULT_SUCCESS = 0x00,
@@ -562,15 +557,6 @@ struct ufs_query_res {
struct utp_upiu_query upiu_res;
};
-#define UFS_VREG_VCC_MIN_UV 2700000 /* uV */
-#define UFS_VREG_VCC_MAX_UV 3600000 /* uV */
-#define UFS_VREG_VCC_1P8_MIN_UV 1700000 /* uV */
-#define UFS_VREG_VCC_1P8_MAX_UV 1950000 /* uV */
-#define UFS_VREG_VCCQ_MIN_UV 1140000 /* uV */
-#define UFS_VREG_VCCQ_MAX_UV 1260000 /* uV */
-#define UFS_VREG_VCCQ2_MIN_UV 1700000 /* uV */
-#define UFS_VREG_VCCQ2_MAX_UV 1950000 /* uV */
-
/*
* VCCQ & VCCQ2 current requirement when UFS device is in sleep state
* and link is in Hibern8 state.
@@ -582,8 +568,6 @@ struct ufs_vreg {
const char *name;
bool always_on;
bool enabled;
- int min_uV;
- int max_uV;
int max_uA;
};
@@ -636,23 +620,4 @@ enum ufs_trace_tsf_t {
UFS_TSF_CDB, UFS_TSF_OSF, UFS_TSF_TM_INPUT, UFS_TSF_TM_OUTPUT
};
-/**
- * ufs_is_valid_unit_desc_lun - checks if the given LUN has a unit descriptor
- * @dev_info: pointer of instance of struct ufs_dev_info
- * @lun: LU number to check
- * @return: true if the lun has a matching unit descriptor, false otherwise
- */
-static inline bool ufs_is_valid_unit_desc_lun(struct ufs_dev_info *dev_info,
- u8 lun, u8 param_offset)
-{
- if (!dev_info || !dev_info->max_lu_supported) {
- pr_err("Max General LU supported by UFS isn't initialized\n");
- return false;
- }
- /* WB is available only for the logical unit from 0 to 7 */
- if (param_offset == UNIT_DESC_PARAM_WB_BUF_ALLOC_UNITS)
- return lun < UFS_UPIU_MAX_WB_LUN_ID;
- return lun == UFS_UPIU_RPMB_WLUN || (lun < dev_info->max_lu_supported);
-}
-
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c
index 39bf204c6ec3..9e9b93867cab 100644
--- a/drivers/scsi/ufs/ufs_bsg.c
+++ b/drivers/scsi/ufs/ufs_bsg.c
@@ -4,7 +4,13 @@
*
* Copyright (C) 2018 Western Digital Corporation
*/
+
+#include <linux/bsg-lib.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
#include "ufs_bsg.h"
+#include "ufshcd.h"
+#include "ufshcd-priv.h"
static int ufs_bsg_get_query_desc_size(struct ufs_hba *hba, int *desc_len,
struct utp_upiu_query *qr)
diff --git a/drivers/scsi/ufs/ufs_bsg.h b/drivers/scsi/ufs/ufs_bsg.h
index d09918758631..57712d2656d2 100644
--- a/drivers/scsi/ufs/ufs_bsg.h
+++ b/drivers/scsi/ufs/ufs_bsg.h
@@ -5,12 +5,7 @@
#ifndef UFS_BSG_H
#define UFS_BSG_H
-#include <linux/bsg-lib.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_host.h>
-
-#include "ufshcd.h"
-#include "ufs.h"
+struct ufs_hba;
#ifdef CONFIG_SCSI_UFS_BSG
void ufs_bsg_remove(struct ufs_hba *hba);
diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h
index 35ec9ea79869..bcb4f004bed5 100644
--- a/drivers/scsi/ufs/ufs_quirks.h
+++ b/drivers/scsi/ufs/ufs_quirks.h
@@ -19,25 +19,16 @@
#define UFS_VENDOR_WDC 0x145
/**
- * ufs_dev_fix - ufs device quirk info
+ * ufs_dev_quirk - ufs device quirk info
* @card: ufs card details
* @quirk: device quirk
*/
-struct ufs_dev_fix {
+struct ufs_dev_quirk {
u16 wmanufacturerid;
- u8 *model;
+ const u8 *model;
unsigned int quirk;
};
-#define END_FIX { }
-
-/* add specific device quirk */
-#define UFS_FIX(_vendor, _model, _quirk) { \
- .wmanufacturerid = (_vendor),\
- .model = (_model), \
- .quirk = (_quirk), \
-}
-
/*
* Some vendor's UFS device sends back to back NACs for the DL data frames
* causing the host controller to raise the DFES error status. Sometimes
diff --git a/drivers/scsi/ufs/ufshcd-crypto.h b/drivers/scsi/ufs/ufshcd-crypto.h
index e18c01276873..9f98f18f9646 100644
--- a/drivers/scsi/ufs/ufshcd-crypto.h
+++ b/drivers/scsi/ufs/ufshcd-crypto.h
@@ -6,10 +6,13 @@
#ifndef _UFSHCD_CRYPTO_H
#define _UFSHCD_CRYPTO_H
-#ifdef CONFIG_SCSI_UFS_CRYPTO
+#include <scsi/scsi_cmnd.h>
#include "ufshcd.h"
+#include "ufshcd-priv.h"
#include "ufshci.h"
+#ifdef CONFIG_SCSI_UFS_CRYPTO
+
static inline void ufshcd_prepare_lrbp_crypto(struct request *rq,
struct ufshcd_lrb *lrbp)
{
diff --git a/drivers/scsi/ufs/ufshcd-dwc.c b/drivers/scsi/ufs/ufshcd-dwc.c
index 5bb9d3a88795..a57973c8d2a1 100644
--- a/drivers/scsi/ufs/ufshcd-dwc.c
+++ b/drivers/scsi/ufs/ufshcd-dwc.c
@@ -7,6 +7,8 @@
* Authors: Joao Pinto <jpinto@synopsys.com>
*/
+#include <linux/module.h>
+
#include "ufshcd.h"
#include "unipro.h"
diff --git a/drivers/scsi/ufs/ufshcd-dwc.h b/drivers/scsi/ufs/ufshcd-dwc.h
index 4268ca2eb64c..43b70794e24f 100644
--- a/drivers/scsi/ufs/ufshcd-dwc.h
+++ b/drivers/scsi/ufs/ufshcd-dwc.h
@@ -10,6 +10,8 @@
#ifndef _UFSHCD_DWC_H
#define _UFSHCD_DWC_H
+#include "ufshcd.h"
+
struct ufshcd_dme_attr_val {
u32 attr_sel;
u32 mib_val;
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c
index f76692053ca1..20af2fbc3af1 100644
--- a/drivers/scsi/ufs/ufshcd-pci.c
+++ b/drivers/scsi/ufs/ufshcd-pci.c
@@ -2,7 +2,6 @@
/*
* Universal Flash Storage Host controller PCI glue driver
*
- * This code is based on drivers/scsi/ufs/ufshcd-pci.c
* Copyright (C) 2011-2013 Samsung India Software Operations
*
* Authors:
@@ -11,6 +10,8 @@
*/
#include "ufshcd.h"
+#include <linux/delay.h>
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
@@ -428,6 +429,12 @@ static int ufs_intel_adl_init(struct ufs_hba *hba)
return ufs_intel_common_init(hba);
}
+static int ufs_intel_mtl_init(struct ufs_hba *hba)
+{
+ hba->caps |= UFSHCD_CAP_CRYPTO | UFSHCD_CAP_WB_EN;
+ return ufs_intel_common_init(hba);
+}
+
static struct ufs_hba_variant_ops ufs_intel_cnl_hba_vops = {
.name = "intel-pci",
.init = ufs_intel_common_init,
@@ -465,6 +472,16 @@ static struct ufs_hba_variant_ops ufs_intel_adl_hba_vops = {
.device_reset = ufs_intel_device_reset,
};
+static struct ufs_hba_variant_ops ufs_intel_mtl_hba_vops = {
+ .name = "intel-pci",
+ .init = ufs_intel_mtl_init,
+ .exit = ufs_intel_common_exit,
+ .hce_enable_notify = ufs_intel_hce_enable_notify,
+ .link_startup_notify = ufs_intel_link_startup_notify,
+ .resume = ufs_intel_resume,
+ .device_reset = ufs_intel_device_reset,
+};
+
#ifdef CONFIG_PM_SLEEP
static int ufshcd_pci_restore(struct device *dev)
{
@@ -579,6 +596,7 @@ static const struct pci_device_id ufshcd_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x98FA), (kernel_ulong_t)&ufs_intel_lkf_hba_vops },
{ PCI_VDEVICE(INTEL, 0x51FF), (kernel_ulong_t)&ufs_intel_adl_hba_vops },
{ PCI_VDEVICE(INTEL, 0x54FF), (kernel_ulong_t)&ufs_intel_adl_hba_vops },
+ { PCI_VDEVICE(INTEL, 0x7E47), (kernel_ulong_t)&ufs_intel_mtl_hba_vops },
{ } /* terminate list */
};
@@ -601,4 +619,3 @@ MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
MODULE_DESCRIPTION("UFS host controller PCI glue driver");
MODULE_LICENSE("GPL");
-MODULE_VERSION(UFSHCD_DRIVER_VERSION);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 87975d1a21c8..f5313f407617 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -8,6 +8,7 @@
* Vinayak Holikatti <h.vinayak@samsung.com>
*/
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
@@ -297,18 +298,20 @@ EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param);
void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param)
{
- dev_param->tx_lanes = 2;
- dev_param->rx_lanes = 2;
- dev_param->hs_rx_gear = UFS_HS_G3;
- dev_param->hs_tx_gear = UFS_HS_G3;
- dev_param->pwm_rx_gear = UFS_PWM_G4;
- dev_param->pwm_tx_gear = UFS_PWM_G4;
- dev_param->rx_pwr_pwm = SLOW_MODE;
- dev_param->tx_pwr_pwm = SLOW_MODE;
- dev_param->rx_pwr_hs = FAST_MODE;
- dev_param->tx_pwr_hs = FAST_MODE;
- dev_param->hs_rate = PA_HS_MODE_B;
- dev_param->desired_working_mode = UFS_HS_MODE;
+ *dev_param = (struct ufs_dev_params){
+ .tx_lanes = 2,
+ .rx_lanes = 2,
+ .hs_rx_gear = UFS_HS_G3,
+ .hs_tx_gear = UFS_HS_G3,
+ .pwm_rx_gear = UFS_PWM_G4,
+ .pwm_tx_gear = UFS_PWM_G4,
+ .rx_pwr_pwm = SLOW_MODE,
+ .tx_pwr_pwm = SLOW_MODE,
+ .rx_pwr_hs = FAST_MODE,
+ .tx_pwr_hs = FAST_MODE,
+ .hs_rate = PA_HS_MODE_B,
+ .desired_working_mode = UFS_HS_MODE,
+ };
}
EXPORT_SYMBOL_GPL(ufshcd_init_pwr_dev_param);
@@ -341,7 +344,7 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
err = ufshcd_alloc_host(dev, &hba);
if (err) {
- dev_err(&pdev->dev, "Allocation failed\n");
+ dev_err(dev, "Allocation failed\n");
goto out;
}
@@ -349,13 +352,13 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
err = ufshcd_parse_clock_info(hba);
if (err) {
- dev_err(&pdev->dev, "%s: clock parse failed %d\n",
+ dev_err(dev, "%s: clock parse failed %d\n",
__func__, err);
goto dealloc_host;
}
err = ufshcd_parse_regulator_info(hba);
if (err) {
- dev_err(&pdev->dev, "%s: regulator init failed %d\n",
+ dev_err(dev, "%s: regulator init failed %d\n",
__func__, err);
goto dealloc_host;
}
@@ -368,8 +371,8 @@ int ufshcd_pltfrm_init(struct platform_device *pdev,
goto dealloc_host;
}
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
return 0;
@@ -384,4 +387,3 @@ MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
MODULE_DESCRIPTION("UFS host controller Platform bus based glue driver");
MODULE_LICENSE("GPL");
-MODULE_VERSION(UFSHCD_DRIVER_VERSION);
diff --git a/drivers/scsi/ufs/ufshcd-priv.h b/drivers/scsi/ufs/ufshcd-priv.h
new file mode 100644
index 000000000000..38bc77d3dbbd
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd-priv.h
@@ -0,0 +1,298 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _UFSHCD_PRIV_H_
+#define _UFSHCD_PRIV_H_
+
+#include <linux/pm_runtime.h>
+#include "ufshcd.h"
+
+static inline bool ufshcd_is_user_access_allowed(struct ufs_hba *hba)
+{
+ return !hba->shutting_down;
+}
+
+void ufshcd_schedule_eh_work(struct ufs_hba *hba);
+
+static inline bool ufshcd_keep_autobkops_enabled_except_suspend(
+ struct ufs_hba *hba)
+{
+ return hba->caps & UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND;
+}
+
+static inline u8 ufshcd_wb_get_query_index(struct ufs_hba *hba)
+{
+ if (hba->dev_info.wb_buffer_type == WB_BUF_MODE_LU_DEDICATED)
+ return hba->dev_info.wb_dedicated_lu;
+ return 0;
+}
+
+#ifdef CONFIG_SCSI_UFS_HWMON
+void ufs_hwmon_probe(struct ufs_hba *hba, u8 mask);
+void ufs_hwmon_remove(struct ufs_hba *hba);
+void ufs_hwmon_notify_event(struct ufs_hba *hba, u8 ee_mask);
+#else
+static inline void ufs_hwmon_probe(struct ufs_hba *hba, u8 mask) {}
+static inline void ufs_hwmon_remove(struct ufs_hba *hba) {}
+static inline void ufs_hwmon_notify_event(struct ufs_hba *hba, u8 ee_mask) {}
+#endif
+
+int ufshcd_read_desc_param(struct ufs_hba *hba,
+ enum desc_idn desc_id,
+ int desc_index,
+ u8 param_offset,
+ u8 *param_read_buf,
+ u8 param_size);
+int ufshcd_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode,
+ enum attr_idn idn, u8 index, u8 selector,
+ u32 *attr_val);
+int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode,
+ enum attr_idn idn, u8 index, u8 selector, u32 *attr_val);
+int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
+ enum flag_idn idn, u8 index, bool *flag_res);
+void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
+
+#define SD_ASCII_STD true
+#define SD_RAW false
+int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index,
+ u8 **buf, bool ascii);
+
+int ufshcd_hold(struct ufs_hba *hba, bool async);
+void ufshcd_release(struct ufs_hba *hba);
+
+void ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
+ int *desc_length);
+
+int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd);
+
+int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
+ struct utp_upiu_req *req_upiu,
+ struct utp_upiu_req *rsp_upiu,
+ int msgcode,
+ u8 *desc_buff, int *buff_len,
+ enum query_opcode desc_op);
+
+int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable);
+
+/* Wrapper functions for safely calling variant operations */
+static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
+{
+ if (hba->vops)
+ return hba->vops->name;
+ return "";
+}
+
+static inline void ufshcd_vops_exit(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->exit)
+ return hba->vops->exit(hba);
+}
+
+static inline u32 ufshcd_vops_get_ufs_hci_version(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->get_ufs_hci_version)
+ return hba->vops->get_ufs_hci_version(hba);
+
+ return ufshcd_readl(hba, REG_UFS_VERSION);
+}
+
+static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba,
+ bool up, enum ufs_notify_change_status status)
+{
+ if (hba->vops && hba->vops->clk_scale_notify)
+ return hba->vops->clk_scale_notify(hba, up, status);
+ return 0;
+}
+
+static inline void ufshcd_vops_event_notify(struct ufs_hba *hba,
+ enum ufs_event_type evt,
+ void *data)
+{
+ if (hba->vops && hba->vops->event_notify)
+ hba->vops->event_notify(hba, evt, data);
+}
+
+static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on,
+ enum ufs_notify_change_status status)
+{
+ if (hba->vops && hba->vops->setup_clocks)
+ return hba->vops->setup_clocks(hba, on, status);
+ return 0;
+}
+
+static inline int ufshcd_vops_hce_enable_notify(struct ufs_hba *hba,
+ bool status)
+{
+ if (hba->vops && hba->vops->hce_enable_notify)
+ return hba->vops->hce_enable_notify(hba, status);
+
+ return 0;
+}
+static inline int ufshcd_vops_link_startup_notify(struct ufs_hba *hba,
+ bool status)
+{
+ if (hba->vops && hba->vops->link_startup_notify)
+ return hba->vops->link_startup_notify(hba, status);
+
+ return 0;
+}
+
+static inline int ufshcd_vops_pwr_change_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status status,
+ struct ufs_pa_layer_attr *dev_max_params,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ if (hba->vops && hba->vops->pwr_change_notify)
+ return hba->vops->pwr_change_notify(hba, status,
+ dev_max_params, dev_req_params);
+
+ return -ENOTSUPP;
+}
+
+static inline void ufshcd_vops_setup_task_mgmt(struct ufs_hba *hba,
+ int tag, u8 tm_function)
+{
+ if (hba->vops && hba->vops->setup_task_mgmt)
+ return hba->vops->setup_task_mgmt(hba, tag, tm_function);
+}
+
+static inline void ufshcd_vops_hibern8_notify(struct ufs_hba *hba,
+ enum uic_cmd_dme cmd,
+ enum ufs_notify_change_status status)
+{
+ if (hba->vops && hba->vops->hibern8_notify)
+ return hba->vops->hibern8_notify(hba, cmd, status);
+}
+
+static inline int ufshcd_vops_apply_dev_quirks(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->apply_dev_quirks)
+ return hba->vops->apply_dev_quirks(hba);
+ return 0;
+}
+
+static inline void ufshcd_vops_fixup_dev_quirks(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->fixup_dev_quirks)
+ hba->vops->fixup_dev_quirks(hba);
+}
+
+static inline int ufshcd_vops_suspend(struct ufs_hba *hba, enum ufs_pm_op op,
+ enum ufs_notify_change_status status)
+{
+ if (hba->vops && hba->vops->suspend)
+ return hba->vops->suspend(hba, op, status);
+
+ return 0;
+}
+
+static inline int ufshcd_vops_resume(struct ufs_hba *hba, enum ufs_pm_op op)
+{
+ if (hba->vops && hba->vops->resume)
+ return hba->vops->resume(hba, op);
+
+ return 0;
+}
+
+static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->dbg_register_dump)
+ hba->vops->dbg_register_dump(hba);
+}
+
+static inline int ufshcd_vops_device_reset(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->device_reset)
+ return hba->vops->device_reset(hba);
+
+ return -EOPNOTSUPP;
+}
+
+static inline void ufshcd_vops_config_scaling_param(struct ufs_hba *hba,
+ struct devfreq_dev_profile *p,
+ struct devfreq_simple_ondemand_data *data)
+{
+ if (hba->vops && hba->vops->config_scaling_param)
+ hba->vops->config_scaling_param(hba, p, data);
+}
+
+extern struct ufs_pm_lvl_states ufs_pm_lvl_states[];
+
+/**
+ * ufshcd_scsi_to_upiu_lun - maps scsi LUN to UPIU LUN
+ * @scsi_lun: scsi LUN id
+ *
+ * Returns UPIU LUN id
+ */
+static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun)
+{
+ if (scsi_is_wlun(scsi_lun))
+ return (scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID)
+ | UFS_UPIU_WLUN_ID;
+ else
+ return scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID;
+}
+
+int __ufshcd_write_ee_control(struct ufs_hba *hba, u32 ee_ctrl_mask);
+int ufshcd_write_ee_control(struct ufs_hba *hba);
+int ufshcd_update_ee_control(struct ufs_hba *hba, u16 *mask, u16 *other_mask,
+ u16 set, u16 clr);
+
+static inline int ufshcd_update_ee_drv_mask(struct ufs_hba *hba,
+ u16 set, u16 clr)
+{
+ return ufshcd_update_ee_control(hba, &hba->ee_drv_mask,
+ &hba->ee_usr_mask, set, clr);
+}
+
+static inline int ufshcd_update_ee_usr_mask(struct ufs_hba *hba,
+ u16 set, u16 clr)
+{
+ return ufshcd_update_ee_control(hba, &hba->ee_usr_mask,
+ &hba->ee_drv_mask, set, clr);
+}
+
+static inline int ufshcd_rpm_get_sync(struct ufs_hba *hba)
+{
+ return pm_runtime_get_sync(&hba->ufs_device_wlun->sdev_gendev);
+}
+
+static inline int ufshcd_rpm_put_sync(struct ufs_hba *hba)
+{
+ return pm_runtime_put_sync(&hba->ufs_device_wlun->sdev_gendev);
+}
+
+static inline void ufshcd_rpm_get_noresume(struct ufs_hba *hba)
+{
+ pm_runtime_get_noresume(&hba->ufs_device_wlun->sdev_gendev);
+}
+
+static inline int ufshcd_rpm_resume(struct ufs_hba *hba)
+{
+ return pm_runtime_resume(&hba->ufs_device_wlun->sdev_gendev);
+}
+
+static inline int ufshcd_rpm_put(struct ufs_hba *hba)
+{
+ return pm_runtime_put(&hba->ufs_device_wlun->sdev_gendev);
+}
+
+/**
+ * ufs_is_valid_unit_desc_lun - checks if the given LUN has a unit descriptor
+ * @dev_info: pointer of instance of struct ufs_dev_info
+ * @lun: LU number to check
+ * @return: true if the lun has a matching unit descriptor, false otherwise
+ */
+static inline bool ufs_is_valid_unit_desc_lun(struct ufs_dev_info *dev_info,
+ u8 lun, u8 param_offset)
+{
+ if (!dev_info || !dev_info->max_lu_supported) {
+ pr_err("Max General LU supported by UFS isn't initialized\n");
+ return false;
+ }
+ /* WB is available only for the logical unit from 0 to 7 */
+ if (param_offset == UNIT_DESC_PARAM_WB_BUF_ALLOC_UNITS)
+ return lun < UFS_UPIU_MAX_WB_LUN_ID;
+ return lun == UFS_UPIU_RPMB_WLUN || (lun < dev_info->max_lu_supported);
+}
+
+#endif /* _UFSHCD_PRIV_H_ */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 3f9caafa91bf..1fb3a8b9b03e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -16,8 +16,16 @@
#include <linux/bitfield.h>
#include <linux/blk-pm.h>
#include <linux/blkdev.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
#include <scsi/scsi_driver.h>
-#include "ufshcd.h"
+#include <scsi/scsi_eh.h>
+#include "ufshcd-priv.h"
#include "ufs_quirks.h"
#include "unipro.h"
#include "ufs-sysfs.h"
@@ -113,8 +121,13 @@ int ufshcd_dump_regs(struct ufs_hba *hba, size_t offset, size_t len,
if (!regs)
return -ENOMEM;
- for (pos = 0; pos < len; pos += 4)
+ for (pos = 0; pos < len; pos += 4) {
+ if (offset == 0 &&
+ pos >= REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER &&
+ pos <= REG_UIC_ERROR_CODE_DME)
+ continue;
regs[pos / 4] = ufshcd_readl(hba, offset + pos);
+ }
ufshcd_hex_dump(prefix, regs, len);
kfree(regs);
@@ -204,26 +217,33 @@ ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state,
return UFS_PM_LVL_0;
}
-static struct ufs_dev_fix ufs_fixups[] = {
+static const struct ufs_dev_quirk ufs_fixups[] = {
/* UFS cards deviations table */
- UFS_FIX(UFS_VENDOR_MICRON, UFS_ANY_MODEL,
- UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM |
- UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ),
- UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
- UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM |
- UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE |
- UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS),
- UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL,
- UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME),
- UFS_FIX(UFS_VENDOR_SKHYNIX, "hB8aL1" /*H28U62301AMR*/,
- UFS_DEVICE_QUIRK_HOST_VS_DEBUGSAVECONFIGTIME),
- UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL,
- UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM),
- UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG",
- UFS_DEVICE_QUIRK_PA_TACTIVATE),
- UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG",
- UFS_DEVICE_QUIRK_PA_TACTIVATE),
- END_FIX
+ { .wmanufacturerid = UFS_VENDOR_MICRON,
+ .model = UFS_ANY_MODEL,
+ .quirk = UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM |
+ UFS_DEVICE_QUIRK_SWAP_L2P_ENTRY_FOR_HPB_READ },
+ { .wmanufacturerid = UFS_VENDOR_SAMSUNG,
+ .model = UFS_ANY_MODEL,
+ .quirk = UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM |
+ UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE |
+ UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS },
+ { .wmanufacturerid = UFS_VENDOR_SKHYNIX,
+ .model = UFS_ANY_MODEL,
+ .quirk = UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME },
+ { .wmanufacturerid = UFS_VENDOR_SKHYNIX,
+ .model = "hB8aL1" /*H28U62301AMR*/,
+ .quirk = UFS_DEVICE_QUIRK_HOST_VS_DEBUGSAVECONFIGTIME },
+ { .wmanufacturerid = UFS_VENDOR_TOSHIBA,
+ .model = UFS_ANY_MODEL,
+ .quirk = UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM },
+ { .wmanufacturerid = UFS_VENDOR_TOSHIBA,
+ .model = "THGLF2G9C8KBADG",
+ .quirk = UFS_DEVICE_QUIRK_PA_TACTIVATE },
+ { .wmanufacturerid = UFS_VENDOR_TOSHIBA,
+ .model = "THGLF2G9D8KBADG",
+ .quirk = UFS_DEVICE_QUIRK_PA_TACTIVATE },
+ {}
};
static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba);
@@ -533,7 +553,7 @@ static void ufshcd_print_tmrs(struct ufs_hba *hba, unsigned long bitmap)
static void ufshcd_print_host_state(struct ufs_hba *hba)
{
- struct scsi_device *sdev_ufs = hba->sdev_ufs_device;
+ struct scsi_device *sdev_ufs = hba->ufs_device_wlun;
dev_err(hba->dev, "UFS Host state=%d\n", hba->ufshcd_state);
dev_err(hba->dev, "outstanding reqs=0x%lx tasks=0x%lx\n",
@@ -639,7 +659,7 @@ EXPORT_SYMBOL_GPL(ufshcd_delay_us);
* Return:
* -ETIMEDOUT on error, zero on success.
*/
-int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
+static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
u32 val, unsigned long interval_us,
unsigned long timeout_ms)
{
@@ -712,8 +732,7 @@ static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
*/
static inline bool ufshcd_is_device_present(struct ufs_hba *hba)
{
- return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) &
- DEVICE_PRESENT) ? true : false;
+ return ufshcd_readl(hba, REG_CONTROLLER_STATUS) & DEVICE_PRESENT;
}
/**
@@ -840,7 +859,7 @@ ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp *ucd_rsp_ptr)
static inline bool ufshcd_is_exception_event(struct utp_upiu_rsp *ucd_rsp_ptr)
{
return be32_to_cpu(ucd_rsp_ptr->header.dword_2) &
- MASK_RSP_EXCEPTION_EVENT ? true : false;
+ MASK_RSP_EXCEPTION_EVENT;
}
/**
@@ -911,12 +930,11 @@ static inline void ufshcd_hba_start(struct ufs_hba *hba)
* ufshcd_is_hba_active - Get controller state
* @hba: per adapter instance
*
- * Returns false if controller is active, true otherwise
+ * Returns true if and only if the controller is active.
*/
static inline bool ufshcd_is_hba_active(struct ufs_hba *hba)
{
- return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & CONTROLLER_ENABLE)
- ? false : true;
+ return ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & CONTROLLER_ENABLE;
}
u32 ufshcd_get_local_unipro_ver(struct ufs_hba *hba)
@@ -940,10 +958,7 @@ static bool ufshcd_is_unipro_pa_params_tuning_req(struct ufs_hba *hba)
* logic simple, we will only do manual tuning if local unipro version
* doesn't support ver1.6 or later.
*/
- if (ufshcd_get_local_unipro_ver(hba) < UFS_UNIPRO_VER_1_6)
- return true;
- else
- return false;
+ return ufshcd_get_local_unipro_ver(hba) < UFS_UNIPRO_VER_1_6;
}
/**
@@ -1350,7 +1365,7 @@ static int ufshcd_devfreq_target(struct device *dev,
}
/* Decide based on the rounded-off frequency and update */
- scale_up = (*freq == clki->max_freq) ? true : false;
+ scale_up = *freq == clki->max_freq;
if (!scale_up)
*freq = clki->min_freq;
/* Update the frequency */
@@ -1862,18 +1877,26 @@ static ssize_t ufshcd_clkgate_delay_show(struct device *dev,
return sysfs_emit(buf, "%lu\n", hba->clk_gating.delay_ms);
}
+void ufshcd_clkgate_delay_set(struct device *dev, unsigned long value)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->clk_gating.delay_ms = value;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ufshcd_clkgate_delay_set);
+
static ssize_t ufshcd_clkgate_delay_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct ufs_hba *hba = dev_get_drvdata(dev);
- unsigned long flags, value;
+ unsigned long value;
if (kstrtoul(buf, 0, &value))
return -EINVAL;
- spin_lock_irqsave(hba->host->host_lock, flags);
- hba->clk_gating.delay_ms = value;
- spin_unlock_irqrestore(hba->host->host_lock, flags);
+ ufshcd_clkgate_delay_set(dev, value);
return count;
}
@@ -2120,9 +2143,6 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
__set_bit(task_tag, &hba->outstanding_reqs);
ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL);
spin_unlock_irqrestore(&hba->outstanding_lock, flags);
-
- /* Make sure that doorbell is committed immediately */
- wmb();
}
/**
@@ -2131,15 +2151,17 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
*/
static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
{
+ u8 *const sense_buffer = lrbp->cmd->sense_buffer;
int len;
- if (lrbp->sense_buffer &&
+
+ if (sense_buffer &&
ufshcd_get_rsp_upiu_data_seg_len(lrbp->ucd_rsp_ptr)) {
int len_to_copy;
len = be16_to_cpu(lrbp->ucd_rsp_ptr->sr.sense_data_len);
len_to_copy = min_t(int, UFS_SENSE_SIZE, len);
- memcpy(lrbp->sense_buffer, lrbp->ucd_rsp_ptr->sr.sense_data,
+ memcpy(sense_buffer, lrbp->ucd_rsp_ptr->sr.sense_data,
len_to_copy);
}
}
@@ -2217,10 +2239,7 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba)
*/
static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
{
- if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY)
- return true;
- else
- return false;
+ return ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY;
}
/**
@@ -2796,11 +2815,9 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
lrbp = &hba->lrb[tag];
WARN_ON(lrbp->cmd);
lrbp->cmd = cmd;
- lrbp->sense_bufflen = UFS_SENSE_SIZE;
- lrbp->sense_buffer = cmd->sense_buffer;
lrbp->task_tag = tag;
lrbp->lun = ufshcd_scsi_to_upiu_lun(cmd->device->lun);
- lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba) ? true : false;
+ lrbp->intr_cmd = !ufshcd_is_intr_aggr_allowed(hba);
ufshcd_prepare_lrbp_crypto(scsi_cmd_to_rq(cmd), lrbp);
@@ -2837,8 +2854,6 @@ static int ufshcd_compose_dev_cmd(struct ufs_hba *hba,
struct ufshcd_lrb *lrbp, enum dev_cmd_type cmd_type, int tag)
{
lrbp->cmd = NULL;
- lrbp->sense_bufflen = 0;
- lrbp->sense_buffer = NULL;
lrbp->task_tag = tag;
lrbp->lun = 0; /* device management cmd is not specific to any LUN */
lrbp->intr_cmd = true; /* No interrupt aggregation */
@@ -4198,7 +4213,7 @@ void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit)
spin_unlock_irqrestore(hba->host->host_lock, flags);
if (update &&
- !pm_runtime_suspended(&hba->sdev_ufs_device->sdev_gendev)) {
+ !pm_runtime_suspended(&hba->ufs_device_wlun->sdev_gendev)) {
ufshcd_rpm_get_sync(hba);
ufshcd_hold(hba, false);
ufshcd_auto_hibern8_enable(hba);
@@ -4210,14 +4225,10 @@ EXPORT_SYMBOL_GPL(ufshcd_auto_hibern8_update);
void ufshcd_auto_hibern8_enable(struct ufs_hba *hba)
{
- unsigned long flags;
-
if (!ufshcd_is_auto_hibern8_supported(hba))
return;
- spin_lock_irqsave(hba->host->host_lock, flags);
ufshcd_writel(hba, hba->ahit, REG_AUTO_HIBERNATE_IDLE_TIMER);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
}
/**
@@ -4328,18 +4339,18 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba,
pwr_mode->lane_rx);
if (pwr_mode->pwr_rx == FASTAUTO_MODE ||
pwr_mode->pwr_rx == FAST_MODE)
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), TRUE);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), true);
else
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), FALSE);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), false);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), pwr_mode->gear_tx);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES),
pwr_mode->lane_tx);
if (pwr_mode->pwr_tx == FASTAUTO_MODE ||
pwr_mode->pwr_tx == FAST_MODE)
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), TRUE);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), true);
else
- ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), FALSE);
+ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), false);
if (pwr_mode->pwr_rx == FASTAUTO_MODE ||
pwr_mode->pwr_tx == FASTAUTO_MODE ||
@@ -4438,7 +4449,7 @@ static int ufshcd_complete_dev_init(struct ufs_hba *hba)
QUERY_FLAG_IDN_FDEVICEINIT, 0, &flag_res);
if (!flag_res)
break;
- usleep_range(5000, 10000);
+ usleep_range(500, 1000);
} while (ktime_before(ktime_get(), timeout));
if (err) {
@@ -4554,7 +4565,7 @@ static int ufshcd_hba_execute_hce(struct ufs_hba *hba)
int retry_inner;
start:
- if (!ufshcd_is_hba_active(hba))
+ if (ufshcd_is_hba_active(hba))
/* change controller state to "reset state" */
ufshcd_hba_stop(hba);
@@ -4580,7 +4591,7 @@ start:
/* wait for the host controller to complete initialization */
retry_inner = 50;
- while (ufshcd_is_hba_active(hba)) {
+ while (!ufshcd_is_hba_active(hba)) {
if (retry_inner) {
retry_inner--;
} else {
@@ -4914,13 +4925,13 @@ static void ufshcd_setup_links(struct ufs_hba *hba, struct scsi_device *sdev)
* Device wlun is the supplier & rest of the luns are consumers.
* This ensures that device wlun suspends after all other luns.
*/
- if (hba->sdev_ufs_device) {
+ if (hba->ufs_device_wlun) {
link = device_link_add(&sdev->sdev_gendev,
- &hba->sdev_ufs_device->sdev_gendev,
+ &hba->ufs_device_wlun->sdev_gendev,
DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE);
if (!link) {
dev_err(&sdev->sdev_gendev, "Failed establishing link - %s\n",
- dev_name(&hba->sdev_ufs_device->sdev_gendev));
+ dev_name(&hba->ufs_device_wlun->sdev_gendev));
return;
}
hba->luns_avail--;
@@ -5056,15 +5067,15 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev)
/* Drop the reference as it won't be needed anymore */
if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN) {
spin_lock_irqsave(hba->host->host_lock, flags);
- hba->sdev_ufs_device = NULL;
+ hba->ufs_device_wlun = NULL;
spin_unlock_irqrestore(hba->host->host_lock, flags);
- } else if (hba->sdev_ufs_device) {
+ } else if (hba->ufs_device_wlun) {
struct device *supplier = NULL;
/* Ensure UFS Device WLUN exists and does not disappear */
spin_lock_irqsave(hba->host->host_lock, flags);
- if (hba->sdev_ufs_device) {
- supplier = &hba->sdev_ufs_device->sdev_gendev;
+ if (hba->ufs_device_wlun) {
+ supplier = &hba->ufs_device_wlun->sdev_gendev;
get_device(supplier);
}
spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -5782,10 +5793,7 @@ static bool ufshcd_wb_presrv_usrspc_keep_vcc_on(struct ufs_hba *hba,
return false;
}
/* Let it continue to flush when available buffer exceeds threshold */
- if (avail_buf < hba->vps->wb_flush_threshold)
- return true;
-
- return false;
+ return avail_buf < hba->vps->wb_flush_threshold;
}
static void ufshcd_wb_force_disable(struct ufs_hba *hba)
@@ -5864,11 +5872,8 @@ static bool ufshcd_wb_need_flush(struct ufs_hba *hba)
return false;
}
- if (!hba->dev_info.b_presrv_uspc_en) {
- if (avail_buf <= UFS_WB_BUF_REMAIN_PERCENT(10))
- return true;
- return false;
- }
+ if (!hba->dev_info.b_presrv_uspc_en)
+ return avail_buf <= UFS_WB_BUF_REMAIN_PERCENT(10);
return ufshcd_wb_presrv_usrspc_keep_vcc_on(hba, avail_buf);
}
@@ -6046,7 +6051,7 @@ static void ufshcd_clk_scaling_suspend(struct ufs_hba *hba, bool suspend)
static void ufshcd_err_handling_prepare(struct ufs_hba *hba)
{
ufshcd_rpm_get_sync(hba);
- if (pm_runtime_status_suspended(&hba->sdev_ufs_device->sdev_gendev) ||
+ if (pm_runtime_status_suspended(&hba->ufs_device_wlun->sdev_gendev) ||
hba->is_sys_suspended) {
enum ufs_pm_op pm_op;
@@ -6091,7 +6096,7 @@ static void ufshcd_err_handling_unprepare(struct ufs_hba *hba)
static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba)
{
return (!hba->is_powered || hba->shutting_down ||
- !hba->sdev_ufs_device ||
+ !hba->ufs_device_wlun ||
hba->ufshcd_state == UFSHCD_STATE_ERROR ||
(!(hba->saved_err || hba->saved_uic_err || hba->force_reset ||
ufshcd_is_link_broken(hba))));
@@ -6110,7 +6115,7 @@ static void ufshcd_recover_pm_error(struct ufs_hba *hba)
* Set RPM status of wlun device to RPM_ACTIVE,
* this also clears its runtime error.
*/
- ret = pm_runtime_set_active(&hba->sdev_ufs_device->sdev_gendev);
+ ret = pm_runtime_set_active(&hba->ufs_device_wlun->sdev_gendev);
/* hba device might have a runtime error otherwise */
if (ret)
@@ -6815,8 +6820,6 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba,
lrbp = &hba->lrb[tag];
WARN_ON(lrbp->cmd);
lrbp->cmd = NULL;
- lrbp->sense_bufflen = 0;
- lrbp->sense_buffer = NULL;
lrbp->task_tag = tag;
lrbp->lun = 0;
lrbp->intr_cmd = true;
@@ -7223,7 +7226,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
* Stop the host controller and complete the requests
* cleared by h/w
*/
- ufshpb_reset_host(hba);
+ ufshpb_toggle_state(hba, HPB_PRESENT, HPB_RESET);
ufshcd_hba_stop(hba);
hba->silence_err_logs = true;
ufshcd_complete_requests(hba);
@@ -7351,7 +7354,7 @@ static u32 ufshcd_get_max_icc_level(int sup_curr_uA, u32 start_scan, char *buff)
u16 unit;
for (i = start_scan; i >= 0; i--) {
- data = be16_to_cpup((__be16 *)&buff[2 * i]);
+ data = get_unaligned_be16(&buff[2 * i]);
unit = (data & ATTR_ICC_LVL_UNIT_MASK) >>
ATTR_ICC_LVL_UNIT_OFFSET;
curr_uA = data & ATTR_ICC_LVL_VALUE_MASK;
@@ -7506,20 +7509,20 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
int ret = 0;
struct scsi_device *sdev_boot, *sdev_rpmb;
- hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0,
+ hba->ufs_device_wlun = __scsi_add_device(hba->host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN), NULL);
- if (IS_ERR(hba->sdev_ufs_device)) {
- ret = PTR_ERR(hba->sdev_ufs_device);
- hba->sdev_ufs_device = NULL;
+ if (IS_ERR(hba->ufs_device_wlun)) {
+ ret = PTR_ERR(hba->ufs_device_wlun);
+ hba->ufs_device_wlun = NULL;
goto out;
}
- scsi_device_put(hba->sdev_ufs_device);
+ scsi_device_put(hba->ufs_device_wlun);
sdev_rpmb = __scsi_add_device(hba->host, 0, 0,
ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL);
if (IS_ERR(sdev_rpmb)) {
ret = PTR_ERR(sdev_rpmb);
- goto remove_sdev_ufs_device;
+ goto remove_ufs_device_wlun;
}
ufshcd_blk_pm_runtime_init(sdev_rpmb);
scsi_device_put(sdev_rpmb);
@@ -7534,8 +7537,8 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba)
}
goto out;
-remove_sdev_ufs_device:
- scsi_remove_device(hba->sdev_ufs_device);
+remove_ufs_device_wlun:
+ scsi_remove_device(hba->ufs_device_wlun);
out:
return ret;
}
@@ -7634,9 +7637,10 @@ static void ufshcd_temp_notif_probe(struct ufs_hba *hba, u8 *desc_buf)
}
}
-void ufshcd_fixup_dev_quirks(struct ufs_hba *hba, struct ufs_dev_fix *fixups)
+void ufshcd_fixup_dev_quirks(struct ufs_hba *hba,
+ const struct ufs_dev_quirk *fixups)
{
- struct ufs_dev_fix *f;
+ const struct ufs_dev_quirk *f;
struct ufs_dev_info *dev_info = &hba->dev_info;
if (!fixups)
@@ -7956,6 +7960,11 @@ out:
return err;
}
+struct ufs_ref_clk {
+ unsigned long freq_hz;
+ enum ufs_ref_clk_freq val;
+};
+
static struct ufs_ref_clk ufs_ref_clk_freqs[] = {
{19200000, REF_CLK_FREQ_19_2_MHZ},
{26000000, REF_CLK_FREQ_26_MHZ},
@@ -8184,7 +8193,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
/* Enable Auto-Hibernate if configured */
ufshcd_auto_hibern8_enable(hba);
- ufshpb_reset(hba);
+ ufshpb_toggle_state(hba, HPB_RESET, HPB_PRESENT);
out:
spin_lock_irqsave(hba->host->host_lock, flags);
if (ret)
@@ -8319,33 +8328,10 @@ static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
static int ufshcd_config_vreg(struct device *dev,
struct ufs_vreg *vreg, bool on)
{
- int ret = 0;
- struct regulator *reg;
- const char *name;
- int min_uV, uA_load;
-
- BUG_ON(!vreg);
-
- reg = vreg->reg;
- name = vreg->name;
-
- if (regulator_count_voltages(reg) > 0) {
- uA_load = on ? vreg->max_uA : 0;
- ret = ufshcd_config_vreg_load(dev, vreg, uA_load);
- if (ret)
- goto out;
+ if (regulator_count_voltages(vreg->reg) <= 0)
+ return 0;
- if (vreg->min_uV && vreg->max_uV) {
- min_uV = on ? vreg->min_uV : 0;
- ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
- if (ret)
- dev_err(dev,
- "%s: %s set voltage failed, err=%d\n",
- __func__, name, ret);
- }
- }
-out:
- return ret;
+ return ufshcd_config_vreg_load(dev, vreg, on ? vreg->max_uA : 0);
}
static int ufshcd_enable_vreg(struct device *dev, struct ufs_vreg *vreg)
@@ -8693,7 +8679,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
int ret, retries;
spin_lock_irqsave(hba->host->host_lock, flags);
- sdp = hba->sdev_ufs_device;
+ sdp = hba->ufs_device_wlun;
if (sdp) {
ret = scsi_device_get(sdp);
if (!ret && !scsi_device_online(sdp)) {
@@ -9257,7 +9243,7 @@ static void ufshcd_wl_shutdown(struct device *dev)
ufshcd_rpm_get_sync(hba);
scsi_device_quiesce(sdev);
shost_for_each_device(sdev, hba->host) {
- if (sdev == hba->sdev_ufs_device)
+ if (sdev == hba->ufs_device_wlun)
continue;
scsi_device_quiesce(sdev);
}
@@ -9478,7 +9464,7 @@ EXPORT_SYMBOL(ufshcd_shutdown);
*/
void ufshcd_remove(struct ufs_hba *hba)
{
- if (hba->sdev_ufs_device)
+ if (hba->ufs_device_wlun)
ufshcd_rpm_get_sync(hba);
ufs_hwmon_remove(hba);
ufs_bsg_remove(hba);
@@ -9806,7 +9792,7 @@ EXPORT_SYMBOL_GPL(ufshcd_resume_complete);
static bool ufshcd_rpm_ok_for_spm(struct ufs_hba *hba)
{
- struct device *dev = &hba->sdev_ufs_device->sdev_gendev;
+ struct device *dev = &hba->ufs_device_wlun->sdev_gendev;
enum ufs_dev_pwr_mode dev_pwr_mode;
enum uic_link_state link_state;
unsigned long flags;
@@ -9835,7 +9821,7 @@ int __ufshcd_suspend_prepare(struct device *dev, bool rpm_ok_for_spm)
* if it's runtime suspended. But ufs doesn't follow that.
* Refer ufshcd_resume_complete()
*/
- if (hba->sdev_ufs_device) {
+ if (hba->ufs_device_wlun) {
/* Prevent runtime suspend */
ufshcd_rpm_get_noresume(hba);
/*
@@ -9956,4 +9942,3 @@ MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
MODULE_DESCRIPTION("Generic UFS host controller driver Core");
MODULE_LICENSE("GPL");
-MODULE_VERSION(UFSHCD_DRIVER_VERSION);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 88c20f3608c2..2b0f3441b813 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -12,44 +12,18 @@
#ifndef _UFSHCD_H
#define _UFSHCD_H
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/rwsem.h>
-#include <linux/workqueue.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/wait.h>
-#include <linux/bitops.h>
-#include <linux/pm_runtime.h>
-#include <linux/clk.h>
-#include <linux/completion.h>
-#include <linux/regulator/consumer.h>
#include <linux/bitfield.h>
-#include <linux/devfreq.h>
#include <linux/blk-crypto-profile.h>
+#include <linux/blk-mq.h>
+#include <linux/devfreq.h>
+#include <linux/pm_runtime.h>
+#include <scsi/scsi_device.h>
#include "unipro.h"
-
-#include <asm/irq.h>
-#include <asm/byteorder.h>
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_eh.h>
-
#include "ufs.h"
#include "ufs_quirks.h"
#include "ufshci.h"
#define UFSHCD "ufshcd"
-#define UFSHCD_DRIVER_VERSION "0.2"
struct ufs_hba;
@@ -181,8 +155,6 @@ struct ufs_pm_lvl_states {
* @ucd_rsp_dma_addr: UPIU response dma address for debug
* @ucd_req_dma_addr: UPIU request dma address for debug
* @cmd: pointer to SCSI command
- * @sense_buffer: pointer to sense buffer address of the SCSI command
- * @sense_bufflen: Length of the sense buffer
* @scsi_status: SCSI status of the command
* @command_type: SCSI, UFS, Query.
* @task_tag: Task tag of the command
@@ -206,8 +178,6 @@ struct ufshcd_lrb {
dma_addr_t ucd_prdt_dma_addr;
struct scsi_cmnd *cmd;
- u8 *sense_buffer;
- unsigned int sense_bufflen;
int scsi_status;
int command_type;
@@ -241,6 +211,7 @@ struct ufs_query {
* @type: device management command type - Query, NOP OUT
* @lock: lock to allow one command at a time
* @complete: internal commands completion
+ * @query: Device management query information
*/
struct ufs_dev_cmd {
enum dev_cmd_type type;
@@ -258,7 +229,7 @@ struct ufs_dev_cmd {
* @min_freq: min frequency that can be used for clock scaling
* @curr_freq: indicates the current frequency that it is set to
* @keep_link_active: indicates that the clk should not be disabled if
- link is active
+ * link is active
* @enabled: variable to check against multiple enable/disable
*/
struct ufs_clk_info {
@@ -313,11 +284,13 @@ struct ufs_pwr_mode_info {
* to set some things
* @hibern8_notify: called around hibern8 enter/exit
* @apply_dev_quirks: called to apply device specific quirks
+ * @fixup_dev_quirks: called to modify device specific quirks
* @suspend: called during host controller PM callback
* @resume: called during host controller PM callback
* @dbg_register_dump: used to dump controller debug information
* @phy_initialization: used to initialize phys
* @device_reset: called to issue a reset pulse on the UFS device
+ * @config_scaling_param: called to configure clock scaling parameters
* @program_key: program or evict an inline encryption key
* @event_notify: called to notify important events
*/
@@ -352,8 +325,8 @@ struct ufs_hba_variant_ops {
int (*phy_initialization)(struct ufs_hba *);
int (*device_reset)(struct ufs_hba *hba);
void (*config_scaling_param)(struct ufs_hba *hba,
- struct devfreq_dev_profile *profile,
- void *data);
+ struct devfreq_dev_profile *profile,
+ struct devfreq_simple_ondemand_data *data);
int (*program_key)(struct ufs_hba *hba,
const union ufs_crypto_cfg_entry *cfg, int slot);
void (*event_notify)(struct ufs_hba *hba,
@@ -384,6 +357,7 @@ enum clk_gating_state {
* @is_initialized: Indicates whether clock gating is initialized or not
* @active_reqs: number of requests that are pending and should be waited for
* completion before gating clocks.
+ * @clk_gating_workq: workqueue for clock gating work.
*/
struct ufs_clk_gating {
struct delayed_work gate_work;
@@ -420,9 +394,9 @@ struct ufs_saved_pwr_info {
* @resume_work: worker to resume devfreq
* @min_gear: lowest HS gear to scale down to
* @is_enabled: tracks if scaling is currently enabled or not, controlled by
- clkscale_enable sysfs node
+ * clkscale_enable sysfs node
* @is_allowed: tracks if scaling is currently allowed or not, used to block
- clock scaling which is not invoked from devfreq governor
+ * clock scaling which is not invoked from devfreq governor
* @is_initialized: Indicates whether clock scaling is initialized or not
* @is_busy_started: tracks if busy period has started or not
* @is_suspended: tracks if devfreq is suspended or not
@@ -449,7 +423,7 @@ struct ufs_clk_scaling {
/**
* struct ufs_event_hist - keeps history of errors
* @pos: index to indicate cyclic buffer position
- * @reg: cyclic buffer for registers value
+ * @val: cyclic buffer for registers value
* @tstamp: cyclic buffer for time stamp
* @cnt: error counter
*/
@@ -468,6 +442,7 @@ struct ufs_event_hist {
* reset this after link-startup.
* @last_hibern8_exit_tstamp: Set time after the hibern8 exit.
* Clear after the first successful command completion.
+ * @event: array with event history.
*/
struct ufs_stats {
u32 last_intr_status;
@@ -737,6 +712,14 @@ struct ufs_hba_monitor {
* @utmrdl_dma_addr: UTMRDL DMA address
* @host: Scsi_Host instance of the driver
* @dev: device handle
+ * @ufs_device_wlun: WLUN that controls the entire UFS device.
+ * @hwmon_device: device instance registered with the hwmon core.
+ * @curr_dev_pwr_mode: active UFS device power mode.
+ * @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_op_in_progress: whether or not a PM operation is in progress.
+ * @ahit: value of Auto-Hibernate Idle Timer register.
* @lrb: local reference block
* @outstanding_tasks: Bits representing outstanding task requests
* @outstanding_lock: Protects @outstanding_reqs.
@@ -747,17 +730,26 @@ struct ufs_hba_monitor {
* @reserved_slot: Used to submit device commands. Protected by @dev_cmd.lock.
* @ufs_version: UFS Version to which controller complies
* @vops: pointer to variant specific operations
+ * @vps: pointer to variant specific parameters
* @priv: pointer to variant specific private data
* @irq: Irq number of the controller
- * @active_uic_cmd: handle of active UIC command
- * @uic_cmd_mutex: mutex for UIC command
+ * @is_irq_enabled: whether or not the UFS controller interrupt is enabled.
+ * @dev_ref_clk_freq: reference clock frequency
+ * @quirks: bitmask with information about deviations from the UFSHCI standard.
+ * @dev_quirks: bitmask with information about deviations from the UFS standard.
* @tmf_tag_set: TMF tag set.
* @tmf_queue: Used to allocate TMF tags.
- * @pwr_done: completion for power mode change
+ * @tmf_rqs: array with pointers to TMF requests while these are in progress.
+ * @active_uic_cmd: handle of active UIC command
+ * @uic_cmd_mutex: mutex for UIC command
+ * @uic_async_done: completion used during UIC processing
* @ufshcd_state: UFSHCD state
* @eh_flags: Error handling flags
* @intr_mask: Interrupt Mask Bits
* @ee_ctrl_mask: Exception event control mask
+ * @ee_drv_mask: Exception event mask for driver
+ * @ee_usr_mask: Exception event mask for user (set via debugfs)
+ * @ee_ctrl_mutex: Used to serialize exception event information.
* @is_powered: flag to check if HBA is powered
* @shutting_down: flag to check if shutdown has been invoked
* @host_sem: semaphore used to serialize concurrent contexts
@@ -768,26 +760,52 @@ struct ufs_hba_monitor {
* @uic_error: UFS interconnect layer error status
* @saved_err: sticky error mask
* @saved_uic_err: sticky UIC error mask
+ * @ufs_stats: various error counters
* @force_reset: flag to force eh_work perform a full reset
* @force_pmc: flag to force a power mode change
* @silence_err_logs: flag to silence error logs
* @dev_cmd: ufs device management command information
* @last_dme_cmd_tstamp: time stamp of the last completed DME command
+ * @nop_out_timeout: NOP OUT timeout value
+ * @dev_info: information about the UFS device
* @auto_bkops_enabled: to track whether bkops is enabled in device
* @vreg_info: UFS device voltage regulator information
* @clk_list_head: UFS host controller clocks list node head
+ * @req_abort_count: number of times ufshcd_abort() has been called
+ * @lanes_per_direction: number of lanes per data direction between the UFS
+ * controller and the UFS device.
* @pwr_info: holds current power mode
* @max_pwr_info: keeps the device max valid pwm
- * @clk_scaling_lock: used to serialize device commands and clock scaling
- * @desc_size: descriptor sizes reported by device
+ * @clk_gating: information related to clock gating
+ * @caps: bitmask with information about UFS controller capabilities
+ * @devfreq: frequency scaling information owned by the devfreq core
+ * @clk_scaling: frequency scaling information owned by the UFS driver
+ * @is_sys_suspended: whether or not the entire system has been suspended
* @urgent_bkops_lvl: keeps track of urgent bkops level for device
* @is_urgent_bkops_lvl_checked: keeps track if the urgent bkops level for
* device is known or not.
+ * @clk_scaling_lock: used to serialize device commands and clock scaling
+ * @desc_size: descriptor sizes reported by device
* @scsi_block_reqs_cnt: reference counting for scsi block requests
+ * @bsg_dev: struct device associated with the BSG queue
+ * @bsg_queue: BSG queue associated with the UFS controller
+ * @rpm_dev_flush_recheck_work: used to suspend from RPM (runtime power
+ * management) after the UFS device has finished a WriteBooster buffer
+ * flush or auto BKOP.
+ * @ufshpb_dev: information related to HPB (Host Performance Booster).
+ * @monitor: statistics about UFS commands
* @crypto_capabilities: Content of crypto capabilities register (0x100)
* @crypto_cap_array: Array of crypto capabilities
* @crypto_cfg_register: Start of the crypto cfg array
* @crypto_profile: the crypto profile of this hba (if applicable)
+ * @debugfs_root: UFS controller debugfs root directory
+ * @debugfs_ee_work: used to restore ee_ctrl_mask after a delay
+ * @debugfs_ee_rate_limit_ms: user configurable delay after which to restore
+ * ee_ctrl_mask
+ * @luns_avail: number of regular and well known LUNs supported by the UFS
+ * device
+ * @complete_put: whether or not to call ufshcd_rpm_put() from inside
+ * ufshcd_resume_complete()
*/
struct ufs_hba {
void __iomem *mmio_base;
@@ -804,11 +822,7 @@ struct ufs_hba {
struct Scsi_Host *host;
struct device *dev;
- /*
- * This field is to keep a reference to "scsi_device" corresponding to
- * "UFS device" W-LU.
- */
- struct scsi_device *sdev_ufs_device;
+ struct scsi_device *ufs_device_wlun;
#ifdef CONFIG_SCSI_UFS_HWMON
struct device *hwmon_device;
@@ -820,8 +834,6 @@ struct ufs_hba {
enum ufs_pm_level rpm_lvl;
/* Desired UFS power management level during system PM */
enum ufs_pm_level spm_lvl;
- struct device_attribute rpm_lvl_attr;
- struct device_attribute spm_lvl_attr;
int pm_op_in_progress;
/* Auto-Hibernate Idle Timer register value */
@@ -861,9 +873,9 @@ struct ufs_hba {
enum ufshcd_state ufshcd_state;
u32 eh_flags;
u32 intr_mask;
- u16 ee_ctrl_mask; /* Exception event mask */
- u16 ee_drv_mask; /* Exception event mask for driver */
- u16 ee_usr_mask; /* Exception event mask for user (via debugfs) */
+ u16 ee_ctrl_mask;
+ u16 ee_drv_mask;
+ u16 ee_usr_mask;
struct mutex ee_ctrl_mutex;
bool is_powered;
bool shutting_down;
@@ -985,7 +997,7 @@ static inline bool ufshcd_is_auto_hibern8_supported(struct ufs_hba *hba)
static inline bool ufshcd_is_auto_hibern8_enabled(struct ufs_hba *hba)
{
- return FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK, hba->ahit) ? true : false;
+ return FIELD_GET(UFSHCI_AHIBERN8_TIMER_MASK, hba->ahit);
}
static inline bool ufshcd_is_wb_allowed(struct ufs_hba *hba)
@@ -993,22 +1005,17 @@ static inline bool ufshcd_is_wb_allowed(struct ufs_hba *hba)
return hba->caps & UFSHCD_CAP_WB_EN;
}
-static inline bool ufshcd_is_user_access_allowed(struct ufs_hba *hba)
-{
- return !hba->shutting_down;
-}
-
#define ufshcd_writel(hba, val, reg) \
writel((val), (hba)->mmio_base + (reg))
#define ufshcd_readl(hba, reg) \
readl((hba)->mmio_base + (reg))
/**
- * ufshcd_rmwl - read modify write into a register
- * @hba - per adapter instance
- * @mask - mask to apply on read value
- * @val - actual value to write
- * @reg - register address
+ * ufshcd_rmwl - perform read/modify/write for a controller register
+ * @hba: per adapter instance
+ * @mask: mask to apply on read value
+ * @val: actual value to write
+ * @reg: register address
*/
static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
{
@@ -1030,9 +1037,6 @@ void ufshcd_remove(struct ufs_hba *);
int ufshcd_uic_hibern8_enter(struct ufs_hba *hba);
int ufshcd_uic_hibern8_exit(struct ufs_hba *hba);
void ufshcd_delay_us(unsigned long us, unsigned long tolerance);
-int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
- u32 val, unsigned long interval_us,
- unsigned long timeout_ms);
void ufshcd_parse_dev_ref_clk_freq(struct ufs_hba *hba, struct clk *refclk);
void ufshcd_update_evt_hist(struct ufs_hba *hba, u32 id, u32 val);
void ufshcd_hba_stop(struct ufs_hba *hba);
@@ -1046,8 +1050,8 @@ static inline void check_upiu_size(void)
/**
* ufshcd_set_variant - set variant specific data to the hba
- * @hba - per adapter instance
- * @variant - pointer to variant specific data
+ * @hba: per adapter instance
+ * @variant: pointer to variant specific data
*/
static inline void ufshcd_set_variant(struct ufs_hba *hba, void *variant)
{
@@ -1057,35 +1061,13 @@ static inline void ufshcd_set_variant(struct ufs_hba *hba, void *variant)
/**
* ufshcd_get_variant - get variant specific data from the hba
- * @hba - per adapter instance
+ * @hba: per adapter instance
*/
static inline void *ufshcd_get_variant(struct ufs_hba *hba)
{
BUG_ON(!hba);
return hba->priv;
}
-static inline bool ufshcd_keep_autobkops_enabled_except_suspend(
- struct ufs_hba *hba)
-{
- return hba->caps & UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND;
-}
-
-static inline u8 ufshcd_wb_get_query_index(struct ufs_hba *hba)
-{
- if (hba->dev_info.wb_buffer_type == WB_BUF_MODE_LU_DEDICATED)
- return hba->dev_info.wb_dedicated_lu;
- return 0;
-}
-
-#ifdef CONFIG_SCSI_UFS_HWMON
-void ufs_hwmon_probe(struct ufs_hba *hba, u8 mask);
-void ufs_hwmon_remove(struct ufs_hba *hba);
-void ufs_hwmon_notify_event(struct ufs_hba *hba, u8 ee_mask);
-#else
-static inline void ufs_hwmon_probe(struct ufs_hba *hba, u8 mask) {}
-static inline void ufs_hwmon_remove(struct ufs_hba *hba) {}
-static inline void ufs_hwmon_notify_event(struct ufs_hba *hba, u8 ee_mask) {}
-#endif
#ifdef CONFIG_PM
extern int ufshcd_runtime_suspend(struct device *dev);
@@ -1187,7 +1169,8 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode,
void ufshcd_auto_hibern8_enable(struct ufs_hba *hba);
void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit);
-void ufshcd_fixup_dev_quirks(struct ufs_hba *hba, struct ufs_dev_fix *fixups);
+void ufshcd_fixup_dev_quirks(struct ufs_hba *hba,
+ const struct ufs_dev_quirk *fixups);
#define SD_ASCII_STD true
#define SD_RAW false
int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index,
@@ -1196,6 +1179,8 @@ int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index,
int ufshcd_hold(struct ufs_hba *hba, bool async);
void ufshcd_release(struct ufs_hba *hba);
+void ufshcd_clkgate_delay_set(struct device *dev, unsigned long value);
+
void ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id,
int *desc_length);
@@ -1216,13 +1201,6 @@ int __ufshcd_suspend_prepare(struct device *dev, bool rpm_ok_for_spm);
void ufshcd_resume_complete(struct device *dev);
/* Wrapper functions for safely calling variant operations */
-static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
-{
- if (hba->vops)
- return hba->vops->name;
- return "";
-}
-
static inline int ufshcd_vops_init(struct ufs_hba *hba)
{
if (hba->vops && hba->vops->init)
@@ -1231,61 +1209,6 @@ static inline int ufshcd_vops_init(struct ufs_hba *hba)
return 0;
}
-static inline void ufshcd_vops_exit(struct ufs_hba *hba)
-{
- if (hba->vops && hba->vops->exit)
- return hba->vops->exit(hba);
-}
-
-static inline u32 ufshcd_vops_get_ufs_hci_version(struct ufs_hba *hba)
-{
- if (hba->vops && hba->vops->get_ufs_hci_version)
- return hba->vops->get_ufs_hci_version(hba);
-
- return ufshcd_readl(hba, REG_UFS_VERSION);
-}
-
-static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba,
- bool up, enum ufs_notify_change_status status)
-{
- if (hba->vops && hba->vops->clk_scale_notify)
- return hba->vops->clk_scale_notify(hba, up, status);
- return 0;
-}
-
-static inline void ufshcd_vops_event_notify(struct ufs_hba *hba,
- enum ufs_event_type evt,
- void *data)
-{
- if (hba->vops && hba->vops->event_notify)
- hba->vops->event_notify(hba, evt, data);
-}
-
-static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on,
- enum ufs_notify_change_status status)
-{
- if (hba->vops && hba->vops->setup_clocks)
- return hba->vops->setup_clocks(hba, on, status);
- return 0;
-}
-
-static inline int ufshcd_vops_hce_enable_notify(struct ufs_hba *hba,
- bool status)
-{
- if (hba->vops && hba->vops->hce_enable_notify)
- return hba->vops->hce_enable_notify(hba, status);
-
- return 0;
-}
-static inline int ufshcd_vops_link_startup_notify(struct ufs_hba *hba,
- bool status)
-{
- if (hba->vops && hba->vops->link_startup_notify)
- return hba->vops->link_startup_notify(hba, status);
-
- return 0;
-}
-
static inline int ufshcd_vops_phy_initialization(struct ufs_hba *hba)
{
if (hba->vops && hba->vops->phy_initialization)
@@ -1294,102 +1217,8 @@ static inline int ufshcd_vops_phy_initialization(struct ufs_hba *hba)
return 0;
}
-static inline int ufshcd_vops_pwr_change_notify(struct ufs_hba *hba,
- enum ufs_notify_change_status status,
- struct ufs_pa_layer_attr *dev_max_params,
- struct ufs_pa_layer_attr *dev_req_params)
-{
- if (hba->vops && hba->vops->pwr_change_notify)
- return hba->vops->pwr_change_notify(hba, status,
- dev_max_params, dev_req_params);
-
- return -ENOTSUPP;
-}
-
-static inline void ufshcd_vops_setup_task_mgmt(struct ufs_hba *hba,
- int tag, u8 tm_function)
-{
- if (hba->vops && hba->vops->setup_task_mgmt)
- return hba->vops->setup_task_mgmt(hba, tag, tm_function);
-}
-
-static inline void ufshcd_vops_hibern8_notify(struct ufs_hba *hba,
- enum uic_cmd_dme cmd,
- enum ufs_notify_change_status status)
-{
- if (hba->vops && hba->vops->hibern8_notify)
- return hba->vops->hibern8_notify(hba, cmd, status);
-}
-
-static inline int ufshcd_vops_apply_dev_quirks(struct ufs_hba *hba)
-{
- if (hba->vops && hba->vops->apply_dev_quirks)
- return hba->vops->apply_dev_quirks(hba);
- return 0;
-}
-
-static inline void ufshcd_vops_fixup_dev_quirks(struct ufs_hba *hba)
-{
- if (hba->vops && hba->vops->fixup_dev_quirks)
- hba->vops->fixup_dev_quirks(hba);
-}
-
-static inline int ufshcd_vops_suspend(struct ufs_hba *hba, enum ufs_pm_op op,
- enum ufs_notify_change_status status)
-{
- if (hba->vops && hba->vops->suspend)
- return hba->vops->suspend(hba, op, status);
-
- return 0;
-}
-
-static inline int ufshcd_vops_resume(struct ufs_hba *hba, enum ufs_pm_op op)
-{
- if (hba->vops && hba->vops->resume)
- return hba->vops->resume(hba, op);
-
- return 0;
-}
-
-static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
-{
- if (hba->vops && hba->vops->dbg_register_dump)
- hba->vops->dbg_register_dump(hba);
-}
-
-static inline int ufshcd_vops_device_reset(struct ufs_hba *hba)
-{
- if (hba->vops && hba->vops->device_reset)
- return hba->vops->device_reset(hba);
-
- return -EOPNOTSUPP;
-}
-
-static inline void ufshcd_vops_config_scaling_param(struct ufs_hba *hba,
- struct devfreq_dev_profile
- *profile, void *data)
-{
- if (hba->vops && hba->vops->config_scaling_param)
- hba->vops->config_scaling_param(hba, profile, data);
-}
-
extern struct ufs_pm_lvl_states ufs_pm_lvl_states[];
-/*
- * ufshcd_scsi_to_upiu_lun - maps scsi LUN to UPIU LUN
- * @scsi_lun: scsi LUN id
- *
- * Returns UPIU LUN id
- */
-static inline u8 ufshcd_scsi_to_upiu_lun(unsigned int scsi_lun)
-{
- if (scsi_is_wlun(scsi_lun))
- return (scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID)
- | UFS_UPIU_WLUN_ID;
- else
- return scsi_lun & UFS_UPIU_MAX_UNIT_NUM_ID;
-}
-
int ufshcd_dump_regs(struct ufs_hba *hba, size_t offset, size_t len,
const char *prefix);
@@ -1398,43 +1227,4 @@ int ufshcd_write_ee_control(struct ufs_hba *hba);
int ufshcd_update_ee_control(struct ufs_hba *hba, u16 *mask, u16 *other_mask,
u16 set, u16 clr);
-static inline int ufshcd_update_ee_drv_mask(struct ufs_hba *hba,
- u16 set, u16 clr)
-{
- return ufshcd_update_ee_control(hba, &hba->ee_drv_mask,
- &hba->ee_usr_mask, set, clr);
-}
-
-static inline int ufshcd_update_ee_usr_mask(struct ufs_hba *hba,
- u16 set, u16 clr)
-{
- return ufshcd_update_ee_control(hba, &hba->ee_usr_mask,
- &hba->ee_drv_mask, set, clr);
-}
-
-static inline int ufshcd_rpm_get_sync(struct ufs_hba *hba)
-{
- return pm_runtime_get_sync(&hba->sdev_ufs_device->sdev_gendev);
-}
-
-static inline int ufshcd_rpm_put_sync(struct ufs_hba *hba)
-{
- return pm_runtime_put_sync(&hba->sdev_ufs_device->sdev_gendev);
-}
-
-static inline void ufshcd_rpm_get_noresume(struct ufs_hba *hba)
-{
- pm_runtime_get_noresume(&hba->sdev_ufs_device->sdev_gendev);
-}
-
-static inline int ufshcd_rpm_resume(struct ufs_hba *hba)
-{
- return pm_runtime_resume(&hba->sdev_ufs_device->sdev_gendev);
-}
-
-static inline int ufshcd_rpm_put(struct ufs_hba *hba)
-{
- return pm_runtime_put(&hba->sdev_ufs_device->sdev_gendev);
-}
-
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index a7ff0e5b5494..f81aa95ffbc4 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -11,6 +11,8 @@
#ifndef _UFSHCI_H
#define _UFSHCI_H
+#include <scsi/scsi_host.h>
+
enum {
TASK_REQ_UPIU_SIZE_DWORDS = 8,
TASK_RSP_UPIU_SIZE_DWORDS = 8,
diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index b2bec19022cd..8882b47f76d3 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -10,8 +10,12 @@
*/
#include <asm/unaligned.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <scsi/scsi_cmnd.h>
-#include "ufshcd.h"
+#include "ufshcd-priv.h"
#include "ufshpb.h"
#include "../sd.h"
@@ -90,12 +94,8 @@ static bool ufshpb_is_general_lun(int lun)
static bool ufshpb_is_pinned_region(struct ufshpb_lu *hpb, int rgn_idx)
{
- if (hpb->lu_pinned_end != PINNED_NOT_SET &&
- rgn_idx >= hpb->lu_pinned_start &&
- rgn_idx <= hpb->lu_pinned_end)
- return true;
-
- return false;
+ return hpb->lu_pinned_end != PINNED_NOT_SET &&
+ rgn_idx >= hpb->lu_pinned_start && rgn_idx <= hpb->lu_pinned_end;
}
static void ufshpb_kick_map_work(struct ufshpb_lu *hpb)
@@ -563,7 +563,7 @@ static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int rgn_idx,
if (list_empty(&srgn->list_act_srgn))
list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn);
- hpb->stats.rb_active_cnt++;
+ hpb->stats.rcmd_active_cnt++;
}
static void ufshpb_update_inactive_info(struct ufshpb_lu *hpb, int rgn_idx)
@@ -580,7 +580,7 @@ static void ufshpb_update_inactive_info(struct ufshpb_lu *hpb, int rgn_idx)
if (list_empty(&rgn->list_inact_rgn))
list_add_tail(&rgn->list_inact_rgn, &hpb->lh_inact_rgn);
- hpb->stats.rb_inactive_cnt++;
+ hpb->stats.rcmd_inactive_cnt++;
}
static void ufshpb_activate_subregion(struct ufshpb_lu *hpb,
@@ -867,12 +867,6 @@ static struct ufshpb_region *ufshpb_victim_lru_info(struct ufshpb_lu *hpb)
struct ufshpb_region *rgn, *victim_rgn = NULL;
list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn) {
- if (!rgn) {
- dev_err(&hpb->sdev_ufs_lu->sdev_dev,
- "%s: no region allocated\n",
- __func__);
- return NULL;
- }
if (ufshpb_check_srgns_issue_state(hpb, rgn))
continue;
@@ -888,6 +882,11 @@ static struct ufshpb_region *ufshpb_victim_lru_info(struct ufshpb_lu *hpb)
break;
}
+ if (!victim_rgn)
+ dev_err(&hpb->sdev_ufs_lu->sdev_dev,
+ "%s: no region allocated\n",
+ __func__);
+
return victim_rgn;
}
@@ -931,11 +930,6 @@ static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb,
return ufshpb_issue_umap_req(hpb, rgn, true);
}
-static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
-{
- return ufshpb_issue_umap_req(hpb, NULL, false);
-}
-
static void __ufshpb_evict_region(struct ufshpb_lu *hpb,
struct ufshpb_region *rgn)
{
@@ -1143,6 +1137,39 @@ out:
spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
return ret;
}
+/**
+ *ufshpb_submit_region_inactive() - submit a region to be inactivated later
+ *@hpb: per-LU HPB instance
+ *@region_index: the index associated with the region that will be inactivated later
+ */
+static void ufshpb_submit_region_inactive(struct ufshpb_lu *hpb, int region_index)
+{
+ int subregion_index;
+ struct ufshpb_region *rgn;
+ struct ufshpb_subregion *srgn;
+
+ /*
+ * Remove this region from active region list and add it to inactive list
+ */
+ spin_lock(&hpb->rsp_list_lock);
+ ufshpb_update_inactive_info(hpb, region_index);
+ spin_unlock(&hpb->rsp_list_lock);
+
+ rgn = hpb->rgn_tbl + region_index;
+
+ /*
+ * Set subregion state to be HPB_SRGN_INVALID, there will no HPB read on this subregion
+ */
+ spin_lock(&hpb->rgn_state_lock);
+ if (rgn->rgn_state != HPB_RGN_INACTIVE) {
+ for (subregion_index = 0; subregion_index < rgn->srgn_cnt; subregion_index++) {
+ srgn = rgn->srgn_tbl + subregion_index;
+ if (srgn->srgn_state == HPB_SRGN_VALID)
+ srgn->srgn_state = HPB_SRGN_INVALID;
+ }
+ }
+ spin_unlock(&hpb->rgn_state_lock);
+}
static void ufshpb_rsp_req_region_update(struct ufshpb_lu *hpb,
struct utp_hpb_rsp *rsp_field)
@@ -1202,25 +1229,8 @@ static void ufshpb_rsp_req_region_update(struct ufshpb_lu *hpb,
for (i = 0; i < rsp_field->inactive_rgn_cnt; i++) {
rgn_i = be16_to_cpu(rsp_field->hpb_inactive_field[i]);
- dev_dbg(&hpb->sdev_ufs_lu->sdev_dev,
- "inactivate(%d) region %d\n", i, rgn_i);
-
- spin_lock(&hpb->rsp_list_lock);
- ufshpb_update_inactive_info(hpb, rgn_i);
- spin_unlock(&hpb->rsp_list_lock);
-
- rgn = hpb->rgn_tbl + rgn_i;
-
- spin_lock(&hpb->rgn_state_lock);
- if (rgn->rgn_state != HPB_RGN_INACTIVE) {
- for (srgn_i = 0; srgn_i < rgn->srgn_cnt; srgn_i++) {
- srgn = rgn->srgn_tbl + srgn_i;
- if (srgn->srgn_state == HPB_SRGN_VALID)
- srgn->srgn_state = HPB_SRGN_INVALID;
- }
- }
- spin_unlock(&hpb->rgn_state_lock);
-
+ dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "inactivate(%d) region %d\n", i, rgn_i);
+ ufshpb_submit_region_inactive(hpb, rgn_i);
}
out:
@@ -1231,7 +1241,10 @@ out:
queue_work(ufshpb_wq, &hpb->map_work);
}
-static void ufshpb_dev_reset_handler(struct ufshpb_lu *hpb)
+/*
+ * Set the flags of all active regions to RGN_FLAG_UPDATE to let host side reload L2P entries later
+ */
+static void ufshpb_set_regions_update(struct ufshpb_lu *hpb)
{
struct victim_select_info *lru_info = &hpb->lru_info;
struct ufshpb_region *rgn;
@@ -1245,6 +1258,42 @@ static void ufshpb_dev_reset_handler(struct ufshpb_lu *hpb)
spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
}
+static void ufshpb_dev_reset_handler(struct ufs_hba *hba)
+{
+ struct scsi_device *sdev;
+ struct ufshpb_lu *hpb;
+
+ __shost_for_each_device(sdev, hba->host) {
+ hpb = ufshpb_get_hpb_data(sdev);
+ if (!hpb)
+ continue;
+
+ if (hpb->is_hcm) {
+ /*
+ * For the HPB host control mode, in case device powered up and lost HPB
+ * information, we will set the region flag to be RGN_FLAG_UPDATE, it will
+ * let host reload its L2P entries(reactivate region in the UFS device).
+ */
+ ufshpb_set_regions_update(hpb);
+ } else {
+ /*
+ * For the HPB device control mode, if host side receives 02h:HPB Operation
+ * in UPIU response, which means device recommends the host side should
+ * inactivate all active regions. Here we add all active regions to inactive
+ * list, they will be inactivated later in ufshpb_map_work_handler().
+ */
+ struct victim_select_info *lru_info = &hpb->lru_info;
+ struct ufshpb_region *rgn;
+
+ list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
+ ufshpb_submit_region_inactive(hpb, rgn->rgn_idx);
+
+ if (ufshpb_get_state(hpb) == HPB_PRESENT)
+ queue_work(ufshpb_wq, &hpb->map_work);
+ }
+ }
+}
+
/*
* This function will parse recommended active subregion information in sense
* data field of response UPIU with SAM_STAT_GOOD state.
@@ -1255,6 +1304,13 @@ void ufshpb_rsp_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
struct utp_hpb_rsp *rsp_field = &lrbp->ucd_rsp_ptr->hr;
int data_seg_len;
+ data_seg_len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2)
+ & MASK_RSP_UPIU_DATA_SEG_LEN;
+
+ /* If data segment length is zero, rsp_field is not valid */
+ if (!data_seg_len)
+ return;
+
if (unlikely(lrbp->lun != rsp_field->lun)) {
struct scsi_device *sdev;
bool found = false;
@@ -1289,24 +1345,12 @@ void ufshpb_rsp_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
return;
}
- data_seg_len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2)
- & MASK_RSP_UPIU_DATA_SEG_LEN;
-
- /* To flush remained rsp_list, we queue the map_work task */
- if (!data_seg_len) {
- if (!ufshpb_is_general_lun(hpb->lun))
- return;
-
- ufshpb_kick_map_work(hpb);
- return;
- }
-
BUILD_BUG_ON(sizeof(struct utp_hpb_rsp) != UTP_HPB_RSP_SIZE);
if (!ufshpb_is_hpb_rsp_valid(hba, lrbp, rsp_field))
return;
- hpb->stats.rb_noti_cnt++;
+ hpb->stats.rcmd_noti_cnt++;
switch (rsp_field->hpb_op) {
case HPB_RSP_REQ_REGION_UPDATE:
@@ -1319,17 +1363,7 @@ void ufshpb_rsp_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
case HPB_RSP_DEV_RESET:
dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
"UFS device lost HPB information during PM.\n");
-
- if (hpb->is_hcm) {
- struct scsi_device *sdev;
-
- __shost_for_each_device(sdev, hba->host) {
- struct ufshpb_lu *h = sdev->hostdata;
-
- if (h)
- ufshpb_dev_reset_handler(h);
- }
- }
+ ufshpb_dev_reset_handler(hba);
break;
default:
@@ -1719,18 +1753,18 @@ static DEVICE_ATTR_RO(__name)
ufshpb_sysfs_attr_show_func(hit_cnt);
ufshpb_sysfs_attr_show_func(miss_cnt);
-ufshpb_sysfs_attr_show_func(rb_noti_cnt);
-ufshpb_sysfs_attr_show_func(rb_active_cnt);
-ufshpb_sysfs_attr_show_func(rb_inactive_cnt);
+ufshpb_sysfs_attr_show_func(rcmd_noti_cnt);
+ufshpb_sysfs_attr_show_func(rcmd_active_cnt);
+ufshpb_sysfs_attr_show_func(rcmd_inactive_cnt);
ufshpb_sysfs_attr_show_func(map_req_cnt);
ufshpb_sysfs_attr_show_func(umap_req_cnt);
static struct attribute *hpb_dev_stat_attrs[] = {
&dev_attr_hit_cnt.attr,
&dev_attr_miss_cnt.attr,
- &dev_attr_rb_noti_cnt.attr,
- &dev_attr_rb_active_cnt.attr,
- &dev_attr_rb_inactive_cnt.attr,
+ &dev_attr_rcmd_noti_cnt.attr,
+ &dev_attr_rcmd_active_cnt.attr,
+ &dev_attr_rcmd_inactive_cnt.attr,
&dev_attr_map_req_cnt.attr,
&dev_attr_umap_req_cnt.attr,
NULL,
@@ -2093,9 +2127,9 @@ static void ufshpb_stat_init(struct ufshpb_lu *hpb)
{
hpb->stats.hit_cnt = 0;
hpb->stats.miss_cnt = 0;
- hpb->stats.rb_noti_cnt = 0;
- hpb->stats.rb_active_cnt = 0;
- hpb->stats.rb_inactive_cnt = 0;
+ hpb->stats.rcmd_noti_cnt = 0;
+ hpb->stats.rcmd_active_cnt = 0;
+ hpb->stats.rcmd_inactive_cnt = 0;
hpb->stats.map_req_cnt = 0;
hpb->stats.umap_req_cnt = 0;
}
@@ -2278,38 +2312,28 @@ out:
return flag_res;
}
-void ufshpb_reset(struct ufs_hba *hba)
+/**
+ * ufshpb_toggle_state - switch HPB state of all LUs
+ * @hba: per-adapter instance
+ * @src: expected current HPB state
+ * @dest: target HPB state to switch to
+ */
+void ufshpb_toggle_state(struct ufs_hba *hba, enum UFSHPB_STATE src, enum UFSHPB_STATE dest)
{
struct ufshpb_lu *hpb;
struct scsi_device *sdev;
shost_for_each_device(sdev, hba->host) {
hpb = ufshpb_get_hpb_data(sdev);
- if (!hpb)
- continue;
-
- if (ufshpb_get_state(hpb) != HPB_RESET)
- continue;
-
- ufshpb_set_state(hpb, HPB_PRESENT);
- }
-}
-
-void ufshpb_reset_host(struct ufs_hba *hba)
-{
- struct ufshpb_lu *hpb;
- struct scsi_device *sdev;
- shost_for_each_device(sdev, hba->host) {
- hpb = ufshpb_get_hpb_data(sdev);
- if (!hpb)
+ if (!hpb || ufshpb_get_state(hpb) != src)
continue;
+ ufshpb_set_state(hpb, dest);
- if (ufshpb_get_state(hpb) != HPB_PRESENT)
- continue;
- ufshpb_set_state(hpb, HPB_RESET);
- ufshpb_cancel_jobs(hpb);
- ufshpb_discard_rsp_lists(hpb);
+ if (dest == HPB_RESET) {
+ ufshpb_cancel_jobs(hpb);
+ ufshpb_discard_rsp_lists(hpb);
+ }
}
}
@@ -2320,11 +2344,9 @@ void ufshpb_suspend(struct ufs_hba *hba)
shost_for_each_device(sdev, hba->host) {
hpb = ufshpb_get_hpb_data(sdev);
- if (!hpb)
+ if (!hpb || ufshpb_get_state(hpb) != HPB_PRESENT)
continue;
- if (ufshpb_get_state(hpb) != HPB_PRESENT)
- continue;
ufshpb_set_state(hpb, HPB_SUSPEND);
ufshpb_cancel_jobs(hpb);
}
@@ -2337,20 +2359,15 @@ void ufshpb_resume(struct ufs_hba *hba)
shost_for_each_device(sdev, hba->host) {
hpb = ufshpb_get_hpb_data(sdev);
- if (!hpb)
+ if (!hpb || ufshpb_get_state(hpb) != HPB_SUSPEND)
continue;
- if ((ufshpb_get_state(hpb) != HPB_PRESENT) &&
- (ufshpb_get_state(hpb) != HPB_SUSPEND))
- continue;
ufshpb_set_state(hpb, HPB_PRESENT);
ufshpb_kick_map_work(hpb);
if (hpb->is_hcm) {
- unsigned int poll =
- hpb->params.timeout_polling_interval_ms;
+ unsigned int poll = hpb->params.timeout_polling_interval_ms;
- schedule_delayed_work(&hpb->ufshpb_read_to_work,
- msecs_to_jiffies(poll));
+ schedule_delayed_work(&hpb->ufshpb_read_to_work, msecs_to_jiffies(poll));
}
}
}
@@ -2456,8 +2473,6 @@ static void ufshpb_hpb_lu_prepared(struct ufs_hba *hba)
ufshpb_set_state(hpb, HPB_PRESENT);
if ((hpb->lu_pinned_end - hpb->lu_pinned_start) > 0)
queue_work(ufshpb_wq, &hpb->map_work);
- if (!hpb->is_hcm)
- ufshpb_issue_umap_all_req(hpb);
} else {
dev_err(hba->dev, "destroy HPB lu %d\n", hpb->lun);
ufshpb_destroy_lu(hba, sdev);
diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
index b475dbd78988..0d6e6004d783 100644
--- a/drivers/scsi/ufs/ufshpb.h
+++ b/drivers/scsi/ufs/ufshpb.h
@@ -59,8 +59,8 @@ enum UFSHPB_MODE {
};
enum UFSHPB_STATE {
- HPB_INIT = 0,
- HPB_PRESENT = 1,
+ HPB_INIT,
+ HPB_PRESENT,
HPB_SUSPEND,
HPB_FAILED,
HPB_RESET,
@@ -211,9 +211,9 @@ struct ufshpb_params {
struct ufshpb_stats {
u64 hit_cnt;
u64 miss_cnt;
- u64 rb_noti_cnt;
- u64 rb_active_cnt;
- u64 rb_inactive_cnt;
+ u64 rcmd_noti_cnt;
+ u64 rcmd_active_cnt;
+ u64 rcmd_inactive_cnt;
u64 map_req_cnt;
u64 pre_req_cnt;
u64 umap_req_cnt;
@@ -288,8 +288,7 @@ static int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) { return 0;
static void ufshpb_rsp_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) {}
static void ufshpb_resume(struct ufs_hba *hba) {}
static void ufshpb_suspend(struct ufs_hba *hba) {}
-static void ufshpb_reset(struct ufs_hba *hba) {}
-static void ufshpb_reset_host(struct ufs_hba *hba) {}
+static void ufshpb_toggle_state(struct ufs_hba *hba, enum UFSHPB_STATE src, enum UFSHPB_STATE dest) {}
static void ufshpb_init(struct ufs_hba *hba) {}
static void ufshpb_init_hpb_lu(struct ufs_hba *hba, struct scsi_device *sdev) {}
static void ufshpb_destroy_lu(struct ufs_hba *hba, struct scsi_device *sdev) {}
@@ -303,8 +302,7 @@ int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp);
void ufshpb_rsp_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp);
void ufshpb_resume(struct ufs_hba *hba);
void ufshpb_suspend(struct ufs_hba *hba);
-void ufshpb_reset(struct ufs_hba *hba);
-void ufshpb_reset_host(struct ufs_hba *hba);
+void ufshpb_toggle_state(struct ufs_hba *hba, enum UFSHPB_STATE src, enum UFSHPB_STATE dest);
void ufshpb_init(struct ufs_hba *hba);
void ufshpb_init_hpb_lu(struct ufs_hba *hba, struct scsi_device *sdev);
void ufshpb_destroy_lu(struct ufs_hba *hba, struct scsi_device *sdev);
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
index 8e9e486a4f7b..0521f887e3ac 100644
--- a/drivers/scsi/ufs/unipro.h
+++ b/drivers/scsi/ufs/unipro.h
@@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
- * drivers/scsi/ufs/unipro.h
- *
* Copyright (C) 2013 Samsung Electronics Co., Ltd.
*/
@@ -103,7 +101,7 @@
#define UNIPRO_CB_OFFSET(x) (0x8000 | x)
/*
- * PHY Adpater attributes
+ * PHY Adapter attributes
*/
#define PA_ACTIVETXDATALANES 0x1560
#define PA_ACTIVERXDATALANES 0x1580
@@ -300,20 +298,6 @@ enum ufs_unipro_ver {
#define T_TC0TXMAXSDUSIZE 0x4060
#define T_TC1TXMAXSDUSIZE 0x4061
-#ifdef FALSE
-#undef FALSE
-#endif
-
-#ifdef TRUE
-#undef TRUE
-#endif
-
-/* Boolean attribute values */
-enum {
- FALSE = 0,
- TRUE,
-};
-
/* CPort setting */
#define E2EFC_ON (1 << 0)
#define E2EFC_OFF (0 << 0)
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index 0e6110da69e7..578c4b6d0f7d 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -988,7 +988,7 @@ static struct virtio_driver virtio_scsi_driver = {
.remove = virtscsi_remove,
};
-static int __init init(void)
+static int __init virtio_scsi_init(void)
{
int ret = -ENOMEM;
@@ -1020,14 +1020,14 @@ error:
return ret;
}
-static void __exit fini(void)
+static void __exit virtio_scsi_fini(void)
{
unregister_virtio_driver(&virtio_scsi_driver);
mempool_destroy(virtscsi_cmd_pool);
kmem_cache_destroy(virtscsi_cmd_cache);
}
-module_init(init);
-module_exit(fini);
+module_init(virtio_scsi_init);
+module_exit(virtio_scsi_fini);
MODULE_DEVICE_TABLE(virtio, id_table);
MODULE_DESCRIPTION("Virtio SCSI HBA driver");
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index 1f037b8ab904..f88ecdb93a8a 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -1324,7 +1324,6 @@ static u32 pvscsi_get_max_targets(struct pvscsi_adapter *adapter)
* indicate success.
*/
header = config_page;
- memset(header, 0, sizeof *header);
header->hostStatus = BTSTAT_INVPARAM;
header->scsiStatus = SDSTAT_CHECK;
diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c
index 12109e4c73d4..51afc66e839d 100644
--- a/drivers/scsi/xen-scsifront.c
+++ b/drivers/scsi/xen-scsifront.c
@@ -58,9 +58,6 @@
#include <asm/xen/hypervisor.h>
-
-#define GRANT_INVALID_REF 0
-
#define VSCSIFRONT_OP_ADD_LUN 1
#define VSCSIFRONT_OP_DEL_LUN 2
#define VSCSIFRONT_OP_READD_LUN 3
@@ -83,6 +80,8 @@ struct vscsifrnt_shadow {
uint16_t rqid;
uint16_t ref_rqid;
+ bool inflight;
+
unsigned int nr_grants; /* number of grants in gref[] */
struct scsiif_request_segment *sg; /* scatter/gather elements */
struct scsiif_request_segment seg[VSCSIIF_SG_TABLESIZE];
@@ -104,7 +103,11 @@ struct vscsifrnt_info {
struct xenbus_device *dev;
struct Scsi_Host *host;
- int host_active;
+ enum {
+ STATE_INACTIVE,
+ STATE_ACTIVE,
+ STATE_ERROR
+ } host_active;
unsigned int evtchn;
unsigned int irq;
@@ -217,6 +220,8 @@ static int scsifront_do_request(struct vscsifrnt_info *info,
for (i = 0; i < (shadow->nr_segments & ~VSCSIIF_SG_GRANT); i++)
ring_req->seg[i] = shadow->seg[i];
+ shadow->inflight = true;
+
RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
if (notify)
notify_remote_via_irq(info->irq);
@@ -224,6 +229,13 @@ static int scsifront_do_request(struct vscsifrnt_info *info,
return 0;
}
+static void scsifront_set_error(struct vscsifrnt_info *info, const char *msg)
+{
+ shost_printk(KERN_ERR, info->host, KBUILD_MODNAME "%s\n"
+ "Disabling device for further use\n", msg);
+ info->host_active = STATE_ERROR;
+}
+
static void scsifront_gnttab_done(struct vscsifrnt_info *info,
struct vscsifrnt_shadow *shadow)
{
@@ -234,15 +246,64 @@ static void scsifront_gnttab_done(struct vscsifrnt_info *info,
for (i = 0; i < shadow->nr_grants; i++) {
if (unlikely(!gnttab_try_end_foreign_access(shadow->gref[i]))) {
- shost_printk(KERN_ALERT, info->host, KBUILD_MODNAME
- "grant still in use by backend\n");
- BUG();
+ scsifront_set_error(info, "grant still in use by backend");
+ return;
}
}
kfree(shadow->sg);
}
+static unsigned int scsifront_host_byte(int32_t rslt)
+{
+ switch (XEN_VSCSIIF_RSLT_HOST(rslt)) {
+ case XEN_VSCSIIF_RSLT_HOST_OK:
+ return DID_OK;
+ case XEN_VSCSIIF_RSLT_HOST_NO_CONNECT:
+ return DID_NO_CONNECT;
+ case XEN_VSCSIIF_RSLT_HOST_BUS_BUSY:
+ return DID_BUS_BUSY;
+ case XEN_VSCSIIF_RSLT_HOST_TIME_OUT:
+ return DID_TIME_OUT;
+ case XEN_VSCSIIF_RSLT_HOST_BAD_TARGET:
+ return DID_BAD_TARGET;
+ case XEN_VSCSIIF_RSLT_HOST_ABORT:
+ return DID_ABORT;
+ case XEN_VSCSIIF_RSLT_HOST_PARITY:
+ return DID_PARITY;
+ case XEN_VSCSIIF_RSLT_HOST_ERROR:
+ return DID_ERROR;
+ case XEN_VSCSIIF_RSLT_HOST_RESET:
+ return DID_RESET;
+ case XEN_VSCSIIF_RSLT_HOST_BAD_INTR:
+ return DID_BAD_INTR;
+ case XEN_VSCSIIF_RSLT_HOST_PASSTHROUGH:
+ return DID_PASSTHROUGH;
+ case XEN_VSCSIIF_RSLT_HOST_SOFT_ERROR:
+ return DID_SOFT_ERROR;
+ case XEN_VSCSIIF_RSLT_HOST_IMM_RETRY:
+ return DID_IMM_RETRY;
+ case XEN_VSCSIIF_RSLT_HOST_REQUEUE:
+ return DID_REQUEUE;
+ case XEN_VSCSIIF_RSLT_HOST_TRANSPORT_DISRUPTED:
+ return DID_TRANSPORT_DISRUPTED;
+ case XEN_VSCSIIF_RSLT_HOST_TRANSPORT_FAILFAST:
+ return DID_TRANSPORT_FAILFAST;
+ case XEN_VSCSIIF_RSLT_HOST_TARGET_FAILURE:
+ return DID_TARGET_FAILURE;
+ case XEN_VSCSIIF_RSLT_HOST_NEXUS_FAILURE:
+ return DID_NEXUS_FAILURE;
+ case XEN_VSCSIIF_RSLT_HOST_ALLOC_FAILURE:
+ return DID_ALLOC_FAILURE;
+ case XEN_VSCSIIF_RSLT_HOST_MEDIUM_ERROR:
+ return DID_MEDIUM_ERROR;
+ case XEN_VSCSIIF_RSLT_HOST_TRANSPORT_MARGINAL:
+ return DID_TRANSPORT_MARGINAL;
+ default:
+ return DID_ERROR;
+ }
+}
+
static void scsifront_cdb_cmd_done(struct vscsifrnt_info *info,
struct vscsiif_response *ring_rsp)
{
@@ -250,7 +311,6 @@ static void scsifront_cdb_cmd_done(struct vscsifrnt_info *info,
struct scsi_cmnd *sc;
uint32_t id;
uint8_t sense_len;
- int result;
id = ring_rsp->rqid;
shadow = info->shadow[id];
@@ -259,14 +319,12 @@ static void scsifront_cdb_cmd_done(struct vscsifrnt_info *info,
BUG_ON(sc == NULL);
scsifront_gnttab_done(info, shadow);
+ if (info->host_active == STATE_ERROR)
+ return;
scsifront_put_rqid(info, id);
- result = ring_rsp->rslt;
- if (result >> 24)
- set_host_byte(sc, DID_ERROR);
- else
- set_host_byte(sc, host_byte(result));
- set_status_byte(sc, result & 0xff);
+ set_host_byte(sc, scsifront_host_byte(ring_rsp->rslt));
+ set_status_byte(sc, XEN_VSCSIIF_RSLT_STATUS(ring_rsp->rslt));
scsi_set_resid(sc, ring_rsp->residual_len);
sense_len = min_t(uint8_t, VSCSIIF_SENSE_BUFFERSIZE,
@@ -290,7 +348,10 @@ static void scsifront_sync_cmd_done(struct vscsifrnt_info *info,
shadow->wait_reset = 1;
switch (shadow->rslt_reset) {
case RSLT_RESET_WAITING:
- shadow->rslt_reset = ring_rsp->rslt;
+ if (ring_rsp->rslt == XEN_VSCSIIF_RSLT_RESET_SUCCESS)
+ shadow->rslt_reset = SUCCESS;
+ else
+ shadow->rslt_reset = FAILED;
break;
case RSLT_RESET_ERR:
kick = _scsifront_put_rqid(info, id);
@@ -300,9 +361,7 @@ static void scsifront_sync_cmd_done(struct vscsifrnt_info *info,
scsifront_wake_up(info);
return;
default:
- shost_printk(KERN_ERR, info->host, KBUILD_MODNAME
- "bad reset state %d, possibly leaking %u\n",
- shadow->rslt_reset, id);
+ scsifront_set_error(info, "bad reset state");
break;
}
spin_unlock_irqrestore(&info->shadow_lock, flags);
@@ -313,28 +372,41 @@ static void scsifront_sync_cmd_done(struct vscsifrnt_info *info,
static void scsifront_do_response(struct vscsifrnt_info *info,
struct vscsiif_response *ring_rsp)
{
- if (WARN(ring_rsp->rqid >= VSCSIIF_MAX_REQS ||
- test_bit(ring_rsp->rqid, info->shadow_free_bitmap),
- "illegal rqid %u returned by backend!\n", ring_rsp->rqid))
+ struct vscsifrnt_shadow *shadow;
+
+ if (ring_rsp->rqid >= VSCSIIF_MAX_REQS ||
+ !info->shadow[ring_rsp->rqid]->inflight) {
+ scsifront_set_error(info, "illegal rqid returned by backend!");
return;
+ }
+ shadow = info->shadow[ring_rsp->rqid];
+ shadow->inflight = false;
- if (info->shadow[ring_rsp->rqid]->act == VSCSIIF_ACT_SCSI_CDB)
+ if (shadow->act == VSCSIIF_ACT_SCSI_CDB)
scsifront_cdb_cmd_done(info, ring_rsp);
else
scsifront_sync_cmd_done(info, ring_rsp);
}
-static int scsifront_ring_drain(struct vscsifrnt_info *info)
+static int scsifront_ring_drain(struct vscsifrnt_info *info,
+ unsigned int *eoiflag)
{
- struct vscsiif_response *ring_rsp;
+ struct vscsiif_response ring_rsp;
RING_IDX i, rp;
int more_to_do = 0;
- rp = info->ring.sring->rsp_prod;
- rmb(); /* ordering required respective to dom0 */
+ rp = READ_ONCE(info->ring.sring->rsp_prod);
+ virt_rmb(); /* ordering required respective to backend */
+ if (RING_RESPONSE_PROD_OVERFLOW(&info->ring, rp)) {
+ scsifront_set_error(info, "illegal number of responses");
+ return 0;
+ }
for (i = info->ring.rsp_cons; i != rp; i++) {
- ring_rsp = RING_GET_RESPONSE(&info->ring, i);
- scsifront_do_response(info, ring_rsp);
+ RING_COPY_RESPONSE(&info->ring, i, &ring_rsp);
+ scsifront_do_response(info, &ring_rsp);
+ if (info->host_active == STATE_ERROR)
+ return 0;
+ *eoiflag &= ~XEN_EOI_FLAG_SPURIOUS;
}
info->ring.rsp_cons = i;
@@ -347,14 +419,15 @@ static int scsifront_ring_drain(struct vscsifrnt_info *info)
return more_to_do;
}
-static int scsifront_cmd_done(struct vscsifrnt_info *info)
+static int scsifront_cmd_done(struct vscsifrnt_info *info,
+ unsigned int *eoiflag)
{
int more_to_do;
unsigned long flags;
spin_lock_irqsave(info->host->host_lock, flags);
- more_to_do = scsifront_ring_drain(info);
+ more_to_do = scsifront_ring_drain(info, eoiflag);
info->wait_ring_available = 0;
@@ -368,20 +441,28 @@ static int scsifront_cmd_done(struct vscsifrnt_info *info)
static irqreturn_t scsifront_irq_fn(int irq, void *dev_id)
{
struct vscsifrnt_info *info = dev_id;
+ unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
- while (scsifront_cmd_done(info))
+ if (info->host_active == STATE_ERROR) {
+ xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS);
+ return IRQ_HANDLED;
+ }
+
+ while (scsifront_cmd_done(info, &eoiflag))
/* Yield point for this unbounded loop. */
cond_resched();
+ xen_irq_lateeoi(irq, eoiflag);
+
return IRQ_HANDLED;
}
static void scsifront_finish_all(struct vscsifrnt_info *info)
{
- unsigned i;
+ unsigned int i, dummy;
struct vscsiif_response resp;
- scsifront_ring_drain(info);
+ scsifront_ring_drain(info, &dummy);
for (i = 0; i < VSCSIIF_MAX_REQS; i++) {
if (test_bit(i, info->shadow_free_bitmap))
@@ -538,6 +619,9 @@ static int scsifront_queuecommand(struct Scsi_Host *shost,
unsigned long flags;
int err;
+ if (info->host_active == STATE_ERROR)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
sc->result = 0;
shadow->sc = sc;
@@ -590,6 +674,9 @@ static int scsifront_action_handler(struct scsi_cmnd *sc, uint8_t act)
struct vscsifrnt_shadow *shadow, *s = scsi_cmd_priv(sc);
int err = 0;
+ if (info->host_active == STATE_ERROR)
+ return FAILED;
+
shadow = kzalloc(sizeof(*shadow), GFP_NOIO);
if (!shadow)
return FAILED;
@@ -661,6 +748,9 @@ static int scsifront_sdev_configure(struct scsi_device *sdev)
struct vscsifrnt_info *info = shost_priv(sdev->host);
int err;
+ if (info->host_active == STATE_ERROR)
+ return -EIO;
+
if (info && current == info->curr) {
err = xenbus_printf(XBT_NIL, info->dev->nodename,
info->dev_state_path, "%d", XenbusStateConnected);
@@ -708,27 +798,15 @@ static int scsifront_alloc_ring(struct vscsifrnt_info *info)
{
struct xenbus_device *dev = info->dev;
struct vscsiif_sring *sring;
- grant_ref_t gref;
- int err = -ENOMEM;
+ int err;
/***** Frontend to Backend ring start *****/
- sring = (struct vscsiif_sring *)__get_free_page(GFP_KERNEL);
- if (!sring) {
- xenbus_dev_fatal(dev, err,
- "fail to allocate shared ring (Front to Back)");
+ err = xenbus_setup_ring(dev, GFP_KERNEL, (void **)&sring, 1,
+ &info->ring_ref);
+ if (err)
return err;
- }
- SHARED_RING_INIT(sring);
- FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
- err = xenbus_grant_ring(dev, sring, 1, &gref);
- if (err < 0) {
- free_page((unsigned long)sring);
- xenbus_dev_fatal(dev, err,
- "fail to grant shared ring (Front to Back)");
- return err;
- }
- info->ring_ref = gref;
+ XEN_FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
err = xenbus_alloc_evtchn(dev, &info->evtchn);
if (err) {
@@ -736,7 +814,7 @@ static int scsifront_alloc_ring(struct vscsifrnt_info *info)
goto free_gnttab;
}
- err = bind_evtchn_to_irq(info->evtchn);
+ err = bind_evtchn_to_irq_lateeoi(info->evtchn);
if (err <= 0) {
xenbus_dev_fatal(dev, err, "bind_evtchn_to_irq");
goto free_gnttab;
@@ -757,8 +835,7 @@ static int scsifront_alloc_ring(struct vscsifrnt_info *info)
free_irq:
unbind_from_irqhandler(info->irq, info);
free_gnttab:
- gnttab_end_foreign_access(info->ring_ref,
- (unsigned long)info->ring.sring);
+ xenbus_teardown_ring((void **)&sring, 1, &info->ring_ref);
return err;
}
@@ -766,8 +843,7 @@ free_gnttab:
static void scsifront_free_ring(struct vscsifrnt_info *info)
{
unbind_from_irqhandler(info->irq, info);
- gnttab_end_foreign_access(info->ring_ref,
- (unsigned long)info->ring.sring);
+ xenbus_teardown_ring((void **)&info->ring.sring, 1, &info->ring_ref);
}
static int scsifront_init_ring(struct vscsifrnt_info *info)
@@ -866,7 +942,7 @@ static int scsifront_probe(struct xenbus_device *dev,
goto free_sring;
}
info->host = host;
- info->host_active = 1;
+ info->host_active = STATE_ACTIVE;
xenbus_switch_state(dev, XenbusStateInitialised);
@@ -934,10 +1010,10 @@ static int scsifront_remove(struct xenbus_device *dev)
pr_debug("%s: %s removed\n", __func__, dev->nodename);
mutex_lock(&scsifront_mutex);
- if (info->host_active) {
+ if (info->host_active != STATE_INACTIVE) {
/* Scsi_host not yet removed */
scsi_remove_host(info->host);
- info->host_active = 0;
+ info->host_active = STATE_INACTIVE;
}
mutex_unlock(&scsifront_mutex);
@@ -961,9 +1037,9 @@ static void scsifront_disconnect(struct vscsifrnt_info *info)
*/
mutex_lock(&scsifront_mutex);
- if (info->host_active) {
+ if (info->host_active != STATE_INACTIVE) {
scsi_remove_host(host);
- info->host_active = 0;
+ info->host_active = STATE_INACTIVE;
}
mutex_unlock(&scsifront_mutex);
@@ -981,6 +1057,9 @@ static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op)
unsigned int hst, chn, tgt, lun;
struct scsi_device *sdev;
+ if (info->host_active == STATE_ERROR)
+ return;
+
dir = xenbus_directory(XBT_NIL, dev->otherend, "vscsi-devs", &dir_n);
if (IS_ERR(dir))
return;
diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c
index 27b9e2baab1a..7acf9193a9e8 100644
--- a/drivers/scsi/zorro7xx.c
+++ b/drivers/scsi/zorro7xx.c
@@ -159,6 +159,8 @@ static void zorro7xx_remove_one(struct zorro_dev *z)
scsi_remove_host(host);
NCR_700_release(host);
+ if (host->base > 0x01000000)
+ iounmap(hostdata->base);
kfree(hostdata);
free_irq(host->irq, host);
zorro_release_device(z);