From b4b7ff4b08e691656c9d77c758fc355833128ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fabian=20Silva=20Delgado?= Date: Wed, 20 Jan 2016 14:01:31 -0300 Subject: Linux-libre 4.4-gnu --- drivers/scsi/53c700.c | 11 +- drivers/scsi/FlashPoint.c | 2 +- drivers/scsi/Kconfig | 10 +- drivers/scsi/Makefile | 1 - drivers/scsi/aacraid/aachba.c | 265 +- drivers/scsi/aacraid/aacraid.h | 20 +- drivers/scsi/aacraid/comminit.c | 147 +- drivers/scsi/aacraid/commsup.c | 113 +- drivers/scsi/aacraid/linit.c | 152 + drivers/scsi/aacraid/rx.c | 1 + drivers/scsi/aacraid/sa.c | 1 + drivers/scsi/aacraid/src.c | 64 +- drivers/scsi/advansys.c | 8 +- drivers/scsi/aic7xxx/aic79xx_osm.c | 1 - drivers/scsi/aic7xxx/aic7xxx_osm.c | 1 - drivers/scsi/aic94xx/aic94xx_init.c | 3 +- drivers/scsi/be2iscsi/Kconfig | 4 +- drivers/scsi/be2iscsi/Makefile | 2 +- drivers/scsi/be2iscsi/be.h | 4 +- drivers/scsi/be2iscsi/be_cmds.c | 4 +- drivers/scsi/be2iscsi/be_cmds.h | 4 +- drivers/scsi/be2iscsi/be_iscsi.c | 4 +- drivers/scsi/be2iscsi/be_main.c | 72 +- drivers/scsi/be2iscsi/be_main.h | 13 +- drivers/scsi/be2iscsi/be_mgmt.c | 28 +- drivers/scsi/be2iscsi/be_mgmt.h | 11 +- drivers/scsi/bfa/bfad_im.c | 2 - drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h | 6 +- drivers/scsi/bnx2fc/Kconfig | 5 +- drivers/scsi/bnx2fc/bnx2fc.h | 9 +- drivers/scsi/bnx2fc/bnx2fc_constants.h | 6 +- drivers/scsi/bnx2fc/bnx2fc_debug.c | 6 +- drivers/scsi/bnx2fc/bnx2fc_debug.h | 6 +- drivers/scsi/bnx2fc/bnx2fc_els.c | 10 +- drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 27 +- drivers/scsi/bnx2fc/bnx2fc_hwi.c | 6 +- drivers/scsi/bnx2fc/bnx2fc_io.c | 106 +- drivers/scsi/bnx2fc/bnx2fc_tgt.c | 12 +- drivers/scsi/csiostor/csio_scsi.c | 2 - drivers/scsi/cxgbi/cxgb3i/Kbuild | 2 +- drivers/scsi/cxgbi/cxgb4i/Kbuild | 2 +- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 2 +- drivers/scsi/cxlflash/common.h | 30 +- drivers/scsi/cxlflash/lunmgt.c | 45 +- drivers/scsi/cxlflash/main.c | 1550 ++--- drivers/scsi/cxlflash/main.h | 1 + drivers/scsi/cxlflash/sislite.h | 8 +- drivers/scsi/cxlflash/superpipe.c | 209 +- drivers/scsi/cxlflash/superpipe.h | 14 +- drivers/scsi/cxlflash/vlun.c | 68 +- drivers/scsi/esas2r/esas2r_main.c | 1 - drivers/scsi/esp_scsi.c | 1 - drivers/scsi/fcoe/fcoe.c | 4 +- drivers/scsi/fnic/fnic_fcs.c | 46 +- drivers/scsi/fnic/fnic_main.c | 8 - drivers/scsi/fnic/fnic_scsi.c | 16 + drivers/scsi/hosts.c | 18 + drivers/scsi/hpsa.c | 1346 +++- drivers/scsi/hpsa.h | 47 +- drivers/scsi/hpsa_cmd.h | 30 +- drivers/scsi/ibmvscsi/ibmvfc.c | 1 - drivers/scsi/ibmvscsi/ibmvscsi.c | 10 +- drivers/scsi/ibmvscsi/ibmvscsi.h | 1 + drivers/scsi/ipr.c | 154 +- drivers/scsi/ipr.h | 22 +- drivers/scsi/isci/init.c | 5 +- drivers/scsi/libfc/fc_npiv.c | 2 +- drivers/scsi/lpfc/lpfc.h | 8 +- drivers/scsi/lpfc/lpfc_attr.c | 23 +- drivers/scsi/lpfc/lpfc_bsg.c | 20 - drivers/scsi/lpfc/lpfc_ct.c | 11 +- drivers/scsi/lpfc/lpfc_els.c | 108 +- drivers/scsi/lpfc/lpfc_hbadisc.c | 27 +- drivers/scsi/lpfc/lpfc_hw.h | 6 +- drivers/scsi/lpfc/lpfc_init.c | 36 +- drivers/scsi/lpfc/lpfc_mbox.c | 19 +- drivers/scsi/lpfc/lpfc_nportdisc.c | 2 - drivers/scsi/lpfc/lpfc_scsi.c | 17 +- drivers/scsi/lpfc/lpfc_sli.c | 10 +- drivers/scsi/lpfc/lpfc_sli4.h | 1 - drivers/scsi/lpfc/lpfc_version.h | 2 +- drivers/scsi/megaraid/megaraid_sas.h | 62 +- drivers/scsi/megaraid/megaraid_sas_base.c | 466 +- drivers/scsi/megaraid/megaraid_sas_fp.c | 28 +- drivers/scsi/megaraid/megaraid_sas_fusion.c | 404 +- drivers/scsi/megaraid/megaraid_sas_fusion.h | 36 +- drivers/scsi/mpt2sas/Kconfig | 67 - drivers/scsi/mpt2sas/Makefile | 7 - drivers/scsi/mpt2sas/mpi/mpi2.h | 1170 ---- drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 3068 ---------- drivers/scsi/mpt2sas/mpi/mpi2_init.h | 461 -- drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | 1708 ------ drivers/scsi/mpt2sas/mpi/mpi2_raid.h | 366 -- drivers/scsi/mpt2sas/mpi/mpi2_sas.h | 288 - drivers/scsi/mpt2sas/mpi/mpi2_tool.h | 481 -- drivers/scsi/mpt2sas/mpi/mpi2_type.h | 61 - drivers/scsi/mpt2sas/mpt2sas_base.c | 4899 --------------- drivers/scsi/mpt2sas/mpt2sas_base.h | 1235 ---- drivers/scsi/mpt2sas/mpt2sas_config.c | 1527 ----- drivers/scsi/mpt2sas/mpt2sas_ctl.c | 3101 ---------- drivers/scsi/mpt2sas/mpt2sas_ctl.h | 419 -- drivers/scsi/mpt2sas/mpt2sas_debug.h | 182 - drivers/scsi/mpt2sas/mpt2sas_scsih.c | 8855 --------------------------- drivers/scsi/mpt2sas/mpt2sas_transport.c | 2173 ------- drivers/scsi/mpt3sas/Kconfig | 27 +- drivers/scsi/mpt3sas/Makefile | 3 +- drivers/scsi/mpt3sas/mpt3sas_base.c | 668 +- drivers/scsi/mpt3sas/mpt3sas_base.h | 233 +- drivers/scsi/mpt3sas/mpt3sas_config.c | 42 +- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 259 +- drivers/scsi/mpt3sas/mpt3sas_ctl.h | 6 +- drivers/scsi/mpt3sas/mpt3sas_debug.h | 16 +- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 1556 +++-- drivers/scsi/mpt3sas/mpt3sas_transport.c | 18 +- drivers/scsi/mpt3sas/mpt3sas_warpdrive.c | 344 ++ drivers/scsi/mvsas/mv_init.c | 7 +- drivers/scsi/mvumi.c | 10 +- drivers/scsi/pm8001/pm8001_defs.h | 2 + drivers/scsi/pm8001/pm8001_init.c | 216 +- drivers/scsi/pm8001/pm8001_sas.h | 6 +- drivers/scsi/pm8001/pm80xx_hwi.c | 34 + drivers/scsi/pmcraid.c | 6 +- drivers/scsi/qla2xxx/qla_nx.c | 3 +- drivers/scsi/qla2xxx/qla_os.c | 1 - drivers/scsi/qla2xxx/tcm_qla2xxx.c | 153 +- drivers/scsi/qla4xxx/ql4_nx.c | 2 +- drivers/scsi/qla4xxx/ql4_os.c | 8 - drivers/scsi/scsi.c | 27 +- drivers/scsi/scsi_debug.c | 9 +- drivers/scsi/scsi_devinfo.c | 181 +- drivers/scsi/scsi_error.c | 2 +- drivers/scsi/scsi_lib.c | 4 +- drivers/scsi/scsi_pm.c | 20 +- drivers/scsi/scsi_scan.c | 18 +- drivers/scsi/scsi_sysfs.c | 50 +- drivers/scsi/sd.c | 170 +- drivers/scsi/sd.h | 1 + drivers/scsi/sd_dif.c | 31 +- drivers/scsi/ses.c | 30 +- drivers/scsi/sg.c | 8 +- drivers/scsi/snic/snic_main.c | 10 - drivers/scsi/snic/snic_trc.c | 4 +- drivers/scsi/snic/snic_trc.h | 2 +- drivers/scsi/st.c | 35 +- drivers/scsi/stex.c | 21 +- drivers/scsi/storvsc_drv.c | 294 +- drivers/scsi/ufs/Kconfig | 2 +- drivers/scsi/ufs/ufs-qcom.c | 905 ++- drivers/scsi/ufs/ufs-qcom.h | 68 +- drivers/scsi/ufs/ufshcd-pltfrm.c | 98 +- drivers/scsi/ufs/ufshcd-pltfrm.h | 41 + drivers/scsi/ufs/ufshcd.c | 130 +- drivers/scsi/ufs/ufshcd.h | 149 +- 153 files changed, 8111 insertions(+), 33965 deletions(-) delete mode 100644 drivers/scsi/mpt2sas/Kconfig delete mode 100644 drivers/scsi/mpt2sas/Makefile delete mode 100644 drivers/scsi/mpt2sas/mpi/mpi2.h delete mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h delete mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_init.h delete mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_ioc.h delete mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_raid.h delete mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_sas.h delete mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_tool.h delete mode 100644 drivers/scsi/mpt2sas/mpi/mpi2_type.h delete mode 100644 drivers/scsi/mpt2sas/mpt2sas_base.c delete mode 100644 drivers/scsi/mpt2sas/mpt2sas_base.h delete mode 100644 drivers/scsi/mpt2sas/mpt2sas_config.c delete mode 100644 drivers/scsi/mpt2sas/mpt2sas_ctl.c delete mode 100644 drivers/scsi/mpt2sas/mpt2sas_ctl.h delete mode 100644 drivers/scsi/mpt2sas/mpt2sas_debug.h delete mode 100644 drivers/scsi/mpt2sas/mpt2sas_scsih.c delete mode 100644 drivers/scsi/mpt2sas/mpt2sas_transport.c create mode 100644 drivers/scsi/mpt3sas/mpt3sas_warpdrive.c create mode 100644 drivers/scsi/ufs/ufshcd-pltfrm.h (limited to 'drivers/scsi') diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index a209c3418..d4c285688 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -325,7 +325,6 @@ NCR_700_detect(struct scsi_host_template *tpnt, tpnt->slave_destroy = NCR_700_slave_destroy; tpnt->slave_alloc = NCR_700_slave_alloc; tpnt->change_queue_depth = NCR_700_change_queue_depth; - tpnt->use_blk_tags = 1; if(tpnt->name == NULL) tpnt->name = "53c700"; @@ -1107,7 +1106,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, BUG(); } if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) { - struct scsi_cmnd *SCp = scsi_find_tag(SDp, hostdata->msgin[2]); + struct scsi_cmnd *SCp; + + SCp = scsi_host_find_tag(SDp->host, hostdata->msgin[2]); if(unlikely(SCp == NULL)) { printk(KERN_ERR "scsi%d: (%d:%d) no saved request for tag %d\n", host->host_no, reselection_id, lun, hostdata->msgin[2]); @@ -1119,7 +1120,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, "reselection is tag %d, slot %p(%d)\n", hostdata->msgin[2], slot, slot->tag); } else { - struct scsi_cmnd *SCp = scsi_find_tag(SDp, SCSI_NO_TAG); + struct scsi_cmnd *SCp; + + SCp = scsi_host_find_tag(SDp->host, SCSI_NO_TAG); if(unlikely(SCp == NULL)) { sdev_printk(KERN_ERR, SDp, "no saved request for untagged cmd\n"); @@ -1823,7 +1826,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *) slot->tag, slot); } else { slot->tag = SCSI_NO_TAG; - /* must populate current_cmnd for scsi_find_tag to work */ + /* must populate current_cmnd for scsi_host_find_tag to work */ SCp->device->current_cmnd = SCp; } /* sanity check: some of the commands generated by the mid-layer diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c index 5c74e4c52..867b864f5 100644 --- a/drivers/scsi/FlashPoint.c +++ b/drivers/scsi/FlashPoint.c @@ -2136,7 +2136,7 @@ static unsigned char FPT_SccbMgr_bad_isr(u32 p_port, unsigned char p_card, * *---------------------------------------------------------------------*/ -static void FPT_SccbMgrTableInitAll() +static void FPT_SccbMgrTableInitAll(void) { unsigned char thisCard; diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 95f7a76cf..64eed87d3 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -242,13 +242,6 @@ config SCSI_SCAN_ASYNC system continues booting, and even probe devices on different busses in parallel, leading to a significant speed-up. - If you have built SCSI as modules, enabling this option can - be a problem as the devices may not have been found by the - time your system expects them to have been. You can load the - scsi_wait_scan module to ensure that all scans have completed. - If you build your SCSI drivers into the kernel, then everything - will work fine if you say Y here. - You can override this choice by specifying "scsi_mod.scan=sync" or async on the kernel's command line. @@ -371,6 +364,7 @@ config SCSI_HPSA tristate "HP Smart Array SCSI driver" depends on PCI && SCSI select CHECK_SIGNATURE + select SCSI_SAS_ATTRS help This driver supports HP Smart Array Controllers (circa 2009). It is a SCSI alternative to the cciss driver, which is a block @@ -506,6 +500,7 @@ config SCSI_ADVANSYS tristate "AdvanSys SCSI support" depends on SCSI depends on ISA || EISA || PCI + depends on ISA_DMA_API || !ISA help This is a driver for all SCSI host adapters manufactured by AdvanSys. It is documented in the kernel source in @@ -541,7 +536,6 @@ config SCSI_ARCMSR source "drivers/scsi/esas2r/Kconfig" source "drivers/scsi/megaraid/Kconfig.megaraid" -source "drivers/scsi/mpt2sas/Kconfig" source "drivers/scsi/mpt3sas/Kconfig" source "drivers/scsi/ufs/Kconfig" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 1a8c9b53f..c14bca4a9 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -106,7 +106,6 @@ obj-$(CONFIG_CXLFLASH) += cxlflash/ obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ obj-$(CONFIG_MEGARAID_SAS) += megaraid/ -obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas/ obj-$(CONFIG_SCSI_MPT3SAS) += mpt3sas/ obj-$(CONFIG_SCSI_UFSHCD) += ufs/ obj-$(CONFIG_SCSI_ACARD) += atp870u.o diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 9b3dd6ef6..e4c243748 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -259,7 +259,7 @@ MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the" " 0=off, 1=on"); module_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(msi, "IRQ handling." - " 0=PIC(default), 1=MSI, 2=MSI-X(unsupported, uses MSI)"); + " 0=PIC(default), 1=MSI, 2=MSI-X)"); module_param(startup_timeout, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for" " adapter to have it's kernel up and\n" @@ -570,7 +570,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd) status = aac_fib_send(ContainerCommand, cmd_fibcontext, - sizeof (struct aac_get_name), + sizeof(struct aac_get_name_resp), FsaNormal, 0, 1, (fib_callback)get_container_name_callback, @@ -1052,7 +1052,7 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd) status = aac_fib_send(ContainerCommand, cmd_fibcontext, - sizeof (struct aac_get_serial), + sizeof(struct aac_get_serial_resp), FsaNormal, 0, 1, (fib_callback) get_container_serial_callback, @@ -2977,11 +2977,16 @@ static void aac_srb_callback(void *context, struct fib * fibptr) return; BUG_ON(fibptr == NULL); - dev = fibptr->dev; - srbreply = (struct aac_srb_reply *) fib_data(fibptr); + scsi_dma_unmap(scsicmd); + /* expose physical device if expose_physicald flag is on */ + if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01) + && expose_physicals > 0) + aac_expose_phy_device(scsicmd); + + srbreply = (struct aac_srb_reply *) fib_data(fibptr); scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */ if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) { @@ -2994,147 +2999,157 @@ static void aac_srb_callback(void *context, struct fib * fibptr) */ scsi_set_resid(scsicmd, scsi_bufflen(scsicmd) - le32_to_cpu(srbreply->data_xfer_length)); - } - - scsi_dma_unmap(scsicmd); - - /* expose physical device if expose_physicald flag is on */ - if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01) - && expose_physicals > 0) - aac_expose_phy_device(scsicmd); + /* + * First check the fib status + */ - /* - * First check the fib status - */ + if (le32_to_cpu(srbreply->status) != ST_OK) { + int len; - if (le32_to_cpu(srbreply->status) != ST_OK){ - int len; - printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status)); - len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), - SCSI_SENSE_BUFFERSIZE); - scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - memcpy(scsicmd->sense_buffer, srbreply->sense_data, len); - } + printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status)); + len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), + SCSI_SENSE_BUFFERSIZE); + scsicmd->result = DID_ERROR << 16 + | COMMAND_COMPLETE << 8 + | SAM_STAT_CHECK_CONDITION; + memcpy(scsicmd->sense_buffer, + srbreply->sense_data, len); + } - /* - * Next check the srb status - */ - switch( (le32_to_cpu(srbreply->srb_status))&0x3f){ - case SRB_STATUS_ERROR_RECOVERY: - case SRB_STATUS_PENDING: - case SRB_STATUS_SUCCESS: - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; - break; - case SRB_STATUS_DATA_OVERRUN: - switch(scsicmd->cmnd[0]){ - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - case READ_16: - case WRITE_16: - if (le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow) { - printk(KERN_WARNING"aacraid: SCSI CMD underflow\n"); - } else { - printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n"); + /* + * Next check the srb status + */ + switch ((le32_to_cpu(srbreply->srb_status))&0x3f) { + case SRB_STATUS_ERROR_RECOVERY: + case SRB_STATUS_PENDING: + case SRB_STATUS_SUCCESS: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + break; + case SRB_STATUS_DATA_OVERRUN: + switch (scsicmd->cmnd[0]) { + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + case READ_12: + case WRITE_12: + case READ_16: + case WRITE_16: + if (le32_to_cpu(srbreply->data_xfer_length) + < scsicmd->underflow) + printk(KERN_WARNING"aacraid: SCSI CMD underflow\n"); + else + printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n"); + scsicmd->result = DID_ERROR << 16 + | COMMAND_COMPLETE << 8; + break; + case INQUIRY: { + scsicmd->result = DID_OK << 16 + | COMMAND_COMPLETE << 8; + break; + } + default: + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + break; } - scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; break; - case INQUIRY: { - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + case SRB_STATUS_ABORTED: + scsicmd->result = DID_ABORT << 16 | ABORT << 8; break; - } - default: - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + case SRB_STATUS_ABORT_FAILED: + /* + * Not sure about this one - but assuming the + * hba was trying to abort for some reason + */ + scsicmd->result = DID_ERROR << 16 | ABORT << 8; + break; + case SRB_STATUS_PARITY_ERROR: + scsicmd->result = DID_PARITY << 16 + | MSG_PARITY_ERROR << 8; + break; + case SRB_STATUS_NO_DEVICE: + case SRB_STATUS_INVALID_PATH_ID: + case SRB_STATUS_INVALID_TARGET_ID: + case SRB_STATUS_INVALID_LUN: + case SRB_STATUS_SELECTION_TIMEOUT: + scsicmd->result = DID_NO_CONNECT << 16 + | COMMAND_COMPLETE << 8; break; - } - break; - case SRB_STATUS_ABORTED: - scsicmd->result = DID_ABORT << 16 | ABORT << 8; - break; - case SRB_STATUS_ABORT_FAILED: - // Not sure about this one - but assuming the hba was trying to abort for some reason - scsicmd->result = DID_ERROR << 16 | ABORT << 8; - break; - case SRB_STATUS_PARITY_ERROR: - scsicmd->result = DID_PARITY << 16 | MSG_PARITY_ERROR << 8; - break; - case SRB_STATUS_NO_DEVICE: - case SRB_STATUS_INVALID_PATH_ID: - case SRB_STATUS_INVALID_TARGET_ID: - case SRB_STATUS_INVALID_LUN: - case SRB_STATUS_SELECTION_TIMEOUT: - scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; - break; - case SRB_STATUS_COMMAND_TIMEOUT: - case SRB_STATUS_TIMEOUT: - scsicmd->result = DID_TIME_OUT << 16 | COMMAND_COMPLETE << 8; - break; + case SRB_STATUS_COMMAND_TIMEOUT: + case SRB_STATUS_TIMEOUT: + scsicmd->result = DID_TIME_OUT << 16 + | COMMAND_COMPLETE << 8; + break; - case SRB_STATUS_BUSY: - scsicmd->result = DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8; - break; + case SRB_STATUS_BUSY: + scsicmd->result = DID_BUS_BUSY << 16 + | COMMAND_COMPLETE << 8; + break; - case SRB_STATUS_BUS_RESET: - scsicmd->result = DID_RESET << 16 | COMMAND_COMPLETE << 8; - break; + case SRB_STATUS_BUS_RESET: + scsicmd->result = DID_RESET << 16 + | COMMAND_COMPLETE << 8; + break; - case SRB_STATUS_MESSAGE_REJECTED: - scsicmd->result = DID_ERROR << 16 | MESSAGE_REJECT << 8; - break; - case SRB_STATUS_REQUEST_FLUSHED: - case SRB_STATUS_ERROR: - case SRB_STATUS_INVALID_REQUEST: - case SRB_STATUS_REQUEST_SENSE_FAILED: - case SRB_STATUS_NO_HBA: - case SRB_STATUS_UNEXPECTED_BUS_FREE: - case SRB_STATUS_PHASE_SEQUENCE_FAILURE: - case SRB_STATUS_BAD_SRB_BLOCK_LENGTH: - case SRB_STATUS_DELAYED_RETRY: - case SRB_STATUS_BAD_FUNCTION: - case SRB_STATUS_NOT_STARTED: - case SRB_STATUS_NOT_IN_USE: - case SRB_STATUS_FORCE_ABORT: - case SRB_STATUS_DOMAIN_VALIDATION_FAIL: - default: + case SRB_STATUS_MESSAGE_REJECTED: + scsicmd->result = DID_ERROR << 16 + | MESSAGE_REJECT << 8; + break; + case SRB_STATUS_REQUEST_FLUSHED: + case SRB_STATUS_ERROR: + case SRB_STATUS_INVALID_REQUEST: + case SRB_STATUS_REQUEST_SENSE_FAILED: + case SRB_STATUS_NO_HBA: + case SRB_STATUS_UNEXPECTED_BUS_FREE: + case SRB_STATUS_PHASE_SEQUENCE_FAILURE: + case SRB_STATUS_BAD_SRB_BLOCK_LENGTH: + case SRB_STATUS_DELAYED_RETRY: + case SRB_STATUS_BAD_FUNCTION: + case SRB_STATUS_NOT_STARTED: + case SRB_STATUS_NOT_IN_USE: + case SRB_STATUS_FORCE_ABORT: + case SRB_STATUS_DOMAIN_VALIDATION_FAIL: + default: #ifdef AAC_DETAILED_STATUS_INFO - printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n", - le32_to_cpu(srbreply->srb_status) & 0x3F, - aac_get_status_string( - le32_to_cpu(srbreply->srb_status) & 0x3F), - scsicmd->cmnd[0], - le32_to_cpu(srbreply->scsi_status)); + printk(KERN_INFO "aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n", + le32_to_cpu(srbreply->srb_status) & 0x3F, + aac_get_status_string( + le32_to_cpu(srbreply->srb_status) & 0x3F), + scsicmd->cmnd[0], + le32_to_cpu(srbreply->scsi_status)); #endif - if ((scsicmd->cmnd[0] == ATA_12) - || (scsicmd->cmnd[0] == ATA_16)) { - if (scsicmd->cmnd[2] & (0x01 << 5)) { - scsicmd->result = DID_OK << 16 - | COMMAND_COMPLETE << 8; + if ((scsicmd->cmnd[0] == ATA_12) + || (scsicmd->cmnd[0] == ATA_16)) { + if (scsicmd->cmnd[2] & (0x01 << 5)) { + scsicmd->result = DID_OK << 16 + | COMMAND_COMPLETE << 8; break; + } else { + scsicmd->result = DID_ERROR << 16 + | COMMAND_COMPLETE << 8; + break; + } } else { scsicmd->result = DID_ERROR << 16 - | COMMAND_COMPLETE << 8; + | COMMAND_COMPLETE << 8; break; } - } else { - scsicmd->result = DID_ERROR << 16 - | COMMAND_COMPLETE << 8; - break; } - } - if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) { - int len; - scsicmd->result |= SAM_STAT_CHECK_CONDITION; - len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), - SCSI_SENSE_BUFFERSIZE); + if (le32_to_cpu(srbreply->scsi_status) + == SAM_STAT_CHECK_CONDITION) { + int len; + + scsicmd->result |= SAM_STAT_CHECK_CONDITION; + len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), + SCSI_SENSE_BUFFERSIZE); #ifdef AAC_DETAILED_STATUS_INFO - printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", - le32_to_cpu(srbreply->status), len); + printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", + le32_to_cpu(srbreply->status), len); #endif - memcpy(scsicmd->sense_buffer, srbreply->sense_data, len); + memcpy(scsicmd->sense_buffer, + srbreply->sense_data, len); + } } /* * OR in the scsi status (already shifted up a bit) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 40fe65c91..074878b55 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -12,7 +12,7 @@ * D E F I N E S *----------------------------------------------------------------------------*/ -#define AAC_MAX_MSIX 8 /* vectors */ +#define AAC_MAX_MSIX 32 /* vectors */ #define AAC_PCI_MSI_ENABLE 0x8000 enum { @@ -62,7 +62,7 @@ enum { #define PMC_GLOBAL_INT_BIT0 0x00000001 #ifndef AAC_DRIVER_BUILD -# define AAC_DRIVER_BUILD 40709 +# define AAC_DRIVER_BUILD 41010 # define AAC_DRIVER_BRANCH "-ms" #endif #define MAXIMUM_NUM_CONTAINERS 32 @@ -547,6 +547,7 @@ struct adapter_ops int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4); int (*adapter_check_health)(struct aac_dev *dev); int (*adapter_restart)(struct aac_dev *dev, int bled); + void (*adapter_start)(struct aac_dev *dev); /* Transport operations */ int (*adapter_ioremap)(struct aac_dev * dev, u32 size); irq_handler_t adapter_intr; @@ -843,6 +844,10 @@ struct src_registers { &((AEP)->regs.src.bar0->CSR)) #define src_writel(AEP, CSR, value) writel(value, \ &((AEP)->regs.src.bar0->CSR)) +#if defined(writeq) +#define src_writeq(AEP, CSR, value) writeq(value, \ + &((AEP)->regs.src.bar0->CSR)) +#endif #define SRC_ODR_SHIFT 12 #define SRC_IDR_SHIFT 9 @@ -1162,6 +1167,11 @@ struct aac_dev struct fsa_dev_info *fsa_dev; struct task_struct *thread; int cardtype; + /* + *This lock will protect the two 32-bit + *writes to the Inbound Queue + */ + spinlock_t iq_lock; /* * The following is the device specific extension. @@ -1247,6 +1257,9 @@ struct aac_dev #define aac_adapter_restart(dev,bled) \ (dev)->a_ops.adapter_restart(dev,bled) +#define aac_adapter_start(dev) \ + ((dev)->a_ops.adapter_start(dev)) + #define aac_adapter_ioremap(dev, size) \ (dev)->a_ops.adapter_ioremap(dev, size) @@ -2097,6 +2110,8 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor) #define AAC_OWNER_ERROR_HANDLER 0x103 #define AAC_OWNER_FIRMWARE 0x106 +int aac_acquire_irq(struct aac_dev *dev); +void aac_free_irq(struct aac_dev *dev); const char *aac_driverinfo(struct Scsi_Host *); struct fib *aac_fib_alloc(struct aac_dev *dev); int aac_fib_setup(struct aac_dev *dev); @@ -2127,6 +2142,7 @@ int aac_sa_init(struct aac_dev *dev); int aac_src_init(struct aac_dev *dev); int aac_srcv_init(struct aac_dev *dev); int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify); +void aac_define_int_mode(struct aac_dev *dev); unsigned int aac_response_normal(struct aac_queue * q); unsigned int aac_command_normal(struct aac_queue * q); unsigned int aac_intr_normal(struct aac_dev *dev, u32 Index, diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 45db84ad3..0e954e37f 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -43,8 +43,6 @@ #include "aacraid.h" -static void aac_define_int_mode(struct aac_dev *dev); - struct aac_common aac_config = { .irq_mod = 1 }; @@ -338,6 +336,74 @@ static int aac_comm_init(struct aac_dev * dev) return 0; } +void aac_define_int_mode(struct aac_dev *dev) +{ + int i, msi_count, min_msix; + + msi_count = i = 0; + /* max. vectors from GET_COMM_PREFERRED_SETTINGS */ + if (dev->max_msix == 0 || + dev->pdev->device == PMC_DEVICE_S6 || + dev->sync_mode) { + dev->max_msix = 1; + dev->vector_cap = + dev->scsi_host_ptr->can_queue + + AAC_NUM_MGT_FIB; + return; + } + + /* Don't bother allocating more MSI-X vectors than cpus */ + msi_count = min(dev->max_msix, + (unsigned int)num_online_cpus()); + + dev->max_msix = msi_count; + + if (msi_count > AAC_MAX_MSIX) + msi_count = AAC_MAX_MSIX; + + for (i = 0; i < msi_count; i++) + dev->msixentry[i].entry = i; + + if (msi_count > 1 && + pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) { + min_msix = 2; + i = pci_enable_msix_range(dev->pdev, + dev->msixentry, + min_msix, + msi_count); + if (i > 0) { + dev->msi_enabled = 1; + msi_count = i; + } else { + dev->msi_enabled = 0; + printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n", + dev->name, dev->id, i); + } + } + + if (!dev->msi_enabled) { + msi_count = 1; + i = pci_enable_msi(dev->pdev); + + if (!i) { + dev->msi_enabled = 1; + dev->msi = 1; + } else { + printk(KERN_ERR "%s%d: MSI not supported!! Will try INTx 0x%x.\n", + dev->name, dev->id, i); + } + } + + if (!dev->msi_enabled) + dev->max_msix = msi_count = 1; + else { + if (dev->max_msix > msi_count) + dev->max_msix = msi_count; + } + dev->vector_cap = + (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) / + msi_count; +} struct aac_dev *aac_init_adapter(struct aac_dev *dev) { u32 status[5]; @@ -350,6 +416,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) dev->management_fib_count = 0; spin_lock_init(&dev->manage_lock); spin_lock_init(&dev->sync_lock); + spin_lock_init(&dev->iq_lock); dev->max_fib_size = sizeof(struct hw_fib); dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size - sizeof(struct aac_fibhdr) @@ -508,79 +575,3 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) return dev; } -static void aac_define_int_mode(struct aac_dev *dev) -{ - - int i, msi_count; - - msi_count = i = 0; - /* max. vectors from GET_COMM_PREFERRED_SETTINGS */ - if (dev->max_msix == 0 || - dev->pdev->device == PMC_DEVICE_S6 || - dev->sync_mode) { - dev->max_msix = 1; - dev->vector_cap = - dev->scsi_host_ptr->can_queue + - AAC_NUM_MGT_FIB; - return; - } - - msi_count = min(dev->max_msix, - (unsigned int)num_online_cpus()); - - dev->max_msix = msi_count; - - if (msi_count > AAC_MAX_MSIX) - msi_count = AAC_MAX_MSIX; - - for (i = 0; i < msi_count; i++) - dev->msixentry[i].entry = i; - - if (msi_count > 1 && - pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) { - i = pci_enable_msix(dev->pdev, - dev->msixentry, - msi_count); - /* Check how many MSIX vectors are allocated */ - if (i >= 0) { - dev->msi_enabled = 1; - if (i) { - msi_count = i; - if (pci_enable_msix(dev->pdev, - dev->msixentry, - msi_count)) { - dev->msi_enabled = 0; - printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n", - dev->name, dev->id, i); - } - } - } else { - dev->msi_enabled = 0; - printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n", - dev->name, dev->id, i); - } - } - - if (!dev->msi_enabled) { - msi_count = 1; - i = pci_enable_msi(dev->pdev); - - if (!i) { - dev->msi_enabled = 1; - dev->msi = 1; - } else { - printk(KERN_ERR "%s%d: MSI not supported!! Will try INTx 0x%x.\n", - dev->name, dev->id, i); - } - } - - if (!dev->msi_enabled) - dev->max_msix = msi_count = 1; - else { - if (dev->max_msix > msi_count) - dev->max_msix = msi_count; - } - dev->vector_cap = - (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) / - msi_count; -} diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 4da574925..a1f90fe84 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1270,13 +1270,12 @@ retry_next: static int _aac_reset_adapter(struct aac_dev *aac, int forced) { int index, quirks; - int retval, i; + int retval; struct Scsi_Host *host; struct scsi_device *dev; struct scsi_cmnd *command; struct scsi_cmnd *command_list; int jafo = 0; - int cpu; /* * Assumptions: @@ -1339,35 +1338,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced) aac->comm_phys = 0; kfree(aac->queues); aac->queues = NULL; - cpu = cpumask_first(cpu_online_mask); - if (aac->pdev->device == PMC_DEVICE_S6 || - aac->pdev->device == PMC_DEVICE_S7 || - aac->pdev->device == PMC_DEVICE_S8 || - aac->pdev->device == PMC_DEVICE_S9) { - if (aac->max_msix > 1) { - for (i = 0; i < aac->max_msix; i++) { - if (irq_set_affinity_hint( - aac->msixentry[i].vector, - NULL)) { - printk(KERN_ERR "%s%d: Failed to reset IRQ affinity for cpu %d\n", - aac->name, - aac->id, - cpu); - } - cpu = cpumask_next(cpu, - cpu_online_mask); - free_irq(aac->msixentry[i].vector, - &(aac->aac_msix[i])); - } - pci_disable_msix(aac->pdev); - } else { - free_irq(aac->pdev->irq, &(aac->aac_msix[0])); - } - } else { - free_irq(aac->pdev->irq, aac); - } - if (aac->msi) - pci_disable_msi(aac->pdev); + aac_free_irq(aac); kfree(aac->fsa_dev); aac->fsa_dev = NULL; quirks = aac_get_driver_ident(index)->quirks; @@ -1978,3 +1949,83 @@ int aac_command_thread(void *data) dev->aif_thread = 0; return 0; } + +int aac_acquire_irq(struct aac_dev *dev) +{ + int i; + int j; + int ret = 0; + int cpu; + + cpu = cpumask_first(cpu_online_mask); + if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) { + for (i = 0; i < dev->max_msix; i++) { + dev->aac_msix[i].vector_no = i; + dev->aac_msix[i].dev = dev; + if (request_irq(dev->msixentry[i].vector, + dev->a_ops.adapter_intr, + 0, "aacraid", &(dev->aac_msix[i]))) { + printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n", + dev->name, dev->id, i); + for (j = 0 ; j < i ; j++) + free_irq(dev->msixentry[j].vector, + &(dev->aac_msix[j])); + pci_disable_msix(dev->pdev); + ret = -1; + } + if (irq_set_affinity_hint(dev->msixentry[i].vector, + get_cpu_mask(cpu))) { + printk(KERN_ERR "%s%d: Failed to set IRQ affinity for cpu %d\n", + dev->name, dev->id, cpu); + } + cpu = cpumask_next(cpu, cpu_online_mask); + } + } else { + dev->aac_msix[0].vector_no = 0; + dev->aac_msix[0].dev = dev; + + if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, + IRQF_SHARED, "aacraid", + &(dev->aac_msix[0])) < 0) { + if (dev->msi) + pci_disable_msi(dev->pdev); + printk(KERN_ERR "%s%d: Interrupt unavailable.\n", + dev->name, dev->id); + ret = -1; + } + } + return ret; +} + +void aac_free_irq(struct aac_dev *dev) +{ + int i; + int cpu; + + cpu = cpumask_first(cpu_online_mask); + if (dev->pdev->device == PMC_DEVICE_S6 || + dev->pdev->device == PMC_DEVICE_S7 || + dev->pdev->device == PMC_DEVICE_S8 || + dev->pdev->device == PMC_DEVICE_S9) { + if (dev->max_msix > 1) { + for (i = 0; i < dev->max_msix; i++) { + if (irq_set_affinity_hint( + dev->msixentry[i].vector, NULL)) { + printk(KERN_ERR "%s%d: Failed to reset IRQ affinity for cpu %d\n", + dev->name, dev->id, cpu); + } + cpu = cpumask_next(cpu, cpu_online_mask); + free_irq(dev->msixentry[i].vector, + &(dev->aac_msix[i])); + } + } else { + free_irq(dev->pdev->irq, &(dev->aac_msix[0])); + } + } else { + free_irq(dev->pdev->irq, dev); + } + if (dev->msi) + pci_disable_msi(dev->pdev); + else if (dev->max_msix > 1) + pci_disable_msix(dev->pdev); +} diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 9eec02733..3b6e5c67e 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1317,6 +1317,154 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) return error; } +#if (defined(CONFIG_PM)) +void aac_release_resources(struct aac_dev *aac) +{ + int i; + + aac_adapter_disable_int(aac); + if (aac->pdev->device == PMC_DEVICE_S6 || + aac->pdev->device == PMC_DEVICE_S7 || + aac->pdev->device == PMC_DEVICE_S8 || + aac->pdev->device == PMC_DEVICE_S9) { + if (aac->max_msix > 1) { + for (i = 0; i < aac->max_msix; i++) + free_irq(aac->msixentry[i].vector, + &(aac->aac_msix[i])); + } else { + free_irq(aac->pdev->irq, &(aac->aac_msix[0])); + } + } else { + free_irq(aac->pdev->irq, aac); + } + if (aac->msi) + pci_disable_msi(aac->pdev); + else if (aac->max_msix > 1) + pci_disable_msix(aac->pdev); + +} + +static int aac_acquire_resources(struct aac_dev *dev) +{ + int i, j; + int instance = dev->id; + const char *name = dev->name; + unsigned long status; + /* + * First clear out all interrupts. Then enable the one's that we + * can handle. + */ + while (!((status = src_readl(dev, MUnit.OMR)) & KERNEL_UP_AND_RUNNING) + || status == 0xffffffff) + msleep(20); + + aac_adapter_disable_int(dev); + aac_adapter_enable_int(dev); + + + if ((dev->pdev->device == PMC_DEVICE_S7 || + dev->pdev->device == PMC_DEVICE_S8 || + dev->pdev->device == PMC_DEVICE_S9)) + aac_define_int_mode(dev); + + if (dev->msi_enabled) + aac_src_access_devreg(dev, AAC_ENABLE_MSIX); + + if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) { + for (i = 0; i < dev->max_msix; i++) { + dev->aac_msix[i].vector_no = i; + dev->aac_msix[i].dev = dev; + + if (request_irq(dev->msixentry[i].vector, + dev->a_ops.adapter_intr, + 0, "aacraid", &(dev->aac_msix[i]))) { + printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n", + name, instance, i); + for (j = 0 ; j < i ; j++) + free_irq(dev->msixentry[j].vector, + &(dev->aac_msix[j])); + pci_disable_msix(dev->pdev); + goto error_iounmap; + } + } + } else { + dev->aac_msix[0].vector_no = 0; + dev->aac_msix[0].dev = dev; + + if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, + IRQF_SHARED, "aacraid", + &(dev->aac_msix[0])) < 0) { + if (dev->msi) + pci_disable_msi(dev->pdev); + printk(KERN_ERR "%s%d: Interrupt unavailable.\n", + name, instance); + goto error_iounmap; + } + } + + aac_adapter_enable_int(dev); + + if (!dev->sync_mode) + aac_adapter_start(dev); + return 0; + +error_iounmap: + return -1; + +} +static int aac_suspend(struct pci_dev *pdev, pm_message_t state) +{ + + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct aac_dev *aac = (struct aac_dev *)shost->hostdata; + + scsi_block_requests(shost); + aac_send_shutdown(aac); + + aac_release_resources(aac); + + pci_set_drvdata(pdev, shost); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int aac_resume(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct aac_dev *aac = (struct aac_dev *)shost->hostdata; + int r; + + pci_set_power_state(pdev, PCI_D0); + pci_enable_wake(pdev, PCI_D0, 0); + pci_restore_state(pdev); + r = pci_enable_device(pdev); + + if (r) + goto fail_device; + + pci_set_master(pdev); + if (aac_acquire_resources(aac)) + goto fail_device; + /* + * reset this flag to unblock ioctl() as it was set at + * aac_send_shutdown() to block ioctls from upperlayer + */ + aac->adapter_shutdown = 0; + scsi_unblock_requests(shost); + + return 0; + +fail_device: + printk(KERN_INFO "%s%d: resume failed.\n", aac->name, aac->id); + scsi_host_put(shost); + pci_disable_device(pdev); + return -ENODEV; +} +#endif + static void aac_shutdown(struct pci_dev *dev) { struct Scsi_Host *shost = pci_get_drvdata(dev); @@ -1356,6 +1504,10 @@ static struct pci_driver aac_pci_driver = { .id_table = aac_pci_tbl, .probe = aac_probe_one, .remove = aac_remove_one, +#if (defined(CONFIG_PM)) + .suspend = aac_suspend, + .resume = aac_resume, +#endif .shutdown = aac_shutdown, }; diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 9570612b8..ac1638069 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -623,6 +623,7 @@ int _aac_rx_init(struct aac_dev *dev) dev->a_ops.adapter_sync_cmd = rx_sync_cmd; dev->a_ops.adapter_check_health = aac_rx_check_health; dev->a_ops.adapter_restart = aac_rx_restart_adapter; + dev->a_ops.adapter_start = aac_rx_start_adapter; /* * First clear out all interrupts. Then enable the one's that we diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index e66477c98..869aea23c 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -372,6 +372,7 @@ int aac_sa_init(struct aac_dev *dev) dev->a_ops.adapter_sync_cmd = sa_sync_cmd; dev->a_ops.adapter_check_health = aac_sa_check_health; dev->a_ops.adapter_restart = aac_sa_restart_adapter; + dev->a_ops.adapter_start = aac_sa_start_adapter; dev->a_ops.adapter_intr = aac_sa_intr; dev->a_ops.adapter_deliver = aac_rx_deliver_producer; dev->a_ops.adapter_ioremap = aac_sa_ioremap; diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c index e63cf9f22..2aa34ea8c 100644 --- a/drivers/scsi/aacraid/src.c +++ b/drivers/scsi/aacraid/src.c @@ -447,6 +447,10 @@ static int aac_src_deliver_message(struct fib *fib) u32 fibsize; dma_addr_t address; struct aac_fib_xporthdr *pFibX; +#if !defined(writeq) + unsigned long flags; +#endif + u16 hdr_size = le16_to_cpu(fib->hw_fib_va->header.Size); atomic_inc(&q->numpending); @@ -511,10 +515,14 @@ static int aac_src_deliver_message(struct fib *fib) return -EINVAL; address |= fibsize; } - +#if defined(writeq) + src_writeq(dev, MUnit.IQ_L, (u64)address); +#else + spin_lock_irqsave(&fib->dev->iq_lock, flags); src_writel(dev, MUnit.IQ_H, upper_32_bits(address) & 0xffffffff); src_writel(dev, MUnit.IQ_L, address & 0xffffffff); - + spin_unlock_irqrestore(&fib->dev->iq_lock, flags); +#endif return 0; } @@ -726,6 +734,7 @@ int aac_src_init(struct aac_dev *dev) dev->a_ops.adapter_sync_cmd = src_sync_cmd; dev->a_ops.adapter_check_health = aac_src_check_health; dev->a_ops.adapter_restart = aac_src_restart_adapter; + dev->a_ops.adapter_start = aac_src_start_adapter; /* * First clear out all interrupts. Then enable the one's that we @@ -741,7 +750,7 @@ int aac_src_init(struct aac_dev *dev) if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1) goto error_iounmap; - dev->msi = aac_msi && !pci_enable_msi(dev->pdev); + dev->msi = !pci_enable_msi(dev->pdev); dev->aac_msix[0].vector_no = 0; dev->aac_msix[0].dev = dev; @@ -789,9 +798,7 @@ int aac_srcv_init(struct aac_dev *dev) unsigned long status; int restart = 0; int instance = dev->id; - int i, j; const char *name = dev->name; - int cpu; dev->a_ops.adapter_ioremap = aac_srcv_ioremap; dev->a_ops.adapter_comm = aac_src_select_comm; @@ -892,6 +899,7 @@ int aac_srcv_init(struct aac_dev *dev) dev->a_ops.adapter_sync_cmd = src_sync_cmd; dev->a_ops.adapter_check_health = aac_src_check_health; dev->a_ops.adapter_restart = aac_src_restart_adapter; + dev->a_ops.adapter_start = aac_src_start_adapter; /* * First clear out all interrupts. Then enable the one's that we @@ -908,48 +916,10 @@ int aac_srcv_init(struct aac_dev *dev) goto error_iounmap; if (dev->msi_enabled) aac_src_access_devreg(dev, AAC_ENABLE_MSIX); - if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) { - cpu = cpumask_first(cpu_online_mask); - for (i = 0; i < dev->max_msix; i++) { - dev->aac_msix[i].vector_no = i; - dev->aac_msix[i].dev = dev; - - if (request_irq(dev->msixentry[i].vector, - dev->a_ops.adapter_intr, - 0, - "aacraid", - &(dev->aac_msix[i]))) { - printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n", - name, instance, i); - for (j = 0 ; j < i ; j++) - free_irq(dev->msixentry[j].vector, - &(dev->aac_msix[j])); - pci_disable_msix(dev->pdev); - goto error_iounmap; - } - if (irq_set_affinity_hint( - dev->msixentry[i].vector, - get_cpu_mask(cpu))) { - printk(KERN_ERR "%s%d: Failed to set IRQ affinity for cpu %d\n", - name, instance, cpu); - } - cpu = cpumask_next(cpu, cpu_online_mask); - } - } else { - dev->aac_msix[0].vector_no = 0; - dev->aac_msix[0].dev = dev; - - if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, - IRQF_SHARED, - "aacraid", - &(dev->aac_msix[0])) < 0) { - if (dev->msi) - pci_disable_msi(dev->pdev); - printk(KERN_ERR "%s%d: Interrupt unavailable.\n", - name, instance); - goto error_iounmap; - } - } + + if (aac_acquire_irq(dev)) + goto error_iounmap; + dev->dbg_base = dev->base_start; dev->dbg_base_mapped = dev->base; dev->dbg_size = dev->base_size; diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 0c67a3124..5f01b0aa7 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -7803,7 +7803,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, return ASC_BUSY; } scsiqp->sense_addr = cpu_to_le32(sense_addr); - scsiqp->sense_len = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); + scsiqp->sense_len = SCSI_SENSE_BUFFERSIZE; /* Build ADV_SCSI_REQ_Q */ @@ -10819,7 +10819,6 @@ static struct scsi_host_template advansys_template = { * by enabling clustering, I/O throughput increases as well. */ .use_clustering = ENABLE_CLUSTERING, - .use_blk_tags = 1, }; static int advansys_wide_init_chip(struct Scsi_Host *shost) @@ -11211,11 +11210,6 @@ static int advansys_board_found(struct Scsi_Host *shost, unsigned int iop, /* Set maximum number of queues the adapter can handle. */ shost->can_queue = adv_dvc_varp->max_host_qng; } - ret = scsi_init_shared_tag_map(shost, shost->can_queue); - if (ret) { - shost_printk(KERN_ERR, shost, "init tag map failed\n"); - goto err_free_dma; - } /* * Set the maximum number of scatter-gather elements the diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index ce96a0be3..2588b8f84 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -925,7 +925,6 @@ struct scsi_host_template aic79xx_driver_template = { .slave_configure = ahd_linux_slave_configure, .target_alloc = ahd_linux_target_alloc, .target_destroy = ahd_linux_target_destroy, - .use_blk_tags = 1, }; /******************************** Bus DMA *************************************/ diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index a2f2c774c..b846a4683 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -812,7 +812,6 @@ struct scsi_host_template aic7xxx_driver_template = { .slave_configure = ahc_linux_slave_configure, .target_alloc = ahc_linux_target_alloc, .target_destroy = ahc_linux_target_destroy, - .use_blk_tags = 1, }; /**************************** Tasklet Handler *********************************/ diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index f6c336b05..662b2321d 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -73,7 +73,6 @@ static struct scsi_host_template aic94xx_sht = { .eh_bus_reset_handler = sas_eh_bus_reset_handler, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -704,10 +703,10 @@ static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha) { int err; + scsi_remove_host(asd_ha->sas_ha.core.shost); err = sas_unregister_ha(&asd_ha->sas_ha); sas_remove_host(asd_ha->sas_ha.core.shost); - scsi_remove_host(asd_ha->sas_ha.core.shost); scsi_host_put(asd_ha->sas_ha.core.shost); kfree(asd_ha->sas_ha.sas_phy); diff --git a/drivers/scsi/be2iscsi/Kconfig b/drivers/scsi/be2iscsi/Kconfig index ceaca32e7..4e7cad272 100644 --- a/drivers/scsi/be2iscsi/Kconfig +++ b/drivers/scsi/be2iscsi/Kconfig @@ -1,9 +1,9 @@ config BE2ISCSI - tristate "ServerEngines' 10Gbps iSCSI - BladeEngine 2" + tristate "Emulex 10Gbps iSCSI - BladeEngine 2" depends on PCI && SCSI && NET select SCSI_ISCSI_ATTRS select ISCSI_BOOT_SYSFS help - This driver implements the iSCSI functionality for ServerEngines' + This driver implements the iSCSI functionality for Emulex 10Gbps Storage adapter - BladeEngine 2. diff --git a/drivers/scsi/be2iscsi/Makefile b/drivers/scsi/be2iscsi/Makefile index c11f443e3..d0488eaaf 100644 --- a/drivers/scsi/be2iscsi/Makefile +++ b/drivers/scsi/be2iscsi/Makefile @@ -1,5 +1,5 @@ # -# Makefile to build the iSCSI driver for ServerEngine's BladeEngine. +# Makefile to build the iSCSI driver for Emulex OneConnect. # # diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h index 32070099c..77f992e74 100644 --- a/drivers/scsi/be2iscsi/be.h +++ b/drivers/scsi/be2iscsi/be.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -10,7 +10,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index 185391a64..2778089b0 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -10,7 +10,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h index cdfbc5c19..4bfca355f 100644 --- a/drivers/scsi/be2iscsi/be_cmds.h +++ b/drivers/scsi/be2iscsi/be_cmds.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -10,7 +10,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c index 2f0700796..b7087ba69 100644 --- a/drivers/scsi/be2iscsi/be_iscsi.c +++ b/drivers/scsi/be2iscsi/be_iscsi.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -12,7 +12,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c index 7a6dbfbcc..fe0c5143f 100644 --- a/drivers/scsi/be2iscsi/be_main.c +++ b/drivers/scsi/be2iscsi/be_main.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -12,7 +12,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ @@ -50,7 +50,7 @@ static unsigned int enable_msix = 1; MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR); MODULE_VERSION(BUILD_STR); -MODULE_AUTHOR("Avago Technologies"); +MODULE_AUTHOR("Emulex Corporation"); MODULE_LICENSE("GPL"); module_param(be_iopoll_budget, int, 0); module_param(enable_msix, int, 0); @@ -552,7 +552,7 @@ MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); static struct scsi_host_template beiscsi_sht = { .module = THIS_MODULE, - .name = "Avago Technologies 10Gbe open-iscsi Initiator Driver", + .name = "Emulex 10Gbe open-iscsi Initiator Driver", .proc_name = DRV_NAME, .queuecommand = iscsi_queuecommand, .change_queue_depth = scsi_change_queue_depth, @@ -1198,14 +1198,16 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) * alloc_wrb_handle - To allocate a wrb handle * @phba: The hba pointer * @cid: The cid to use for allocation + * @pwrb_context: ptr to ptr to wrb context * * This happens under session_lock until submission to chip */ -struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid) +struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, + struct hwi_wrb_context **pcontext) { struct hwi_wrb_context *pwrb_context; struct hwi_controller *phwi_ctrlr; - struct wrb_handle *pwrb_handle, *pwrb_handle_tmp; + struct wrb_handle *pwrb_handle; uint16_t cri_index = BE_GET_CRI_FROM_CID(cid); phwi_ctrlr = phba->phwi_ctrlr; @@ -1219,9 +1221,9 @@ struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid) pwrb_context->alloc_index = 0; else pwrb_context->alloc_index++; - pwrb_handle_tmp = pwrb_context->pwrb_handle_base[ - pwrb_context->alloc_index]; - pwrb_handle->nxt_wrb_index = pwrb_handle_tmp->wrb_index; + + /* Return the context address */ + *pcontext = pwrb_context; } else pwrb_handle = NULL; return pwrb_handle; @@ -3184,7 +3186,7 @@ be_sgl_create_contiguous(void *virtual_address, { WARN_ON(!virtual_address); WARN_ON(!physical_address); - WARN_ON(!length > 0); + WARN_ON(!length); WARN_ON(!sgl); sgl->va = virtual_address; @@ -4678,6 +4680,7 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, struct beiscsi_offload_params *params) { struct wrb_handle *pwrb_handle; + struct hwi_wrb_context *pwrb_context = NULL; struct beiscsi_hba *phba = beiscsi_conn->phba; struct iscsi_task *task = beiscsi_conn->task; struct iscsi_session *session = task->conn->session; @@ -4692,14 +4695,17 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, beiscsi_cleanup_task(task); spin_unlock_bh(&session->back_lock); - pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid); + pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid, + &pwrb_context); /* Check for the adapter family */ if (is_chip_be2_be3r(phba)) beiscsi_offload_cxn_v0(params, pwrb_handle, - phba->init_mem); + phba->init_mem, + pwrb_context); else - beiscsi_offload_cxn_v2(params, pwrb_handle); + beiscsi_offload_cxn_v2(params, pwrb_handle, + pwrb_context); be_dws_le_to_cpu(pwrb_handle->pwrb, sizeof(struct iscsi_target_context_update_wrb)); @@ -4769,7 +4775,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) goto free_hndls; } io_task->pwrb_handle = alloc_wrb_handle(phba, - beiscsi_conn->beiscsi_conn_cid); + beiscsi_conn->beiscsi_conn_cid, + &io_task->pwrb_context); if (!io_task->pwrb_handle) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, @@ -4803,7 +4810,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) io_task->psgl_handle; io_task->pwrb_handle = alloc_wrb_handle(phba, - beiscsi_conn->beiscsi_conn_cid); + beiscsi_conn->beiscsi_conn_cid, + &io_task->pwrb_context); if (!io_task->pwrb_handle) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | @@ -4839,7 +4847,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) } io_task->pwrb_handle = alloc_wrb_handle(phba, - beiscsi_conn->beiscsi_conn_cid); + beiscsi_conn->beiscsi_conn_cid, + &io_task->pwrb_context); if (!io_task->pwrb_handle) { beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG, @@ -4925,7 +4934,12 @@ int beiscsi_iotask_v2(struct iscsi_task *task, struct scatterlist *sg, hwi_write_sgl_v2(pwrb, sg, num_sg, io_task); AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, pwrb, - io_task->pwrb_handle->nxt_wrb_index); + io_task->pwrb_handle->wrb_index); + if (io_task->pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, + io_task->pwrb_context->plast_wrb, + io_task->pwrb_handle->wrb_index); + io_task->pwrb_context->plast_wrb = pwrb; be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); @@ -4982,7 +4996,13 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, hwi_write_sgl(pwrb, sg, num_sg, io_task); AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb, - io_task->pwrb_handle->nxt_wrb_index); + io_task->pwrb_handle->wrb_index); + if (io_task->pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, + io_task->pwrb_context->plast_wrb, + io_task->pwrb_handle->wrb_index); + io_task->pwrb_context->plast_wrb = pwrb; + be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; @@ -5020,7 +5040,13 @@ static int beiscsi_mtask(struct iscsi_task *task) AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, task->data_count); AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb, - io_task->pwrb_handle->nxt_wrb_index); + io_task->pwrb_handle->wrb_index); + if (io_task->pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, + io_task->pwrb_context->plast_wrb, + io_task->pwrb_handle->wrb_index); + io_task->pwrb_context->plast_wrb = pwrb; + pwrb_typeoffset = BE_WRB_TYPE_OFFSET; } else { AMAP_SET_BITS(struct amap_iscsi_wrb_v2, cmdsn_itt, pwrb, @@ -5032,7 +5058,13 @@ static int beiscsi_mtask(struct iscsi_task *task) AMAP_SET_BITS(struct amap_iscsi_wrb_v2, r2t_exp_dtl, pwrb, task->data_count); AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, pwrb, - io_task->pwrb_handle->nxt_wrb_index); + io_task->pwrb_handle->wrb_index); + if (io_task->pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, + io_task->pwrb_context->plast_wrb, + io_task->pwrb_handle->wrb_index); + io_task->pwrb_context->plast_wrb = pwrb; + pwrb_typeoffset = SKH_WRB_TYPE_OFFSET; } diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h index b8c0c7819..5c67c0732 100644 --- a/drivers/scsi/be2iscsi/be_main.h +++ b/drivers/scsi/be2iscsi/be_main.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -12,7 +12,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ @@ -36,8 +36,8 @@ #include #define DRV_NAME "be2iscsi" -#define BUILD_STR "10.6.0.0" -#define BE_NAME "Avago Technologies OneConnect" \ +#define BUILD_STR "10.6.0.1" +#define BE_NAME "Emulex OneConnect" \ "Open-iSCSI Driver version" BUILD_STR #define DRV_DESC BE_NAME " " "Driver" @@ -502,6 +502,7 @@ struct beiscsi_io_task { struct sgl_handle *psgl_handle; struct beiscsi_conn *conn; struct scsi_cmnd *scsi_cmnd; + struct hwi_wrb_context *pwrb_context; unsigned int cmd_sn; unsigned int flags; unsigned short cid; @@ -833,7 +834,8 @@ struct amap_iscsi_wrb_v2 { } __packed; -struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid); +struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid, + struct hwi_wrb_context **pcontext); void free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle); @@ -1044,7 +1046,6 @@ enum hwh_type_enum { struct wrb_handle { enum hwh_type_enum type; unsigned short wrb_index; - unsigned short nxt_wrb_index; struct iscsi_task *pio_handle; struct iscsi_wrb *pwrb; diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c index ca4016f20..aea3e6b94 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.c +++ b/drivers/scsi/be2iscsi/be_mgmt.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -12,7 +12,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ @@ -1573,7 +1573,8 @@ beiscsi_phys_port_disp(struct device *dev, struct device_attribute *attr, void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params, struct wrb_handle *pwrb_handle, - struct be_mem_descriptor *mem_descr) + struct be_mem_descriptor *mem_descr, + struct hwi_wrb_context *pwrb_context) { struct iscsi_wrb *pwrb = pwrb_handle->pwrb; @@ -1617,7 +1618,14 @@ void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params, max_burst_length) / 32]); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ptr2nextwrb, - pwrb, pwrb_handle->nxt_wrb_index); + pwrb, pwrb_handle->wrb_index); + if (pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, + ptr2nextwrb, + pwrb_context->plast_wrb, + pwrb_handle->wrb_index); + pwrb_context->plast_wrb = pwrb; + AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, session_state, pwrb, 0); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, compltonack, @@ -1637,7 +1645,8 @@ void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params, } void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, - struct wrb_handle *pwrb_handle) + struct wrb_handle *pwrb_handle, + struct hwi_wrb_context *pwrb_context) { struct iscsi_wrb *pwrb = pwrb_handle->pwrb; @@ -1652,7 +1661,14 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, BE_TGT_CTX_UPDT_CMD); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, ptr2nextwrb, - pwrb, pwrb_handle->nxt_wrb_index); + pwrb, pwrb_handle->wrb_index); + if (pwrb_context->plast_wrb) + AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, + ptr2nextwrb, + pwrb_context->plast_wrb, + pwrb_handle->wrb_index); + pwrb_context->plast_wrb = pwrb; + AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, wrb_idx, pwrb, pwrb_handle->wrb_index); AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h index b58a7decb..c1dbb690e 100644 --- a/drivers/scsi/be2iscsi/be_mgmt.h +++ b/drivers/scsi/be2iscsi/be_mgmt.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2005 - 2015 Avago Technologies + * Copyright (C) 2005 - 2015 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -12,7 +12,7 @@ * Contact Information: * linux-drivers@avagotech.com * - * Avago Technologies + * Emulex * 3333 Susan Street * Costa Mesa, CA 92626 */ @@ -330,10 +330,13 @@ ssize_t beiscsi_phys_port_disp(struct device *dev, void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params, struct wrb_handle *pwrb_handle, - struct be_mem_descriptor *mem_descr); + struct be_mem_descriptor *mem_descr, + struct hwi_wrb_context *pwrb_context); void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, - struct wrb_handle *pwrb_handle); + struct wrb_handle *pwrb_handle, + struct hwi_wrb_context *pwrb_context); + void beiscsi_ue_detect(struct beiscsi_hba *phba); int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, struct be_set_eqd *, int num); diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c index 8367c11d5..299c6f80d 100644 --- a/drivers/scsi/bfa/bfad_im.c +++ b/drivers/scsi/bfa/bfad_im.c @@ -800,7 +800,6 @@ struct scsi_host_template bfad_im_scsi_host_template = { .shost_attrs = bfad_im_host_attrs, .max_sectors = BFAD_MAX_SECTORS, .vendor_id = BFA_PCI_VENDOR_ID_BROCADE, - .use_blk_tags = 1, }; struct scsi_host_template bfad_im_vport_template = { @@ -822,7 +821,6 @@ struct scsi_host_template bfad_im_vport_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = bfad_im_vport_attrs, .max_sectors = BFAD_MAX_SECTORS, - .use_blk_tags = 1, }; bfa_status_t diff --git a/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h index fe2106c91..ac1c0b631 100644 --- a/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h +++ b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h @@ -1,9 +1,9 @@ -/* 57xx_hsi_bnx2fc.h: QLogic NetXtreme II Linux FCoE offload driver. +/* 57xx_hsi_bnx2fc.h: QLogic Linux FCoE offload driver. * Handles operations such as session offload/upload etc, and manages * session resources such as connection id and qp resources. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic Corporation * * 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 diff --git a/drivers/scsi/bnx2fc/Kconfig b/drivers/scsi/bnx2fc/Kconfig index 097882882..d401a096d 100644 --- a/drivers/scsi/bnx2fc/Kconfig +++ b/drivers/scsi/bnx2fc/Kconfig @@ -1,5 +1,5 @@ config SCSI_BNX2X_FCOE - tristate "QLogic NetXtreme II FCoE support" + tristate "QLogic FCoE offload support" depends on PCI depends on (IPV6 || IPV6=n) depends on LIBFC @@ -9,5 +9,4 @@ config SCSI_BNX2X_FCOE select NET_VENDOR_BROADCOM select CNIC ---help--- - This driver supports FCoE offload for the QLogic NetXtreme II - devices. + This driver supports FCoE offload for the QLogic devices. diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index 1346e052e..499e369ea 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -1,7 +1,7 @@ -/* bnx2fc.h: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc.h: QLogic Linux FCoE offload driver. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic Corporation * * 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 @@ -65,7 +65,7 @@ #include "bnx2fc_constants.h" #define BNX2FC_NAME "bnx2fc" -#define BNX2FC_VERSION "2.4.2" +#define BNX2FC_VERSION "2.9.6" #define PFX "bnx2fc: " @@ -303,7 +303,6 @@ struct bnx2fc_rport { #define BNX2FC_FLAG_OFLD_REQ_CMPL 0x5 #define BNX2FC_FLAG_CTX_ALLOC_FAILURE 0x6 #define BNX2FC_FLAG_UPLD_REQ_COMPL 0x7 -#define BNX2FC_FLAG_EXPL_LOGO 0x8 #define BNX2FC_FLAG_DISABLE_FAILED 0x9 #define BNX2FC_FLAG_ENABLED 0xa diff --git a/drivers/scsi/bnx2fc/bnx2fc_constants.h b/drivers/scsi/bnx2fc/bnx2fc_constants.h index e147cc7ee..5b20efb66 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_constants.h +++ b/drivers/scsi/bnx2fc/bnx2fc_constants.h @@ -1,9 +1,9 @@ -/* bnx2fc_constants.h: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_constants.h: QLogic Linux FCoE offload driver. * Handles operations such as session offload/upload etc, and manages * session resources such as connection id and qp resources. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic Corporation * * 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 diff --git a/drivers/scsi/bnx2fc/bnx2fc_debug.c b/drivers/scsi/bnx2fc/bnx2fc_debug.c index d055df01f..c9e0bc7fa 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_debug.c +++ b/drivers/scsi/bnx2fc/bnx2fc_debug.c @@ -1,9 +1,9 @@ -/* bnx2fc_debug.c: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_debug.c: QLogic Linux FCoE offload driver. * Handles operations such as session offload/upload etc, and manages * session resources such as connection id and qp resources. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic Corporation * * 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 diff --git a/drivers/scsi/bnx2fc/bnx2fc_debug.h b/drivers/scsi/bnx2fc/bnx2fc_debug.h index 2b9006774..34fda3e04 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_debug.h +++ b/drivers/scsi/bnx2fc/bnx2fc_debug.h @@ -1,9 +1,9 @@ -/* bnx2fc_debug.h: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_debug.h: QLogic Linux FCoE offload driver. * Handles operations such as session offload/upload etc, and manages * session resources such as connection id and qp resources. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic Corporation * * 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 diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c index ef355c13c..5beea776b 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_els.c +++ b/drivers/scsi/bnx2fc/bnx2fc_els.c @@ -1,10 +1,10 @@ /* - * bnx2fc_els.c: QLogic NetXtreme II Linux FCoE offload driver. + * bnx2fc_els.c: QLogic Linux FCoE offload driver. * This file contains helper routines that handle ELS requests * and responses. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic Corporation * * 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 @@ -689,8 +689,7 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op, rc = -EINVAL; goto els_err; } - if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) || - (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags))) { + if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags))) { printk(KERN_ERR PFX "els 0x%x: tgt not ready\n", op); rc = -EINVAL; goto els_err; @@ -707,6 +706,7 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op, els_req->cb_func = cb_func; cb_arg->io_req = els_req; els_req->cb_arg = cb_arg; + els_req->data_xfer_len = data_len; mp_req = (struct bnx2fc_mp_req *)&(els_req->mp_req); rc = bnx2fc_init_mp_req(els_req); diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index d5cdc4776..67405c628 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -1,10 +1,10 @@ -/* bnx2fc_fcoe.c: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_fcoe.c: QLogic Linux FCoE offload driver. * This file contains the code that interacts with libfc, libfcoe, * cnic modules to create FCoE instances, send/receive non-offloaded * FIP/FCoE packets, listen to link events etc. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic Corporation * * 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 @@ -23,16 +23,16 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); #define DRV_MODULE_NAME "bnx2fc" #define DRV_MODULE_VERSION BNX2FC_VERSION -#define DRV_MODULE_RELDATE "Dec 11, 2013" +#define DRV_MODULE_RELDATE "October 15, 2015" static char version[] = - "QLogic NetXtreme II FCoE Driver " DRV_MODULE_NAME \ + "QLogic FCoE Driver " DRV_MODULE_NAME \ " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("Bhanu Prakash Gollapudi "); -MODULE_DESCRIPTION("QLogic NetXtreme II BCM57710 FCoE Driver"); +MODULE_DESCRIPTION("QLogic FCoE Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); @@ -856,7 +856,6 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event, return; default: - printk(KERN_ERR PFX "Unknown netevent %ld", event); return; } @@ -2092,7 +2091,7 @@ static int __bnx2fc_enable(struct fcoe_ctlr *ctlr) { struct bnx2fc_interface *interface = fcoe_ctlr_priv(ctlr); struct bnx2fc_hba *hba; - struct cnic_fc_npiv_tbl npiv_tbl; + struct cnic_fc_npiv_tbl *npiv_tbl; struct fc_lport *lport; if (interface->enabled == false) { @@ -2124,11 +2123,16 @@ static int __bnx2fc_enable(struct fcoe_ctlr *ctlr) if (!hba->cnic->get_fc_npiv_tbl) goto done; - memset(&npiv_tbl, 0, sizeof(npiv_tbl)); - if (hba->cnic->get_fc_npiv_tbl(hba->cnic, &npiv_tbl)) + npiv_tbl = kzalloc(sizeof(struct cnic_fc_npiv_tbl), GFP_KERNEL); + if (!npiv_tbl) goto done; - bnx2fc_npiv_create_vports(lport, &npiv_tbl); + if (hba->cnic->get_fc_npiv_tbl(hba->cnic, npiv_tbl)) + goto done_free; + + bnx2fc_npiv_create_vports(lport, npiv_tbl); +done_free: + kfree(npiv_tbl); done: return 0; } @@ -2863,7 +2867,6 @@ static struct scsi_host_template bnx2fc_shost_template = { .use_clustering = ENABLE_CLUSTERING, .sg_tablesize = BNX2FC_MAX_BDS_PER_CMD, .max_sectors = 1024, - .use_blk_tags = 1, .track_queue_depth = 1, }; diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index c6688d72a..28c671b60 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -1,9 +1,9 @@ -/* bnx2fc_hwi.c: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_hwi.c: QLogic Linux FCoE offload driver. * This file contains the code that low level functions that interact * with 57712 FCoE firmware. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic Corporation * * 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 diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 9ecca8504..0002caf68 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1,8 +1,8 @@ -/* bnx2fc_io.c: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_io.c: QLogic Linux FCoE offload driver. * IO manager and SCSI IO processing. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic Corporation * * 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 @@ -40,11 +40,8 @@ static void bnx2fc_cmd_timeout(struct work_struct *work) { struct bnx2fc_cmd *io_req = container_of(work, struct bnx2fc_cmd, timeout_work.work); - struct fc_lport *lport; - struct fc_rport_priv *rdata; u8 cmd_type = io_req->cmd_type; struct bnx2fc_rport *tgt = io_req->tgt; - int logo_issued; int rc; BNX2FC_IO_DBG(io_req, "cmd_timeout, cmd_type = %d," @@ -80,25 +77,14 @@ static void bnx2fc_cmd_timeout(struct work_struct *work) io_req->refcount.refcount.counter); if (!(test_and_set_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags))) { - - lport = io_req->port->lport; - rdata = io_req->tgt->rdata; - logo_issued = test_and_set_bit( - BNX2FC_FLAG_EXPL_LOGO, - &tgt->flags); + /* + * Cleanup and return original command to + * mid-layer. + */ + bnx2fc_initiate_cleanup(io_req); kref_put(&io_req->refcount, bnx2fc_cmd_release); spin_unlock_bh(&tgt->tgt_lock); - /* Explicitly logo the target */ - if (!logo_issued) { - BNX2FC_IO_DBG(io_req, "Explicit " - "logo - tgt flags = 0x%lx\n", - tgt->flags); - - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_logoff(rdata); - mutex_unlock(&lport->disc.disc_mutex); - } return; } } else { @@ -116,28 +102,10 @@ static void bnx2fc_cmd_timeout(struct work_struct *work) rc = bnx2fc_initiate_abts(io_req); if (rc == SUCCESS) goto done; - /* - * Explicitly logo the target if - * abts initiation fails - */ - lport = io_req->port->lport; - rdata = io_req->tgt->rdata; - logo_issued = test_and_set_bit( - BNX2FC_FLAG_EXPL_LOGO, - &tgt->flags); + kref_put(&io_req->refcount, bnx2fc_cmd_release); spin_unlock_bh(&tgt->tgt_lock); - if (!logo_issued) { - BNX2FC_IO_DBG(io_req, "Explicit " - "logo - tgt flags = 0x%lx\n", - tgt->flags); - - - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_logoff(rdata); - mutex_unlock(&lport->disc.disc_mutex); - } return; } else { BNX2FC_IO_DBG(io_req, "IO already in " @@ -152,22 +120,9 @@ static void bnx2fc_cmd_timeout(struct work_struct *work) if (!test_and_set_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags)) { - lport = io_req->port->lport; - rdata = io_req->tgt->rdata; - logo_issued = test_and_set_bit( - BNX2FC_FLAG_EXPL_LOGO, - &tgt->flags); kref_put(&io_req->refcount, bnx2fc_cmd_release); spin_unlock_bh(&tgt->tgt_lock); - /* Explicitly logo the target */ - if (!logo_issued) { - BNX2FC_IO_DBG(io_req, "Explicitly logo" - "(els)\n"); - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_logoff(rdata); - mutex_unlock(&lport->disc.disc_mutex); - } return; } } else { @@ -623,8 +578,12 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req) mp_req = (struct bnx2fc_mp_req *)&(io_req->mp_req); memset(mp_req, 0, sizeof(struct bnx2fc_mp_req)); - mp_req->req_len = sizeof(struct fcp_cmnd); - io_req->data_xfer_len = mp_req->req_len; + if (io_req->cmd_type != BNX2FC_ELS) { + mp_req->req_len = sizeof(struct fcp_cmnd); + io_req->data_xfer_len = mp_req->req_len; + } else + mp_req->req_len = io_req->data_xfer_len; + mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE, &mp_req->req_buf_dma, GFP_ATOMIC); @@ -1108,18 +1067,11 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd) return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); } -int bnx2fc_expl_logo(struct fc_lport *lport, struct bnx2fc_cmd *io_req) +int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req) { struct bnx2fc_rport *tgt = io_req->tgt; - struct fc_rport_priv *rdata = tgt->rdata; - int logo_issued; int rc = SUCCESS; - int wait_cnt = 0; - BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n", - tgt->flags); - logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO, - &tgt->flags); io_req->wait_for_comp = 1; bnx2fc_initiate_cleanup(io_req); @@ -1132,21 +1084,8 @@ int bnx2fc_expl_logo(struct fc_lport *lport, struct bnx2fc_cmd *io_req) * release the reference taken in eh_abort to allow the * target to re-login after flushing IOs */ - kref_put(&io_req->refcount, bnx2fc_cmd_release); - - if (!logo_issued) { - clear_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags); - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_logoff(rdata); - mutex_unlock(&lport->disc.disc_mutex); - do { - msleep(BNX2FC_RELOGIN_WAIT_TIME); - if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) { - rc = FAILED; - break; - } - } while (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)); - } + kref_put(&io_req->refcount, bnx2fc_cmd_release); + spin_lock_bh(&tgt->tgt_lock); return rc; } @@ -1248,7 +1187,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) if (cancel_delayed_work(&io_req->timeout_work)) kref_put(&io_req->refcount, bnx2fc_cmd_release); /* drop timer hold */ - rc = bnx2fc_expl_logo(lport, io_req); + rc = bnx2fc_abts_cleanup(io_req); /* This only occurs when an task abort was requested while ABTS is in progress. Setting the IO_CLEANUP flag will skip the RRQ process in the case when the fw generated SCSI_CMD cmpl @@ -1287,7 +1226,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) /* Let the scsi-ml try to recover this command */ printk(KERN_ERR PFX "abort failed, xid = 0x%x\n", io_req->xid); - rc = bnx2fc_expl_logo(lport, io_req); + rc = bnx2fc_abts_cleanup(io_req); goto out; } else { /* @@ -1755,7 +1694,10 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, int fcp_rsp_len = 0; io_req->fcp_status = FC_GOOD; - io_req->fcp_resid = fcp_rsp->fcp_resid; + io_req->fcp_resid = 0; + if (rsp_flags & (FCOE_FCP_RSP_FLAGS_FCP_RESID_OVER | + FCOE_FCP_RSP_FLAGS_FCP_RESID_UNDER)) + io_req->fcp_resid = fcp_rsp->fcp_resid; io_req->scsi_comp_flags = rsp_flags; CMD_SCSI_STATUS(sc_cmd) = io_req->cdb_status = diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c index c66c70841..08ec318af 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c @@ -1,9 +1,9 @@ -/* bnx2fc_tgt.c: QLogic NetXtreme II Linux FCoE offload driver. +/* bnx2fc_tgt.c: QLogic Linux FCoE offload driver. * Handles operations such as session offload/upload etc, and manages * session resources such as connection id and qp resources. * - * Copyright (c) 2008 - 2013 Broadcom Corporation - * Copyright (c) 2014, QLogic Corporation + * Copyright (c) 2008-2013 Broadcom Corporation + * Copyright (c) 2014-2015 QLogic Corporation * * 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 @@ -560,12 +560,6 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport, (hba->num_ofld_sess == 0)) { wake_up_interruptible(&hba->shutdown_wait); } - if (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags)) { - printk(KERN_ERR PFX "Relogin to the tgt\n"); - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_login(rdata); - mutex_unlock(&lport->disc.disc_mutex); - } mutex_unlock(&hba->hba_mutex); break; diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c index 2c4562d82..c2a6f9f29 100644 --- a/drivers/scsi/csiostor/csio_scsi.c +++ b/drivers/scsi/csiostor/csio_scsi.c @@ -2283,7 +2283,6 @@ struct scsi_host_template csio_fcoe_shost_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = csio_fcoe_lport_attrs, .max_sectors = CSIO_MAX_SECTOR_SIZE, - .use_blk_tags = 1, }; struct scsi_host_template csio_fcoe_shost_vport_template = { @@ -2303,7 +2302,6 @@ struct scsi_host_template csio_fcoe_shost_vport_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = csio_fcoe_vport_attrs, .max_sectors = CSIO_MAX_SECTOR_SIZE, - .use_blk_tags = 1, }; /* diff --git a/drivers/scsi/cxgbi/cxgb3i/Kbuild b/drivers/scsi/cxgbi/cxgb3i/Kbuild index 6f095e28a..961a12f6d 100644 --- a/drivers/scsi/cxgbi/cxgb3i/Kbuild +++ b/drivers/scsi/cxgbi/cxgb3i/Kbuild @@ -1,3 +1,3 @@ -EXTRA_CFLAGS += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb3 +ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb3 obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i.o diff --git a/drivers/scsi/cxgbi/cxgb4i/Kbuild b/drivers/scsi/cxgbi/cxgb4i/Kbuild index 8290cdaa4..374586437 100644 --- a/drivers/scsi/cxgbi/cxgb4i/Kbuild +++ b/drivers/scsi/cxgbi/cxgb4i/Kbuild @@ -1,3 +1,3 @@ -EXTRA_CFLAGS += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4 +ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4 obj-$(CONFIG_SCSI_CXGB4_ISCSI) += cxgb4i.o diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index de6feb896..804806e1c 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -160,7 +160,7 @@ static struct scsi_transport_template *cxgb4i_stt; #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) #define RCV_BUFSIZ_MASK 0x3FFU -#define MAX_IMM_TX_PKT_LEN 128 +#define MAX_IMM_TX_PKT_LEN 256 static int push_tx_frames(struct cxgbi_sock *, int); diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 1c5603714..c11cd193f 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -16,10 +16,12 @@ #define _CXLFLASH_COMMON_H #include +#include #include #include #include +extern const struct file_operations cxlflash_cxl_fops; #define MAX_CONTEXT CXLFLASH_MAX_CONTEXT /* num contexts per afu */ @@ -78,7 +80,7 @@ enum cxlflash_init_state { enum cxlflash_state { STATE_NORMAL, /* Normal running state, everything good */ - STATE_LIMBO, /* Limbo running state, trying to reset/recover */ + STATE_RESET, /* Reset state, trying to reset/recover */ STATE_FAILTERM /* Failed/terminating state, error out users/threads */ }; @@ -101,29 +103,28 @@ struct cxlflash_cfg { enum cxlflash_init_state init_state; enum cxlflash_lr_state lr_state; int lr_port; + atomic_t scan_host_needed; struct cxl_afu *cxl_afu; - - struct pci_pool *cxlflash_cmd_pool; struct pci_dev *parent_dev; atomic_t recovery_threads; struct mutex ctx_recovery_mutex; struct mutex ctx_tbl_list_mutex; + struct rw_semaphore ioctl_rwsem; struct ctx_info *ctx_tbl[MAX_CONTEXT]; struct list_head ctx_err_recovery; /* contexts w/ recovery pending */ struct file_operations cxl_fops; - atomic_t num_user_contexts; - /* Parameters that are LUN table related */ int last_lun_index[CXLFLASH_NUM_FC_PORTS]; int promote_lun_index; struct list_head lluns; /* list of llun_info structs */ wait_queue_head_t tmf_waitq; + spinlock_t tmf_slock; bool tmf_active; - wait_queue_head_t limbo_waitq; + wait_queue_head_t reset_waitq; enum cxlflash_state state; }; @@ -160,9 +161,9 @@ struct afu { /* AFU HW */ struct cxl_ioctl_start_work work; - struct cxlflash_afu_map *afu_map; /* entire MMIO map */ - struct sisl_host_map *host_map; /* MC host map */ - struct sisl_ctrl_map *ctrl_map; /* MC control map */ + struct cxlflash_afu_map __iomem *afu_map; /* entire MMIO map */ + struct sisl_host_map __iomem *host_map; /* MC host map */ + struct sisl_ctrl_map __iomem *ctrl_map; /* MC control map */ ctx_hndl_t ctx_hndl; /* master's context handle */ u64 *hrrq_start; @@ -175,7 +176,7 @@ struct afu { u32 cmd_couts; /* Number of command checkouts */ u32 internal_lun; /* User-desired LUN mode for this AFU */ - char version[8]; + char version[16]; u64 interface_version; struct cxlflash_cfg *parent; /* Pointer back to parent cxlflash_cfg */ @@ -184,17 +185,12 @@ struct afu { static inline u64 lun_to_lunid(u64 lun) { - u64 lun_id; + __be64 lun_id; int_to_scsilun(lun, (struct scsi_lun *)&lun_id); - return swab64(lun_id); + return be64_to_cpu(lun_id); } -int cxlflash_send_cmd(struct afu *, struct afu_cmd *); -void cxlflash_wait_resp(struct afu *, struct afu_cmd *); -int cxlflash_afu_reset(struct cxlflash_cfg *); -struct afu_cmd *cxlflash_cmd_checkout(struct afu *); -void cxlflash_cmd_checkin(struct afu_cmd *); int cxlflash_afu_sync(struct afu *, ctx_hndl_t, res_hndl_t, u8); void cxlflash_list_init(void); void cxlflash_term_global_luns(void); diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c index d98ad0ff6..a0923cade 100644 --- a/drivers/scsi/cxlflash/lunmgt.c +++ b/drivers/scsi/cxlflash/lunmgt.c @@ -41,7 +41,6 @@ static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid) } lli->sdev = sdev; - lli->newly_created = true; lli->host_no = sdev->host->host_no; lli->in_table = false; @@ -74,24 +73,19 @@ out: } /** - * refresh_local() - find and update local LUN information structure by WWID + * lookup_local() - find a local LUN information structure by WWID * @cfg: Internal structure associated with the host. * @wwid: WWID associated with LUN. * - * When the LUN is found, mark it by updating it's newly_created field. - * * Return: Found local lun_info structure on success, NULL on failure - * If a LUN with the WWID is found in the list, refresh it's state. */ -static struct llun_info *refresh_local(struct cxlflash_cfg *cfg, u8 *wwid) +static struct llun_info *lookup_local(struct cxlflash_cfg *cfg, u8 *wwid) { struct llun_info *lli, *temp; list_for_each_entry_safe(lli, temp, &cfg->lluns, list) - if (!memcmp(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN)) { - lli->newly_created = false; + if (!memcmp(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN)) return lli; - } return NULL; } @@ -120,7 +114,8 @@ static struct glun_info *lookup_global(u8 *wwid) * * The LUN is kept both in a local list (per adapter) and in a global list * (across all adapters). Certain attributes of the LUN are local to the - * adapter (such as index, port selection mask etc.). + * adapter (such as index, port selection mask, etc.). + * * The block allocation map is shared across all adapters (i.e. associated * wih the global list). Since different attributes are associated with * the per adapter and global entries, allocate two separate structures for each @@ -128,6 +123,8 @@ static struct glun_info *lookup_global(u8 *wwid) * * Keep a pointer back from the local to the global entry. * + * This routine assumes the caller holds the global mutex. + * * Return: Found/Allocated local lun_info structure on success, NULL on failure */ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) @@ -137,11 +134,10 @@ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) struct Scsi_Host *shost = sdev->host; struct cxlflash_cfg *cfg = shost_priv(shost); - mutex_lock(&global.mutex); if (unlikely(!wwid)) goto out; - lli = refresh_local(cfg, wwid); + lli = lookup_local(cfg, wwid); if (lli) goto out; @@ -169,7 +165,6 @@ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) list_add(&gli->list, &global.gluns); out: - mutex_unlock(&global.mutex); pr_debug("%s: returning %p\n", __func__, lli); return lli; } @@ -235,10 +230,11 @@ int cxlflash_manage_lun(struct scsi_device *sdev, u64 flags = manage->hdr.flags; u32 chan = sdev->channel; + mutex_lock(&global.mutex); lli = find_and_create_lun(sdev, manage->wwid); pr_debug("%s: ENTER: WWID = %016llX%016llX, flags = %016llX li = %p\n", - __func__, get_unaligned_le64(&manage->wwid[0]), - get_unaligned_le64(&manage->wwid[8]), + __func__, get_unaligned_be64(&manage->wwid[0]), + get_unaligned_be64(&manage->wwid[8]), manage->hdr.flags, lli); if (unlikely(!lli)) { rc = -ENOMEM; @@ -246,21 +242,28 @@ int cxlflash_manage_lun(struct scsi_device *sdev, } if (flags & DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE) { - if (lli->newly_created) - lli->port_sel = CHAN2PORT(chan); - else - lli->port_sel = BOTH_PORTS; - /* Store off lun in unpacked, AFU-friendly format */ + /* + * Update port selection mask based upon channel, store off LUN + * in unpacked, AFU-friendly format, and hang LUN reference in + * the sdev. + */ + lli->port_sel |= CHAN2PORT(chan); lli->lun_id[chan] = lun_to_lunid(sdev->lun); sdev->hostdata = lli; } else if (flags & DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE) { if (lli->parent->mode != MODE_NONE) rc = -EBUSY; - else + else { sdev->hostdata = NULL; + lli->port_sel &= ~CHAN2PORT(chan); + } } + pr_debug("%s: port_sel = %08X chan = %u lun_id = %016llX\n", __func__, + lli->port_sel, chan, lli->lun_id[chan]); + out: + mutex_unlock(&global.mutex); pr_debug("%s: returning rc=%d\n", __func__, rc); return rc; } diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 3e3ccf16e..1e5bf0ca8 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -34,9 +34,8 @@ MODULE_AUTHOR("Manoj N. Kumar "); MODULE_AUTHOR("Matthew R. Ochs "); MODULE_LICENSE("GPL"); - /** - * cxlflash_cmd_checkout() - checks out an AFU command + * cmd_checkout() - checks out an AFU command * @afu: AFU to checkout from. * * Commands are checked out in a round-robin fashion. Note that since @@ -47,7 +46,7 @@ MODULE_LICENSE("GPL"); * * Return: The checked out command or NULL when command pool is empty. */ -struct afu_cmd *cxlflash_cmd_checkout(struct afu *afu) +static struct afu_cmd *cmd_checkout(struct afu *afu) { int k, dec = CXLFLASH_NUM_CMDS; struct afu_cmd *cmd; @@ -58,8 +57,8 @@ struct afu_cmd *cxlflash_cmd_checkout(struct afu *afu) cmd = &afu->cmd[k]; if (!atomic_dec_if_positive(&cmd->free)) { - pr_debug("%s: returning found index=%d\n", - __func__, cmd->slot); + pr_devel("%s: returning found index=%d cmd=%p\n", + __func__, cmd->slot, cmd); memset(cmd->buf, 0, CMD_BUFSIZE); memset(cmd->rcb.cdb, 0, sizeof(cmd->rcb.cdb)); return cmd; @@ -70,7 +69,7 @@ struct afu_cmd *cxlflash_cmd_checkout(struct afu *afu) } /** - * cxlflash_cmd_checkin() - checks in an AFU command + * cmd_checkin() - checks in an AFU command * @cmd: AFU command to checkin. * * Safe to pass commands that have already been checked in. Several @@ -79,7 +78,7 @@ struct afu_cmd *cxlflash_cmd_checkout(struct afu *afu) * to avoid clobbering values in the event that the command is checked * out right away. */ -void cxlflash_cmd_checkin(struct afu_cmd *cmd) +static void cmd_checkin(struct afu_cmd *cmd) { cmd->rcb.scp = NULL; cmd->rcb.timeout = 0; @@ -93,7 +92,7 @@ void cxlflash_cmd_checkin(struct afu_cmd *cmd) return; } - pr_debug("%s: released cmd %p index=%d\n", __func__, cmd, cmd->slot); + pr_devel("%s: released cmd %p index=%d\n", __func__, cmd, cmd->slot); } /** @@ -107,6 +106,7 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) { struct sisl_ioarcb *ioarcb; struct sisl_ioasa *ioasa; + u32 resid; if (unlikely(!cmd)) return; @@ -115,9 +115,10 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) ioasa = &(cmd->sa); if (ioasa->rc.flags & SISL_RC_FLAGS_UNDERRUN) { - pr_debug("%s: cmd underrun cmd = %p scp = %p\n", - __func__, cmd, scp); - scp->result = (DID_ERROR << 16); + resid = ioasa->resid; + scsi_set_resid(scp, resid); + pr_debug("%s: cmd underrun cmd = %p scp = %p, resid = %d\n", + __func__, cmd, scp, resid); } if (ioasa->rc.flags & SISL_RC_FLAGS_OVERRUN) { @@ -127,7 +128,7 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) } pr_debug("%s: cmd failed afu_rc=%d scsi_rc=%d fc_rc=%d " - "afu_extra=0x%X, scsi_entra=0x%X, fc_extra=0x%X\n", + "afu_extra=0x%X, scsi_extra=0x%X, fc_extra=0x%X\n", __func__, ioasa->rc.afu_rc, ioasa->rc.scsi_rc, ioasa->rc.fc_rc, ioasa->afu_extra, ioasa->scsi_extra, ioasa->fc_extra); @@ -158,8 +159,7 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) /* If the SISL_RC_FLAGS_OVERRUN flag was set, * then we will handle this error else where. * If not then we must handle it here. - * This is probably an AFU bug. We will - * attempt a retry to see if that resolves it. + * This is probably an AFU bug. */ scp->result = (DID_ERROR << 16); } @@ -183,7 +183,7 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) /* We have an AFU error */ switch (ioasa->rc.afu_rc) { case SISL_AFU_RC_NO_CHANNELS: - scp->result = (DID_MEDIUM_ERROR << 16); + scp->result = (DID_NO_CONNECT << 16); break; case SISL_AFU_RC_DATA_DMA_ERR: switch (ioasa->afu_extra) { @@ -217,7 +217,6 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) static void cmd_complete(struct afu_cmd *cmd) { struct scsi_cmnd *scp; - u32 resid; ulong lock_flags; struct afu *afu = cmd->parent; struct cxlflash_cfg *cfg = afu->parent; @@ -229,36 +228,171 @@ static void cmd_complete(struct afu_cmd *cmd) if (cmd->rcb.scp) { scp = cmd->rcb.scp; - if (unlikely(cmd->sa.rc.afu_rc || - cmd->sa.rc.scsi_rc || - cmd->sa.rc.fc_rc)) + if (unlikely(cmd->sa.ioasc)) process_cmd_err(cmd, scp); else scp->result = (DID_OK << 16); - resid = cmd->sa.resid; cmd_is_tmf = cmd->cmd_tmf; - cxlflash_cmd_checkin(cmd); /* Don't use cmd after here */ + cmd_checkin(cmd); /* Don't use cmd after here */ - pr_debug("%s: calling scsi_set_resid, scp=%p " - "result=%X resid=%d\n", __func__, - scp, scp->result, resid); + pr_debug_ratelimited("%s: calling scsi_done scp=%p result=%X " + "ioasc=%d\n", __func__, scp, scp->result, + cmd->sa.ioasc); - scsi_set_resid(scp, resid); scsi_dma_unmap(scp); scp->scsi_done(scp); if (cmd_is_tmf) { - spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + spin_lock_irqsave(&cfg->tmf_slock, lock_flags); cfg->tmf_active = false; wake_up_all_locked(&cfg->tmf_waitq); - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, - lock_flags); + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); } } else complete(&cmd->cevent); } +/** + * context_reset() - timeout handler for AFU commands + * @cmd: AFU command that timed out. + * + * Sends a reset to the AFU. + */ +static void context_reset(struct afu_cmd *cmd) +{ + int nretry = 0; + u64 rrin = 0x1; + u64 room = 0; + struct afu *afu = cmd->parent; + ulong lock_flags; + + pr_debug("%s: cmd=%p\n", __func__, cmd); + + spin_lock_irqsave(&cmd->slock, lock_flags); + + /* Already completed? */ + if (cmd->sa.host_use_b[0] & B_DONE) { + spin_unlock_irqrestore(&cmd->slock, lock_flags); + return; + } + + cmd->sa.host_use_b[0] |= (B_DONE | B_ERROR | B_TIMEOUT); + spin_unlock_irqrestore(&cmd->slock, lock_flags); + + /* + * We really want to send this reset at all costs, so spread + * out wait time on successive retries for available room. + */ + do { + room = readq_be(&afu->host_map->cmd_room); + atomic64_set(&afu->room, room); + if (room) + goto write_rrin; + udelay(nretry); + } while (nretry++ < MC_ROOM_RETRY_CNT); + + pr_err("%s: no cmd_room to send reset\n", __func__); + return; + +write_rrin: + nretry = 0; + writeq_be(rrin, &afu->host_map->ioarrin); + do { + rrin = readq_be(&afu->host_map->ioarrin); + if (rrin != 0x1) + break; + /* Double delay each time */ + udelay(2 << nretry); + } while (nretry++ < MC_ROOM_RETRY_CNT); +} + +/** + * send_cmd() - sends an AFU command + * @afu: AFU associated with the host. + * @cmd: AFU command to send. + * + * Return: + * 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure + */ +static int send_cmd(struct afu *afu, struct afu_cmd *cmd) +{ + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; + int nretry = 0; + int rc = 0; + u64 room; + long newval; + + /* + * This routine is used by critical users such an AFU sync and to + * send a task management function (TMF). Thus we want to retry a + * bit before returning an error. To avoid the performance penalty + * of MMIO, we spread the update of 'room' over multiple commands. + */ +retry: + newval = atomic64_dec_if_positive(&afu->room); + if (!newval) { + do { + room = readq_be(&afu->host_map->cmd_room); + atomic64_set(&afu->room, room); + if (room) + goto write_ioarrin; + udelay(nretry); + } while (nretry++ < MC_ROOM_RETRY_CNT); + + dev_err(dev, "%s: no cmd_room to send 0x%X\n", + __func__, cmd->rcb.cdb[0]); + + goto no_room; + } else if (unlikely(newval < 0)) { + /* This should be rare. i.e. Only if two threads race and + * decrement before the MMIO read is done. In this case + * just benefit from the other thread having updated + * afu->room. + */ + if (nretry++ < MC_ROOM_RETRY_CNT) { + udelay(nretry); + goto retry; + } + + goto no_room; + } + +write_ioarrin: + writeq_be((u64)&cmd->rcb, &afu->host_map->ioarrin); +out: + pr_devel("%s: cmd=%p len=%d ea=%p rc=%d\n", __func__, cmd, + cmd->rcb.data_len, (void *)cmd->rcb.data_ea, rc); + return rc; + +no_room: + afu->read_room = true; + schedule_work(&cfg->work_q); + rc = SCSI_MLQUEUE_HOST_BUSY; + goto out; +} + +/** + * wait_resp() - polls for a response or timeout to a sent AFU command + * @afu: AFU associated with the host. + * @cmd: AFU command that was sent. + */ +static void wait_resp(struct afu *afu, struct afu_cmd *cmd) +{ + ulong timeout = msecs_to_jiffies(cmd->rcb.timeout * 2 * 1000); + + timeout = wait_for_completion_timeout(&cmd->cevent, timeout); + if (!timeout) + context_reset(cmd); + + if (unlikely(cmd->sa.ioasc != 0)) + pr_err("%s: CMD 0x%X failed, IOASC: flags 0x%X, afu_rc 0x%X, " + "scsi_rc 0x%X, fc_rc 0x%X\n", __func__, cmd->rcb.cdb[0], + cmd->sa.rc.flags, cmd->sa.rc.afu_rc, cmd->sa.rc.scsi_rc, + cmd->sa.rc.fc_rc); +} + /** * send_tmf() - sends a Task Management Function (TMF) * @afu: AFU to checkout from. @@ -266,8 +400,7 @@ static void cmd_complete(struct afu_cmd *cmd) * @tmfcmd: TMF command to send. * * Return: - * 0 on success - * SCSI_MLQUEUE_HOST_BUSY when host is busy + * 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure */ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) { @@ -277,25 +410,27 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) short lflag = 0; struct Scsi_Host *host = scp->device->host; struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct device *dev = &cfg->dev->dev; ulong lock_flags; int rc = 0; + ulong to; - cmd = cxlflash_cmd_checkout(afu); + cmd = cmd_checkout(afu); if (unlikely(!cmd)) { - pr_err("%s: could not get a free command\n", __func__); + dev_err(dev, "%s: could not get a free command\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; } - /* If a Task Management Function is active, do not send one more. - */ - spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + /* When Task Management Function is active do not send another */ + spin_lock_irqsave(&cfg->tmf_slock, lock_flags); if (cfg->tmf_active) - wait_event_interruptible_locked_irq(cfg->tmf_waitq, - !cfg->tmf_active); + wait_event_interruptible_lock_irq(cfg->tmf_waitq, + !cfg->tmf_active, + cfg->tmf_slock); cfg->tmf_active = true; cmd->cmd_tmf = true; - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); cmd->rcb.ctx_id = afu->ctx_hndl; cmd->rcb.port_sel = port_sel; @@ -313,18 +448,27 @@ static int send_tmf(struct afu *afu, struct scsi_cmnd *scp, u64 tmfcmd) memcpy(cmd->rcb.cdb, &tmfcmd, sizeof(tmfcmd)); /* Send the command */ - rc = cxlflash_send_cmd(afu, cmd); + rc = send_cmd(afu, cmd); if (unlikely(rc)) { - cxlflash_cmd_checkin(cmd); - spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + cmd_checkin(cmd); + spin_lock_irqsave(&cfg->tmf_slock, lock_flags); cfg->tmf_active = false; - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); goto out; } - spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); - wait_event_interruptible_locked_irq(cfg->tmf_waitq, !cfg->tmf_active); - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + spin_lock_irqsave(&cfg->tmf_slock, lock_flags); + to = msecs_to_jiffies(5000); + to = wait_event_interruptible_lock_irq_timeout(cfg->tmf_waitq, + !cfg->tmf_active, + cfg->tmf_slock, + to); + if (!to) { + cfg->tmf_active = false; + dev_err(dev, "%s: TMF timed out!\n", __func__); + rc = -1; + } + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); out: return rc; } @@ -345,15 +489,13 @@ static const char *cxlflash_driver_info(struct Scsi_Host *host) * @host: SCSI host associated with device. * @scp: SCSI command to send. * - * Return: - * 0 on success - * SCSI_MLQUEUE_HOST_BUSY when host is busy + * Return: 0 on success, SCSI_MLQUEUE_HOST_BUSY on failure */ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) { struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; struct afu *afu = cfg->afu; - struct pci_dev *pdev = cfg->dev; + struct device *dev = &cfg->dev->dev; struct afu_cmd *cmd; u32 port_sel = scp->device->channel + 1; int nseg, i, ncount; @@ -362,34 +504,34 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) short lflag = 0; int rc = 0; - pr_debug("%s: (scp=%p) %d/%d/%d/%llu cdb=(%08X-%08X-%08X-%08X)\n", - __func__, scp, host->host_no, scp->device->channel, - scp->device->id, scp->device->lun, - get_unaligned_be32(&((u32 *)scp->cmnd)[0]), - get_unaligned_be32(&((u32 *)scp->cmnd)[1]), - get_unaligned_be32(&((u32 *)scp->cmnd)[2]), - get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu " + "cdb=(%08X-%08X-%08X-%08X)\n", + __func__, scp, host->host_no, scp->device->channel, + scp->device->id, scp->device->lun, + get_unaligned_be32(&((u32 *)scp->cmnd)[0]), + get_unaligned_be32(&((u32 *)scp->cmnd)[1]), + get_unaligned_be32(&((u32 *)scp->cmnd)[2]), + get_unaligned_be32(&((u32 *)scp->cmnd)[3])); - /* If a Task Management Function is active, wait for it to complete + /* + * If a Task Management Function is active, wait for it to complete * before continuing with regular commands. */ - spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + spin_lock_irqsave(&cfg->tmf_slock, lock_flags); if (cfg->tmf_active) { - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; } - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); switch (cfg->state) { - case STATE_LIMBO: - dev_dbg_ratelimited(&cfg->dev->dev, "%s: device in limbo!\n", - __func__); + case STATE_RESET: + dev_dbg_ratelimited(dev, "%s: device is in reset!\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; case STATE_FAILTERM: - dev_dbg_ratelimited(&cfg->dev->dev, "%s: device has failed!\n", - __func__); + dev_dbg_ratelimited(dev, "%s: device has failed!\n", __func__); scp->result = (DID_NO_CONNECT << 16); scp->scsi_done(scp); rc = 0; @@ -398,9 +540,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) break; } - cmd = cxlflash_cmd_checkout(afu); + cmd = cmd_checkout(afu); if (unlikely(!cmd)) { - pr_err("%s: could not get a free command\n", __func__); + dev_err(dev, "%s: could not get a free command\n", __func__); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; } @@ -422,7 +564,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) nseg = scsi_dma_map(scp); if (unlikely(nseg < 0)) { - dev_err(&pdev->dev, "%s: Fail DMA map! nseg=%d\n", + dev_err(dev, "%s: Fail DMA map! nseg=%d\n", __func__, nseg); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; @@ -438,369 +580,56 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) memcpy(cmd->rcb.cdb, scp->cmnd, sizeof(cmd->rcb.cdb)); /* Send the command */ - rc = cxlflash_send_cmd(afu, cmd); + rc = send_cmd(afu, cmd); if (unlikely(rc)) { - cxlflash_cmd_checkin(cmd); + cmd_checkin(cmd); scsi_dma_unmap(scp); } out: + pr_devel("%s: returning rc=%d\n", __func__, rc); return rc; } /** - * cxlflash_eh_device_reset_handler() - reset a single LUN - * @scp: SCSI command to send. - * - * Return: - * SUCCESS as defined in scsi/scsi.h - * FAILED as defined in scsi/scsi.h + * cxlflash_wait_for_pci_err_recovery() - wait for error recovery during probe + * @cfg: Internal structure associated with the host. */ -static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) +static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg) { - int rc = SUCCESS; - struct Scsi_Host *host = scp->device->host; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; - struct afu *afu = cfg->afu; - int rcr = 0; - - pr_debug("%s: (scp=%p) %d/%d/%d/%llu " - "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, - host->host_no, scp->device->channel, - scp->device->id, scp->device->lun, - get_unaligned_be32(&((u32 *)scp->cmnd)[0]), - get_unaligned_be32(&((u32 *)scp->cmnd)[1]), - get_unaligned_be32(&((u32 *)scp->cmnd)[2]), - get_unaligned_be32(&((u32 *)scp->cmnd)[3])); - - switch (cfg->state) { - case STATE_NORMAL: - rcr = send_tmf(afu, scp, TMF_LUN_RESET); - if (unlikely(rcr)) - rc = FAILED; - break; - case STATE_LIMBO: - wait_event(cfg->limbo_waitq, cfg->state != STATE_LIMBO); - if (cfg->state == STATE_NORMAL) - break; - /* fall through */ - default: - rc = FAILED; - break; - } + struct pci_dev *pdev = cfg->dev; - pr_debug("%s: returning rc=%d\n", __func__, rc); - return rc; + if (pci_channel_offline(pdev)) + wait_event_timeout(cfg->reset_waitq, + !pci_channel_offline(pdev), + CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT); } /** - * cxlflash_eh_host_reset_handler() - reset the host adapter - * @scp: SCSI command from stack identifying host. - * - * Return: - * SUCCESS as defined in scsi/scsi.h - * FAILED as defined in scsi/scsi.h + * free_mem() - free memory associated with the AFU + * @cfg: Internal structure associated with the host. */ -static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) +static void free_mem(struct cxlflash_cfg *cfg) { - int rc = SUCCESS; - int rcr = 0; - struct Scsi_Host *host = scp->device->host; - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + int i; + char *buf = NULL; + struct afu *afu = cfg->afu; - pr_debug("%s: (scp=%p) %d/%d/%d/%llu " - "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, - host->host_no, scp->device->channel, - scp->device->id, scp->device->lun, - get_unaligned_be32(&((u32 *)scp->cmnd)[0]), - get_unaligned_be32(&((u32 *)scp->cmnd)[1]), - get_unaligned_be32(&((u32 *)scp->cmnd)[2]), - get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + if (cfg->afu) { + for (i = 0; i < CXLFLASH_NUM_CMDS; i++) { + buf = afu->cmd[i].buf; + if (!((u64)buf & (PAGE_SIZE - 1))) + free_page((ulong)buf); + } - switch (cfg->state) { - case STATE_NORMAL: - cfg->state = STATE_LIMBO; - scsi_block_requests(cfg->host); - cxlflash_mark_contexts_error(cfg); - rcr = cxlflash_afu_reset(cfg); - if (rcr) { - rc = FAILED; - cfg->state = STATE_FAILTERM; - } else - cfg->state = STATE_NORMAL; - wake_up_all(&cfg->limbo_waitq); - scsi_unblock_requests(cfg->host); - break; - case STATE_LIMBO: - wait_event(cfg->limbo_waitq, cfg->state != STATE_LIMBO); - if (cfg->state == STATE_NORMAL) - break; - /* fall through */ - default: - rc = FAILED; - break; + free_pages((ulong)afu, get_order(sizeof(struct afu))); + cfg->afu = NULL; } - - pr_debug("%s: returning rc=%d\n", __func__, rc); - return rc; } /** - * cxlflash_change_queue_depth() - change the queue depth for the device - * @sdev: SCSI device destined for queue depth change. - * @qdepth: Requested queue depth value to set. - * - * The requested queue depth is capped to the maximum supported value. - * - * Return: The actual queue depth set. - */ -static int cxlflash_change_queue_depth(struct scsi_device *sdev, int qdepth) -{ - - if (qdepth > CXLFLASH_MAX_CMDS_PER_LUN) - qdepth = CXLFLASH_MAX_CMDS_PER_LUN; - - scsi_change_queue_depth(sdev, qdepth); - return sdev->queue_depth; -} - -/** - * cxlflash_show_port_status() - queries and presents the current port status - * @dev: Generic device associated with the host owning the port. - * @attr: Device attribute representing the port. - * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t cxlflash_show_port_status(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; - struct afu *afu = cfg->afu; - - char *disp_status; - int rc; - u32 port; - u64 status; - u64 *fc_regs; - - rc = kstrtouint((attr->attr.name + 4), 10, &port); - if (rc || (port >= NUM_FC_PORTS)) - return 0; - - fc_regs = &afu->afu_map->global.fc_regs[port][0]; - status = - (readq_be(&fc_regs[FC_MTIP_STATUS / 8]) & FC_MTIP_STATUS_MASK); - - if (status == FC_MTIP_STATUS_ONLINE) - disp_status = "online"; - else if (status == FC_MTIP_STATUS_OFFLINE) - disp_status = "offline"; - else - disp_status = "unknown"; - - return snprintf(buf, PAGE_SIZE, "%s\n", disp_status); -} - -/** - * cxlflash_show_lun_mode() - presents the current LUN mode of the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the lun mode. - * @buf: Buffer of length PAGE_SIZE to report back the LUN mode in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t cxlflash_show_lun_mode(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; - struct afu *afu = cfg->afu; - - return snprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun); -} - -/** - * cxlflash_store_lun_mode() - sets the LUN mode of the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the lun mode. - * @buf: Buffer of length PAGE_SIZE containing the LUN mode in ASCII. - * @count: Length of data resizing in @buf. - * - * The CXL Flash AFU supports a dummy LUN mode where the external - * links and storage are not required. Space on the FPGA is used - * to create 1 or 2 small LUNs which are presented to the system - * as if they were a normal storage device. This feature is useful - * during development and also provides manufacturing with a way - * to test the AFU without an actual device. - * - * 0 = external LUN[s] (default) - * 1 = internal LUN (1 x 64K, 512B blocks, id 0) - * 2 = internal LUN (1 x 64K, 4K blocks, id 0) - * 3 = internal LUN (2 x 32K, 512B blocks, ids 0,1) - * 4 = internal LUN (2 x 32K, 4K blocks, ids 0,1) - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t cxlflash_store_lun_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; - struct afu *afu = cfg->afu; - int rc; - u32 lun_mode; - - rc = kstrtouint(buf, 10, &lun_mode); - if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) { - afu->internal_lun = lun_mode; - cxlflash_afu_reset(cfg); - scsi_scan_host(cfg->host); - } - - return count; -} - -/** - * cxlflash_show_ioctl_version() - presents the current ioctl version of the host - * @dev: Generic device associated with the host. - * @attr: Device attribute representing the ioctl version. - * @buf: Buffer of length PAGE_SIZE to report back the ioctl version. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t cxlflash_show_ioctl_version(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return scnprintf(buf, PAGE_SIZE, "%u\n", DK_CXLFLASH_VERSION_0); -} - -/** - * cxlflash_show_dev_mode() - presents the current mode of the device - * @dev: Generic device associated with the device. - * @attr: Device attribute representing the device mode. - * @buf: Buffer of length PAGE_SIZE to report back the dev mode in ASCII. - * - * Return: The size of the ASCII string returned in @buf. - */ -static ssize_t cxlflash_show_dev_mode(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - - return snprintf(buf, PAGE_SIZE, "%s\n", - sdev->hostdata ? "superpipe" : "legacy"); -} - -/** - * cxlflash_wait_for_pci_err_recovery() - wait for error recovery during probe - * @cxlflash: Internal structure associated with the host. - */ -static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg) -{ - struct pci_dev *pdev = cfg->dev; - - if (pci_channel_offline(pdev)) - wait_event_timeout(cfg->limbo_waitq, - !pci_channel_offline(pdev), - CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT); -} - -/* - * Host attributes - */ -static DEVICE_ATTR(port0, S_IRUGO, cxlflash_show_port_status, NULL); -static DEVICE_ATTR(port1, S_IRUGO, cxlflash_show_port_status, NULL); -static DEVICE_ATTR(lun_mode, S_IRUGO | S_IWUSR, cxlflash_show_lun_mode, - cxlflash_store_lun_mode); -static DEVICE_ATTR(ioctl_version, S_IRUGO, cxlflash_show_ioctl_version, NULL); - -static struct device_attribute *cxlflash_host_attrs[] = { - &dev_attr_port0, - &dev_attr_port1, - &dev_attr_lun_mode, - &dev_attr_ioctl_version, - NULL -}; - -/* - * Device attributes - */ -static DEVICE_ATTR(mode, S_IRUGO, cxlflash_show_dev_mode, NULL); - -static struct device_attribute *cxlflash_dev_attrs[] = { - &dev_attr_mode, - NULL -}; - -/* - * Host template - */ -static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .name = CXLFLASH_ADAPTER_NAME, - .info = cxlflash_driver_info, - .ioctl = cxlflash_ioctl, - .proc_name = CXLFLASH_NAME, - .queuecommand = cxlflash_queuecommand, - .eh_device_reset_handler = cxlflash_eh_device_reset_handler, - .eh_host_reset_handler = cxlflash_eh_host_reset_handler, - .change_queue_depth = cxlflash_change_queue_depth, - .cmd_per_lun = 16, - .can_queue = CXLFLASH_MAX_CMDS, - .this_id = -1, - .sg_tablesize = SG_NONE, /* No scatter gather support. */ - .max_sectors = CXLFLASH_MAX_SECTORS, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = cxlflash_host_attrs, - .sdev_attrs = cxlflash_dev_attrs, -}; - -/* - * Device dependent values - */ -static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS }; - -/* - * PCI device binding table - */ -static struct pci_device_id cxlflash_pci_table[] = { - {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals}, - {} -}; - -MODULE_DEVICE_TABLE(pci, cxlflash_pci_table); - -/** - * free_mem() - free memory associated with the AFU - * @cxlflash: Internal structure associated with the host. - */ -static void free_mem(struct cxlflash_cfg *cfg) -{ - int i; - char *buf = NULL; - struct afu *afu = cfg->afu; - - if (cfg->afu) { - for (i = 0; i < CXLFLASH_NUM_CMDS; i++) { - buf = afu->cmd[i].buf; - if (!((u64)buf & (PAGE_SIZE - 1))) - free_page((ulong)buf); - } - - free_pages((ulong)afu, get_order(sizeof(struct afu))); - cfg->afu = NULL; - } -} - -/** - * stop_afu() - stops the AFU command timers and unmaps the MMIO space - * @cxlflash: Internal structure associated with the host. + * stop_afu() - stops the AFU command timers and unmaps the MMIO space + * @cfg: Internal structure associated with the host. * * Safe to call with AFU in a partially allocated/initialized state. */ @@ -814,7 +643,7 @@ static void stop_afu(struct cxlflash_cfg *cfg) complete(&afu->cmd[i].cevent); if (likely(afu->afu_map)) { - cxl_psa_unmap((void *)afu->afu_map); + cxl_psa_unmap((void __iomem *)afu->afu_map); afu->afu_map = NULL; } } @@ -822,7 +651,7 @@ static void stop_afu(struct cxlflash_cfg *cfg) /** * term_mc() - terminates the master context - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * @level: Depth of allocation, where to begin waterfall tear down. * * Safe to call with AFU/MC in partially allocated/initialized state. @@ -831,9 +660,10 @@ static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level) { int rc = 0; struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; if (!afu || !cfg->mcctx) { - pr_err("%s: returning from term_mc with NULL afu or MC\n", + dev_err(dev, "%s: returning from term_mc with NULL afu or MC\n", __func__); return; } @@ -857,7 +687,7 @@ static void term_mc(struct cxlflash_cfg *cfg, enum undo_level level) /** * term_afu() - terminates the AFU - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * * Safe to call with AFU/MC in partially allocated/initialized state. */ @@ -885,11 +715,12 @@ static void cxlflash_remove(struct pci_dev *pdev) /* If a Task Management Function is active, wait for it to complete * before continuing with remove. */ - spin_lock_irqsave(&cfg->tmf_waitq.lock, lock_flags); + spin_lock_irqsave(&cfg->tmf_slock, lock_flags); if (cfg->tmf_active) - wait_event_interruptible_locked_irq(cfg->tmf_waitq, - !cfg->tmf_active); - spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + wait_event_interruptible_lock_irq(cfg->tmf_waitq, + !cfg->tmf_active, + cfg->tmf_slock); + spin_unlock_irqrestore(&cfg->tmf_slock, lock_flags); cfg->state = STATE_FAILTERM; cxlflash_stop_term_user_contexts(cfg); @@ -898,16 +729,16 @@ static void cxlflash_remove(struct pci_dev *pdev) case INIT_STATE_SCSI: cxlflash_term_local_luns(cfg); scsi_remove_host(cfg->host); - scsi_host_put(cfg->host); - /* Fall through */ + /* fall through */ case INIT_STATE_AFU: term_afu(cfg); + cancel_work_sync(&cfg->work_q); case INIT_STATE_PCI: pci_release_regions(cfg->dev); pci_disable_device(pdev); case INIT_STATE_NONE: - flush_work(&cfg->work_q); free_mem(cfg); + scsi_host_put(cfg->host); break; } @@ -916,7 +747,7 @@ static void cxlflash_remove(struct pci_dev *pdev) /** * alloc_mem() - allocates the AFU and its command pool - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * * A partially allocated state remains on failure. * @@ -929,15 +760,14 @@ static int alloc_mem(struct cxlflash_cfg *cfg) int rc = 0; int i; char *buf = NULL; + struct device *dev = &cfg->dev->dev; - /* This allocation is about 12K, i.e. only 1 64k page - * and upto 4 4k pages - */ + /* AFU is ~12k, i.e. only one 64k page or up to four 4k pages */ cfg->afu = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, get_order(sizeof(struct afu))); if (unlikely(!cfg->afu)) { - pr_err("%s: cannot get %d free pages\n", - __func__, get_order(sizeof(struct afu))); + dev_err(dev, "%s: cannot get %d free pages\n", + __func__, get_order(sizeof(struct afu))); rc = -ENOMEM; goto out; } @@ -948,7 +778,8 @@ static int alloc_mem(struct cxlflash_cfg *cfg) if (!((u64)buf & (PAGE_SIZE - 1))) { buf = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); if (unlikely(!buf)) { - pr_err("%s: Allocate command buffers fail!\n", + dev_err(dev, + "%s: Allocate command buffers fail!\n", __func__); rc = -ENOMEM; free_mem(cfg); @@ -967,12 +798,9 @@ out: /** * init_pci() - initializes the host as a PCI device - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * - * Return: - * 0 on success - * -EIO on unable to communicate with device - * A return code from the PCI sub-routines + * Return: 0 on success, -errno on failure */ static int init_pci(struct cxlflash_cfg *cfg) { @@ -1052,11 +880,9 @@ out_release_regions: /** * init_scsi() - adds the host to the SCSI stack and kicks off host scan - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * - * Return: - * 0 on success - * A return code from adding the host + * Return: 0 on success, -errno on failure */ static int init_scsi(struct cxlflash_cfg *cfg) { @@ -1085,7 +911,7 @@ out: * that the FC link layer has synced, completed the handshaking process, and * is ready for login to start. */ -static void set_port_online(u64 *fc_regs) +static void set_port_online(__be64 __iomem *fc_regs) { u64 cmdcfg; @@ -1101,7 +927,7 @@ static void set_port_online(u64 *fc_regs) * * The provided MMIO region must be mapped prior to call. */ -static void set_port_offline(u64 *fc_regs) +static void set_port_offline(__be64 __iomem *fc_regs) { u64 cmdcfg; @@ -1125,7 +951,7 @@ static void set_port_offline(u64 *fc_regs) * FALSE (0) when the specified port fails to come online after timeout * -EINVAL when @delay_us is less than 1000 */ -static int wait_port_online(u64 *fc_regs, u32 delay_us, u32 nretry) +static int wait_port_online(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) { u64 status; @@ -1156,7 +982,7 @@ static int wait_port_online(u64 *fc_regs, u32 delay_us, u32 nretry) * FALSE (0) when the specified port fails to go offline after timeout * -EINVAL when @delay_us is less than 1000 */ -static int wait_port_offline(u64 *fc_regs, u32 delay_us, u32 nretry) +static int wait_port_offline(__be64 __iomem *fc_regs, u32 delay_us, u32 nretry) { u64 status; @@ -1191,9 +1017,10 @@ static int wait_port_offline(u64 *fc_regs, u32 delay_us, u32 nretry) * 0 when the WWPN is successfully written and the port comes back online * -1 when the port fails to go offline or come back up online */ -static int afu_set_wwpn(struct afu *afu, int port, u64 *fc_regs, u64 wwpn) +static int afu_set_wwpn(struct afu *afu, int port, __be64 __iomem *fc_regs, + u64 wwpn) { - int ret = 0; + int rc = 0; set_port_offline(fc_regs); @@ -1201,33 +1028,26 @@ static int afu_set_wwpn(struct afu *afu, int port, u64 *fc_regs, u64 wwpn) FC_PORT_STATUS_RETRY_CNT)) { pr_debug("%s: wait on port %d to go offline timed out\n", __func__, port); - ret = -1; /* but continue on to leave the port back online */ + rc = -1; /* but continue on to leave the port back online */ } - if (ret == 0) + if (rc == 0) writeq_be(wwpn, &fc_regs[FC_PNAME / 8]); + /* Always return success after programming WWPN */ + rc = 0; + set_port_online(fc_regs); if (!wait_port_online(fc_regs, FC_PORT_STATUS_RETRY_INTERVAL_US, FC_PORT_STATUS_RETRY_CNT)) { - pr_debug("%s: wait on port %d to go online timed out\n", - __func__, port); - ret = -1; - - /* - * Override for internal lun!!! - */ - if (afu->internal_lun) { - pr_debug("%s: Overriding port %d online timeout!!!\n", - __func__, port); - ret = 0; - } + pr_err("%s: wait on port %d to go online timed out\n", + __func__, port); } - pr_debug("%s: returning rc=%d\n", __func__, ret); + pr_debug("%s: returning rc=%d\n", __func__, rc); - return ret; + return rc; } /** @@ -1243,7 +1063,7 @@ static int afu_set_wwpn(struct afu *afu, int port, u64 *fc_regs, u64 wwpn) * the alternate port exclusively while the reset takes place. * failure to come online is overridden. */ -static void afu_link_reset(struct afu *afu, int port, u64 *fc_regs) +static void afu_link_reset(struct afu *afu, int port, __be64 __iomem *fc_regs) { u64 port_sel; @@ -1280,19 +1100,19 @@ static const struct asyc_intr_info ainfo[] = { {SISL_ASTATUS_FC0_OTHER, "other error", 0, CLR_FC_ERROR | LINK_RESET}, {SISL_ASTATUS_FC0_LOGO, "target initiated LOGO", 0, 0}, {SISL_ASTATUS_FC0_CRC_T, "CRC threshold exceeded", 0, LINK_RESET}, - {SISL_ASTATUS_FC0_LOGI_R, "login timed out, retrying", 0, 0}, + {SISL_ASTATUS_FC0_LOGI_R, "login timed out, retrying", 0, LINK_RESET}, {SISL_ASTATUS_FC0_LOGI_F, "login failed", 0, CLR_FC_ERROR}, - {SISL_ASTATUS_FC0_LOGI_S, "login succeeded", 0, 0}, + {SISL_ASTATUS_FC0_LOGI_S, "login succeeded", 0, SCAN_HOST}, {SISL_ASTATUS_FC0_LINK_DN, "link down", 0, 0}, - {SISL_ASTATUS_FC0_LINK_UP, "link up", 0, 0}, + {SISL_ASTATUS_FC0_LINK_UP, "link up", 0, SCAN_HOST}, {SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET}, {SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0}, {SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET}, {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, 0}, {SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR}, - {SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, 0}, + {SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, SCAN_HOST}, {SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0}, - {SISL_ASTATUS_FC1_LINK_UP, "link up", 1, 0}, + {SISL_ASTATUS_FC1_LINK_UP, "link up", 1, SCAN_HOST}, {0x0, "", 0, 0} /* terminator */ }; @@ -1454,47 +1274,46 @@ static irqreturn_t cxlflash_rrq_irq(int irq, void *data) static irqreturn_t cxlflash_async_err_irq(int irq, void *data) { struct afu *afu = (struct afu *)data; - struct cxlflash_cfg *cfg; + struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; u64 reg_unmasked; const struct asyc_intr_info *info; - struct sisl_global_map *global = &afu->afu_map->global; + struct sisl_global_map __iomem *global = &afu->afu_map->global; u64 reg; u8 port; int i; - cfg = afu->parent; - reg = readq_be(&global->regs.aintr_status); reg_unmasked = (reg & SISL_ASTATUS_UNMASK); if (reg_unmasked == 0) { - pr_err("%s: spurious interrupt, aintr_status 0x%016llX\n", - __func__, reg); + dev_err(dev, "%s: spurious interrupt, aintr_status 0x%016llX\n", + __func__, reg); goto out; } - /* it is OK to clear AFU status before FC_ERROR */ + /* FYI, it is 'okay' to clear AFU status before FC_ERROR */ writeq_be(reg_unmasked, &global->regs.aintr_clear); - /* check each bit that is on */ + /* Check each bit that is on */ for (i = 0; reg_unmasked; i++, reg_unmasked = (reg_unmasked >> 1)) { info = find_ainfo(1ULL << i); - if ((reg_unmasked & 0x1) || !info) + if (((reg_unmasked & 0x1) == 0) || !info) continue; port = info->port; - pr_err("%s: FC Port %d -> %s, fc_status 0x%08llX\n", - __func__, port, info->desc, + dev_err(dev, "%s: FC Port %d -> %s, fc_status 0x%08llX\n", + __func__, port, info->desc, readq_be(&global->fc_regs[port][FC_STATUS / 8])); /* - * do link reset first, some OTHER errors will set FC_ERROR + * Do link reset first, some OTHER errors will set FC_ERROR * again if cleared before or w/o a reset */ if (info->action & LINK_RESET) { - pr_err("%s: FC Port %d: resetting link\n", - __func__, port); + dev_err(dev, "%s: FC Port %d: resetting link\n", + __func__, port); cfg->lr_state = LINK_RESET_REQUIRED; cfg->lr_port = port; schedule_work(&cfg->work_q); @@ -1504,26 +1323,31 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data) reg = readq_be(&global->fc_regs[port][FC_ERROR / 8]); /* - * since all errors are unmasked, FC_ERROR and FC_ERRCAP + * Since all errors are unmasked, FC_ERROR and FC_ERRCAP * should be the same and tracing one is sufficient. */ - pr_err("%s: fc %d: clearing fc_error 0x%08llX\n", - __func__, port, reg); + dev_err(dev, "%s: fc %d: clearing fc_error 0x%08llX\n", + __func__, port, reg); writeq_be(reg, &global->fc_regs[port][FC_ERROR / 8]); writeq_be(0, &global->fc_regs[port][FC_ERRCAP / 8]); } + + if (info->action & SCAN_HOST) { + atomic_inc(&cfg->scan_host_needed); + schedule_work(&cfg->work_q); + } } out: - pr_debug("%s: returning rc=%d, afu=%p\n", __func__, IRQ_HANDLED, afu); + dev_dbg(dev, "%s: returning IRQ_HANDLED, afu=%p\n", __func__, afu); return IRQ_HANDLED; } /** * start_context() - starts the master context - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * * Return: A success or failure value from CXL services. */ @@ -1541,12 +1365,10 @@ static int start_context(struct cxlflash_cfg *cfg) /** * read_vpd() - obtains the WWPNs from VPD - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * @wwpn: Array of size NUM_FC_PORTS to pass back WWPNs * - * Return: - * 0 on success - * -ENODEV when VPD or WWPN keywords not found + * Return: 0 on success, -errno on failure */ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) { @@ -1561,7 +1383,7 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) /* Get the VPD data from the device */ vpd_size = pci_read_vpd(dev, 0, sizeof(vpd_data), vpd_data); if (unlikely(vpd_size <= 0)) { - pr_err("%s: Unable to read VPD (size = %ld)\n", + dev_err(&dev->dev, "%s: Unable to read VPD (size = %ld)\n", __func__, vpd_size); rc = -ENODEV; goto out; @@ -1571,7 +1393,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) ro_start = pci_vpd_find_tag(vpd_data, 0, vpd_size, PCI_VPD_LRDT_RO_DATA); if (unlikely(ro_start < 0)) { - pr_err("%s: VPD Read-only data not found\n", __func__); + dev_err(&dev->dev, "%s: VPD Read-only data not found\n", + __func__); rc = -ENODEV; goto out; } @@ -1600,8 +1423,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) i = pci_vpd_find_info_keyword(vpd_data, i, j, wwpn_vpd_tags[k]); if (unlikely(i < 0)) { - pr_err("%s: Port %d WWPN not found in VPD\n", - __func__, k); + dev_err(&dev->dev, "%s: Port %d WWPN not found " + "in VPD\n", __func__, k); rc = -ENODEV; goto out; } @@ -1609,7 +1432,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) j = pci_vpd_info_field_size(&vpd_data[i]); i += PCI_VPD_INFO_FLD_HDR_SIZE; if (unlikely((i + j > vpd_size) || (j != WWPN_LEN))) { - pr_err("%s: Port %d WWPN incomplete or VPD corrupt\n", + dev_err(&dev->dev, "%s: Port %d WWPN incomplete or " + "VPD corrupt\n", __func__, k); rc = -ENODEV; goto out; @@ -1618,8 +1442,8 @@ static int read_vpd(struct cxlflash_cfg *cfg, u64 wwpn[]) memcpy(tmp_buf, &vpd_data[i], WWPN_LEN); rc = kstrtoul(tmp_buf, WWPN_LEN, (ulong *)&wwpn[k]); if (unlikely(rc)) { - pr_err("%s: Fail to convert port %d WWPN to integer\n", - __func__, k); + dev_err(&dev->dev, "%s: Fail to convert port %d WWPN " + "to integer\n", __func__, k); rc = -ENODEV; goto out; } @@ -1631,91 +1455,36 @@ out: } /** - * cxlflash_context_reset() - timeout handler for AFU commands - * @cmd: AFU command that timed out. + * init_pcr() - initialize the provisioning and control registers + * @cfg: Internal structure associated with the host. * - * Sends a reset to the AFU. + * Also sets up fast access to the mapped registers and initializes AFU + * command fields that never change. */ -void cxlflash_context_reset(struct afu_cmd *cmd) +static void init_pcr(struct cxlflash_cfg *cfg) { - int nretry = 0; - u64 rrin = 0x1; - u64 room = 0; - struct afu *afu = cmd->parent; - ulong lock_flags; - - pr_debug("%s: cmd=%p\n", __func__, cmd); - - spin_lock_irqsave(&cmd->slock, lock_flags); - - /* Already completed? */ - if (cmd->sa.host_use_b[0] & B_DONE) { - spin_unlock_irqrestore(&cmd->slock, lock_flags); - return; - } - - cmd->sa.host_use_b[0] |= (B_DONE | B_ERROR | B_TIMEOUT); - spin_unlock_irqrestore(&cmd->slock, lock_flags); - - /* - * We really want to send this reset at all costs, so spread - * out wait time on successive retries for available room. - */ - do { - room = readq_be(&afu->host_map->cmd_room); - atomic64_set(&afu->room, room); - if (room) - goto write_rrin; - udelay(nretry); - } while (nretry++ < MC_ROOM_RETRY_CNT); - - pr_err("%s: no cmd_room to send reset\n", __func__); - return; - -write_rrin: - nretry = 0; - writeq_be(rrin, &afu->host_map->ioarrin); - do { - rrin = readq_be(&afu->host_map->ioarrin); - if (rrin != 0x1) - break; - /* Double delay each time */ - udelay(2 ^ nretry); - } while (nretry++ < MC_ROOM_RETRY_CNT); -} - -/** - * init_pcr() - initialize the provisioning and control registers - * @cxlflash: Internal structure associated with the host. - * - * Also sets up fast access to the mapped registers and initializes AFU - * command fields that never change. - */ -void init_pcr(struct cxlflash_cfg *cfg) -{ - struct afu *afu = cfg->afu; - struct sisl_ctrl_map *ctrl_map; - int i; + struct afu *afu = cfg->afu; + struct sisl_ctrl_map __iomem *ctrl_map; + int i; for (i = 0; i < MAX_CONTEXT; i++) { ctrl_map = &afu->afu_map->ctrls[i].ctrl; - /* disrupt any clients that could be running */ - /* e. g. clients that survived a master restart */ + /* Disrupt any clients that could be running */ + /* e.g. clients that survived a master restart */ writeq_be(0, &ctrl_map->rht_start); writeq_be(0, &ctrl_map->rht_cnt_id); writeq_be(0, &ctrl_map->ctx_cap); } - /* copy frequently used fields into afu */ + /* Copy frequently used fields into afu */ afu->ctx_hndl = (u16) cxl_process_element(cfg->mcctx); - /* ctx_hndl is 16 bits in CAIA */ afu->host_map = &afu->afu_map->hosts[afu->ctx_hndl].host; afu->ctrl_map = &afu->afu_map->ctrls[afu->ctx_hndl].ctrl; /* Program the Endian Control for the master context */ writeq_be(SISL_ENDIAN_CTRL, &afu->host_map->endian_ctrl); - /* initialize cmd fields that never change */ + /* Initialize cmd fields that never change */ for (i = 0; i < CXLFLASH_NUM_CMDS; i++) { afu->cmd[i].rcb.ctx_id = afu->ctx_hndl; afu->cmd[i].rcb.msi = SISL_MSI_RRQ_UPDATED; @@ -1725,11 +1494,12 @@ void init_pcr(struct cxlflash_cfg *cfg) /** * init_global() - initialize AFU global registers - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. */ -int init_global(struct cxlflash_cfg *cfg) +static int init_global(struct cxlflash_cfg *cfg) { struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; u64 wwpn[NUM_FC_PORTS]; /* wwpn of AFU ports */ int i = 0, num_ports = 0; int rc = 0; @@ -1737,13 +1507,13 @@ int init_global(struct cxlflash_cfg *cfg) rc = read_vpd(cfg, &wwpn[0]); if (rc) { - pr_err("%s: could not read vpd rc=%d\n", __func__, rc); + dev_err(dev, "%s: could not read vpd rc=%d\n", __func__, rc); goto out; } pr_debug("%s: wwpn0=0x%llX wwpn1=0x%llX\n", __func__, wwpn[0], wwpn[1]); - /* set up RRQ in AFU for master issued cmds */ + /* Set up RRQ in AFU for master issued cmds */ writeq_be((u64) afu->hrrq_start, &afu->host_map->rrq_start); writeq_be((u64) afu->hrrq_end, &afu->host_map->rrq_end); @@ -1756,9 +1526,9 @@ int init_global(struct cxlflash_cfg *cfg) /* checker on if dual afu */ writeq_be(reg, &afu->afu_map->global.regs.afu_config); - /* global port select: select either port */ + /* Global port select: select either port */ if (afu->internal_lun) { - /* only use port 0 */ + /* Only use port 0 */ writeq_be(PORT0, &afu->afu_map->global.regs.afu_port_sel); num_ports = NUM_FC_PORTS - 1; } else { @@ -1767,20 +1537,20 @@ int init_global(struct cxlflash_cfg *cfg) } for (i = 0; i < num_ports; i++) { - /* unmask all errors (but they are still masked at AFU) */ + /* Unmask all errors (but they are still masked at AFU) */ writeq_be(0, &afu->afu_map->global.fc_regs[i][FC_ERRMSK / 8]); - /* clear CRC error cnt & set a threshold */ + /* Clear CRC error cnt & set a threshold */ (void)readq_be(&afu->afu_map->global. fc_regs[i][FC_CNT_CRCERR / 8]); writeq_be(MC_CRC_THRESH, &afu->afu_map->global.fc_regs[i] [FC_CRC_THRESH / 8]); - /* set WWPNs. If already programmed, wwpn[i] is 0 */ + /* Set WWPNs. If already programmed, wwpn[i] is 0 */ if (wwpn[i] != 0 && afu_set_wwpn(afu, i, &afu->afu_map->global.fc_regs[i][0], wwpn[i])) { - pr_err("%s: failed to set WWPN on port %d\n", + dev_err(dev, "%s: failed to set WWPN on port %d\n", __func__, i); rc = -EIO; goto out; @@ -1789,18 +1559,17 @@ int init_global(struct cxlflash_cfg *cfg) * offline/online transitions and a PLOGI */ msleep(100); - } - /* set up master's own CTX_CAP to allow real mode, host translation */ - /* tbls, afu cmds and read/write GSCSI cmds. */ + /* Set up master's own CTX_CAP to allow real mode, host translation */ + /* tables, afu cmds and read/write GSCSI cmds. */ /* First, unlock ctx_cap write by reading mbox */ (void)readq_be(&afu->ctrl_map->mbox_r); /* unlock ctx_cap */ writeq_be((SISL_CTX_CAP_REAL_MODE | SISL_CTX_CAP_HOST_XLATE | SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD | SISL_CTX_CAP_AFU_CMD | SISL_CTX_CAP_GSCSI_CMD), &afu->ctrl_map->ctx_cap); - /* init heartbeat */ + /* Initialize heartbeat */ afu->hb = readq_be(&afu->afu_map->global.regs.afu_hb); out: @@ -1809,7 +1578,7 @@ out: /** * start_afu() - initializes and starts the AFU - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. */ static int start_afu(struct cxlflash_cfg *cfg) { @@ -1829,7 +1598,10 @@ static int start_afu(struct cxlflash_cfg *cfg) init_pcr(cfg); - /* initialize RRQ pointers */ + /* After an AFU reset, RRQ entries are stale, clear them */ + memset(&afu->rrq_entry, 0, sizeof(afu->rrq_entry)); + + /* Initialize RRQ pointers */ afu->hrrq_start = &afu->rrq_entry[0]; afu->hrrq_end = &afu->rrq_entry[NUM_RRQ_ENTRY - 1]; afu->hrrq_curr = afu->hrrq_start; @@ -1843,12 +1615,9 @@ static int start_afu(struct cxlflash_cfg *cfg) /** * init_mc() - create and register as the master context - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * - * Return: - * 0 on success - * -ENOMEM when unable to obtain a context from CXL services - * A failure value from CXL services. + * Return: 0 on success, -errno on failure */ static int init_mc(struct cxlflash_cfg *cfg) { @@ -1932,15 +1701,12 @@ out: /** * init_afu() - setup as master context and start AFU - * @cxlflash: Internal structure associated with the host. + * @cfg: Internal structure associated with the host. * * This routine is a higher level of control for configuring the * AFU on probe and reset paths. * - * Return: - * 0 on success - * -ENOMEM when unable to map the AFU MMIO space - * A failure value from internal services. + * Return: 0 on success, -errno on failure */ static int init_afu(struct cxlflash_cfg *cfg) { @@ -1955,36 +1721,38 @@ static int init_afu(struct cxlflash_cfg *cfg) if (rc) { dev_err(dev, "%s: call to init_mc failed, rc=%d!\n", __func__, rc); - goto err1; + goto out; } - /* Map the entire MMIO space of the AFU. - */ + /* Map the entire MMIO space of the AFU */ afu->afu_map = cxl_psa_map(cfg->mcctx); if (!afu->afu_map) { - rc = -ENOMEM; - term_mc(cfg, UNDO_START); dev_err(dev, "%s: call to cxl_psa_map failed!\n", __func__); + rc = -ENOMEM; goto err1; } - /* don't byte reverse on reading afu_version, else the string form */ - /* will be backwards */ - reg = afu->afu_map->global.regs.afu_version; - memcpy(afu->version, ®, 8); + /* No byte reverse on reading afu_version or string will be backwards */ + reg = readq(&afu->afu_map->global.regs.afu_version); + memcpy(afu->version, ®, sizeof(reg)); afu->interface_version = readq_be(&afu->afu_map->global.regs.interface_version); - pr_debug("%s: afu version %s, interface version 0x%llX\n", - __func__, afu->version, afu->interface_version); + if ((afu->interface_version + 1) == 0) { + pr_err("Back level AFU, please upgrade. AFU version %s " + "interface version 0x%llx\n", afu->version, + afu->interface_version); + rc = -EINVAL; + goto err2; + } + + pr_debug("%s: afu version %s, interface version 0x%llX\n", __func__, + afu->version, afu->interface_version); rc = start_afu(cfg); if (rc) { dev_err(dev, "%s: call to start_afu failed, rc=%d!\n", __func__, rc); - term_mc(cfg, UNDO_START); - cxl_psa_unmap((void *)afu->afu_map); - afu->afu_map = NULL; - goto err1; + goto err2; } afu_err_intr_init(cfg->afu); @@ -1992,97 +1760,18 @@ static int init_afu(struct cxlflash_cfg *cfg) /* Restore the LUN mappings */ cxlflash_restore_luntable(cfg); -err1: - pr_debug("%s: returning rc=%d\n", __func__, rc); - return rc; -} - -/** - * cxlflash_send_cmd() - sends an AFU command - * @afu: AFU associated with the host. - * @cmd: AFU command to send. - * - * Return: - * 0 on success - * -1 on failure - */ -int cxlflash_send_cmd(struct afu *afu, struct afu_cmd *cmd) -{ - struct cxlflash_cfg *cfg = afu->parent; - int nretry = 0; - int rc = 0; - u64 room; - long newval; - - /* - * This routine is used by critical users such an AFU sync and to - * send a task management function (TMF). Thus we want to retry a - * bit before returning an error. To avoid the performance penalty - * of MMIO, we spread the update of 'room' over multiple commands. - */ -retry: - newval = atomic64_dec_if_positive(&afu->room); - if (!newval) { - do { - room = readq_be(&afu->host_map->cmd_room); - atomic64_set(&afu->room, room); - if (room) - goto write_ioarrin; - udelay(nretry); - } while (nretry++ < MC_ROOM_RETRY_CNT); - - pr_err("%s: no cmd_room to send 0x%X\n", - __func__, cmd->rcb.cdb[0]); - - goto no_room; - } else if (unlikely(newval < 0)) { - /* This should be rare. i.e. Only if two threads race and - * decrement before the MMIO read is done. In this case - * just benefit from the other thread having updated - * afu->room. - */ - if (nretry++ < MC_ROOM_RETRY_CNT) { - udelay(nretry); - goto retry; - } - - goto no_room; - } - -write_ioarrin: - writeq_be((u64)&cmd->rcb, &afu->host_map->ioarrin); out: - pr_debug("%s: cmd=%p len=%d ea=%p rc=%d\n", __func__, cmd, - cmd->rcb.data_len, (void *)cmd->rcb.data_ea, rc); + pr_debug("%s: returning rc=%d\n", __func__, rc); return rc; -no_room: - afu->read_room = true; - schedule_work(&cfg->work_q); - rc = SCSI_MLQUEUE_HOST_BUSY; +err2: + cxl_psa_unmap((void __iomem *)afu->afu_map); + afu->afu_map = NULL; +err1: + term_mc(cfg, UNDO_START); goto out; } -/** - * cxlflash_wait_resp() - polls for a response or timeout to a sent AFU command - * @afu: AFU associated with the host. - * @cmd: AFU command that was sent. - */ -void cxlflash_wait_resp(struct afu *afu, struct afu_cmd *cmd) -{ - ulong timeout = jiffies + (cmd->rcb.timeout * 2 * HZ); - - timeout = wait_for_completion_timeout(&cmd->cevent, timeout); - if (!timeout) - cxlflash_context_reset(cmd); - - if (unlikely(cmd->sa.ioasc != 0)) - pr_err("%s: CMD 0x%X failed, IOASC: flags 0x%X, afu_rc 0x%X, " - "scsi_rc 0x%X, fc_rc 0x%X\n", __func__, cmd->rcb.cdb[0], - cmd->sa.rc.flags, cmd->sa.rc.afu_rc, cmd->sa.rc.scsi_rc, - cmd->sa.rc.fc_rc); -} - /** * cxlflash_afu_sync() - builds and sends an AFU sync command * @afu: AFU associated with the host. @@ -2091,7 +1780,7 @@ void cxlflash_wait_resp(struct afu *afu, struct afu_cmd *cmd) * @mode: Type of sync to issue (lightweight, heavyweight, global). * * The AFU can only take 1 sync command at a time. This routine enforces this - * limitation by using a mutex to provide exlusive access to the AFU during + * limitation by using a mutex to provide exclusive access to the AFU during * the sync. This design point requires calling threads to not be on interrupt * context due to the possibility of sleeping during concurrent sync operations. * @@ -2109,6 +1798,7 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, res_hndl_t res_hndl_u, u8 mode) { struct cxlflash_cfg *cfg = afu->parent; + struct device *dev = &cfg->dev->dev; struct afu_cmd *cmd = NULL; int rc = 0; int retry_cnt = 0; @@ -2121,13 +1811,13 @@ int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, mutex_lock(&sync_active); retry: - cmd = cxlflash_cmd_checkout(afu); + cmd = cmd_checkout(afu); if (unlikely(!cmd)) { retry_cnt++; udelay(1000 * retry_cnt); if (retry_cnt < MC_RETRY_CNT) goto retry; - pr_err("%s: could not get a free command\n", __func__); + dev_err(dev, "%s: could not get a free command\n", __func__); rc = -1; goto out; } @@ -2147,36 +1837,34 @@ retry: cmd->rcb.cdb[1] = mode; /* The cdb is aligned, no unaligned accessors required */ - *((u16 *)&cmd->rcb.cdb[2]) = swab16(ctx_hndl_u); - *((u32 *)&cmd->rcb.cdb[4]) = swab32(res_hndl_u); + *((__be16 *)&cmd->rcb.cdb[2]) = cpu_to_be16(ctx_hndl_u); + *((__be32 *)&cmd->rcb.cdb[4]) = cpu_to_be32(res_hndl_u); - rc = cxlflash_send_cmd(afu, cmd); + rc = send_cmd(afu, cmd); if (unlikely(rc)) goto out; - cxlflash_wait_resp(afu, cmd); + wait_resp(afu, cmd); - /* set on timeout */ + /* Set on timeout */ if (unlikely((cmd->sa.ioasc != 0) || (cmd->sa.host_use_b[0] & B_ERROR))) rc = -1; out: mutex_unlock(&sync_active); if (cmd) - cxlflash_cmd_checkin(cmd); + cmd_checkin(cmd); pr_debug("%s: returning rc=%d\n", __func__, rc); return rc; } /** - * cxlflash_afu_reset() - resets the AFU - * @cxlflash: Internal structure associated with the host. + * afu_reset() - resets the AFU + * @cfg: Internal structure associated with the host. * - * Return: - * 0 on success - * A failure value from internal services. + * Return: 0 on success, -errno on failure */ -int cxlflash_afu_reset(struct cxlflash_cfg *cfg) +static int afu_reset(struct cxlflash_cfg *cfg) { int rc = 0; /* Stop the context before the reset. Since the context is @@ -2191,6 +1879,413 @@ int cxlflash_afu_reset(struct cxlflash_cfg *cfg) return rc; } +/** + * cxlflash_eh_device_reset_handler() - reset a single LUN + * @scp: SCSI command to send. + * + * Return: + * SUCCESS as defined in scsi/scsi.h + * FAILED as defined in scsi/scsi.h + */ +static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) +{ + int rc = SUCCESS; + struct Scsi_Host *host = scp->device->host; + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + struct afu *afu = cfg->afu; + int rcr = 0; + + pr_debug("%s: (scp=%p) %d/%d/%d/%llu " + "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, + host->host_no, scp->device->channel, + scp->device->id, scp->device->lun, + get_unaligned_be32(&((u32 *)scp->cmnd)[0]), + get_unaligned_be32(&((u32 *)scp->cmnd)[1]), + get_unaligned_be32(&((u32 *)scp->cmnd)[2]), + get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + +retry: + switch (cfg->state) { + case STATE_NORMAL: + rcr = send_tmf(afu, scp, TMF_LUN_RESET); + if (unlikely(rcr)) + rc = FAILED; + break; + case STATE_RESET: + wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); + goto retry; + default: + rc = FAILED; + break; + } + + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * cxlflash_eh_host_reset_handler() - reset the host adapter + * @scp: SCSI command from stack identifying host. + * + * Return: + * SUCCESS as defined in scsi/scsi.h + * FAILED as defined in scsi/scsi.h + */ +static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) +{ + int rc = SUCCESS; + int rcr = 0; + struct Scsi_Host *host = scp->device->host; + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; + + pr_debug("%s: (scp=%p) %d/%d/%d/%llu " + "cdb=(%08X-%08X-%08X-%08X)\n", __func__, scp, + host->host_no, scp->device->channel, + scp->device->id, scp->device->lun, + get_unaligned_be32(&((u32 *)scp->cmnd)[0]), + get_unaligned_be32(&((u32 *)scp->cmnd)[1]), + get_unaligned_be32(&((u32 *)scp->cmnd)[2]), + get_unaligned_be32(&((u32 *)scp->cmnd)[3])); + + switch (cfg->state) { + case STATE_NORMAL: + cfg->state = STATE_RESET; + cxlflash_mark_contexts_error(cfg); + rcr = afu_reset(cfg); + if (rcr) { + rc = FAILED; + cfg->state = STATE_FAILTERM; + } else + cfg->state = STATE_NORMAL; + wake_up_all(&cfg->reset_waitq); + break; + case STATE_RESET: + wait_event(cfg->reset_waitq, cfg->state != STATE_RESET); + if (cfg->state == STATE_NORMAL) + break; + /* fall through */ + default: + rc = FAILED; + break; + } + + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * cxlflash_change_queue_depth() - change the queue depth for the device + * @sdev: SCSI device destined for queue depth change. + * @qdepth: Requested queue depth value to set. + * + * The requested queue depth is capped to the maximum supported value. + * + * Return: The actual queue depth set. + */ +static int cxlflash_change_queue_depth(struct scsi_device *sdev, int qdepth) +{ + + if (qdepth > CXLFLASH_MAX_CMDS_PER_LUN) + qdepth = CXLFLASH_MAX_CMDS_PER_LUN; + + scsi_change_queue_depth(sdev, qdepth); + return sdev->queue_depth; +} + +/** + * cxlflash_show_port_status() - queries and presents the current port status + * @port: Desired port for status reporting. + * @afu: AFU owning the specified port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_show_port_status(u32 port, struct afu *afu, char *buf) +{ + char *disp_status; + u64 status; + __be64 __iomem *fc_regs; + + if (port >= NUM_FC_PORTS) + return 0; + + fc_regs = &afu->afu_map->global.fc_regs[port][0]; + status = readq_be(&fc_regs[FC_MTIP_STATUS / 8]); + status &= FC_MTIP_STATUS_MASK; + + if (status == FC_MTIP_STATUS_ONLINE) + disp_status = "online"; + else if (status == FC_MTIP_STATUS_OFFLINE) + disp_status = "offline"; + else + disp_status = "unknown"; + + return scnprintf(buf, PAGE_SIZE, "%s\n", disp_status); +} + +/** + * port0_show() - queries and presents the current status of port 0 + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t port0_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + + return cxlflash_show_port_status(0, afu, buf); +} + +/** + * port1_show() - queries and presents the current status of port 1 + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t port1_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + + return cxlflash_show_port_status(1, afu, buf); +} + +/** + * lun_mode_show() - presents the current LUN mode of the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the LUN mode. + * @buf: Buffer of length PAGE_SIZE to report back the LUN mode in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t lun_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + + return scnprintf(buf, PAGE_SIZE, "%u\n", afu->internal_lun); +} + +/** + * lun_mode_store() - sets the LUN mode of the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the LUN mode. + * @buf: Buffer of length PAGE_SIZE containing the LUN mode in ASCII. + * @count: Length of data resizing in @buf. + * + * The CXL Flash AFU supports a dummy LUN mode where the external + * links and storage are not required. Space on the FPGA is used + * to create 1 or 2 small LUNs which are presented to the system + * as if they were a normal storage device. This feature is useful + * during development and also provides manufacturing with a way + * to test the AFU without an actual device. + * + * 0 = external LUN[s] (default) + * 1 = internal LUN (1 x 64K, 512B blocks, id 0) + * 2 = internal LUN (1 x 64K, 4K blocks, id 0) + * 3 = internal LUN (2 x 32K, 512B blocks, ids 0,1) + * 4 = internal LUN (2 x 32K, 4K blocks, ids 0,1) + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t lun_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + int rc; + u32 lun_mode; + + rc = kstrtouint(buf, 10, &lun_mode); + if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) { + afu->internal_lun = lun_mode; + afu_reset(cfg); + scsi_scan_host(cfg->host); + } + + return count; +} + +/** + * ioctl_version_show() - presents the current ioctl version of the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the ioctl version. + * @buf: Buffer of length PAGE_SIZE to report back the ioctl version. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t ioctl_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%u\n", DK_CXLFLASH_VERSION_0); +} + +/** + * cxlflash_show_port_lun_table() - queries and presents the port LUN table + * @port: Desired port for status reporting. + * @afu: AFU owning the specified port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_show_port_lun_table(u32 port, + struct afu *afu, + char *buf) +{ + int i; + ssize_t bytes = 0; + __be64 __iomem *fc_port; + + if (port >= NUM_FC_PORTS) + return 0; + + fc_port = &afu->afu_map->global.fc_port[port][0]; + + for (i = 0; i < CXLFLASH_NUM_VLUNS; i++) + bytes += scnprintf(buf + bytes, PAGE_SIZE - bytes, + "%03d: %016llX\n", i, readq_be(&fc_port[i])); + return bytes; +} + +/** + * port0_lun_table_show() - presents the current LUN table of port 0 + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t port0_lun_table_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + + return cxlflash_show_port_lun_table(0, afu, buf); +} + +/** + * port1_lun_table_show() - presents the current LUN table of port 1 + * @dev: Generic device associated with the host owning the port. + * @attr: Device attribute representing the port. + * @buf: Buffer of length PAGE_SIZE to report back port status in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t port1_lun_table_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)shost->hostdata; + struct afu *afu = cfg->afu; + + return cxlflash_show_port_lun_table(1, afu, buf); +} + +/** + * mode_show() - presents the current mode of the device + * @dev: Generic device associated with the device. + * @attr: Device attribute representing the device mode. + * @buf: Buffer of length PAGE_SIZE to report back the dev mode in ASCII. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", + sdev->hostdata ? "superpipe" : "legacy"); +} + +/* + * Host attributes + */ +static DEVICE_ATTR_RO(port0); +static DEVICE_ATTR_RO(port1); +static DEVICE_ATTR_RW(lun_mode); +static DEVICE_ATTR_RO(ioctl_version); +static DEVICE_ATTR_RO(port0_lun_table); +static DEVICE_ATTR_RO(port1_lun_table); + +static struct device_attribute *cxlflash_host_attrs[] = { + &dev_attr_port0, + &dev_attr_port1, + &dev_attr_lun_mode, + &dev_attr_ioctl_version, + &dev_attr_port0_lun_table, + &dev_attr_port1_lun_table, + NULL +}; + +/* + * Device attributes + */ +static DEVICE_ATTR_RO(mode); + +static struct device_attribute *cxlflash_dev_attrs[] = { + &dev_attr_mode, + NULL +}; + +/* + * Host template + */ +static struct scsi_host_template driver_template = { + .module = THIS_MODULE, + .name = CXLFLASH_ADAPTER_NAME, + .info = cxlflash_driver_info, + .ioctl = cxlflash_ioctl, + .proc_name = CXLFLASH_NAME, + .queuecommand = cxlflash_queuecommand, + .eh_device_reset_handler = cxlflash_eh_device_reset_handler, + .eh_host_reset_handler = cxlflash_eh_host_reset_handler, + .change_queue_depth = cxlflash_change_queue_depth, + .cmd_per_lun = 16, + .can_queue = CXLFLASH_MAX_CMDS, + .this_id = -1, + .sg_tablesize = SG_NONE, /* No scatter gather support */ + .max_sectors = CXLFLASH_MAX_SECTORS, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = cxlflash_host_attrs, + .sdev_attrs = cxlflash_dev_attrs, +}; + +/* + * Device dependent values + */ +static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS }; + +/* + * PCI device binding table + */ +static struct pci_device_id cxlflash_pci_table[] = { + {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals}, + {} +}; + +MODULE_DEVICE_TABLE(pci, cxlflash_pci_table); + /** * cxlflash_worker_thread() - work thread handler for the AFU * @work: Work structure contained within cxlflash associated with host. @@ -2199,12 +2294,14 @@ int cxlflash_afu_reset(struct cxlflash_cfg *cfg) * - Link reset which cannot be performed on interrupt context due to * blocking up to a few seconds * - Read AFU command room + * - Rescan the host */ static void cxlflash_worker_thread(struct work_struct *work) { struct cxlflash_cfg *cfg = container_of(work, struct cxlflash_cfg, work_q); struct afu *afu = cfg->afu; + struct device *dev = &cfg->dev->dev; int port; ulong lock_flags; @@ -2218,15 +2315,15 @@ static void cxlflash_worker_thread(struct work_struct *work) if (cfg->lr_state == LINK_RESET_REQUIRED) { port = cfg->lr_port; if (port < 0) - pr_err("%s: invalid port index %d\n", __func__, port); + dev_err(dev, "%s: invalid port index %d\n", + __func__, port); else { spin_unlock_irqrestore(cfg->host->host_lock, lock_flags); /* The reset can block... */ afu_link_reset(afu, port, - &afu->afu_map-> - global.fc_regs[port][0]); + &afu->afu_map->global.fc_regs[port][0]); spin_lock_irqsave(cfg->host->host_lock, lock_flags); } @@ -2239,6 +2336,9 @@ static void cxlflash_worker_thread(struct work_struct *work) } spin_unlock_irqrestore(cfg->host->host_lock, lock_flags); + + if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0) + scsi_scan_host(cfg->host); } /** @@ -2246,7 +2346,7 @@ static void cxlflash_worker_thread(struct work_struct *work) * @pdev: PCI device associated with the host. * @dev_id: PCI device id associated with device. * - * Return: 0 on success / non-zero on failure + * Return: 0 on success, -errno on failure */ static int cxlflash_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) @@ -2281,14 +2381,16 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->host = host; rc = alloc_mem(cfg); if (rc) { - dev_err(&pdev->dev, "%s: call to scsi_host_alloc failed!\n", + dev_err(&pdev->dev, "%s: call to alloc_mem failed!\n", __func__); rc = -ENOMEM; + scsi_host_put(cfg->host); goto out; } cfg->init_state = INIT_STATE_NONE; cfg->dev = pdev; + cfg->cxl_fops = cxlflash_cxl_fops; /* * The promoted LUNs move to the top of the LUN table. The rest stay @@ -2301,28 +2403,30 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->last_lun_index[1] = CXLFLASH_NUM_VLUNS/2 - 1; cfg->dev_id = (struct pci_device_id *)dev_id; - cfg->mcctx = NULL; init_waitqueue_head(&cfg->tmf_waitq); - init_waitqueue_head(&cfg->limbo_waitq); + init_waitqueue_head(&cfg->reset_waitq); INIT_WORK(&cfg->work_q, cxlflash_worker_thread); cfg->lr_state = LINK_RESET_INVALID; cfg->lr_port = -1; + spin_lock_init(&cfg->tmf_slock); mutex_init(&cfg->ctx_tbl_list_mutex); mutex_init(&cfg->ctx_recovery_mutex); + init_rwsem(&cfg->ioctl_rwsem); INIT_LIST_HEAD(&cfg->ctx_err_recovery); INIT_LIST_HEAD(&cfg->lluns); pci_set_drvdata(pdev, cfg); - /* Use the special service provided to look up the physical + /* + * Use the special service provided to look up the physical * PCI device, since we are called on the probe of the virtual * PCI host bus (vphb) */ phys_dev = cxl_get_phys_dev(pdev); if (!dev_is_pci(phys_dev)) { - pr_err("%s: not a pci dev\n", __func__); + dev_err(&pdev->dev, "%s: not a pci dev\n", __func__); rc = -ENODEV; goto out_remove; } @@ -2346,7 +2450,6 @@ static int cxlflash_probe(struct pci_dev *pdev, } cfg->init_state = INIT_STATE_AFU; - rc = init_scsi(cfg); if (rc) { dev_err(&pdev->dev, "%s: call to init_scsi " @@ -2364,6 +2467,19 @@ out_remove: goto out; } +/** + * drain_ioctls() - wait until all currently executing ioctls have completed + * @cfg: Internal structure associated with the host. + * + * Obtain write access to read/write semaphore that wraps ioctl + * handling to 'drain' ioctls currently executing. + */ +static void drain_ioctls(struct cxlflash_cfg *cfg) +{ + down_write(&cfg->ioctl_rwsem); + up_write(&cfg->ioctl_rwsem); +} + /** * cxlflash_pci_error_detected() - called when a PCI error is detected * @pdev: PCI device struct. @@ -2382,21 +2498,19 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, switch (state) { case pci_channel_io_frozen: - cfg->state = STATE_LIMBO; - - /* Turn off legacy I/O */ + cfg->state = STATE_RESET; scsi_block_requests(cfg->host); + drain_ioctls(cfg); rc = cxlflash_mark_contexts_error(cfg); if (unlikely(rc)) dev_err(dev, "%s: Failed to mark user contexts!(%d)\n", __func__, rc); term_mc(cfg, UNDO_START); stop_afu(cfg); - return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: cfg->state = STATE_FAILTERM; - wake_up_all(&cfg->limbo_waitq); + wake_up_all(&cfg->reset_waitq); scsi_unblock_requests(cfg->host); return PCI_ERS_RESULT_DISCONNECT; default: @@ -2443,7 +2557,7 @@ static void cxlflash_pci_resume(struct pci_dev *pdev) dev_dbg(dev, "%s: pdev=%p\n", __func__, pdev); cfg->state = STATE_NORMAL; - wake_up_all(&cfg->limbo_waitq); + wake_up_all(&cfg->reset_waitq); scsi_unblock_requests(cfg->host); } @@ -2467,7 +2581,7 @@ static struct pci_driver cxlflash_driver = { /** * init_cxlflash() - module entry point * - * Return: 0 on success / non-zero on failure + * Return: 0 on success, -errno on failure */ static int __init init_cxlflash(void) { diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h index cf0e80938..60324566c 100644 --- a/drivers/scsi/cxlflash/main.h +++ b/drivers/scsi/cxlflash/main.h @@ -99,6 +99,7 @@ struct asyc_intr_info { u8 action; #define CLR_FC_ERROR 0x01 #define LINK_RESET 0x02 +#define SCAN_HOST 0x04 }; #ifndef CONFIG_CXL_EEH diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 63bf394fe..0b3366f5e 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -146,7 +146,7 @@ struct sisl_rc { #define SISL_FC_RC_ABORTFAIL 0x59 /* pending abort completed w/fail */ #define SISL_FC_RC_RESID 0x5A /* ioasa underrun/overrun flags set */ #define SISL_FC_RC_RESIDERR 0x5B /* actual data len does not match SCSI - reported len, possbly due to dropped + reported len, possibly due to dropped frames */ #define SISL_FC_RC_TGTABORT 0x5C /* command aborted by target */ }; @@ -258,7 +258,7 @@ struct sisl_host_map { __be64 rrq_start; /* start & end are both inclusive */ __be64 rrq_end; /* write sequence: start followed by end */ __be64 cmd_room; - __be64 ctx_ctrl; /* least signiifcant byte or b56:63 is LISN# */ + __be64 ctx_ctrl; /* least significant byte or b56:63 is LISN# */ __be64 mbox_w; /* restricted use */ }; @@ -290,7 +290,7 @@ struct sisl_global_regs { #define SISL_ASTATUS_FC0_LOGO 0x4000ULL /* b49, target sent FLOGI/PLOGI/LOGO while logged in */ #define SISL_ASTATUS_FC0_CRC_T 0x2000ULL /* b50, CRC threshold exceeded */ -#define SISL_ASTATUS_FC0_LOGI_R 0x1000ULL /* b51, login state mechine timed out +#define SISL_ASTATUS_FC0_LOGI_R 0x1000ULL /* b51, login state machine timed out and retrying */ #define SISL_ASTATUS_FC0_LOGI_F 0x0800ULL /* b52, login failed, FC_ERROR[19:0] */ @@ -340,7 +340,7 @@ struct sisl_global_regs { #define SISL_AFUCONF_MBOX_CLR_READ 0x0010ULL __be64 afu_config; __be64 rsvd[0xf8]; - __be64 afu_version; + __le64 afu_version; __be64 interface_version; }; diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index f1b62cea7..cac2e6a50 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -76,7 +76,7 @@ void cxlflash_free_errpage(void) * * When the host needs to go down, all users must be quiesced and their * memory freed. This is accomplished by putting the contexts in error - * state which will notify the user and let them 'drive' the tear-down. + * state which will notify the user and let them 'drive' the tear down. * Meanwhile, this routine camps until all user contexts have been removed. */ void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg) @@ -100,7 +100,7 @@ void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg) dev_dbg(dev, "%s: Wait for user contexts to quiesce...\n", __func__); - wake_up_all(&cfg->limbo_waitq); + wake_up_all(&cfg->reset_waitq); ssleep(1); } } @@ -162,10 +162,7 @@ struct ctx_info *get_context(struct cxlflash_cfg *cfg, u64 rctxid, if (likely(ctxid < MAX_CONTEXT)) { while (true) { - rc = mutex_lock_interruptible(&cfg->ctx_tbl_list_mutex); - if (rc) - goto out; - + mutex_lock(&cfg->ctx_tbl_list_mutex); ctxi = cfg->ctx_tbl[ctxid]; if (ctxi) if ((file && (ctxi->file != file)) || @@ -253,7 +250,7 @@ static int afu_attach(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) { struct device *dev = &cfg->dev->dev; struct afu *afu = cfg->afu; - struct sisl_ctrl_map *ctrl_map = ctxi->ctrl_map; + struct sisl_ctrl_map __iomem *ctrl_map = ctxi->ctrl_map; int rc = 0; u64 val; @@ -283,6 +280,24 @@ out: * @sdev: SCSI device associated with LUN. * @lli: LUN destined for capacity request. * + * The READ_CAP16 can take quite a while to complete. Should an EEH occur while + * in scsi_execute(), the EEH handler will attempt to recover. As part of the + * recovery, the handler drains all currently running ioctls, waiting until they + * have completed before proceeding with a reset. As this routine is used on the + * ioctl path, this can create a condition where the EEH handler becomes stuck, + * infinitely waiting for this ioctl thread. To avoid this behavior, temporarily + * unmark this thread as an ioctl thread by releasing the ioctl read semaphore. + * This will allow the EEH handler to proceed with a recovery while this thread + * is still running. Once the scsi_execute() returns, reacquire the ioctl read + * semaphore and check the adapter state in case it changed while inside of + * scsi_execute(). The state check will wait if the adapter is still being + * recovered or return a failure if the recovery failed. In the event that the + * adapter reset failed, simply return the failure as the ioctl would be unable + * to continue. + * + * Note that the above puts a requirement on this routine to only be called on + * an ioctl thread. + * * Return: 0 on success, -errno on failure */ static int read_cap16(struct scsi_device *sdev, struct llun_info *lli) @@ -296,7 +311,7 @@ static int read_cap16(struct scsi_device *sdev, struct llun_info *lli) int rc = 0; int result = 0; int retry_cnt = 0; - u32 tout = (MC_DISCOVERY_TIMEOUT * HZ); + u32 to = CMD_TIMEOUT * HZ; retry: cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL); @@ -314,8 +329,18 @@ retry: dev_dbg(dev, "%s: %ssending cmd(0x%x)\n", __func__, retry_cnt ? "re" : "", scsi_cmd[0]); + /* Drop the ioctl read semahpore across lengthy call */ + up_read(&cfg->ioctl_rwsem); result = scsi_execute(sdev, scsi_cmd, DMA_FROM_DEVICE, cmd_buf, - CMD_BUFSIZE, sense_buf, tout, 5, 0, NULL); + CMD_BUFSIZE, sense_buf, to, CMD_RETRIES, 0, NULL); + down_read(&cfg->ioctl_rwsem); + rc = check_state(cfg); + if (rc) { + dev_err(dev, "%s: Failed state! result=0x08%X\n", + __func__, result); + rc = -ENODEV; + goto out; + } if (driver_byte(result) == DRIVER_SENSE) { result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */ @@ -365,8 +390,8 @@ retry: * as the buffer is allocated on an aligned boundary. */ mutex_lock(&gli->mutex); - gli->max_lba = be64_to_cpu(*((u64 *)&cmd_buf[0])); - gli->blk_len = be32_to_cpu(*((u32 *)&cmd_buf[8])); + gli->max_lba = be64_to_cpu(*((__be64 *)&cmd_buf[0])); + gli->blk_len = be32_to_cpu(*((__be32 *)&cmd_buf[8])); mutex_unlock(&gli->mutex); out: @@ -712,7 +737,6 @@ static void destroy_context(struct cxlflash_cfg *cfg, kfree(ctxi->rht_needs_ws); kfree(ctxi->rht_lun); kfree(ctxi); - atomic_dec_if_positive(&cfg->num_user_contexts); } /** @@ -737,7 +761,7 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg, struct afu *afu = cfg->afu; struct ctx_info *ctxi = NULL; struct llun_info **lli = NULL; - bool *ws = NULL; + u8 *ws = NULL; struct sisl_rht_entry *rhte; ctxi = kzalloc(sizeof(*ctxi), GFP_KERNEL); @@ -769,7 +793,6 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg, INIT_LIST_HEAD(&ctxi->luns); INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */ - atomic_inc(&cfg->num_user_contexts); mutex_lock(&ctxi->mutex); out: return ctxi; @@ -880,6 +903,9 @@ static int _cxlflash_disk_detach(struct scsi_device *sdev, sys_close(lfd); } + /* Release the sdev reference that bound this LUN to the context */ + scsi_device_put(sdev); + out: if (put_ctx) put_context(ctxi); @@ -1161,10 +1187,7 @@ out: return rc; } -/* - * Local fops for adapter file descriptor - */ -static const struct file_operations cxlflash_cxl_fops = { +const struct file_operations cxlflash_cxl_fops = { .owner = THIS_MODULE, .mmap = cxlflash_cxl_mmap, .release = cxlflash_cxl_release, @@ -1210,6 +1233,46 @@ static const struct file_operations null_fops = { .owner = THIS_MODULE, }; +/** + * check_state() - checks and responds to the current adapter state + * @cfg: Internal structure associated with the host. + * + * This routine can block and should only be used on process context. + * It assumes that the caller is an ioctl thread and holding the ioctl + * read semaphore. This is temporarily let up across the wait to allow + * for draining actively running ioctls. Also note that when waking up + * from waiting in reset, the state is unknown and must be checked again + * before proceeding. + * + * Return: 0 on success, -errno on failure + */ +int check_state(struct cxlflash_cfg *cfg) +{ + struct device *dev = &cfg->dev->dev; + int rc = 0; + +retry: + switch (cfg->state) { + case STATE_RESET: + dev_dbg(dev, "%s: Reset state, going to wait...\n", __func__); + up_read(&cfg->ioctl_rwsem); + rc = wait_event_interruptible(cfg->reset_waitq, + cfg->state != STATE_RESET); + down_read(&cfg->ioctl_rwsem); + if (unlikely(rc)) + break; + goto retry; + case STATE_FAILTERM: + dev_dbg(dev, "%s: Failed/Terminating!\n", __func__); + rc = -ENODEV; + break; + default: + break; + } + + return rc; +} + /** * cxlflash_disk_attach() - attach a LUN to a context * @sdev: SCSI device associated with LUN. @@ -1243,10 +1306,6 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, int fd = -1; - /* On first attach set fileops */ - if (atomic_read(&cfg->num_user_contexts) == 0) - cfg->cxl_fops = cxlflash_cxl_fops; - if (attach->num_interrupts > 4) { dev_dbg(dev, "%s: Cannot support this many interrupts %llu\n", __func__, attach->num_interrupts); @@ -1287,11 +1346,17 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, } } + rc = scsi_device_get(sdev); + if (unlikely(rc)) { + dev_err(dev, "%s: Unable to get sdev reference!\n", __func__); + goto out; + } + lun_access = kzalloc(sizeof(*lun_access), GFP_KERNEL); if (unlikely(!lun_access)) { dev_err(dev, "%s: Unable to allocate lun_access!\n", __func__); rc = -ENOMEM; - goto out; + goto err0; } lun_access->lli = lli; @@ -1311,21 +1376,21 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, dev_err(dev, "%s: Could not initialize context %p\n", __func__, ctx); rc = -ENODEV; - goto err0; + goto err1; } ctxid = cxl_process_element(ctx); if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) { dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid); rc = -EPERM; - goto err1; + goto err2; } file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd); if (unlikely(fd < 0)) { rc = -ENODEV; dev_err(dev, "%s: Could not get file descriptor\n", __func__); - goto err1; + goto err2; } /* Translate read/write O_* flags from fcntl.h to AFU permission bits */ @@ -1335,7 +1400,7 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, if (unlikely(!ctxi)) { dev_err(dev, "%s: Failed to create context! (%d)\n", __func__, ctxid); - goto err2; + goto err3; } work = &ctxi->work; @@ -1346,13 +1411,13 @@ static int cxlflash_disk_attach(struct scsi_device *sdev, if (unlikely(rc)) { dev_dbg(dev, "%s: Could not start context rc=%d\n", __func__, rc); - goto err3; + goto err4; } rc = afu_attach(cfg, ctxi); if (unlikely(rc)) { dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc); - goto err4; + goto err5; } /* @@ -1375,7 +1440,8 @@ out_attach: attach->block_size = gli->blk_len; attach->mmio_size = sizeof(afu->afu_map->hosts[0].harea); attach->last_lba = gli->max_lba; - attach->max_xfer = (sdev->host->max_sectors * 512) / gli->blk_len; + attach->max_xfer = sdev->host->max_sectors * MAX_SECTOR_UNIT; + attach->max_xfer /= gli->blk_len; out: attach->adap_fd = fd; @@ -1387,13 +1453,13 @@ out: __func__, ctxid, fd, attach->block_size, rc, attach->last_lba); return rc; -err4: +err5: cxl_stop_context(ctx); -err3: +err4: put_context(ctxi); destroy_context(cfg, ctxi); ctxi = NULL; -err2: +err3: /* * Here, we're overriding the fops with a dummy all-NULL fops because * fput() calls the release fop, which will cause us to mistakenly @@ -1405,10 +1471,12 @@ err2: fput(file); put_unused_fd(fd); fd = -1; -err1: +err2: cxl_release_context(ctx); -err0: +err1: kfree(lun_access); +err0: + scsi_device_put(sdev); goto out; } @@ -1510,41 +1578,6 @@ err1: goto out; } -/** - * check_state() - checks and responds to the current adapter state - * @cfg: Internal structure associated with the host. - * - * This routine can block and should only be used on process context. - * Note that when waking up from waiting in limbo, the state is unknown - * and must be checked again before proceeding. - * - * Return: 0 on success, -errno on failure - */ -static int check_state(struct cxlflash_cfg *cfg) -{ - struct device *dev = &cfg->dev->dev; - int rc = 0; - -retry: - switch (cfg->state) { - case STATE_LIMBO: - dev_dbg(dev, "%s: Limbo, going to wait...\n", __func__); - rc = wait_event_interruptible(cfg->limbo_waitq, - cfg->state != STATE_LIMBO); - if (unlikely(rc)) - break; - goto retry; - case STATE_FAILTERM: - dev_dbg(dev, "%s: Failed/Terminating!\n", __func__); - rc = -ENODEV; - break; - default: - break; - } - - return rc; -} - /** * cxlflash_afu_recover() - initiates AFU recovery * @sdev: SCSI device associated with LUN. @@ -1561,10 +1594,10 @@ retry: * quite possible for this routine to act as the kernel's EEH detection * source (MMIO read of mbox_r). Because of this, there is a window of * time where an EEH might have been detected but not yet 'serviced' - * (callback invoked, causing the device to enter limbo state). To avoid + * (callback invoked, causing the device to enter reset state). To avoid * looping in this routine during that window, a 1 second sleep is in place * between the time the MMIO failure is detected and the time a wait on the - * limbo wait queue is attempted via check_state(). + * reset wait queue is attempted via check_state(). * * Return: 0 on success, -errno on failure */ @@ -1634,9 +1667,14 @@ retry_recover: /* Test if in error state */ reg = readq_be(&afu->ctrl_map->mbox_r); if (reg == -1) { - dev_dbg(dev, "%s: MMIO read fail! Wait for recovery...\n", - __func__); - mutex_unlock(&ctxi->mutex); + dev_dbg(dev, "%s: MMIO fail, wait for recovery.\n", __func__); + + /* + * Before checking the state, put back the context obtained with + * get_context() as it is no longer needed and sleep for a short + * period of time (see prolog notes). + */ + put_context(ctxi); ctxi = NULL; ssleep(1); rc = check_state(cfg); @@ -1765,12 +1803,21 @@ static int cxlflash_disk_verify(struct scsi_device *sdev, * inquiry (i.e. the Unit attention is due to the WWN changing). */ if (verify->hint & DK_CXLFLASH_VERIFY_HINT_SENSE) { + /* Can't hold mutex across process_sense/read_cap16, + * since we could have an intervening EEH event. + */ + ctxi->unavail = true; + mutex_unlock(&ctxi->mutex); rc = process_sense(sdev, verify); if (unlikely(rc)) { dev_err(dev, "%s: Failed to validate sense data (%d)\n", __func__, rc); + mutex_lock(&ctxi->mutex); + ctxi->unavail = false; goto out; } + mutex_lock(&ctxi->mutex); + ctxi->unavail = false; } switch (gli->mode) { @@ -1955,6 +2002,14 @@ out: * @cmd: IOCTL command. * @arg: Userspace ioctl data structure. * + * A read/write semaphore is used to implement a 'drain' of currently + * running ioctls. The read semaphore is taken at the beginning of each + * ioctl thread and released upon concluding execution. Additionally the + * semaphore should be released and then reacquired in any ioctl execution + * path which will wait for an event to occur that is outside the scope of + * the ioctl (i.e. an adapter reset). To drain the ioctls currently running, + * a thread simply needs to acquire the write semaphore. + * * Return: 0 on success, -errno on failure */ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) @@ -1989,6 +2044,9 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) {sizeof(struct dk_cxlflash_clone), (sioctl)cxlflash_disk_clone}, }; + /* Hold read semaphore so we can drain if needed */ + down_read(&cfg->ioctl_rwsem); + /* Restrict command set to physical support only for internal LUN */ if (afu->internal_lun) switch (cmd) { @@ -2070,6 +2128,7 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) /* fall through to exit */ cxlflash_ioctl_exit: + up_read(&cfg->ioctl_rwsem); if (unlikely(rc && known_ioctl)) dev_err(dev, "%s: ioctl %s (%08X) on dev(%d/%d/%d/%llu) " "returned rc %d\n", __func__, diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index d7dc88bc6..bede574bc 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -28,7 +28,10 @@ extern struct cxlflash_global global; */ #define MC_CHUNK_SIZE (1 << MC_RHT_NMASK) /* in LBAs */ -#define MC_DISCOVERY_TIMEOUT 5 /* 5 secs */ +#define CMD_TIMEOUT 30 /* 30 secs */ +#define CMD_RETRIES 5 /* 5 retries for scsi_execute */ + +#define MAX_SECTOR_UNIT 512 /* max_sector is in 512 byte multiples */ #define CHAN2PORT(_x) ((_x) + 1) #define PORT2CHAN(_x) ((_x) - 1) @@ -60,7 +63,6 @@ struct llun_info { u32 lun_index; /* Index in the LUN table */ u32 host_no; /* host_no from Scsi_host */ u32 port_sel; /* What port to use for this LUN */ - bool newly_created; /* Whether the LUN was just discovered */ bool in_table; /* Whether a LUN table entry was created */ u8 wwid[16]; /* Keep a duplicate copy here? */ @@ -84,17 +86,17 @@ enum ctx_ctrl { CTX_CTRL_FILE = (1 << 5) }; -#define ENCODE_CTXID(_ctx, _id) (((((u64)_ctx) & 0xFFFFFFFF0) << 28) | _id) +#define ENCODE_CTXID(_ctx, _id) (((((u64)_ctx) & 0xFFFFFFFF0ULL) << 28) | _id) #define DECODE_CTXID(_val) (_val & 0xFFFFFFFF) struct ctx_info { - struct sisl_ctrl_map *ctrl_map; /* initialized at startup */ + struct sisl_ctrl_map __iomem *ctrl_map; /* initialized at startup */ struct sisl_rht_entry *rht_start; /* 1 page (req'd for alignment), alloc/free on attach/detach */ u32 rht_out; /* Number of checked out RHT entries */ u32 rht_perms; /* User-defined permissions for RHT entries */ struct llun_info **rht_lun; /* Mapping of RHT entries to LUNs */ - bool *rht_needs_ws; /* User-desired write-same function per RHTE */ + u8 *rht_needs_ws; /* User-desired write-same function per RHTE */ struct cxl_ioctl_start_work work; u64 ctxid; @@ -144,4 +146,6 @@ void cxlflash_ba_terminate(struct ba_lun *); int cxlflash_manage_lun(struct scsi_device *, struct dk_cxlflash_manage_lun *); +int check_state(struct cxlflash_cfg *); + #endif /* ifndef _CXLFLASH_SUPERPIPE_H */ diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c index 6155cb1d4..a53f583e2 100644 --- a/drivers/scsi/cxlflash/vlun.c +++ b/drivers/scsi/cxlflash/vlun.c @@ -132,7 +132,7 @@ static int ba_init(struct ba_lun *ba_lun) return -ENOMEM; } - /* Pass the allocated lun info as a handle to the user */ + /* Pass the allocated LUN info as a handle to the user */ ba_lun->ba_lun_handle = bali; pr_debug("%s: Successfully initialized the LUN: " @@ -165,7 +165,7 @@ static int find_free_range(u32 low, num_bits = (sizeof(*lam) * BITS_PER_BYTE); bit_pos = find_first_bit(lam, num_bits); - pr_devel("%s: Found free bit %llX in lun " + pr_devel("%s: Found free bit %llX in LUN " "map entry %llX at bitmap index = %X\n", __func__, bit_pos, bali->lun_alloc_map[i], i); @@ -400,6 +400,24 @@ static int init_vlun(struct llun_info *lli) * @lba: Logical block address to start write same. * @nblks: Number of logical blocks to write same. * + * The SCSI WRITE_SAME16 can take quite a while to complete. Should an EEH occur + * while in scsi_execute(), the EEH handler will attempt to recover. As part of + * the recovery, the handler drains all currently running ioctls, waiting until + * they have completed before proceeding with a reset. As this routine is used + * on the ioctl path, this can create a condition where the EEH handler becomes + * stuck, infinitely waiting for this ioctl thread. To avoid this behavior, + * temporarily unmark this thread as an ioctl thread by releasing the ioctl read + * semaphore. This will allow the EEH handler to proceed with a recovery while + * this thread is still running. Once the scsi_execute() returns, reacquire the + * ioctl read semaphore and check the adapter state in case it changed while + * inside of scsi_execute(). The state check will wait if the adapter is still + * being recovered or return a failure if the recovery failed. In the event that + * the adapter reset failed, simply return the failure as the ioctl would be + * unable to continue. + * + * Note that the above puts a requirement on this routine to only be called on + * an ioctl thread. + * * Return: 0 on success, -errno on failure */ static int write_same16(struct scsi_device *sdev, @@ -414,7 +432,7 @@ static int write_same16(struct scsi_device *sdev, int ws_limit = SISLITE_MAX_WS_BLOCKS; u64 offset = lba; int left = nblks; - u32 tout = sdev->request_queue->rq_timeout; + u32 to = sdev->request_queue->rq_timeout; struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; struct device *dev = &cfg->dev->dev; @@ -433,8 +451,20 @@ static int write_same16(struct scsi_device *sdev, put_unaligned_be32(ws_limit < left ? ws_limit : left, &scsi_cmd[10]); + /* Drop the ioctl read semahpore across lengthy call */ + up_read(&cfg->ioctl_rwsem); result = scsi_execute(sdev, scsi_cmd, DMA_TO_DEVICE, cmd_buf, - CMD_BUFSIZE, sense_buf, tout, 5, 0, NULL); + CMD_BUFSIZE, sense_buf, to, CMD_RETRIES, + 0, NULL); + down_read(&cfg->ioctl_rwsem); + rc = check_state(cfg); + if (rc) { + dev_err(dev, "%s: Failed state! result=0x08%X\n", + __func__, result); + rc = -ENODEV; + goto out; + } + if (result) { dev_err_ratelimited(dev, "%s: command failed for " "offset %lld result=0x%x\n", @@ -681,14 +711,14 @@ out: } /** - * _cxlflash_vlun_resize() - changes the size of a virtual lun + * _cxlflash_vlun_resize() - changes the size of a virtual LUN * @sdev: SCSI device associated with LUN owning virtual LUN. * @ctxi: Context owning resources. * @resize: Resize ioctl data structure. * * On successful return, the user is informed of the new size (in blocks) - * of the virtual lun in last LBA format. When the size of the virtual - * lun is zero, the last LBA is reflected as -1. See comment in the + * of the virtual LUN in last LBA format. When the size of the virtual + * LUN is zero, the last LBA is reflected as -1. See comment in the * prologue for _cxlflash_disk_release() regarding AFU syncs and contexts * on the error recovery list. * @@ -785,7 +815,7 @@ void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) u32 chan; u32 lind; struct afu *afu = cfg->afu; - struct sisl_global_map *agm = &afu->afu_map->global; + struct sisl_global_map __iomem *agm = &afu->afu_map->global; mutex_lock(&global.mutex); @@ -830,7 +860,7 @@ static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) u32 lind; int rc = 0; struct afu *afu = cfg->afu; - struct sisl_global_map *agm = &afu->afu_map->global; + struct sisl_global_map __iomem *agm = &afu->afu_map->global; mutex_lock(&global.mutex); @@ -885,8 +915,8 @@ out: * @arg: UVirtual ioctl data structure. * * On successful return, the user is informed of the resource handle - * to be used to identify the virtual lun and the size (in blocks) of - * the virtual lun in last LBA format. When the size of the virtual lun + * to be used to identify the virtual LUN and the size (in blocks) of + * the virtual LUN in last LBA format. When the size of the virtual LUN * is zero, the last LBA is reflected as -1. * * Return: 0 on success, -errno on failure @@ -914,16 +944,9 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) pr_debug("%s: ctxid=%llu ls=0x%llx\n", __func__, ctxid, lun_size); + /* Setup the LUNs block allocator on first call */ mutex_lock(&gli->mutex); if (gli->mode == MODE_NONE) { - /* Setup the LUN table and block allocator on first call */ - rc = init_luntable(cfg, lli); - if (rc) { - dev_err(dev, "%s: call to init_luntable failed " - "rc=%d!\n", __func__, rc); - goto err0; - } - rc = init_vlun(lli); if (rc) { dev_err(dev, "%s: call to init_vlun failed rc=%d!\n", @@ -941,6 +964,13 @@ int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) } mutex_unlock(&gli->mutex); + rc = init_luntable(cfg, lli); + if (rc) { + dev_err(dev, "%s: call to init_luntable failed rc=%d!\n", + __func__, rc); + goto err1; + } + ctxi = get_context(cfg, rctxid, lli, 0); if (unlikely(!ctxi)) { dev_err(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c index 31f8966b2..33581ba43 100644 --- a/drivers/scsi/esas2r/esas2r_main.c +++ b/drivers/scsi/esas2r/esas2r_main.c @@ -256,7 +256,6 @@ static struct scsi_host_template driver_template = { .proc_name = ESAS2R_DRVR_NAME, .change_queue_depth = scsi_change_queue_depth, .max_sectors = 0xFFFF, - .use_blk_tags = 1, }; int sgl_page_size = 512; diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 065b25df7..71cb05b1c 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c @@ -2694,7 +2694,6 @@ struct scsi_host_template scsi_esp_template = { .use_clustering = ENABLE_CLUSTERING, .max_sectors = 0xffff, .skip_settle_delay = 1, - .use_blk_tags = 1, }; EXPORT_SYMBOL(scsi_esp_template); diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index d3eb80c46..f4424063b 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -287,7 +287,6 @@ static struct scsi_host_template fcoe_shost_template = { .use_clustering = ENABLE_CLUSTERING, .sg_tablesize = SG_ALL, .max_sectors = 0xffff, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -1873,7 +1872,6 @@ static int fcoe_percpu_receive_thread(void *arg) set_user_nice(current, MIN_NICE); -retry: while (!kthread_should_stop()) { spin_lock_bh(&p->fcoe_rx_list.lock); @@ -1883,7 +1881,7 @@ retry: set_current_state(TASK_INTERRUPTIBLE); spin_unlock_bh(&p->fcoe_rx_list.lock); schedule(); - goto retry; + continue; } spin_unlock_bh(&p->fcoe_rx_list.lock); diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index bf0bbd42e..67669a9e7 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -939,6 +939,7 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq) struct sk_buff *skb; u16 len; dma_addr_t pa; + int r; len = FC_FRAME_HEADROOM + FC_MAX_FRAME + FC_FRAME_TAILROOM; skb = dev_alloc_skb(len); @@ -952,8 +953,19 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq) skb_reset_network_header(skb); skb_put(skb, len); pa = pci_map_single(fnic->pdev, skb->data, len, PCI_DMA_FROMDEVICE); + + r = pci_dma_mapping_error(fnic->pdev, pa); + if (r) { + printk(KERN_ERR "PCI mapping failed with error %d\n", r); + goto free_skb; + } + fnic_queue_rq_desc(rq, skb, pa, len); return 0; + +free_skb: + kfree_skb(skb); + return r; } void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) @@ -981,6 +993,7 @@ void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb) struct ethhdr *eth_hdr; struct vlan_ethhdr *vlan_hdr; unsigned long flags; + int r; if (!fnic->vlan_hw_insert) { eth_hdr = (struct ethhdr *)skb_mac_header(skb); @@ -1003,18 +1016,27 @@ void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb) pa = pci_map_single(fnic->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - spin_lock_irqsave(&fnic->wq_lock[0], flags); - if (!vnic_wq_desc_avail(wq)) { - pci_unmap_single(fnic->pdev, pa, skb->len, PCI_DMA_TODEVICE); - spin_unlock_irqrestore(&fnic->wq_lock[0], flags); - kfree_skb(skb); - return; + r = pci_dma_mapping_error(fnic->pdev, pa); + if (r) { + printk(KERN_ERR "PCI mapping failed with error %d\n", r); + goto free_skb; } + spin_lock_irqsave(&fnic->wq_lock[0], flags); + if (!vnic_wq_desc_avail(wq)) + goto irq_restore; + fnic_queue_wq_eth_desc(wq, skb, pa, skb->len, 0 /* hw inserts cos value */, fnic->vlan_id, 1); spin_unlock_irqrestore(&fnic->wq_lock[0], flags); + return; + +irq_restore: + spin_unlock_irqrestore(&fnic->wq_lock[0], flags); + pci_unmap_single(fnic->pdev, pa, skb->len, PCI_DMA_TODEVICE); +free_skb: + kfree_skb(skb); } /* @@ -1071,6 +1093,12 @@ static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp) pa = pci_map_single(fnic->pdev, eth_hdr, tot_len, PCI_DMA_TODEVICE); + ret = pci_dma_mapping_error(fnic->pdev, pa); + if (ret) { + printk(KERN_ERR "DMA map failed with error %d\n", ret); + goto free_skb_on_err; + } + if ((fnic_fc_trace_set_data(fnic->lport->host->host_no, FNIC_FC_SEND, (char *)eth_hdr, tot_len)) != 0) { printk(KERN_ERR "fnic ctlr frame trace error!!!"); @@ -1082,15 +1110,17 @@ static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp) pci_unmap_single(fnic->pdev, pa, tot_len, PCI_DMA_TODEVICE); ret = -1; - goto fnic_send_frame_end; + goto irq_restore; } fnic_queue_wq_desc(wq, skb, pa, tot_len, fr_eof(fp), 0 /* hw inserts cos value */, fnic->vlan_id, 1, 1, 1); -fnic_send_frame_end: + +irq_restore: spin_unlock_irqrestore(&fnic->wq_lock[0], flags); +free_skb_on_err: if (ret) dev_kfree_skb_any(fp_skb(fp)); diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 8a0d4d7b3..58ce9020d 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -118,7 +118,6 @@ static struct scsi_host_template fnic_host_template = { .sg_tablesize = FNIC_MAX_SG_DESC_CNT, .max_sectors = 0xffff, .shost_attrs = fnic_attrs, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -697,13 +696,6 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } fnic->fnic_max_tag_id = host->can_queue; - err = scsi_init_shared_tag_map(host, fnic->fnic_max_tag_id); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Unable to alloc shared tag map\n"); - goto err_out_dev_close; - } - host->max_lun = fnic->config.luns_per_tgt; host->max_id = FNIC_MAX_FCP_TARGET; host->max_cmd_len = FCOE_MAX_CMD_LEN; diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 25436cd28..266b909fe 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -330,6 +330,7 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, int flags; u8 exch_flags; struct scsi_lun fc_lun; + int r; if (sg_count) { /* For each SGE, create a device desc entry */ @@ -346,6 +347,12 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, io_req->sgl_list, sizeof(io_req->sgl_list[0]) * sg_count, PCI_DMA_TODEVICE); + + r = pci_dma_mapping_error(fnic->pdev, io_req->sgl_list_pa); + if (r) { + printk(KERN_ERR "PCI mapping failed with error %d\n", r); + return SCSI_MLQUEUE_HOST_BUSY; + } } io_req->sense_buf_pa = pci_map_single(fnic->pdev, @@ -353,6 +360,15 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE); + r = pci_dma_mapping_error(fnic->pdev, io_req->sense_buf_pa); + if (r) { + pci_unmap_single(fnic->pdev, io_req->sgl_list_pa, + sizeof(io_req->sgl_list[0]) * sg_count, + PCI_DMA_TODEVICE); + printk(KERN_ERR "PCI mapping failed with error %d\n", r); + return SCSI_MLQUEUE_HOST_BUSY; + } + int_to_scsilun(sc->device->lun, &fc_lun); /* Enqueue the descriptor in the Copy WQ */ diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 8bb173e01..82ac1cd81 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -217,6 +217,13 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, error = scsi_mq_setup_tags(shost); if (error) goto fail; + } else { + shost->bqt = blk_init_tags(shost->can_queue, + shost->hostt->tag_alloc_policy); + if (!shost->bqt) { + error = -ENOMEM; + goto fail; + } } /* @@ -326,6 +333,17 @@ static void scsi_host_dev_release(struct device *dev) kfree(queuedata); } + if (shost->shost_state == SHOST_CREATED) { + /* + * Free the shost_dev device name here if scsi_host_alloc() + * and scsi_host_put() have been called but neither + * scsi_host_add() nor scsi_host_remove() has been called. + * This avoids that the memory allocated for the shost_dev + * name is leaked. + */ + kfree(dev_name(&shost->shost_dev)); + } + scsi_destroy_command_freelist(shost); if (shost_use_blk_mq(shost)) { if (shost->tag_set.tags) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 40669f8dd..a3860367b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -54,8 +55,11 @@ #include "hpsa_cmd.h" #include "hpsa.h" -/* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */ -#define HPSA_DRIVER_VERSION "3.4.10-0" +/* + * HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' + * with an optional trailing '-' followed by a byte value (0-255). + */ +#define HPSA_DRIVER_VERSION "3.4.14-0" #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" #define HPSA "hpsa" @@ -205,6 +209,16 @@ static struct board_type products[] = { {0xFFFF103C, "Unknown Smart Array", &SA5_access}, }; +static struct scsi_transport_template *hpsa_sas_transport_template; +static int hpsa_add_sas_host(struct ctlr_info *h); +static void hpsa_delete_sas_host(struct ctlr_info *h); +static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node, + struct hpsa_scsi_dev_t *device); +static void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device); +static struct hpsa_scsi_dev_t + *hpsa_find_device_by_sas_rphy(struct ctlr_info *h, + struct sas_rphy *rphy); + #define SCSI_CMD_BUSY ((struct scsi_cmnd *)&hpsa_cmd_busy) static const struct scsi_cmnd hpsa_cmd_busy; #define SCSI_CMD_IDLE ((struct scsi_cmnd *)&hpsa_cmd_idle) @@ -230,6 +244,7 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, int cmd_type); static void hpsa_free_cmd_pool(struct ctlr_info *h); #define VPD_PAGE (1 << 8) +#define HPSA_SIMPLE_ERROR_BITS 0x03 static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); static void hpsa_scan_start(struct Scsi_Host *); @@ -243,7 +258,7 @@ static int hpsa_slave_alloc(struct scsi_device *sdev); static int hpsa_slave_configure(struct scsi_device *sdev); static void hpsa_slave_destroy(struct scsi_device *sdev); -static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno); +static void hpsa_update_scsi_devices(struct ctlr_info *h); static int check_for_unit_attention(struct ctlr_info *h, struct CommandList *c); static void check_ioctl_unit_attention(struct ctlr_info *h, @@ -274,7 +289,10 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, static void hpsa_command_resubmit_worker(struct work_struct *work); static u32 lockup_detected(struct ctlr_info *h); static int detect_controller_lockup(struct ctlr_info *h); -static int is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device); +static void hpsa_disable_rld_caching(struct ctlr_info *h); +static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h, + struct ReportExtendedLUNdata *buf, int bufsize); +static int hpsa_luns_changed(struct ctlr_info *h); static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) { @@ -606,7 +624,7 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[]) } static const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6", - "1(+0)ADM", "UNKNOWN" + "1(+0)ADM", "UNKNOWN", "PHYS DRV" }; #define HPSA_RAID_0 0 #define HPSA_RAID_4 1 @@ -615,7 +633,13 @@ static const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6", #define HPSA_RAID_51 4 #define HPSA_RAID_6 5 /* also used for RAID 60 */ #define HPSA_RAID_ADM 6 /* also used for RAID 1+0 ADM */ -#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 1) +#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 2) +#define PHYSICAL_DRIVE (ARRAY_SIZE(raid_label) - 1) + +static inline bool is_logical_device(struct hpsa_scsi_dev_t *device) +{ + return !device->physical_device; +} static ssize_t raid_level_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -637,7 +661,7 @@ static ssize_t raid_level_show(struct device *dev, } /* Is this even a logical drive? */ - if (!is_logical_dev_addr_mode(hdev->scsi3addr)) { + if (!is_logical_device(hdev)) { spin_unlock_irqrestore(&h->lock, flags); l = snprintf(buf, PAGE_SIZE, "N/A\n"); return l; @@ -726,7 +750,6 @@ static ssize_t host_show_hp_ssd_smart_path_enabled(struct device *dev, } #define MAX_PATHS 8 -#define PATH_STRING_LEN 50 static ssize_t path_info_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -742,9 +765,7 @@ static ssize_t path_info_show(struct device *dev, u8 path_map_index = 0; char *active; unsigned char phys_connector[2]; - unsigned char path[MAX_PATHS][PATH_STRING_LEN]; - memset(path, 0, MAX_PATHS * PATH_STRING_LEN); sdev = to_scsi_device(dev); h = sdev_to_hba(sdev); spin_lock_irqsave(&h->devlock, flags); @@ -764,18 +785,19 @@ static ssize_t path_info_show(struct device *dev, else continue; - output_len = snprintf(path[i], - PATH_STRING_LEN, "[%d:%d:%d:%d] %20.20s ", + output_len += scnprintf(buf + output_len, + PAGE_SIZE - output_len, + "[%d:%d:%d:%d] %20.20s ", h->scsi_host->host_no, hdev->bus, hdev->target, hdev->lun, scsi_device_type(hdev->devtype)); - if (is_ext_target(h, hdev) || - (hdev->devtype == TYPE_RAID) || - is_logical_dev_addr_mode(hdev->scsi3addr)) { - output_len += snprintf(path[i] + output_len, - PATH_STRING_LEN, "%s\n", - active); + if (hdev->external || + hdev->devtype == TYPE_RAID || + is_logical_device(hdev)) { + output_len += snprintf(buf + output_len, + PAGE_SIZE - output_len, + "%s\n", active); continue; } @@ -787,36 +809,33 @@ static ssize_t path_info_show(struct device *dev, if (phys_connector[1] < '0') phys_connector[1] = '0'; if (hdev->phys_connector[i] > 0) - output_len += snprintf(path[i] + output_len, - PATH_STRING_LEN, + output_len += snprintf(buf + output_len, + PAGE_SIZE - output_len, "PORT: %.2s ", phys_connector); - if (hdev->devtype == TYPE_DISK && - hdev->expose_state != HPSA_DO_NOT_EXPOSE) { + if (hdev->devtype == TYPE_DISK && hdev->expose_device) { if (box == 0 || box == 0xFF) { - output_len += snprintf(path[i] + output_len, - PATH_STRING_LEN, + output_len += snprintf(buf + output_len, + PAGE_SIZE - output_len, "BAY: %hhu %s\n", bay, active); } else { - output_len += snprintf(path[i] + output_len, - PATH_STRING_LEN, + output_len += snprintf(buf + output_len, + PAGE_SIZE - output_len, "BOX: %hhu BAY: %hhu %s\n", box, bay, active); } } else if (box != 0 && box != 0xFF) { - output_len += snprintf(path[i] + output_len, - PATH_STRING_LEN, "BOX: %hhu %s\n", + output_len += snprintf(buf + output_len, + PAGE_SIZE - output_len, "BOX: %hhu %s\n", box, active); } else - output_len += snprintf(path[i] + output_len, - PATH_STRING_LEN, "%s\n", active); + output_len += snprintf(buf + output_len, + PAGE_SIZE - output_len, "%s\n", active); } spin_unlock_irqrestore(&h->devlock, flags); - return snprintf(buf, output_len+1, "%s%s%s%s%s%s%s%s", - path[0], path[1], path[2], path[3], - path[4], path[5], path[6], path[7]); + return output_len; } static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL); @@ -848,7 +867,6 @@ static struct device_attribute *hpsa_sdev_attrs[] = { &dev_attr_unique_id, &dev_attr_hp_ssd_smart_path_enabled, &dev_attr_path_info, - &dev_attr_lockup_detected, NULL, }; @@ -860,6 +878,7 @@ static struct device_attribute *hpsa_shost_attrs[] = { &dev_attr_resettable, &dev_attr_hp_ssd_smart_path_status, &dev_attr_raid_offload_debug, + &dev_attr_lockup_detected, NULL, }; @@ -1134,25 +1153,62 @@ static int hpsa_find_target_lun(struct ctlr_info *h, return !found; } -static inline void hpsa_show_dev_msg(const char *level, struct ctlr_info *h, +static void hpsa_show_dev_msg(const char *level, struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, char *description) { +#define LABEL_SIZE 25 + char label[LABEL_SIZE]; + + if (h == NULL || h->pdev == NULL || h->scsi_host == NULL) + return; + + switch (dev->devtype) { + case TYPE_RAID: + snprintf(label, LABEL_SIZE, "controller"); + break; + case TYPE_ENCLOSURE: + snprintf(label, LABEL_SIZE, "enclosure"); + break; + case TYPE_DISK: + if (dev->external) + snprintf(label, LABEL_SIZE, "external"); + else if (!is_logical_dev_addr_mode(dev->scsi3addr)) + snprintf(label, LABEL_SIZE, "%s", + raid_label[PHYSICAL_DRIVE]); + else + snprintf(label, LABEL_SIZE, "RAID-%s", + dev->raid_level > RAID_UNKNOWN ? "?" : + raid_label[dev->raid_level]); + break; + case TYPE_ROM: + snprintf(label, LABEL_SIZE, "rom"); + break; + case TYPE_TAPE: + snprintf(label, LABEL_SIZE, "tape"); + break; + case TYPE_MEDIUM_CHANGER: + snprintf(label, LABEL_SIZE, "changer"); + break; + default: + snprintf(label, LABEL_SIZE, "UNKNOWN"); + break; + } + dev_printk(level, &h->pdev->dev, - "scsi %d:%d:%d:%d: %s %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n", + "scsi %d:%d:%d:%d: %s %s %.8s %.16s %s SSDSmartPathCap%c En%c Exp=%d\n", h->scsi_host->host_no, dev->bus, dev->target, dev->lun, description, scsi_device_type(dev->devtype), dev->vendor, dev->model, - dev->raid_level > RAID_UNKNOWN ? - "RAID-?" : raid_label[dev->raid_level], + label, dev->offload_config ? '+' : '-', dev->offload_enabled ? '+' : '-', - dev->expose_state); + dev->expose_device); } /* Add an entry into h->dev[] array. */ -static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, +static int hpsa_scsi_add_entry(struct ctlr_info *h, struct hpsa_scsi_dev_t *device, struct hpsa_scsi_dev_t *added[], int *nadded) { @@ -1221,14 +1277,14 @@ lun_assigned: added[*nadded] = device; (*nadded)++; hpsa_show_dev_msg(KERN_INFO, h, device, - device->expose_state & HPSA_SCSI_ADD ? "added" : "masked"); + device->expose_device ? "added" : "masked"); device->offload_to_be_enabled = device->offload_enabled; device->offload_enabled = 0; return 0; } /* Update an entry in h->dev[] array. */ -static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, +static void hpsa_scsi_update_entry(struct ctlr_info *h, int entry, struct hpsa_scsi_dev_t *new_entry) { int offload_enabled; @@ -1276,7 +1332,7 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, } /* Replace an entry from h->dev[] array. */ -static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, +static void hpsa_scsi_replace_entry(struct ctlr_info *h, int entry, struct hpsa_scsi_dev_t *new_entry, struct hpsa_scsi_dev_t *added[], int *nadded, struct hpsa_scsi_dev_t *removed[], int *nremoved) @@ -1304,7 +1360,7 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, } /* Remove an entry from h->dev[] array. */ -static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, +static void hpsa_scsi_remove_entry(struct ctlr_info *h, int entry, struct hpsa_scsi_dev_t *removed[], int *nremoved) { /* assumes h->devlock is held */ @@ -1415,6 +1471,9 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle, #define DEVICE_CHANGED 1 #define DEVICE_SAME 2 #define DEVICE_UPDATED 3 + if (needle == NULL) + return DEVICE_NOT_FOUND; + for (i = 0; i < haystack_size; i++) { if (haystack[i] == NULL) /* previously removed. */ continue; @@ -1577,9 +1636,11 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h, if (!logical_drive->offload_config) continue; for (j = 0; j < ndevices; j++) { + if (dev[j] == NULL) + continue; if (dev[j]->devtype != TYPE_DISK) continue; - if (is_logical_dev_addr_mode(dev[j]->scsi3addr)) + if (is_logical_device(dev[j])) continue; if (dev[j]->ioaccel_handle != dd[i].ioaccel_handle) continue; @@ -1620,9 +1681,11 @@ static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h, int i; for (i = 0; i < ndevices; i++) { + if (dev[i] == NULL) + continue; if (dev[i]->devtype != TYPE_DISK) continue; - if (!is_logical_dev_addr_mode(dev[i]->scsi3addr)) + if (!is_logical_device(dev[i])) continue; /* @@ -1638,7 +1701,50 @@ static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h, } } -static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, +static int hpsa_add_device(struct ctlr_info *h, struct hpsa_scsi_dev_t *device) +{ + int rc = 0; + + if (!h->scsi_host) + return 1; + + if (is_logical_device(device)) /* RAID */ + rc = scsi_add_device(h->scsi_host, device->bus, + device->target, device->lun); + else /* HBA */ + rc = hpsa_add_sas_device(h->sas_host, device); + + return rc; +} + +static void hpsa_remove_device(struct ctlr_info *h, + struct hpsa_scsi_dev_t *device) +{ + struct scsi_device *sdev = NULL; + + if (!h->scsi_host) + return; + + if (is_logical_device(device)) { /* RAID */ + sdev = scsi_device_lookup(h->scsi_host, device->bus, + device->target, device->lun); + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } else { + /* + * We don't expect to get here. Future commands + * to this device will get a selection timeout as + * if the device were gone. + */ + hpsa_show_dev_msg(KERN_WARNING, h, device, + "didn't find device for removal."); + } + } else /* HBA */ + hpsa_remove_sas_device(device); +} + +static void adjust_hpsa_scsi_table(struct ctlr_info *h, struct hpsa_scsi_dev_t *sd[], int nsds) { /* sd contains scsi3 addresses and devtypes, and inquiry @@ -1650,7 +1756,15 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, unsigned long flags; struct hpsa_scsi_dev_t **added, **removed; int nadded, nremoved; - struct Scsi_Host *sh = NULL; + + /* + * A reset can cause a device status to change + * re-schedule the scan to see what happened. + */ + if (h->reset_in_progress) { + h->drv_req_rescan = 1; + return; + } added = kzalloc(sizeof(*added) * HPSA_MAX_DEVICES, GFP_KERNEL); removed = kzalloc(sizeof(*removed) * HPSA_MAX_DEVICES, GFP_KERNEL); @@ -1678,19 +1792,18 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, device_change = hpsa_scsi_find_entry(csd, sd, nsds, &entry); if (device_change == DEVICE_NOT_FOUND) { changes++; - hpsa_scsi_remove_entry(h, hostno, i, - removed, &nremoved); + hpsa_scsi_remove_entry(h, i, removed, &nremoved); continue; /* remove ^^^, hence i not incremented */ } else if (device_change == DEVICE_CHANGED) { changes++; - hpsa_scsi_replace_entry(h, hostno, i, sd[entry], + hpsa_scsi_replace_entry(h, i, sd[entry], added, &nadded, removed, &nremoved); /* Set it to NULL to prevent it from being freed * at the bottom of hpsa_update_scsi_devices() */ sd[entry] = NULL; } else if (device_change == DEVICE_UPDATED) { - hpsa_scsi_update_entry(h, hostno, i, sd[entry]); + hpsa_scsi_update_entry(h, i, sd[entry]); } i++; } @@ -1718,8 +1831,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, h->ndevices, &entry); if (device_change == DEVICE_NOT_FOUND) { changes++; - if (hpsa_scsi_add_entry(h, hostno, sd[i], - added, &nadded) != 0) + if (hpsa_scsi_add_entry(h, sd[i], added, &nadded) != 0) break; sd[i] = NULL; /* prevent from being freed later. */ } else if (device_change == DEVICE_CHANGED) { @@ -1735,8 +1847,11 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, /* Now that h->dev[]->phys_disk[] is coherent, we can enable * any logical drives that need it enabled. */ - for (i = 0; i < h->ndevices; i++) + for (i = 0; i < h->ndevices; i++) { + if (h->dev[i] == NULL) + continue; h->dev[i]->offload_enabled = h->dev[i]->offload_to_be_enabled; + } spin_unlock_irqrestore(&h->devlock, flags); @@ -1755,47 +1870,37 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, * (or if there are no changes) scsi_scan_host will do it later the * first time through. */ - if (hostno == -1 || !changes) + if (!changes) goto free_and_out; - sh = h->scsi_host; /* Notify scsi mid layer of any removed devices */ for (i = 0; i < nremoved; i++) { - if (removed[i]->expose_state & HPSA_SCSI_ADD) { - struct scsi_device *sdev = - scsi_device_lookup(sh, removed[i]->bus, - removed[i]->target, removed[i]->lun); - if (sdev != NULL) { - scsi_remove_device(sdev); - scsi_device_put(sdev); - } else { - /* - * We don't expect to get here. - * future cmds to this device will get selection - * timeout as if the device was gone. - */ - hpsa_show_dev_msg(KERN_WARNING, h, removed[i], - "didn't find device for removal."); - } - } + if (removed[i] == NULL) + continue; + if (removed[i]->expose_device) + hpsa_remove_device(h, removed[i]); kfree(removed[i]); removed[i] = NULL; } /* Notify scsi mid layer of any added devices */ for (i = 0; i < nadded; i++) { - if (!(added[i]->expose_state & HPSA_SCSI_ADD)) + int rc = 0; + + if (added[i] == NULL) + continue; + if (!(added[i]->expose_device)) continue; - if (scsi_add_device(sh, added[i]->bus, - added[i]->target, added[i]->lun) == 0) + rc = hpsa_add_device(h, added[i]); + if (!rc) continue; - hpsa_show_dev_msg(KERN_WARNING, h, added[i], - "addition failed, device not added."); + dev_warn(&h->pdev->dev, + "addition failed %d, device not added.", rc); /* now we have to remove it from h->dev, * since it didn't get added to scsi mid layer */ fixup_botched_add(h, added[i]); - added[i] = NULL; + h->drv_req_rescan = 1; } free_and_out: @@ -1829,11 +1934,24 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) h = sdev_to_hba(sdev); spin_lock_irqsave(&h->devlock, flags); - sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), - sdev_id(sdev), sdev->lun); - if (likely(sd)) { + if (sdev_channel(sdev) == HPSA_PHYSICAL_DEVICE_BUS) { + struct scsi_target *starget; + struct sas_rphy *rphy; + + starget = scsi_target(sdev); + rphy = target_to_rphy(starget); + sd = hpsa_find_device_by_sas_rphy(h, rphy); + if (sd) { + sd->target = sdev_id(sdev); + sd->lun = sdev->lun; + } + } else + sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), + sdev_id(sdev), sdev->lun); + + if (sd && sd->expose_device) { atomic_set(&sd->ioaccel_cmds_out, 0); - sdev->hostdata = (sd->expose_state & HPSA_SCSI_ADD) ? sd : NULL; + sdev->hostdata = sd; } else sdev->hostdata = NULL; spin_unlock_irqrestore(&h->devlock, flags); @@ -1847,7 +1965,7 @@ static int hpsa_slave_configure(struct scsi_device *sdev) int queue_depth; sd = sdev->hostdata; - sdev->no_uld_attach = !sd || !(sd->expose_state & HPSA_ULD_ATTACH); + sdev->no_uld_attach = !sd || !sd->expose_device; if (sd) queue_depth = sd->queue_depth != 0 ? @@ -1955,7 +2073,7 @@ static int hpsa_map_ioaccel2_sg_chain_block(struct ctlr_info *h, u32 chain_size; chain_block = h->ioaccel2_cmd_sg_list[c->cmdindex]; - chain_size = le32_to_cpu(cp->data_len); + chain_size = le32_to_cpu(cp->sg[0].length); temp64 = pci_map_single(h->pdev, chain_block, chain_size, PCI_DMA_TODEVICE); if (dma_mapping_error(&h->pdev->dev, temp64)) { @@ -1976,7 +2094,7 @@ static void hpsa_unmap_ioaccel2_sg_chain_block(struct ctlr_info *h, chain_sg = cp->sg; temp64 = le64_to_cpu(chain_sg->address); - chain_size = le32_to_cpu(cp->data_len); + chain_size = le32_to_cpu(cp->sg[0].length); pci_unmap_single(h->pdev, temp64, chain_size, PCI_DMA_TODEVICE); } @@ -2210,7 +2328,7 @@ static void process_ioaccel2_completion(struct ctlr_info *h, * the normal I/O path so the controller can handle whatever's * wrong. */ - if (is_logical_dev_addr_mode(dev->scsi3addr) && + if (is_logical_device(dev) && c2->error_data.serv_response == IOACCEL2_SERV_RESPONSE_FAILURE) { if (c2->error_data.status == @@ -2330,7 +2448,7 @@ static void complete_scsi_command(struct CommandList *cp) * the normal I/O path so the controller can handle whatever's * wrong. */ - if (is_logical_dev_addr_mode(dev->scsi3addr)) { + if (is_logical_device(dev)) { if (ei->CommandStatus == CMD_IOACCEL_DISABLED) dev->offload_enabled = 0; return hpsa_retry_cmd(h, cp); @@ -2709,9 +2827,8 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, /* fill_cmd can't fail here, no data buffer to map. */ - (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, + (void) fill_cmd(c, reset_type, h, NULL, 0, 0, scsi3addr, TYPE_MSG); - c->Request.CDB[1] = reset_type; /* fill_cmd defaults to LUN reset */ rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT); if (rc) { dev_warn(&h->pdev->dev, "Failed to send reset command\n"); @@ -2984,6 +3101,66 @@ out: return rc; } +static int hpsa_bmic_sense_subsystem_information(struct ctlr_info *h, + unsigned char scsi3addr[], u16 bmic_device_index, + struct bmic_sense_subsystem_info *buf, size_t bufsize) +{ + int rc = IO_OK; + struct CommandList *c; + struct ErrorInfo *ei; + + c = cmd_alloc(h); + + rc = fill_cmd(c, BMIC_SENSE_SUBSYSTEM_INFORMATION, h, buf, bufsize, + 0, RAID_CTLR_LUNID, TYPE_CMD); + if (rc) + goto out; + + c->Request.CDB[2] = bmic_device_index & 0xff; + c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff; + + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if (rc) + goto out; + ei = c->err_info; + if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { + hpsa_scsi_interpret_error(h, c); + rc = -1; + } +out: + cmd_free(h, c); + return rc; +} + +static int hpsa_bmic_id_controller(struct ctlr_info *h, + struct bmic_identify_controller *buf, size_t bufsize) +{ + int rc = IO_OK; + struct CommandList *c; + struct ErrorInfo *ei; + + c = cmd_alloc(h); + + rc = fill_cmd(c, BMIC_IDENTIFY_CONTROLLER, h, buf, bufsize, + 0, RAID_CTLR_LUNID, TYPE_CMD); + if (rc) + goto out; + + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if (rc) + goto out; + ei = c->err_info; + if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { + hpsa_scsi_interpret_error(h, c); + rc = -1; + } +out: + cmd_free(h, c); + return rc; +} + static int hpsa_bmic_id_physical_device(struct ctlr_info *h, unsigned char scsi3addr[], u16 bmic_device_index, struct bmic_identify_physical_device *buf, size_t bufsize) @@ -3010,9 +3187,71 @@ static int hpsa_bmic_id_physical_device(struct ctlr_info *h, } out: cmd_free(h, c); + return rc; } +static u64 hpsa_get_sas_address_from_report_physical(struct ctlr_info *h, + unsigned char *scsi3addr) +{ + struct ReportExtendedLUNdata *physdev; + u32 nphysicals; + u64 sa = 0; + int i; + + physdev = kzalloc(sizeof(*physdev), GFP_KERNEL); + if (!physdev) + return 0; + + if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) { + dev_err(&h->pdev->dev, "report physical LUNs failed.\n"); + kfree(physdev); + return 0; + } + nphysicals = get_unaligned_be32(physdev->LUNListLength) / 24; + + for (i = 0; i < nphysicals; i++) + if (!memcmp(&physdev->LUN[i].lunid[0], scsi3addr, 8)) { + sa = get_unaligned_be64(&physdev->LUN[i].wwid[0]); + break; + } + + kfree(physdev); + + return sa; +} + +static void hpsa_get_sas_address(struct ctlr_info *h, unsigned char *scsi3addr, + struct hpsa_scsi_dev_t *dev) +{ + int rc; + u64 sa = 0; + + if (is_hba_lunid(scsi3addr)) { + struct bmic_sense_subsystem_info *ssi; + + ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); + if (ssi == NULL) { + dev_warn(&h->pdev->dev, + "%s: out of memory\n", __func__); + return; + } + + rc = hpsa_bmic_sense_subsystem_information(h, + scsi3addr, 0, ssi, sizeof(*ssi)); + if (rc == 0) { + sa = get_unaligned_be64(ssi->primary_world_wide_id); + h->sas_address = sa; + } + + kfree(ssi); + } else + sa = hpsa_get_sas_address_from_report_physical(h, scsi3addr); + + dev->sas_address = sa; +} + +/* Get a device id from inquiry page 0x83 */ static int hpsa_vpd_page_supported(struct ctlr_info *h, unsigned char scsi3addr[], u8 page) { @@ -3097,7 +3336,7 @@ out: /* Get the device id from inquiry page 0x83 */ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr, - unsigned char *device_id, int buflen) + unsigned char *device_id, int index, int buflen) { int rc; unsigned char *buf; @@ -3109,8 +3348,10 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr, return -ENOMEM; rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0x83, buf, 64); if (rc == 0) - memcpy(device_id, &buf[8], buflen); + memcpy(device_id, &buf[index], buflen); + kfree(buf); + return rc != 0; } @@ -3339,6 +3580,18 @@ static int hpsa_device_supports_aborts(struct ctlr_info *h, return rc; } +static void sanitize_inquiry_string(unsigned char *s, int len) +{ + bool terminated = false; + + for (; len > 0; (--len, ++s)) { + if (*s == 0) + terminated = true; + if (terminated || *s < 0x20 || *s > 0x7e) + *s = ' '; + } +} + static int hpsa_update_device_info(struct ctlr_info *h, unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device, unsigned char *is_OBDR_device) @@ -3351,10 +3604,13 @@ static int hpsa_update_device_info(struct ctlr_info *h, unsigned char *inq_buff; unsigned char *obdr_sig; + int rc = 0; inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); - if (!inq_buff) + if (!inq_buff) { + rc = -ENOMEM; goto bail_out; + } /* Do an inquiry to the device to see what it is. */ if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff, @@ -3362,9 +3618,13 @@ static int hpsa_update_device_info(struct ctlr_info *h, /* Inquiry failed (msg printed already) */ dev_err(&h->pdev->dev, "hpsa_update_device_info: inquiry failed\n"); + rc = -EIO; goto bail_out; } + sanitize_inquiry_string(&inq_buff[8], 8); + sanitize_inquiry_string(&inq_buff[16], 16); + this_device->devtype = (inq_buff[0] & 0x1f); memcpy(this_device->scsi3addr, scsi3addr, 8); memcpy(this_device->vendor, &inq_buff[8], @@ -3373,7 +3633,7 @@ static int hpsa_update_device_info(struct ctlr_info *h, sizeof(this_device->model)); memset(this_device->device_id, 0, sizeof(this_device->device_id)); - hpsa_get_device_id(h, scsi3addr, this_device->device_id, + hpsa_get_device_id(h, scsi3addr, this_device->device_id, 8, sizeof(this_device->device_id)); if (this_device->devtype == TYPE_DISK && @@ -3411,7 +3671,7 @@ static int hpsa_update_device_info(struct ctlr_info *h, bail_out: kfree(inq_buff); - return 1; + return rc; } static void hpsa_update_device_supports_aborts(struct ctlr_info *h, @@ -3439,115 +3699,39 @@ static void hpsa_update_device_supports_aborts(struct ctlr_info *h, } } -static unsigned char *ext_target_model[] = { - "MSA2012", - "MSA2024", - "MSA2312", - "MSA2324", - "P2000 G3 SAS", - "MSA 2040 SAS", - NULL, -}; - -static int is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device) -{ - int i; - - for (i = 0; ext_target_model[i]; i++) - if (strncmp(device->model, ext_target_model[i], - strlen(ext_target_model[i])) == 0) - return 1; - return 0; -} - -/* Helper function to assign bus, target, lun mapping of devices. - * Puts non-external target logical volumes on bus 0, external target logical - * volumes on bus 1, physical devices on bus 2. and the hba on bus 3. +/* + * Helper function to assign bus, target, lun mapping of devices. * Logical drive target and lun are assigned at this time, but * physical device lun and target assignment are deferred (assigned * in hpsa_find_target_lun, called by hpsa_scsi_add_entry.) - */ +*/ static void figure_bus_target_lun(struct ctlr_info *h, u8 *lunaddrbytes, struct hpsa_scsi_dev_t *device) { - u32 lunid = le32_to_cpu(*((__le32 *) lunaddrbytes)); + u32 lunid = get_unaligned_le32(lunaddrbytes); if (!is_logical_dev_addr_mode(lunaddrbytes)) { /* physical device, target and lun filled in later */ if (is_hba_lunid(lunaddrbytes)) - hpsa_set_bus_target_lun(device, 3, 0, lunid & 0x3fff); + hpsa_set_bus_target_lun(device, + HPSA_HBA_BUS, 0, lunid & 0x3fff); else /* defer target, lun assignment for physical devices */ - hpsa_set_bus_target_lun(device, 2, -1, -1); + hpsa_set_bus_target_lun(device, + HPSA_PHYSICAL_DEVICE_BUS, -1, -1); return; } /* It's a logical device */ - if (is_ext_target(h, device)) { - /* external target way, put logicals on bus 1 - * and match target/lun numbers box - * reports, other smart array, bus 0, target 0, match lunid - */ + if (device->external) { hpsa_set_bus_target_lun(device, - 1, (lunid >> 16) & 0x3fff, lunid & 0x00ff); + HPSA_EXTERNAL_RAID_VOLUME_BUS, (lunid >> 16) & 0x3fff, + lunid & 0x00ff); return; } - hpsa_set_bus_target_lun(device, 0, 0, lunid & 0x3fff); + hpsa_set_bus_target_lun(device, HPSA_RAID_VOLUME_BUS, + 0, lunid & 0x3fff); } -/* - * If there is no lun 0 on a target, linux won't find any devices. - * For the external targets (arrays), we have to manually detect the enclosure - * which is at lun zero, as CCISS_REPORT_PHYSICAL_LUNS doesn't report - * it for some reason. *tmpdevice is the target we're adding, - * this_device is a pointer into the current element of currentsd[] - * that we're building up in update_scsi_devices(), below. - * lunzerobits is a bitmap that tracks which targets already have a - * lun 0 assigned. - * Returns 1 if an enclosure was added, 0 if not. - */ -static int add_ext_target_dev(struct ctlr_info *h, - struct hpsa_scsi_dev_t *tmpdevice, - struct hpsa_scsi_dev_t *this_device, u8 *lunaddrbytes, - unsigned long lunzerobits[], int *n_ext_target_devs) -{ - unsigned char scsi3addr[8]; - - if (test_bit(tmpdevice->target, lunzerobits)) - return 0; /* There is already a lun 0 on this target. */ - - if (!is_logical_dev_addr_mode(lunaddrbytes)) - return 0; /* It's the logical targets that may lack lun 0. */ - - if (!is_ext_target(h, tmpdevice)) - return 0; /* Only external target devices have this problem. */ - - if (tmpdevice->lun == 0) /* if lun is 0, then we have a lun 0. */ - return 0; - - memset(scsi3addr, 0, 8); - scsi3addr[3] = tmpdevice->target; - if (is_hba_lunid(scsi3addr)) - return 0; /* Don't add the RAID controller here. */ - - if (is_scsi_rev_5(h)) - return 0; /* p1210m doesn't need to do this. */ - - if (*n_ext_target_devs >= MAX_EXT_TARGETS) { - dev_warn(&h->pdev->dev, "Maximum number of external " - "target devices exceeded. Check your hardware " - "configuration."); - return 0; - } - - if (hpsa_update_device_info(h, scsi3addr, this_device, NULL)) - return 0; - (*n_ext_target_devs)++; - hpsa_set_bus_target_lun(this_device, - tmpdevice->bus, tmpdevice->target, 0); - hpsa_update_device_supports_aborts(h, this_device, scsi3addr); - set_bit(tmpdevice->target, lunzerobits); - return 1; -} /* * Get address of physical disk used for an ioaccel2 mode command: @@ -3577,6 +3761,27 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h, return 0; } +static int figure_external_status(struct ctlr_info *h, int raid_ctlr_position, + int i, int nphysicals, int nlocal_logicals) +{ + /* In report logicals, local logicals are listed first, + * then any externals. + */ + int logicals_start = nphysicals + (raid_ctlr_position == 0); + + if (i == raid_ctlr_position) + return 0; + + if (i < logicals_start) + return 0; + + /* i is in logicals range, but still within local logicals */ + if ((i - nphysicals - (raid_ctlr_position == 0)) < nlocal_logicals) + return 0; + + return 1; /* it's an external lun */ +} + /* * Do CISS_REPORT_PHYS and CISS_REPORT_LOG. Data is returned in physdev, * logdev. The number of luns in physdev and logdev are returned in @@ -3650,19 +3855,18 @@ static u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, /* get physical drive ioaccel handle and queue depth */ static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, - u8 *lunaddrbytes, + struct ReportExtendedLUNdata *rlep, int rle_index, struct bmic_identify_physical_device *id_phys) { int rc; - struct ext_report_lun_entry *rle = - (struct ext_report_lun_entry *) lunaddrbytes; + struct ext_report_lun_entry *rle = &rlep->LUN[rle_index]; dev->ioaccel_handle = rle->ioaccel_handle; - if (PHYS_IOACCEL(lunaddrbytes) && dev->ioaccel_handle) + if ((rle->device_flags & 0x08) && dev->ioaccel_handle) dev->hba_ioaccel_enabled = 1; memset(id_phys, 0, sizeof(*id_phys)); - rc = hpsa_bmic_id_physical_device(h, lunaddrbytes, - GET_BMIC_DRIVE_NUMBER(lunaddrbytes), id_phys, + rc = hpsa_bmic_id_physical_device(h, &rle->lunid[0], + GET_BMIC_DRIVE_NUMBER(&rle->lunid[0]), id_phys, sizeof(*id_phys)); if (!rc) /* Reserve space for FW operations */ @@ -3673,16 +3877,15 @@ static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h, DRIVE_CMDS_RESERVED_FOR_FW; else dev->queue_depth = DRIVE_QUEUE_DEPTH; /* conservative */ - atomic_set(&dev->ioaccel_cmds_out, 0); - atomic_set(&dev->reset_cmds_out, 0); } static void hpsa_get_path_info(struct hpsa_scsi_dev_t *this_device, - u8 *lunaddrbytes, + struct ReportExtendedLUNdata *rlep, int rle_index, struct bmic_identify_physical_device *id_phys) { - if (PHYS_IOACCEL(lunaddrbytes) - && this_device->ioaccel_handle) + struct ext_report_lun_entry *rle = &rlep->LUN[rle_index]; + + if ((rle->device_flags & 0x08) && this_device->ioaccel_handle) this_device->hba_ioaccel_enabled = 1; memcpy(&this_device->active_path_index, @@ -3702,7 +3905,33 @@ static void hpsa_get_path_info(struct hpsa_scsi_dev_t *this_device, sizeof(this_device->bay)); } -static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) +/* get number of local logical disks. */ +static int hpsa_set_local_logical_count(struct ctlr_info *h, + struct bmic_identify_controller *id_ctlr, + u32 *nlocals) +{ + int rc; + + if (!id_ctlr) { + dev_warn(&h->pdev->dev, "%s: id_ctlr buffer is NULL.\n", + __func__); + return -ENOMEM; + } + memset(id_ctlr, 0, sizeof(*id_ctlr)); + rc = hpsa_bmic_id_controller(h, id_ctlr, sizeof(*id_ctlr)); + if (!rc) + if (id_ctlr->configured_logical_drive_count < 256) + *nlocals = id_ctlr->configured_logical_drive_count; + else + *nlocals = le16_to_cpu( + id_ctlr->extended_logical_unit_count); + else + *nlocals = -1; + return rc; +} + + +static void hpsa_update_scsi_devices(struct ctlr_info *h) { /* the idea here is we could get notified * that some devices have changed, so we do a report @@ -3717,13 +3946,16 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) struct ReportExtendedLUNdata *physdev_list = NULL; struct ReportLUNdata *logdev_list = NULL; struct bmic_identify_physical_device *id_phys = NULL; + struct bmic_identify_controller *id_ctlr = NULL; u32 nphysicals = 0; u32 nlogicals = 0; + u32 nlocal_logicals = 0; u32 ndev_allocated = 0; struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice; int ncurrent = 0; int i, n_ext_target_devs, ndevs_to_allocate; int raid_ctlr_position; + bool physical_device; DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS); currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL); @@ -3731,17 +3963,29 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL); tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL); id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL); + id_ctlr = kzalloc(sizeof(*id_ctlr), GFP_KERNEL); if (!currentsd || !physdev_list || !logdev_list || - !tmpdevice || !id_phys) { + !tmpdevice || !id_phys || !id_ctlr) { dev_err(&h->pdev->dev, "out of memory\n"); goto out; } memset(lunzerobits, 0, sizeof(lunzerobits)); + h->drv_req_rescan = 0; /* cancel scheduled rescan - we're doing it. */ + if (hpsa_gather_lun_info(h, physdev_list, &nphysicals, - logdev_list, &nlogicals)) + logdev_list, &nlogicals)) { + h->drv_req_rescan = 1; goto out; + } + + /* Set number of local logicals (non PTRAID) */ + if (hpsa_set_local_logical_count(h, id_ctlr, &nlocal_logicals)) { + dev_warn(&h->pdev->dev, + "%s: Can't determine number of local logical devices.\n", + __func__); + } /* We might see up to the maximum number of logical and physical disks * plus external target devices, and a device for the local RAID @@ -3762,6 +4006,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) if (!currentsd[i]) { dev_warn(&h->pdev->dev, "out of memory at %s:%d\n", __FILE__, __LINE__); + h->drv_req_rescan = 1; goto out; } ndev_allocated++; @@ -3776,49 +4021,74 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) n_ext_target_devs = 0; for (i = 0; i < nphysicals + nlogicals + 1; i++) { u8 *lunaddrbytes, is_OBDR = 0; + int rc = 0; + int phys_dev_index = i - (raid_ctlr_position == 0); + + physical_device = i < nphysicals + (raid_ctlr_position == 0); /* Figure out where the LUN ID info is coming from */ lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position, i, nphysicals, nlogicals, physdev_list, logdev_list); /* skip masked non-disk devices */ - if (MASKED_DEVICE(lunaddrbytes)) - if (i < nphysicals + (raid_ctlr_position == 0) && - NON_DISK_PHYS_DEV(lunaddrbytes)) - continue; + if (MASKED_DEVICE(lunaddrbytes) && physical_device && + (physdev_list->LUN[phys_dev_index].device_flags & 0x01)) + continue; /* Get device type, vendor, model, device id */ - if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice, - &is_OBDR)) - continue; /* skip it if we can't talk to it. */ + rc = hpsa_update_device_info(h, lunaddrbytes, tmpdevice, + &is_OBDR); + if (rc == -ENOMEM) { + dev_warn(&h->pdev->dev, + "Out of memory, rescan deferred.\n"); + h->drv_req_rescan = 1; + goto out; + } + if (rc) { + dev_warn(&h->pdev->dev, + "Inquiry failed, skipping device.\n"); + continue; + } + + /* Determine if this is a lun from an external target array */ + tmpdevice->external = + figure_external_status(h, raid_ctlr_position, i, + nphysicals, nlocal_logicals); + figure_bus_target_lun(h, lunaddrbytes, tmpdevice); hpsa_update_device_supports_aborts(h, tmpdevice, lunaddrbytes); this_device = currentsd[ncurrent]; - /* - * For external target devices, we have to insert a LUN 0 which - * doesn't show up in CCISS_REPORT_PHYSICAL data, but there - * is nonetheless an enclosure device there. We have to - * present that otherwise linux won't find anything if - * there is no lun 0. + /* Turn on discovery_polling if there are ext target devices. + * Event-based change notification is unreliable for those. */ - if (add_ext_target_dev(h, tmpdevice, this_device, - lunaddrbytes, lunzerobits, - &n_ext_target_devs)) { - ncurrent++; - this_device = currentsd[ncurrent]; + if (!h->discovery_polling) { + if (tmpdevice->external) { + h->discovery_polling = 1; + dev_info(&h->pdev->dev, + "External target, activate discovery polling.\n"); + } } + *this_device = *tmpdevice; + this_device->physical_device = physical_device; - /* do not expose masked devices */ - if (MASKED_DEVICE(lunaddrbytes) && - i < nphysicals + (raid_ctlr_position == 0)) { - this_device->expose_state = HPSA_DO_NOT_EXPOSE; - } else { - this_device->expose_state = - HPSA_SG_ATTACH | HPSA_ULD_ATTACH; - } + /* + * Expose all devices except for physical devices that + * are masked. + */ + if (MASKED_DEVICE(lunaddrbytes) && this_device->physical_device) + this_device->expose_device = 0; + else + this_device->expose_device = 1; + + + /* + * Get the SAS address for physical devices that are exposed. + */ + if (this_device->physical_device && this_device->expose_device) + hpsa_get_sas_address(h, lunaddrbytes, this_device); switch (this_device->devtype) { case TYPE_ROM: @@ -3833,14 +4103,14 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) ncurrent++; break; case TYPE_DISK: - if (i < nphysicals + (raid_ctlr_position == 0)) { + if (this_device->physical_device) { /* The disk is in HBA mode. */ /* Never use RAID mapper in HBA mode. */ this_device->offload_enabled = 0; hpsa_get_ioaccel_drive_info(h, this_device, - lunaddrbytes, id_phys); - hpsa_get_path_info(this_device, lunaddrbytes, - id_phys); + physdev_list, phys_dev_index, id_phys); + hpsa_get_path_info(this_device, + physdev_list, phys_dev_index, id_phys); } ncurrent++; break; @@ -3865,7 +4135,19 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) if (ncurrent >= HPSA_MAX_DEVICES) break; } - adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent); + + if (h->sas_host == NULL) { + int rc = 0; + + rc = hpsa_add_sas_host(h); + if (rc) { + dev_warn(&h->pdev->dev, + "Could not add sas host %d\n", rc); + goto out; + } + } + + adjust_hpsa_scsi_table(h, currentsd, ncurrent); out: kfree(tmpdevice); for (i = 0; i < ndev_allocated; i++) @@ -3873,6 +4155,7 @@ out: kfree(currentsd); kfree(physdev_list); kfree(logdev_list); + kfree(id_ctlr); kfree(id_phys); } @@ -3978,19 +4261,14 @@ static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len) case READ_6: case READ_12: if (*cdb_len == 6) { - block = (((u32) cdb[2]) << 8) | cdb[3]; + block = get_unaligned_be16(&cdb[2]); block_cnt = cdb[4]; + if (block_cnt == 0) + block_cnt = 256; } else { BUG_ON(*cdb_len != 12); - block = (((u32) cdb[2]) << 24) | - (((u32) cdb[3]) << 16) | - (((u32) cdb[4]) << 8) | - cdb[5]; - block_cnt = - (((u32) cdb[6]) << 24) | - (((u32) cdb[7]) << 16) | - (((u32) cdb[8]) << 8) | - cdb[9]; + block = get_unaligned_be32(&cdb[2]); + block_cnt = get_unaligned_be32(&cdb[6]); } if (block_cnt > 0xffff) return IO_ACCEL_INELIGIBLE; @@ -4272,6 +4550,7 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, /* fill in sg elements */ if (use_sg > h->ioaccel_maxsg) { cp->sg_count = 1; + cp->sg[0].length = cpu_to_le32(use_sg * sizeof(cp->sg[0])); if (hpsa_map_ioaccel2_sg_chain_block(h, cp, c)) { atomic_dec(&phys_disk->ioaccel_cmds_out); scsi_dma_unmap(cmd); @@ -4376,9 +4655,7 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h, case WRITE_6: is_write = 1; case READ_6: - first_block = - (((u64) cmd->cmnd[2]) << 8) | - cmd->cmnd[3]; + first_block = get_unaligned_be16(&cmd->cmnd[2]); block_cnt = cmd->cmnd[4]; if (block_cnt == 0) block_cnt = 256; @@ -4947,7 +5224,7 @@ static void hpsa_scan_start(struct Scsi_Host *sh) if (unlikely(lockup_detected(h))) return hpsa_scan_complete(h); - hpsa_update_scsi_devices(h, h->scsi_host->host_no); + hpsa_update_scsi_devices(h); hpsa_scan_complete(h); } @@ -4983,7 +5260,6 @@ static int hpsa_scan_finished(struct Scsi_Host *sh, static int hpsa_scsi_host_alloc(struct ctlr_info *h) { struct Scsi_Host *sh; - int error; sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h)); if (sh == NULL) { @@ -5001,17 +5277,11 @@ static int hpsa_scsi_host_alloc(struct ctlr_info *h) sh->can_queue = h->nr_cmds - HPSA_NRESERVED_CMDS; sh->cmd_per_lun = sh->can_queue; sh->sg_tablesize = h->maxsgentries; + sh->transportt = hpsa_sas_transport_template; sh->hostdata[0] = (unsigned long) h; sh->irq = h->intr[h->intr_mode]; sh->unique_id = sh->irq; - error = scsi_init_shared_tag_map(sh, sh->can_queue); - if (error) { - dev_err(&h->pdev->dev, - "%s: scsi_init_shared_tag_map failed for controller %d\n", - __func__, h->ctlr); - scsi_host_put(sh); - return error; - } + h->scsi_host = sh; return 0; } @@ -5167,6 +5437,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) int rc; struct ctlr_info *h; struct hpsa_scsi_dev_t *dev; + u8 reset_type; char msg[48]; /* find the controller to which the command to be aborted was sent */ @@ -5205,14 +5476,25 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) if (is_hba_lunid(dev->scsi3addr)) return SUCCESS; - hpsa_show_dev_msg(KERN_WARNING, h, dev, "resetting"); + if (is_logical_dev_addr_mode(dev->scsi3addr)) + reset_type = HPSA_DEVICE_RESET_MSG; + else + reset_type = HPSA_PHYS_TARGET_RESET; + + sprintf(msg, "resetting %s", + reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical "); + hpsa_show_dev_msg(KERN_WARNING, h, dev, msg); + + h->reset_in_progress = 1; /* send a reset to the SCSI LUN which the command was sent to */ - rc = hpsa_do_reset(h, dev, dev->scsi3addr, HPSA_RESET_TYPE_LUN, + rc = hpsa_do_reset(h, dev, dev->scsi3addr, reset_type, DEFAULT_REPLY_QUEUE); - snprintf(msg, sizeof(msg), "reset %s", - rc == 0 ? "completed successfully" : "failed"); + sprintf(msg, "reset %s %s", + reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical ", + rc == 0 ? "completed successfully" : "failed"); hpsa_show_dev_msg(KERN_WARNING, h, dev, msg); + h->reset_in_progress = 0; return rc == 0 ? SUCCESS : FAILED; } @@ -6270,6 +6552,24 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[8] = (size >> 8) & 0xFF; c->Request.CDB[9] = size & 0xFF; break; + case BMIC_SENSE_DIAG_OPTIONS: + c->Request.CDBLen = 16; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); + c->Request.Timeout = 0; + /* Spec says this should be BMIC_WRITE */ + c->Request.CDB[0] = BMIC_READ; + c->Request.CDB[6] = BMIC_SENSE_DIAG_OPTIONS; + break; + case BMIC_SET_DIAG_OPTIONS: + c->Request.CDBLen = 16; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, + ATTR_SIMPLE, XFER_WRITE); + c->Request.Timeout = 0; + c->Request.CDB[0] = BMIC_WRITE; + c->Request.CDB[6] = BMIC_SET_DIAG_OPTIONS; + break; case HPSA_CACHE_FLUSH: c->Request.CDBLen = 12; c->Request.type_attr_dir = @@ -6319,6 +6619,32 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[7] = (size >> 16) & 0xFF; c->Request.CDB[8] = (size >> 8) & 0XFF; break; + case BMIC_SENSE_SUBSYSTEM_INFORMATION: + c->Request.CDBLen = 10; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); + c->Request.Timeout = 0; + c->Request.CDB[0] = BMIC_READ; + c->Request.CDB[6] = BMIC_SENSE_SUBSYSTEM_INFORMATION; + c->Request.CDB[7] = (size >> 16) & 0xFF; + c->Request.CDB[8] = (size >> 8) & 0XFF; + break; + case BMIC_IDENTIFY_CONTROLLER: + c->Request.CDBLen = 10; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); + c->Request.Timeout = 0; + c->Request.CDB[0] = BMIC_READ; + c->Request.CDB[1] = 0; + c->Request.CDB[2] = 0; + c->Request.CDB[3] = 0; + c->Request.CDB[4] = 0; + c->Request.CDB[5] = 0; + c->Request.CDB[6] = BMIC_IDENTIFY_CONTROLLER; + c->Request.CDB[7] = (size >> 16) & 0xFF; + c->Request.CDB[8] = (size >> 8) & 0XFF; + c->Request.CDB[9] = 0; + break; default: dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd); BUG(); @@ -6327,6 +6653,20 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, } else if (cmd_type == TYPE_MSG) { switch (cmd) { + case HPSA_PHYS_TARGET_RESET: + c->Request.CDBLen = 16; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE); + c->Request.Timeout = 0; /* Don't time out */ + memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB)); + c->Request.CDB[0] = HPSA_RESET; + c->Request.CDB[1] = HPSA_TARGET_RESET_TYPE; + /* Physical target reset needs no control bytes 4-7*/ + c->Request.CDB[4] = 0x00; + c->Request.CDB[5] = 0x00; + c->Request.CDB[6] = 0x00; + c->Request.CDB[7] = 0x00; + break; case HPSA_DEVICE_RESET_MSG: c->Request.CDBLen = 16; c->Request.type_attr_dir = @@ -6440,16 +6780,6 @@ static inline void finish_cmd(struct CommandList *c) complete(c->waiting); } - -static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag) -{ -#define HPSA_PERF_ERROR_BITS ((1 << DIRECT_LOOKUP_SHIFT) - 1) -#define HPSA_SIMPLE_ERROR_BITS 0x03 - if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant))) - return tag & ~HPSA_SIMPLE_ERROR_BITS; - return tag & ~HPSA_PERF_ERROR_BITS; -} - /* process completion of an indexed ("direct lookup") command */ static inline void process_indexed_cmd(struct ctlr_info *h, u32 raw_tag) @@ -7860,6 +8190,11 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h) */ static int hpsa_ctlr_needs_rescan(struct ctlr_info *h) { + if (h->drv_req_rescan) { + h->drv_req_rescan = 0; + return 1; + } + if (!(h->fw_support & MISC_FW_EVENT_NOTIFY)) return 0; @@ -7893,6 +8228,41 @@ static int hpsa_offline_devices_ready(struct ctlr_info *h) return 0; } +static int hpsa_luns_changed(struct ctlr_info *h) +{ + int rc = 1; /* assume there are changes */ + struct ReportLUNdata *logdev = NULL; + + /* if we can't find out if lun data has changed, + * assume that it has. + */ + + if (!h->lastlogicals) + goto out; + + logdev = kzalloc(sizeof(*logdev), GFP_KERNEL); + if (!logdev) { + dev_warn(&h->pdev->dev, + "Out of memory, can't track lun changes.\n"); + goto out; + } + if (hpsa_scsi_do_report_luns(h, 1, logdev, sizeof(*logdev), 0)) { + dev_warn(&h->pdev->dev, + "report luns failed, can't track lun changes.\n"); + goto out; + } + if (memcmp(logdev, h->lastlogicals, sizeof(*logdev))) { + dev_info(&h->pdev->dev, + "Lun changes detected.\n"); + memcpy(h->lastlogicals, logdev, sizeof(*logdev)); + goto out; + } else + rc = 0; /* no changes detected. */ +out: + kfree(logdev); + return rc; +} + static void hpsa_rescan_ctlr_worker(struct work_struct *work) { unsigned long flags; @@ -7908,6 +8278,19 @@ static void hpsa_rescan_ctlr_worker(struct work_struct *work) hpsa_ack_ctlr_events(h); hpsa_scan_start(h->scsi_host); scsi_host_put(h->scsi_host); + } else if (h->discovery_polling) { + hpsa_disable_rld_caching(h); + if (hpsa_luns_changed(h)) { + struct Scsi_Host *sh = NULL; + + dev_info(&h->pdev->dev, + "driver discovery polling rescan.\n"); + sh = scsi_host_get(h->scsi_host); + if (sh != NULL) { + hpsa_scan_start(sh); + scsi_host_put(sh); + } + } } spin_lock_irqsave(&h->lock, flags); if (!h->remove_in_progress) @@ -8148,6 +8531,8 @@ reinit_after_soft_reset: /* Enable Accelerated IO path at driver layer */ h->acciopath_status = 1; + /* Disable discovery polling.*/ + h->discovery_polling = 0; /* Turn the interrupts on so we can service requests */ @@ -8155,6 +8540,11 @@ reinit_after_soft_reset: hpsa_hba_inquiry(h); + h->lastlogicals = kzalloc(sizeof(*(h->lastlogicals)), GFP_KERNEL); + if (!h->lastlogicals) + dev_info(&h->pdev->dev, + "Can't track change to report lun data\n"); + /* Monitor the controller for firmware lockups */ h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL; INIT_DELAYED_WORK(&h->monitor_ctlr_work, hpsa_monitor_ctlr_worker); @@ -8227,6 +8617,71 @@ out: kfree(flush_buf); } +/* Make controller gather fresh report lun data each time we + * send down a report luns request + */ +static void hpsa_disable_rld_caching(struct ctlr_info *h) +{ + u32 *options; + struct CommandList *c; + int rc; + + /* Don't bother trying to set diag options if locked up */ + if (unlikely(h->lockup_detected)) + return; + + options = kzalloc(sizeof(*options), GFP_KERNEL); + if (!options) { + dev_err(&h->pdev->dev, + "Error: failed to disable rld caching, during alloc.\n"); + return; + } + + c = cmd_alloc(h); + + /* first, get the current diag options settings */ + if (fill_cmd(c, BMIC_SENSE_DIAG_OPTIONS, h, options, 4, 0, + RAID_CTLR_LUNID, TYPE_CMD)) + goto errout; + + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if ((rc != 0) || (c->err_info->CommandStatus != 0)) + goto errout; + + /* Now, set the bit for disabling the RLD caching */ + *options |= HPSA_DIAG_OPTS_DISABLE_RLD_CACHING; + + if (fill_cmd(c, BMIC_SET_DIAG_OPTIONS, h, options, 4, 0, + RAID_CTLR_LUNID, TYPE_CMD)) + goto errout; + + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_TODEVICE, NO_TIMEOUT); + if ((rc != 0) || (c->err_info->CommandStatus != 0)) + goto errout; + + /* Now verify that it got set: */ + if (fill_cmd(c, BMIC_SENSE_DIAG_OPTIONS, h, options, 4, 0, + RAID_CTLR_LUNID, TYPE_CMD)) + goto errout; + + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if ((rc != 0) || (c->err_info->CommandStatus != 0)) + goto errout; + + if (*options & HPSA_DIAG_OPTS_DISABLE_RLD_CACHING) + goto out; + +errout: + dev_err(&h->pdev->dev, + "Error: failed to disable report lun data caching.\n"); +out: + cmd_free(h, c); + kfree(options); +} + static void hpsa_shutdown(struct pci_dev *pdev) { struct ctlr_info *h; @@ -8292,6 +8747,7 @@ static void hpsa_remove_one(struct pci_dev *pdev) hpsa_free_performant_mode(h); /* init_one 7 */ hpsa_free_sg_chain_blocks(h); /* init_one 6 */ hpsa_free_cmd_pool(h); /* init_one 5 */ + kfree(h->lastlogicals); /* hpsa_free_irqs already called via hpsa_shutdown init_one 4 */ @@ -8304,6 +8760,9 @@ static void hpsa_remove_one(struct pci_dev *pdev) free_percpu(h->lockup_detected); /* init_one 2 */ h->lockup_detected = NULL; /* init_one 2 */ /* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */ + + hpsa_delete_sas_host(h); + kfree(h); /* init_one 1 */ } @@ -8766,18 +9225,369 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h) } while (1); } +static struct hpsa_sas_phy *hpsa_alloc_sas_phy( + struct hpsa_sas_port *hpsa_sas_port) +{ + struct hpsa_sas_phy *hpsa_sas_phy; + struct sas_phy *phy; + + hpsa_sas_phy = kzalloc(sizeof(*hpsa_sas_phy), GFP_KERNEL); + if (!hpsa_sas_phy) + return NULL; + + phy = sas_phy_alloc(hpsa_sas_port->parent_node->parent_dev, + hpsa_sas_port->next_phy_index); + if (!phy) { + kfree(hpsa_sas_phy); + return NULL; + } + + hpsa_sas_port->next_phy_index++; + hpsa_sas_phy->phy = phy; + hpsa_sas_phy->parent_port = hpsa_sas_port; + + return hpsa_sas_phy; +} + +static void hpsa_free_sas_phy(struct hpsa_sas_phy *hpsa_sas_phy) +{ + struct sas_phy *phy = hpsa_sas_phy->phy; + + sas_port_delete_phy(hpsa_sas_phy->parent_port->port, phy); + sas_phy_free(phy); + if (hpsa_sas_phy->added_to_port) + list_del(&hpsa_sas_phy->phy_list_entry); + kfree(hpsa_sas_phy); +} + +static int hpsa_sas_port_add_phy(struct hpsa_sas_phy *hpsa_sas_phy) +{ + int rc; + struct hpsa_sas_port *hpsa_sas_port; + struct sas_phy *phy; + struct sas_identify *identify; + + hpsa_sas_port = hpsa_sas_phy->parent_port; + phy = hpsa_sas_phy->phy; + + identify = &phy->identify; + memset(identify, 0, sizeof(*identify)); + identify->sas_address = hpsa_sas_port->sas_address; + identify->device_type = SAS_END_DEVICE; + identify->initiator_port_protocols = SAS_PROTOCOL_STP; + identify->target_port_protocols = SAS_PROTOCOL_STP; + phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; + phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; + phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN; + phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; + phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; + + rc = sas_phy_add(hpsa_sas_phy->phy); + if (rc) + return rc; + + sas_port_add_phy(hpsa_sas_port->port, hpsa_sas_phy->phy); + list_add_tail(&hpsa_sas_phy->phy_list_entry, + &hpsa_sas_port->phy_list_head); + hpsa_sas_phy->added_to_port = true; + + return 0; +} + +static int + hpsa_sas_port_add_rphy(struct hpsa_sas_port *hpsa_sas_port, + struct sas_rphy *rphy) +{ + struct sas_identify *identify; + + identify = &rphy->identify; + identify->sas_address = hpsa_sas_port->sas_address; + identify->initiator_port_protocols = SAS_PROTOCOL_STP; + identify->target_port_protocols = SAS_PROTOCOL_STP; + + return sas_rphy_add(rphy); +} + +static struct hpsa_sas_port + *hpsa_alloc_sas_port(struct hpsa_sas_node *hpsa_sas_node, + u64 sas_address) +{ + int rc; + struct hpsa_sas_port *hpsa_sas_port; + struct sas_port *port; + + hpsa_sas_port = kzalloc(sizeof(*hpsa_sas_port), GFP_KERNEL); + if (!hpsa_sas_port) + return NULL; + + INIT_LIST_HEAD(&hpsa_sas_port->phy_list_head); + hpsa_sas_port->parent_node = hpsa_sas_node; + + port = sas_port_alloc_num(hpsa_sas_node->parent_dev); + if (!port) + goto free_hpsa_port; + + rc = sas_port_add(port); + if (rc) + goto free_sas_port; + + hpsa_sas_port->port = port; + hpsa_sas_port->sas_address = sas_address; + list_add_tail(&hpsa_sas_port->port_list_entry, + &hpsa_sas_node->port_list_head); + + return hpsa_sas_port; + +free_sas_port: + sas_port_free(port); +free_hpsa_port: + kfree(hpsa_sas_port); + + return NULL; +} + +static void hpsa_free_sas_port(struct hpsa_sas_port *hpsa_sas_port) +{ + struct hpsa_sas_phy *hpsa_sas_phy; + struct hpsa_sas_phy *next; + + list_for_each_entry_safe(hpsa_sas_phy, next, + &hpsa_sas_port->phy_list_head, phy_list_entry) + hpsa_free_sas_phy(hpsa_sas_phy); + + sas_port_delete(hpsa_sas_port->port); + list_del(&hpsa_sas_port->port_list_entry); + kfree(hpsa_sas_port); +} + +static struct hpsa_sas_node *hpsa_alloc_sas_node(struct device *parent_dev) +{ + struct hpsa_sas_node *hpsa_sas_node; + + hpsa_sas_node = kzalloc(sizeof(*hpsa_sas_node), GFP_KERNEL); + if (hpsa_sas_node) { + hpsa_sas_node->parent_dev = parent_dev; + INIT_LIST_HEAD(&hpsa_sas_node->port_list_head); + } + + return hpsa_sas_node; +} + +static void hpsa_free_sas_node(struct hpsa_sas_node *hpsa_sas_node) +{ + struct hpsa_sas_port *hpsa_sas_port; + struct hpsa_sas_port *next; + + if (!hpsa_sas_node) + return; + + list_for_each_entry_safe(hpsa_sas_port, next, + &hpsa_sas_node->port_list_head, port_list_entry) + hpsa_free_sas_port(hpsa_sas_port); + + kfree(hpsa_sas_node); +} + +static struct hpsa_scsi_dev_t + *hpsa_find_device_by_sas_rphy(struct ctlr_info *h, + struct sas_rphy *rphy) +{ + int i; + struct hpsa_scsi_dev_t *device; + + for (i = 0; i < h->ndevices; i++) { + device = h->dev[i]; + if (!device->sas_port) + continue; + if (device->sas_port->rphy == rphy) + return device; + } + + return NULL; +} + +static int hpsa_add_sas_host(struct ctlr_info *h) +{ + int rc; + struct device *parent_dev; + struct hpsa_sas_node *hpsa_sas_node; + struct hpsa_sas_port *hpsa_sas_port; + struct hpsa_sas_phy *hpsa_sas_phy; + + parent_dev = &h->scsi_host->shost_gendev; + + hpsa_sas_node = hpsa_alloc_sas_node(parent_dev); + if (!hpsa_sas_node) + return -ENOMEM; + + hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, h->sas_address); + if (!hpsa_sas_port) { + rc = -ENODEV; + goto free_sas_node; + } + + hpsa_sas_phy = hpsa_alloc_sas_phy(hpsa_sas_port); + if (!hpsa_sas_phy) { + rc = -ENODEV; + goto free_sas_port; + } + + rc = hpsa_sas_port_add_phy(hpsa_sas_phy); + if (rc) + goto free_sas_phy; + + h->sas_host = hpsa_sas_node; + + return 0; + +free_sas_phy: + hpsa_free_sas_phy(hpsa_sas_phy); +free_sas_port: + hpsa_free_sas_port(hpsa_sas_port); +free_sas_node: + hpsa_free_sas_node(hpsa_sas_node); + + return rc; +} + +static void hpsa_delete_sas_host(struct ctlr_info *h) +{ + hpsa_free_sas_node(h->sas_host); +} + +static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node, + struct hpsa_scsi_dev_t *device) +{ + int rc; + struct hpsa_sas_port *hpsa_sas_port; + struct sas_rphy *rphy; + + hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, device->sas_address); + if (!hpsa_sas_port) + return -ENOMEM; + + rphy = sas_end_device_alloc(hpsa_sas_port->port); + if (!rphy) { + rc = -ENODEV; + goto free_sas_port; + } + + hpsa_sas_port->rphy = rphy; + device->sas_port = hpsa_sas_port; + + rc = hpsa_sas_port_add_rphy(hpsa_sas_port, rphy); + if (rc) + goto free_sas_port; + + return 0; + +free_sas_port: + hpsa_free_sas_port(hpsa_sas_port); + device->sas_port = NULL; + + return rc; +} + +static void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device) +{ + if (device->sas_port) { + hpsa_free_sas_port(device->sas_port); + device->sas_port = NULL; + } +} + +static int +hpsa_sas_get_linkerrors(struct sas_phy *phy) +{ + return 0; +} + +static int +hpsa_sas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) +{ + return 0; +} + +static int +hpsa_sas_get_bay_identifier(struct sas_rphy *rphy) +{ + return -ENXIO; +} + +static int +hpsa_sas_phy_reset(struct sas_phy *phy, int hard_reset) +{ + return 0; +} + +static int +hpsa_sas_phy_enable(struct sas_phy *phy, int enable) +{ + return 0; +} + +static int +hpsa_sas_phy_setup(struct sas_phy *phy) +{ + return 0; +} + +static void +hpsa_sas_phy_release(struct sas_phy *phy) +{ +} + +static int +hpsa_sas_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) +{ + return -EINVAL; +} + +/* SMP = Serial Management Protocol */ +static int +hpsa_sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, +struct request *req) +{ + return -EINVAL; +} + +static struct sas_function_template hpsa_sas_transport_functions = { + .get_linkerrors = hpsa_sas_get_linkerrors, + .get_enclosure_identifier = hpsa_sas_get_enclosure_identifier, + .get_bay_identifier = hpsa_sas_get_bay_identifier, + .phy_reset = hpsa_sas_phy_reset, + .phy_enable = hpsa_sas_phy_enable, + .phy_setup = hpsa_sas_phy_setup, + .phy_release = hpsa_sas_phy_release, + .set_phy_speed = hpsa_sas_phy_speed, + .smp_handler = hpsa_sas_smp_handler, +}; + /* * This is it. Register the PCI driver information for the cards we control * the OS will call our registered routines when it finds one of our cards. */ static int __init hpsa_init(void) { - return pci_register_driver(&hpsa_pci_driver); + int rc; + + hpsa_sas_transport_template = + sas_attach_transport(&hpsa_sas_transport_functions); + if (!hpsa_sas_transport_template) + return -ENODEV; + + rc = pci_register_driver(&hpsa_pci_driver); + + if (rc) + sas_release_transport(hpsa_sas_transport_template); + + return rc; } static void __exit hpsa_cleanup(void) { pci_unregister_driver(&hpsa_pci_driver); + sas_release_transport(hpsa_sas_transport_template); } static void __attribute__((unused)) verify_offsets(void) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 27debb363..ae5beda1b 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -33,12 +33,38 @@ struct access_method { unsigned long (*command_completed)(struct ctlr_info *h, u8 q); }; +/* for SAS hosts and SAS expanders */ +struct hpsa_sas_node { + struct device *parent_dev; + struct list_head port_list_head; +}; + +struct hpsa_sas_port { + struct list_head port_list_entry; + u64 sas_address; + struct sas_port *port; + int next_phy_index; + struct list_head phy_list_head; + struct hpsa_sas_node *parent_node; + struct sas_rphy *rphy; +}; + +struct hpsa_sas_phy { + struct list_head phy_list_entry; + struct sas_phy *phy; + struct hpsa_sas_port *parent_port; + bool added_to_port; +}; + struct hpsa_scsi_dev_t { - int devtype; + unsigned int devtype; int bus, target, lun; /* as presented to the OS */ unsigned char scsi3addr[8]; /* as presented to the HW */ + u8 physical_device : 1; + u8 expose_device; #define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0" unsigned char device_id[16]; /* from inquiry pg. 0x83 */ + u64 sas_address; unsigned char vendor[8]; /* bytes 8-15 of inquiry data */ unsigned char model[16]; /* bytes 16-31 of inquiry data */ unsigned char raid_level; /* from inquiry page 0xC1 */ @@ -75,11 +101,8 @@ struct hpsa_scsi_dev_t { struct hpsa_scsi_dev_t *phys_disk[RAID_MAP_MAX_ENTRIES]; int nphysical_disks; int supports_aborts; -#define HPSA_DO_NOT_EXPOSE 0x0 -#define HPSA_SG_ATTACH 0x1 -#define HPSA_ULD_ATTACH 0x2 -#define HPSA_SCSI_ADD (HPSA_SG_ATTACH | HPSA_ULD_ATTACH) - u8 expose_state; + struct hpsa_sas_port *sas_port; + int external; /* 1-from external array 0-not <0-unknown */ }; struct reply_queue_buffer { @@ -136,6 +159,7 @@ struct ctlr_info { char *product_name; struct pci_dev *pdev; u32 board_id; + u64 sas_address; void __iomem *vaddr; unsigned long paddr; int nr_cmds; /* Number of commands allowed on this controller */ @@ -262,7 +286,10 @@ struct ctlr_info { spinlock_t offline_device_lock; struct list_head offline_device_list; int acciopath_status; + int drv_req_rescan; int raid_offload_debug; + int discovery_polling; + struct ReportLUNdata *lastlogicals; int needs_abort_tags_swizzled; struct workqueue_struct *resubmit_wq; struct workqueue_struct *rescan_ctlr_wq; @@ -270,6 +297,8 @@ struct ctlr_info { wait_queue_head_t abort_cmd_wait_queue; wait_queue_head_t event_sync_wait_queue; struct mutex reset_mutex; + u8 reset_in_progress; + struct hpsa_sas_node *sas_host; }; struct offline_device_entry { @@ -283,6 +312,7 @@ struct offline_device_entry { #define HPSA_RESET_TYPE_BUS 0x01 #define HPSA_RESET_TYPE_TARGET 0x03 #define HPSA_RESET_TYPE_LUN 0x04 +#define HPSA_PHYS_TARGET_RESET 0x99 /* not defined by cciss spec */ #define HPSA_MSG_SEND_RETRY_LIMIT 10 #define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS (10000) @@ -367,6 +397,11 @@ struct offline_device_entry { #define IOACCEL2_INBOUND_POSTQ_64_LOW 0xd0 #define IOACCEL2_INBOUND_POSTQ_64_HI 0xd4 +#define HPSA_PHYSICAL_DEVICE_BUS 0 +#define HPSA_RAID_VOLUME_BUS 1 +#define HPSA_EXTERNAL_RAID_VOLUME_BUS 2 +#define HPSA_HBA_BUS 3 + /* Send the command to the hardware */ diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 47c756ba8..d92ef0d35 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -260,8 +260,6 @@ struct ext_report_lun_entry { u8 wwid[8]; u8 device_type; u8 device_flags; -#define NON_DISK_PHYS_DEV(x) ((x)[17] & 0x01) -#define PHYS_IOACCEL(x) ((x)[17] & 0x08) u8 lun_count; /* multi-lun device, how many luns */ u8 redundant_paths; u32 ioaccel_handle; /* ioaccel1 only uses lower 16 bits */ @@ -288,6 +286,11 @@ struct SenseSubsystem_info { #define BMIC_FLASH_FIRMWARE 0xF7 #define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64 #define BMIC_IDENTIFY_PHYSICAL_DEVICE 0x15 +#define BMIC_IDENTIFY_CONTROLLER 0x11 +#define BMIC_SET_DIAG_OPTIONS 0xF4 +#define BMIC_SENSE_DIAG_OPTIONS 0xF5 +#define HPSA_DIAG_OPTS_DISABLE_RLD_CACHING 0x40000000 +#define BMIC_SENSE_SUBSYSTEM_INFORMATION 0x66 /* Command List Structure */ union SCSI3Addr { @@ -684,6 +687,16 @@ struct hpsa_pci_info { u32 board_id; }; +struct bmic_identify_controller { + u8 configured_logical_drive_count; /* offset 0 */ + u8 pad1[153]; + __le16 extended_logical_unit_count; /* offset 154 */ + u8 pad2[136]; + u8 controller_mode; /* offset 292 */ + u8 pad3[32]; +}; + + struct bmic_identify_physical_device { u8 scsi_bus; /* SCSI Bus number on controller */ u8 scsi_id; /* SCSI ID on this bus */ @@ -816,5 +829,18 @@ struct bmic_identify_physical_device { u8 padding[112]; }; +struct bmic_sense_subsystem_info { + u8 primary_slot_number; + u8 reserved[3]; + u8 chasis_serial_number[32]; + u8 primary_world_wide_id[8]; + u8 primary_array_serial_number[32]; /* NULL terminated */ + u8 primary_cache_serial_number[32]; /* NULL terminated */ + u8 reserved_2[8]; + u8 secondary_array_serial_number[32]; + u8 secondary_cache_serial_number[32]; + u8 pad[332]; +}; + #pragma pack() #endif /* HPSA_CMD_H */ diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 057d27721..6aa317c30 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -3095,7 +3095,6 @@ static struct scsi_host_template driver_template = { .max_sectors = IBMVFC_MAX_SECTORS, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = ibmvfc_attrs, - .use_blk_tags = 1, .track_queue_depth = 1, }; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 6a41c36b1..adfef9db6 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -106,9 +106,9 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(IBMVSCSI_VERSION); module_param_named(max_id, max_id, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(max_id, "Largest ID value for each channel"); +MODULE_PARM_DESC(max_id, "Largest ID value for each channel [Default=64]"); module_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(max_channel, "Largest channel value"); +MODULE_PARM_DESC(max_channel, "Largest channel value [Default=3]"); module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds"); module_param_named(max_requests, max_requests, int, S_IRUGO); @@ -2289,11 +2289,15 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) goto init_pool_failed; } - host->max_lun = 8; + host->max_lun = IBMVSCSI_MAX_LUN; host->max_id = max_id; host->max_channel = max_channel; host->max_cmd_len = 16; + dev_info(dev, + "Maximum ID: %d Maximum LUN: %llu Maximum Channel: %d\n", + host->max_id, host->max_lun, host->max_channel); + if (scsi_add_host(hostdata->host, hostdata->dev)) goto add_host_failed; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 7d64867c5..106736739 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -48,6 +48,7 @@ struct Scsi_Host; #define IBMVSCSI_CMDS_PER_LUN_DEFAULT 16 #define IBMVSCSI_MAX_SECTORS_DEFAULT 256 /* 32 * 8 = default max I/O 32 pages */ #define IBMVSCSI_MAX_CMDS_PER_LUN 64 +#define IBMVSCSI_MAX_LUN 32 /* ------------------------------------------------------------ * Data Structures diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index b62836ddb..536cd5a80 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6363,15 +6363,19 @@ static int ipr_queuecommand(struct Scsi_Host *shost, ipr_cmd->scsi_cmd = scsi_cmd; ipr_cmd->done = ipr_scsi_eh_done; - if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) { + if (ipr_is_gscsi(res)) { if (scsi_cmd->underflow == 0) ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; - if (ipr_is_gscsi(res) && res->reset_occurred) { + if (res->reset_occurred) { res->reset_occurred = 0; ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST; } + } + + if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) { + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; + ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR; if (scsi_cmd->flags & SCMD_TAGGED) ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_SIMPLE_TASK; @@ -6502,7 +6506,6 @@ static struct scsi_host_template driver_template = { .shost_attrs = ipr_ioa_attrs, .sdev_attrs = ipr_dev_attrs, .proc_name = IPR_NAME, - .use_blk_tags = 1, }; /** @@ -7671,6 +7674,63 @@ static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd) return IPR_RC_JOB_RETURN; } +static int ipr_ioa_service_action_failed(struct ipr_cmnd *ipr_cmd) +{ + u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); + + if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) + return IPR_RC_JOB_CONTINUE; + + return ipr_reset_cmd_failed(ipr_cmd); +} + +static void ipr_build_ioa_service_action(struct ipr_cmnd *ipr_cmd, + __be32 res_handle, u8 sa_code) +{ + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + + ioarcb->res_handle = res_handle; + ioarcb->cmd_pkt.cdb[0] = IPR_IOA_SERVICE_ACTION; + ioarcb->cmd_pkt.cdb[1] = sa_code; + ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; +} + +/** + * ipr_ioafp_set_caching_parameters - Issue Set Cache parameters service + * action + * + * Return value: + * none + **/ +static int ipr_ioafp_set_caching_parameters(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_inquiry_pageC4 *pageC4 = &ioa_cfg->vpd_cbs->pageC4_data; + + ENTER; + + ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg; + + if (pageC4->cache_cap[0] & IPR_CAP_SYNC_CACHE) { + ipr_build_ioa_service_action(ipr_cmd, + cpu_to_be32(IPR_IOA_RES_HANDLE), + IPR_IOA_SA_CHANGE_CACHE_PARAMS); + + ioarcb->cmd_pkt.cdb[2] = 0x40; + + ipr_cmd->job_step_failed = ipr_ioa_service_action_failed; + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, + IPR_SET_SUP_DEVICE_TIMEOUT); + + LEAVE; + return IPR_RC_JOB_RETURN; + } + + LEAVE; + return IPR_RC_JOB_CONTINUE; +} + /** * ipr_ioafp_inquiry - Send an Inquiry to the adapter. * @ipr_cmd: ipr command struct @@ -7721,6 +7781,39 @@ static int ipr_inquiry_page_supported(struct ipr_inquiry_page0 *page0, u8 page) return 0; } +/** + * ipr_ioafp_pageC4_inquiry - Send a Page 0xC4 Inquiry to the adapter. + * @ipr_cmd: ipr command struct + * + * This function sends a Page 0xC4 inquiry to the adapter + * to retrieve software VPD information. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_pageC4_inquiry(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data; + struct ipr_inquiry_pageC4 *pageC4 = &ioa_cfg->vpd_cbs->pageC4_data; + + ENTER; + ipr_cmd->job_step = ipr_ioafp_set_caching_parameters; + memset(pageC4, 0, sizeof(*pageC4)); + + if (ipr_inquiry_page_supported(page0, 0xC4)) { + ipr_ioafp_inquiry(ipr_cmd, 1, 0xC4, + (ioa_cfg->vpd_cbs_dma + + offsetof(struct ipr_misc_cbs, + pageC4_data)), + sizeof(struct ipr_inquiry_pageC4)); + return IPR_RC_JOB_RETURN; + } + + LEAVE; + return IPR_RC_JOB_CONTINUE; +} + /** * ipr_ioafp_cap_inquiry - Send a Page 0xD0 Inquiry to the adapter. * @ipr_cmd: ipr command struct @@ -7738,7 +7831,7 @@ static int ipr_ioafp_cap_inquiry(struct ipr_cmnd *ipr_cmd) struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap; ENTER; - ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg; + ipr_cmd->job_step = ipr_ioafp_pageC4_inquiry; memset(cap, 0, sizeof(*cap)); if (ipr_inquiry_page_supported(page0, 0xD0)) { @@ -8277,6 +8370,42 @@ static int ipr_reset_get_unit_check_job(struct ipr_cmnd *ipr_cmd) return IPR_RC_JOB_RETURN; } +static int ipr_dump_mailbox_wait(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + + ENTER; + + if (ioa_cfg->sdt_state != GET_DUMP) + return IPR_RC_JOB_RETURN; + + if (!ioa_cfg->sis64 || !ipr_cmd->u.time_left || + (readl(ioa_cfg->regs.sense_interrupt_reg) & + IPR_PCII_MAILBOX_STABLE)) { + + if (!ipr_cmd->u.time_left) + dev_err(&ioa_cfg->pdev->dev, + "Timed out waiting for Mailbox register.\n"); + + ioa_cfg->sdt_state = READ_DUMP; + ioa_cfg->dump_timeout = 0; + if (ioa_cfg->sis64) + ipr_reset_start_timer(ipr_cmd, IPR_SIS64_DUMP_TIMEOUT); + else + ipr_reset_start_timer(ipr_cmd, IPR_SIS32_DUMP_TIMEOUT); + ipr_cmd->job_step = ipr_reset_wait_for_dump; + schedule_work(&ioa_cfg->work_q); + + } else { + ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT; + ipr_reset_start_timer(ipr_cmd, + IPR_CHECK_FOR_RESET_TIMEOUT); + } + + LEAVE; + return IPR_RC_JOB_RETURN; +} + /** * ipr_reset_restore_cfg_space - Restore PCI config space. * @ipr_cmd: ipr command struct @@ -8326,20 +8455,11 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) if (ioa_cfg->in_ioa_bringdown) { ipr_cmd->job_step = ipr_ioa_bringdown_done; + } else if (ioa_cfg->sdt_state == GET_DUMP) { + ipr_cmd->job_step = ipr_dump_mailbox_wait; + ipr_cmd->u.time_left = IPR_WAIT_FOR_MAILBOX; } else { ipr_cmd->job_step = ipr_reset_enable_ioa; - - if (GET_DUMP == ioa_cfg->sdt_state) { - ioa_cfg->sdt_state = READ_DUMP; - ioa_cfg->dump_timeout = 0; - if (ioa_cfg->sis64) - ipr_reset_start_timer(ipr_cmd, IPR_SIS64_DUMP_TIMEOUT); - else - ipr_reset_start_timer(ipr_cmd, IPR_SIS32_DUMP_TIMEOUT); - ipr_cmd->job_step = ipr_reset_wait_for_dump; - schedule_work(&ioa_cfg->work_q); - return IPR_RC_JOB_RETURN; - } } LEAVE; diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index e4fb17a58..a34c7a5a9 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -39,8 +39,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.6.2" -#define IPR_DRIVER_DATE "(June 11, 2015)" +#define IPR_DRIVER_VERSION "2.6.3" +#define IPR_DRIVER_DATE "(October 17, 2015)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding @@ -216,6 +216,10 @@ #define IPR_SET_ALL_SUPPORTED_DEVICES 0x80 #define IPR_IOA_SHUTDOWN 0xF7 #define IPR_WR_BUF_DOWNLOAD_AND_SAVE 0x05 +#define IPR_IOA_SERVICE_ACTION 0xD2 + +/* IOA Service Actions */ +#define IPR_IOA_SA_CHANGE_CACHE_PARAMS 0x14 /* * Timeouts @@ -279,6 +283,9 @@ #define IPR_IPL_INIT_STAGE_TIME_MASK 0x0000ffff #define IPR_PCII_IPL_STAGE_CHANGE (0x80000000 >> 0) +#define IPR_PCII_MAILBOX_STABLE (0x80000000 >> 4) +#define IPR_WAIT_FOR_MAILBOX (2 * HZ) + #define IPR_PCII_IOA_TRANS_TO_OPER (0x80000000 >> 0) #define IPR_PCII_IOARCB_XFER_FAILED (0x80000000 >> 3) #define IPR_PCII_IOA_UNIT_CHECKED (0x80000000 >> 4) @@ -846,6 +853,16 @@ struct ipr_inquiry_page0 { u8 page[IPR_INQUIRY_PAGE0_ENTRIES]; }__attribute__((packed)); +struct ipr_inquiry_pageC4 { + u8 peri_qual_dev_type; + u8 page_code; + u8 reserved1; + u8 len; + u8 cache_cap[4]; +#define IPR_CAP_SYNC_CACHE 0x08 + u8 reserved2[20]; +} __packed; + struct ipr_hostrcb_device_data_entry { struct ipr_vpd vpd; struct ipr_res_addr dev_res_addr; @@ -1319,6 +1336,7 @@ struct ipr_misc_cbs { struct ipr_inquiry_page0 page0_data; struct ipr_inquiry_page3 page3_data; struct ipr_inquiry_cap cap; + struct ipr_inquiry_pageC4 pageC4_data; struct ipr_mode_pages mode_pages; struct ipr_supported_device supp_dev; }; diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 0dfcabe3c..77128d680 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c @@ -170,7 +170,6 @@ static struct scsi_host_template isci_sht = { .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, .shost_attrs = isci_host_attrs, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -272,11 +271,11 @@ static void isci_unregister(struct isci_host *isci_host) if (!isci_host) return; + shost = to_shost(isci_host); + scsi_remove_host(shost); sas_unregister_ha(&isci_host->sas_ha); - shost = to_shost(isci_host); sas_remove_host(shost); - scsi_remove_host(shost); scsi_host_put(shost); } diff --git a/drivers/scsi/libfc/fc_npiv.c b/drivers/scsi/libfc/fc_npiv.c index 9fbf78ed8..c168321b5 100644 --- a/drivers/scsi/libfc/fc_npiv.c +++ b/drivers/scsi/libfc/fc_npiv.c @@ -25,7 +25,7 @@ #include /** - * fc_vport_create() - Create a new NPIV vport instance + * libfc_vport_create() - Create a new NPIV vport instance * @vport: fc_vport structure from scsi_transport_fc * @privsize: driver private data size to allocate along with the Scsi_Host */ diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index a5a56fa31..ceee9a3fd 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -495,15 +495,17 @@ struct unsol_rcv_ct_ctx { #define LPFC_USER_LINK_SPEED_8G 8 /* 8 Gigabaud */ #define LPFC_USER_LINK_SPEED_10G 10 /* 10 Gigabaud */ #define LPFC_USER_LINK_SPEED_16G 16 /* 16 Gigabaud */ -#define LPFC_USER_LINK_SPEED_MAX LPFC_USER_LINK_SPEED_16G -#define LPFC_USER_LINK_SPEED_BITMAP ((1 << LPFC_USER_LINK_SPEED_16G) | \ +#define LPFC_USER_LINK_SPEED_32G 32 /* 32 Gigabaud */ +#define LPFC_USER_LINK_SPEED_MAX LPFC_USER_LINK_SPEED_32G +#define LPFC_USER_LINK_SPEED_BITMAP ((1ULL << LPFC_USER_LINK_SPEED_32G) | \ + (1 << LPFC_USER_LINK_SPEED_16G) | \ (1 << LPFC_USER_LINK_SPEED_10G) | \ (1 << LPFC_USER_LINK_SPEED_8G) | \ (1 << LPFC_USER_LINK_SPEED_4G) | \ (1 << LPFC_USER_LINK_SPEED_2G) | \ (1 << LPFC_USER_LINK_SPEED_1G) | \ (1 << LPFC_USER_LINK_SPEED_AUTO)) -#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16" +#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16, 32" enum nemb_type { nemb_mse = 1, diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index d65bd178d..f6446d759 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1642,8 +1642,6 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ struct Scsi_Host *shost = class_to_shost(dev);\ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ struct lpfc_hba *phba = vport->phba;\ - uint val = 0;\ - val = phba->cfg_##attr;\ return snprintf(buf, PAGE_SIZE, "%d\n",\ phba->cfg_##attr);\ } @@ -1808,8 +1806,6 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ { \ struct Scsi_Host *shost = class_to_shost(dev);\ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ - uint val = 0;\ - val = vport->cfg_##attr;\ return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\ } @@ -1835,8 +1831,6 @@ lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ { \ struct Scsi_Host *shost = class_to_shost(dev);\ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ - uint val = 0;\ - val = vport->cfg_##attr;\ return snprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\ } @@ -3282,15 +3276,20 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr, if (val >= 0 && val <= 6) { prev_val = phba->cfg_topology; - phba->cfg_topology = val; if (phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G && val == 4) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "3113 Loop mode not supported at speed %d\n", - phba->cfg_link_speed); - phba->cfg_topology = prev_val; + val); return -EINVAL; } + if (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC && + val == 4) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "3114 Loop mode not supported\n"); + return -EINVAL; + } + phba->cfg_topology = val; if (nolip) return strlen(buf); @@ -3731,7 +3730,8 @@ lpfc_link_speed_store(struct device *dev, struct device_attribute *attr, ((val == LPFC_USER_LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) || ((val == LPFC_USER_LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) || ((val == LPFC_USER_LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)) || - ((val == LPFC_USER_LINK_SPEED_16G) && !(phba->lmt & LMT_16Gb))) { + ((val == LPFC_USER_LINK_SPEED_16G) && !(phba->lmt & LMT_16Gb)) || + ((val == LPFC_USER_LINK_SPEED_32G) && !(phba->lmt & LMT_32Gb))) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2879 lpfc_link_speed attribute cannot be set " "to %d. Speed is not supported by this port.\n", @@ -5267,6 +5267,9 @@ lpfc_get_host_speed(struct Scsi_Host *shost) case LPFC_LINK_SPEED_16GHZ: fc_host_speed(shost) = FC_PORTSPEED_16GBIT; break; + case LPFC_LINK_SPEED_32GHZ: + fc_host_speed(shost) = FC_PORTSPEED_32GBIT; + break; default: fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; break; diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index b70506807..05dcc2abd 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -904,7 +904,6 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, { uint32_t evt_req_id = 0; uint32_t cmd; - uint32_t len; struct lpfc_dmabuf *dmabuf = NULL; struct lpfc_bsg_event *evt; struct event_data *evt_dat = NULL; @@ -946,7 +945,6 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; evt_req_id = ct_req->FsType; cmd = ct_req->CommandResponse.bits.CmdRsp; - len = ct_req->CommandResponse.bits.Size; if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); @@ -2988,7 +2986,6 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) { struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; - struct diag_mode_test *diag_mode; struct lpfc_bsg_event *evt; struct event_data *evdat; struct lpfc_sli *psli = &phba->sli; @@ -3031,8 +3028,6 @@ lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) rc = -EINVAL; goto loopback_test_exit; } - diag_mode = (struct diag_mode_test *) - job->request->rqst_data.h_vendor.vendor_cmd; if ((phba->link_state == LPFC_HBA_ERROR) || (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || @@ -3293,7 +3288,6 @@ lpfc_bsg_get_dfc_rev(struct fc_bsg_job *job) { struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; struct lpfc_hba *phba = vport->phba; - struct get_mgmt_rev *event_req; struct get_mgmt_rev_reply *event_reply; int rc = 0; @@ -3306,9 +3300,6 @@ lpfc_bsg_get_dfc_rev(struct fc_bsg_job *job) goto job_error; } - event_req = (struct get_mgmt_rev *) - job->request->rqst_data.h_vendor.vendor_cmd; - event_reply = (struct get_mgmt_rev_reply *) job->reply->reply_data.vendor_reply.vendor_rsp; @@ -4348,7 +4339,6 @@ static int lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job, struct lpfc_dmabuf *dmabuf) { - struct lpfc_sli_config_mbox *sli_cfg_mbx; struct bsg_job_data *dd_data = NULL; LPFC_MBOXQ_t *pmboxq = NULL; MAILBOX_t *pmb; @@ -4362,9 +4352,6 @@ lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job, phba->mbox_ext_buf_ctx.seqNum++; nemb_tp = phba->mbox_ext_buf_ctx.nembType; - sli_cfg_mbx = (struct lpfc_sli_config_mbox *) - phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); if (!dd_data) { rc = -ENOMEM; @@ -4606,7 +4593,6 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t transmit_length, receive_length, mode; struct lpfc_mbx_sli4_config *sli4_config; struct lpfc_mbx_nembed_cmd *nembed_sge; - struct mbox_header *header; struct ulp_bde64 *bde; uint8_t *ext = NULL; int rc = 0; @@ -4804,8 +4790,6 @@ lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, /* rebuild the command for sli4 using our * own buffers like we do for biu diags */ - header = (struct mbox_header *) - &pmb->un.varWords[0]; nembed_sge = (struct lpfc_mbx_nembed_cmd *) &pmb->un.varWords[0]; receive_length = nembed_sge->sge[0].length; @@ -5048,7 +5032,6 @@ lpfc_menlo_cmd(struct fc_bsg_job *job) IOCB_t *cmd; int rc = 0; struct menlo_command *menlo_cmd; - struct menlo_response *menlo_resp; struct lpfc_dmabuf *bmp = NULL, *cmp = NULL, *rmp = NULL; int request_nseg; int reply_nseg; @@ -5088,9 +5071,6 @@ lpfc_menlo_cmd(struct fc_bsg_job *job) menlo_cmd = (struct menlo_command *) job->request->rqst_data.h_vendor.vendor_cmd; - menlo_resp = (struct menlo_response *) - job->reply->reply_data.vendor_reply.vendor_rsp; - /* allocate our bsg tracking structure */ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); if (!dd_data) { diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index af129966b..8fded1f76 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -55,6 +55,7 @@ #define HBA_PORTSPEED_10GBIT 0x0004 /* 10 GBit/sec */ #define HBA_PORTSPEED_8GBIT 0x0010 /* 8 GBit/sec */ #define HBA_PORTSPEED_16GBIT 0x0020 /* 16 GBit/sec */ +#define HBA_PORTSPEED_32GBIT 0x0040 /* 32 GBit/sec */ #define HBA_PORTSPEED_UNKNOWN 0x0800 /* Unknown */ #define FOURBYTES 4 @@ -575,7 +576,6 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = cmdiocb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; - struct lpfc_dmabuf *bmp; struct lpfc_dmabuf *outp; struct lpfc_sli_ct_request *CTrsp; struct lpfc_nodelist *ndlp; @@ -588,7 +588,6 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, cmdiocb->context_un.rsp_iocb = rspiocb; outp = (struct lpfc_dmabuf *) cmdiocb->context2; - bmp = (struct lpfc_dmabuf *) cmdiocb->context3; irsp = &rspiocb->iocb; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, @@ -1733,12 +1732,9 @@ hba_out: case SLI_MGMT_RPRT: case SLI_MGMT_RPA: { - lpfc_vpd_t *vp; struct serv_parm *hsp; int len = 0; - vp = &phba->vpd; - if (cmdcode == SLI_MGMT_RPRT) { rh = (struct lpfc_fdmi_reg_hba *) &CtReq->un.PortID; @@ -1778,6 +1774,8 @@ hba_out: ad->AttrType = cpu_to_be16(RPRT_SUPPORTED_SPEED); ad->AttrLen = cpu_to_be16(FOURBYTES + 4); ae->un.SupportSpeed = 0; + if (phba->lmt & LMT_32Gb) + ae->un.SupportSpeed |= HBA_PORTSPEED_32GBIT; if (phba->lmt & LMT_16Gb) ae->un.SupportSpeed |= HBA_PORTSPEED_16GBIT; if (phba->lmt & LMT_10Gb) @@ -1821,6 +1819,9 @@ hba_out: case LPFC_LINK_SPEED_16GHZ: ae->un.PortSpeed = HBA_PORTSPEED_16GBIT; break; + case LPFC_LINK_SPEED_32GHZ: + ae->un.PortSpeed = HBA_PORTSPEED_32GBIT; + break; default: ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN; break; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 36bf58ba7..b6fa257ea 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -457,11 +457,9 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *mboxq; struct lpfc_nodelist *ndlp; - struct serv_parm *sp; struct lpfc_dmabuf *dmabuf; int rc = 0; - sp = &phba->fc_fabparam; /* move forward in case of SLI4 FC port loopback test and pt2pt mode */ if ((phba->sli_rev == LPFC_SLI_REV4) && !(phba->link_flag & LS_LOOPBACK_MODE) && @@ -1028,9 +1026,11 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, stop_rr_fcf_flogi: /* FLOGI failure */ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2858 FLOGI failure Status:x%x/x%x TMO:x%x\n", + "2858 FLOGI failure Status:x%x/x%x TMO:x%x " + "Data x%x x%x\n", irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout); + irsp->ulpTimeout, phba->hba_flag, + phba->fcf.fcf_flag); /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) @@ -1154,6 +1154,9 @@ stop_rr_fcf_flogi: } flogifail: + spin_lock_irq(&phba->hbalock); + phba->fcf.fcf_flag &= ~FCF_DISCOVERY; + spin_unlock_irq(&phba->hbalock); lpfc_nlp_put(ndlp); if (!lpfc_error_lost_link(irsp)) { @@ -1205,14 +1208,11 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct serv_parm *sp; IOCB_t *icmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli_ring *pring; uint8_t *pcmd; uint16_t cmdsize; uint32_t tmo; int rc; - pring = &phba->sli.ring[LPFC_ELS_RING]; - cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_FLOGI); @@ -1454,8 +1454,6 @@ lpfc_initial_fdisc(struct lpfc_vport *vport) void lpfc_more_plogi(struct lpfc_vport *vport) { - int sentplogi; - if (vport->num_disc_nodes) vport->num_disc_nodes--; @@ -1468,7 +1466,7 @@ lpfc_more_plogi(struct lpfc_vport *vport) /* Check to see if there are more PLOGIs to be sent */ if (vport->fc_flag & FC_NLP_MORE) /* go thru NPR nodes and issue any remaining ELS PLOGIs */ - sentplogi = lpfc_els_disc_plogi(vport); + lpfc_els_disc_plogi(vport); return; } @@ -1956,16 +1954,12 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) { struct lpfc_hba *phba = vport->phba; struct serv_parm *sp; - IOCB_t *icmd; struct lpfc_nodelist *ndlp; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int ret; - psli = &phba->sli; - ndlp = lpfc_findnode_did(vport, did); if (ndlp && !NLP_CHK_NODE_ACT(ndlp)) ndlp = NULL; @@ -1977,7 +1971,6 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) if (!elsiocb) return 1; - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); /* For PLOGI request, remainder of payload is service parameters */ @@ -2034,10 +2027,8 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = cmdiocb->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; - struct lpfc_sli *psli; struct lpfc_nodelist *ndlp; - psli = &phba->sli; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->context_un.rsp_iocb = rspiocb; @@ -2117,7 +2108,6 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; PRLI *npr; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; @@ -2128,7 +2118,6 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); /* For PRLI request, remainder of payload is service parameters */ @@ -2413,7 +2402,6 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; ADISC *ap; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; @@ -2424,7 +2412,6 @@ lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); /* For ADISC request, remainder of payload is service parameters */ @@ -2478,12 +2465,10 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_vport *vport = ndlp->vport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; - struct lpfc_sli *psli; struct lpfcMboxq *mbox; unsigned long flags; uint32_t skip_recovery = 0; - psli = &phba->sli; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->context_un.rsp_iocb = rspiocb; @@ -2609,7 +2594,6 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; @@ -2628,7 +2612,6 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_LOGO; pcmd += sizeof(uint32_t); @@ -2742,14 +2725,11 @@ int lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) { struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; struct lpfc_nodelist *ndlp; - psli = &phba->sli; cmdsize = (sizeof(uint32_t) + sizeof(SCR)); ndlp = lpfc_findnode_did(vport, nportid); @@ -2776,7 +2756,6 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) return 1; } - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_SCR; @@ -2836,9 +2815,7 @@ static int lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) { struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; FARP *fp; uint8_t *pcmd; uint32_t *lp; @@ -2846,7 +2823,6 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) struct lpfc_nodelist *ondlp; struct lpfc_nodelist *ndlp; - psli = &phba->sli; cmdsize = (sizeof(uint32_t) + sizeof(FARP)); ndlp = lpfc_findnode_did(vport, nportid); @@ -2872,7 +2848,6 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) return 1; } - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_FARPR; @@ -3922,13 +3897,11 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, IOCB_t *icmd; IOCB_t *oldcmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; ELS_PKT *els_pkt_ptr; - psli = &phba->sli; oldcmd = &oldiocb->iocb; switch (flag) { @@ -4061,12 +4034,10 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, IOCB_t *icmd; IOCB_t *oldcmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; - psli = &phba->sli; cmdsize = 2 * sizeof(uint32_t); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, ndlp->nlp_DID, ELS_CMD_LS_RJT); @@ -4212,13 +4183,10 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, IOCB_t *icmd; IOCB_t *oldcmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; - psli = &phba->sli; - cmdsize = sizeof(uint32_t) + sizeof(PRLI); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK))); @@ -4315,12 +4283,10 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format, RNID *rn; IOCB_t *icmd, *oldcmd; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; - psli = &phba->sli; cmdsize = sizeof(uint32_t) + sizeof(uint32_t) + (2 * sizeof(struct lpfc_name)); if (format) @@ -4447,12 +4413,10 @@ lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data, { struct lpfc_hba *phba = vport->phba; struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; uint8_t *pcmd; uint16_t cmdsize; int rc; - psli = &phba->sli; cmdsize = oldiocb->iocb.unsli3.rcvsli3.acc_len; /* The accumulated length can exceed the BPL_SIZE. For @@ -4746,6 +4710,8 @@ lpfc_rdp_res_speed(struct fc_rdp_port_speed_desc *desc, struct lpfc_hba *phba) desc->info.port_speed.speed = cpu_to_be16(rdp_speed); + if (phba->lmt & LMT_32Gb) + rdp_cap |= RDP_PS_32GB; if (phba->lmt & LMT_16Gb) rdp_cap |= RDP_PS_16GB; if (phba->lmt & LMT_10Gb) @@ -5181,14 +5147,12 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, { struct lpfc_hba *phba = vport->phba; struct lpfc_dmabuf *pcmd; - IOCB_t *icmd; uint8_t *lp; struct fc_lcb_request_frame *beacon; struct lpfc_lcb_context *lcb_context; uint8_t state, rjt_err; struct ls_rjt stat; - icmd = &cmdiocb->iocb; pcmd = (struct lpfc_dmabuf *)cmdiocb->context2; lp = (uint8_t *)pcmd->virt; beacon = (struct fc_lcb_request_frame *)pcmd->virt; @@ -5209,7 +5173,6 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, rjt_err = LSRJT_CMD_UNSUPPORTED; goto rjt; } - lcb_context = kmalloc(sizeof(struct lpfc_lcb_context), GFP_KERNEL); if (phba->hba_flag & HBA_FCOE_MODE) { rjt_err = LSRJT_CMD_UNSUPPORTED; @@ -5240,6 +5203,12 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, goto rjt; } + lcb_context = kmalloc(sizeof(*lcb_context), GFP_KERNEL); + if (!lcb_context) { + rjt_err = LSRJT_UNABLE_TPC; + goto rjt; + } + state = (beacon->lcb_sub_command == LPFC_LCB_ON) ? 1 : 0; lcb_context->sub_command = beacon->lcb_sub_command; lcb_context->type = beacon->lcb_type; @@ -5250,6 +5219,7 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if (lpfc_sli4_set_beacon(vport, lcb_context, state)) { lpfc_printf_vlog(ndlp->vport, KERN_ERR, LOG_ELS, "0193 failed to send mail box"); + kfree(lcb_context); lpfc_nlp_put(ndlp); rjt_err = LSRJT_UNABLE_TPC; goto rjt; @@ -5444,7 +5414,7 @@ lpfc_send_rscn_event(struct lpfc_vport *vport, fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(struct lpfc_els_event_header) + payload_len, + sizeof(struct lpfc_rscn_event_header) + payload_len, (char *)rscn_event_data, LPFC_NL_VENDOR_ID); @@ -5481,13 +5451,11 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, struct lpfc_hba *phba = vport->phba; struct lpfc_dmabuf *pcmd; uint32_t *lp, *datap; - IOCB_t *icmd; uint32_t payload_len, length, nportid, *cmd; int rscn_cnt; int rscn_id = 0, hba_id = 0; int i; - icmd = &cmdiocb->iocb; pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; lp = (uint32_t *) pcmd->virt; @@ -5893,6 +5861,13 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, return 1; } + /* send our FLOGI first */ + if (vport->port_state < LPFC_FLOGI) { + vport->fc_myDID = 0; + lpfc_initial_flogi(vport); + vport->fc_myDID = Fabric_DID; + } + /* Send back ACC */ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL); @@ -5943,12 +5918,10 @@ lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, { struct lpfc_dmabuf *pcmd; uint32_t *lp; - IOCB_t *icmd; RNID *rn; struct ls_rjt stat; uint32_t cmd; - icmd = &cmdiocb->iocb; pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; lp = (uint32_t *) pcmd->virt; @@ -6259,7 +6232,6 @@ lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, { struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *mbox; - struct lpfc_dmabuf *pcmd; struct ls_rjt stat; if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && @@ -6267,8 +6239,6 @@ lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* reject the unsolicited RPS request and done with it */ goto reject_out; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC); if (mbox) { lpfc_read_lnk_stat(phba, mbox); @@ -6482,7 +6452,6 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_hba *phba = vport->phba; struct RRQ *els_rrq; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; @@ -6501,7 +6470,6 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!elsiocb) return 1; - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); /* For RRQ request, remainder of payload is Exchange IDs */ @@ -7374,6 +7342,15 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, "Data: x%x x%x x%x x%x\n", cmd, did, vport->port_state, vport->fc_flag, vport->fc_myDID, vport->fc_prevDID); + + /* reject till our FLOGI completes */ + if ((vport->port_state < LPFC_FABRIC_CFG_LINK) && + (cmd != ELS_CMD_FLOGI)) { + rjt_err = LSRJT_UNABLE_TPC; + rjt_exp = LSEXP_NOTHING_MORE; + goto lsrjt; + } + switch (cmd) { case ELS_CMD_PLOGI: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -7411,20 +7388,6 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, rjt_exp = LSEXP_NOTHING_MORE; break; } - /* We get here, and drop thru, if we are PT2PT with - * another NPort and the other side has initiated - * the PLOGI before responding to our FLOGI. - */ - if (phba->sli_rev == LPFC_SLI_REV4 && - (phba->fc_topology_changed || - vport->fc_myDID != vport->fc_prevDID)) { - lpfc_unregister_fcf_prep(phba); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VFI_REGISTERED; - spin_unlock_irq(shost->host_lock); - phba->fc_topology_changed = 0; - lpfc_issue_reg_vfi(vport); - } } spin_lock_irq(shost->host_lock); @@ -7655,6 +7618,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, break; } +lsrjt: /* check if need to LS_RJT received ELS cmd */ if (rjt_err) { memset(&stat, 0, sizeof(stat)); @@ -8428,7 +8392,6 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; uint16_t cmdsize; @@ -8439,7 +8402,6 @@ lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (!elsiocb) return 1; - icmd = &elsiocb->iocb; pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_LOGO; pcmd += sizeof(uint32_t); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 759cbebed..bfc2442dd 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -800,7 +800,6 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp, *next_ndlp; - int rc; list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { if (!NLP_CHK_NODE_ACT(ndlp)) @@ -816,10 +815,10 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) if ((phba->sli_rev < LPFC_SLI_REV4) && (!remove && ndlp->nlp_type & NLP_FABRIC)) continue; - rc = lpfc_disc_state_machine(vport, ndlp, NULL, - remove - ? NLP_EVT_DEVICE_RM - : NLP_EVT_DEVICE_RECOVERY); + lpfc_disc_state_machine(vport, ndlp, NULL, + remove + ? NLP_EVT_DEVICE_RM + : NLP_EVT_DEVICE_RECOVERY); } if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) { if (phba->sli_rev == LPFC_SLI_REV4) @@ -1774,7 +1773,6 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, uint16_t *next_fcf_index) { void *virt_addr; - dma_addr_t phys_addr; struct lpfc_mbx_sge sge; struct lpfc_mbx_read_fcf_tbl *read_fcf; uint32_t shdr_status, shdr_add_status, if_type; @@ -1785,7 +1783,6 @@ lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, * routine only uses a single SGE. */ lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); - phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); if (unlikely(!mboxq->sge_array)) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, "2524 Failed to get the non-embedded SGE " @@ -2977,7 +2974,8 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) MAILBOX_t *mb = &pmb->u.mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1; struct lpfc_vport *vport = pmb->vport; - + struct serv_parm *sp = &vport->fc_sparam; + uint32_t ed_tov; /* Check for error */ if (mb->mbxStatus) { @@ -2992,6 +2990,18 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) memcpy((uint8_t *) &vport->fc_sparam, (uint8_t *) mp->virt, sizeof (struct serv_parm)); + + ed_tov = be32_to_cpu(sp->cmn.e_d_tov); + if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */ + ed_tov = (ed_tov + 999999) / 1000000; + + phba->fc_edtov = ed_tov; + phba->fc_ratov = (2 * ed_tov) / 1000; + if (phba->fc_ratov < FF_DEF_RATOV) { + /* RA_TOV should be atleast 10sec for initial flogi */ + phba->fc_ratov = FF_DEF_RATOV; + } + lpfc_update_vport_wwn(vport); if (vport->port_type == LPFC_PHYSICAL_PORT) { memcpy(&phba->wwnn, &vport->fc_nodename, sizeof(phba->wwnn)); @@ -3032,6 +3042,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) case LPFC_LINK_SPEED_8GHZ: case LPFC_LINK_SPEED_10GHZ: case LPFC_LINK_SPEED_16GHZ: + case LPFC_LINK_SPEED_32GHZ: phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la); break; default: diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 892c5257d..2cce88e96 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -33,7 +33,7 @@ #define FF_DEF_EDTOV 2000 /* Default E_D_TOV (2000ms) */ #define FF_DEF_ALTOV 15 /* Default AL_TIME (15ms) */ -#define FF_DEF_RATOV 2 /* Default RA_TOV (2s) */ +#define FF_DEF_RATOV 10 /* Default RA_TOV (10s) */ #define FF_DEF_ARBTOV 1900 /* Default ARB_TOV (1900ms) */ #define LPFC_BUF_RING0 64 /* Number of buffers to post to RING @@ -1400,6 +1400,7 @@ struct lpfc_fdmi_reg_portattr { #define PCI_DEVICE_ID_LANCER_FC_VF 0xe208 #define PCI_DEVICE_ID_LANCER_FCOE 0xe260 #define PCI_DEVICE_ID_LANCER_FCOE_VF 0xe268 +#define PCI_DEVICE_ID_LANCER_G6_FC 0xe300 #define PCI_DEVICE_ID_SAT_SMB 0xf011 #define PCI_DEVICE_ID_SAT_MID 0xf015 #define PCI_DEVICE_ID_RFLY 0xf095 @@ -2075,6 +2076,7 @@ typedef struct { #define LINK_SPEED_8G 0x8 /* 8 Gigabaud */ #define LINK_SPEED_10G 0x10 /* 10 Gigabaud */ #define LINK_SPEED_16G 0x11 /* 16 Gigabaud */ +#define LINK_SPEED_32G 0x14 /* 32 Gigabaud */ } INIT_LINK_VAR; @@ -2246,6 +2248,7 @@ typedef struct { #define LMT_8Gb 0x080 #define LMT_10Gb 0x100 #define LMT_16Gb 0x200 +#define LMT_32Gb 0x400 uint32_t rsvd2; uint32_t rsvd3; uint32_t max_xri; @@ -2727,6 +2730,7 @@ struct lpfc_mbx_read_top { #define LPFC_LINK_SPEED_8GHZ 0x20 #define LPFC_LINK_SPEED_10GHZ 0x40 #define LPFC_LINK_SPEED_16GHZ 0x80 +#define LPFC_LINK_SPEED_32GHZ 0x90 }; /* Structure for MB Command CLEAR_LA (22) */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index bffe48095..dbb8e1bbd 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -699,7 +699,9 @@ lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)) || ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G) && - !(phba->lmt & LMT_16Gb))) { + !(phba->lmt & LMT_16Gb)) || + ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_32G) && + !(phba->lmt & LMT_32Gb))) { /* Reset link speed to auto */ lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1302 Invalid speed for this board:%d " @@ -2035,7 +2037,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) && descp && descp[0] != '\0') return; - if (phba->lmt & LMT_16Gb) + if (phba->lmt & LMT_32Gb) + max_speed = 32; + else if (phba->lmt & LMT_16Gb) max_speed = 16; else if (phba->lmt & LMT_10Gb) max_speed = 10; @@ -2229,6 +2233,9 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) m = (typeof(m)){"OCe15100", "PCIe", "Obsolete, Unsupported FCoE"}; break; + case PCI_DEVICE_ID_LANCER_G6_FC: + m = (typeof(m)){"LPe32000", "PCIe", "Fibre Channel Adapter"}; + break; case PCI_DEVICE_ID_SKYHAWK: case PCI_DEVICE_ID_SKYHAWK_VF: oneConnect = 1; @@ -2253,7 +2260,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) phba->Port); else if (max_speed == 0) snprintf(descp, 255, - "Emulex %s %s %s ", + "Emulex %s %s %s", m.name, m.bus, m.function); else snprintf(descp, 255, @@ -3491,6 +3498,8 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) sizeof fc_host_symbolic_name(shost)); fc_host_supported_speeds(shost) = 0; + if (phba->lmt & LMT_32Gb) + fc_host_supported_speeds(shost) |= FC_PORTSPEED_32GBIT; if (phba->lmt & LMT_16Gb) fc_host_supported_speeds(shost) |= FC_PORTSPEED_16GBIT; if (phba->lmt & LMT_10Gb) @@ -3854,6 +3863,9 @@ lpfc_sli4_port_speed_parse(struct lpfc_hba *phba, uint32_t evt_code, case LPFC_FC_LA_SPEED_16G: port_speed = 16000; break; + case LPFC_FC_LA_SPEED_32G: + port_speed = 32000; + break; default: port_speed = 0; } @@ -4982,8 +4994,7 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) } if (!phba->sli.ring) - phba->sli.ring = (struct lpfc_sli_ring *) - kzalloc(LPFC_SLI3_MAX_RING * + phba->sli.ring = kzalloc(LPFC_SLI3_MAX_RING * sizeof(struct lpfc_sli_ring), GFP_KERNEL); if (!phba->sli.ring) return -ENOMEM; @@ -4995,7 +5006,7 @@ lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) /* Initialize the host templates the configured values. */ lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt; - lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt; + lpfc_template_s3.sg_tablesize = phba->cfg_sg_seg_cnt; /* There are going to be 2 reserved BDEs: 1 FCP cmnd + 1 FCP rsp */ if (phba->cfg_enable_bg) { @@ -8679,7 +8690,6 @@ lpfc_sli4_set_affinity(struct lpfc_hba *phba, int vectors) #ifdef CONFIG_X86 struct cpuinfo_x86 *cpuinfo; #endif - struct cpumask *mask; uint8_t chann[LPFC_FCP_IO_CHAN_MAX+1]; /* If there is no mapping, just return */ @@ -8773,11 +8783,8 @@ found: first_cpu = cpu; /* Now affinitize to the selected CPU */ - mask = &cpup->maskbits; - cpumask_clear(mask); - cpumask_set_cpu(cpu, mask); i = irq_set_affinity_hint(phba->sli4_hba.msix_entries[idx]. - vector, mask); + vector, get_cpu_mask(cpu)); lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3330 Set Affinity: CPU %d channel %d " @@ -10287,7 +10294,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) struct lpfc_hba *phba; struct lpfc_vport *vport = NULL; struct Scsi_Host *shost = NULL; - int error, ret; + int error; uint32_t cfg_mode, intr_mode; int adjusted_fcp_io_channel; @@ -10411,7 +10418,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* check for firmware upgrade or downgrade */ if (phba->cfg_request_firmware_upgrade) - ret = lpfc_sli4_request_firmware_update(phba, INT_FW_UPGRADE); + lpfc_sli4_request_firmware_update(phba, INT_FW_UPGRADE); /* Check if there are static vports to be created. */ lpfc_create_static_vport(phba); @@ -11354,6 +11361,8 @@ static struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE_VF, PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_G6_FC, + PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK, PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SKYHAWK_VF, @@ -11477,6 +11486,7 @@ lpfc_exit(void) free_pages((unsigned long)_dump_buf_dif, _dump_buf_dif_order); } kfree(lpfc_used_cpu); + idr_destroy(&lpfc_hba_index); } module_init(lpfc_init); diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 4abb93a83..f87f90e9b 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -289,9 +289,7 @@ lpfc_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, struct lpfc_dmabuf *mp) { MAILBOX_t *mb; - struct lpfc_sli *psli; - psli = &phba->sli; mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); @@ -483,13 +481,11 @@ lpfc_init_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint32_t topology, uint32_t linkspeed) { lpfc_vpd_t *vpd; - struct lpfc_sli *psli; MAILBOX_t *mb; mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - psli = &phba->sli; switch (topology) { case FLAGS_TOPOLOGY_MODE_LOOP_PT: mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP; @@ -510,6 +506,13 @@ lpfc_init_link(struct lpfc_hba * phba, break; } + if (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC && + mb->un.varInitLnk.link_flags & FLAGS_TOPOLOGY_MODE_LOOP) { + /* Failover is not tried for Lancer G6 */ + mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT; + phba->cfg_topology = FLAGS_TOPOLOGY_MODE_PT_PT; + } + /* Enable asynchronous ABTS responses from firmware */ mb->un.varInitLnk.link_flags |= FLAGS_IMED_ABORT; @@ -543,6 +546,10 @@ lpfc_init_link(struct lpfc_hba * phba, mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; mb->un.varInitLnk.link_speed = LINK_SPEED_16G; break; + case LPFC_USER_LINK_SPEED_32G: + mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; + mb->un.varInitLnk.link_speed = LINK_SPEED_32G; + break; case LPFC_USER_LINK_SPEED_AUTO: default: mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO; @@ -585,9 +592,7 @@ lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi) { struct lpfc_dmabuf *mp; MAILBOX_t *mb; - struct lpfc_sli *psli; - psli = &phba->sli; mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); @@ -2010,7 +2015,6 @@ lpfc_sli4_mbx_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index) { void *virt_addr; - dma_addr_t phys_addr; uint8_t *bytep; struct lpfc_mbx_sge sge; uint32_t alloc_len, req_len; @@ -2039,7 +2043,6 @@ lpfc_sli4_mbx_read_fcf_rec(struct lpfc_hba *phba, * routine only uses a single SGE. */ lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); - phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); virt_addr = mboxq->sge_array->addr[0]; read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr; diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index af3b38aba..ed9a2c80c 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -820,7 +820,6 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, { struct lpfc_hba *phba; LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; - MAILBOX_t *mb; uint16_t rpi; phba = vport->phba; @@ -828,7 +827,6 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (!(phba->pport->load_flag & FC_UNLOADING) && (evt == NLP_EVT_CMPL_REG_LOGIN) && (!pmb->u.mb.mbxStatus)) { - mb = &pmb->u.mb; rpi = pmb->u.mb.un.varWords[0]; lpfc_release_rpi(phba, vport, rpi); } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index e5eb40d2c..4679ed444 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1293,7 +1293,6 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint32_t *reftag, uint16_t *apptag, uint32_t new_guard) { struct scatterlist *sgpe; /* s/g prot entry */ - struct scatterlist *sgde; /* s/g data entry */ struct lpfc_scsi_buf *lpfc_cmd = NULL; struct scsi_dif_tuple *src = NULL; struct lpfc_nodelist *ndlp; @@ -1309,7 +1308,6 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, return 0; sgpe = scsi_prot_sglist(sc); - sgde = scsi_sglist(sc); lba = scsi_get_lba(sc); /* First check if we need to match the LBA */ @@ -1882,7 +1880,6 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, #endif uint32_t checking = 1; uint32_t reftag; - unsigned blksize; uint8_t txop, rxop; status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop); @@ -1890,7 +1887,6 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, goto out; /* extract some info from the scsi command for pde*/ - blksize = lpfc_cmd_blksize(sc); reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */ #ifdef CONFIG_SCSI_LPFC_DEBUG_FS @@ -2263,7 +2259,6 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, dma_addr_t physaddr; int i = 0, num_sge = 0, status; uint32_t reftag; - unsigned blksize; uint8_t txop, rxop; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS uint32_t rc; @@ -2277,7 +2272,6 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, goto out; /* extract some info from the scsi command for pde*/ - blksize = lpfc_cmd_blksize(sc); reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */ #ifdef CONFIG_SCSI_LPFC_DEBUG_FS @@ -2881,7 +2875,7 @@ lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) struct scsi_cmnd *cmd = lpfc_cmd->pCmd; struct scsi_dif_tuple *src = NULL; uint8_t *data_src = NULL; - uint16_t guard_tag, guard_type; + uint16_t guard_tag; uint16_t start_app_tag, app_tag; uint32_t start_ref_tag, ref_tag; int prot, protsegcnt; @@ -2922,7 +2916,6 @@ lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) data_len = sgde->length; if ((data_len & (blksize - 1)) == 0) chk_guard = 1; - guard_type = scsi_host_get_guard(cmd->device->host); src = (struct scsi_dif_tuple *)sg_virt(sgpe); start_ref_tag = (uint32_t)scsi_get_lba(cmd); /* Truncate LBA */ @@ -3908,12 +3901,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, struct lpfc_rport_data *rdata = lpfc_cmd->rdata; struct lpfc_nodelist *pnode = rdata->pnode; struct scsi_cmnd *cmd; - int result; int depth; unsigned long flags; struct lpfc_fast_path_event *fast_path_evt; struct Scsi_Host *shost; - uint32_t queue_depth, scsi_id; uint32_t logit = LOG_FCP; /* Sanity check on return of outstanding command */ @@ -4095,7 +4086,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } lpfc_update_stats(phba, lpfc_cmd); - result = cmd->result; if (vport->cfg_max_scsicmpl_time && time_after(jiffies, lpfc_cmd->start_time + msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { @@ -4132,8 +4122,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); /* The sdev is not guaranteed to be valid post scsi_done upcall. */ - queue_depth = cmd->device->queue_depth; - scsi_id = cmd->device->id; cmd->scsi_done(cmd); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { @@ -5926,7 +5914,6 @@ struct scsi_host_template lpfc_template_s3 = { .max_sectors = 0xFFFF, .vendor_id = LPFC_NL_VENDOR_ID, .change_queue_depth = scsi_change_queue_depth, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -5952,7 +5939,6 @@ struct scsi_host_template lpfc_template = { .max_sectors = 0xFFFF, .vendor_id = LPFC_NL_VENDOR_ID, .change_queue_depth = scsi_change_queue_depth, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -5976,6 +5962,5 @@ struct scsi_host_template lpfc_vport_template = { .shost_attrs = lpfc_vport_attrs, .max_sectors = 0xFFFF, .change_queue_depth = scsi_change_queue_depth, - .use_blk_tags = 1, .track_queue_depth = 1, }; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 4feb9312a..f9585cdd8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -6696,7 +6696,7 @@ lpfc_mbox_timeout(unsigned long ptr) * This function checks if any mailbox completions are present on the mailbox * completion queue. **/ -bool +static bool lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba) { @@ -12491,12 +12491,10 @@ lpfc_sli4_fof_intr_handler(int irq, void *dev_id) struct lpfc_eqe *eqe; unsigned long iflag; int ecount = 0; - uint32_t eqidx; /* Get the driver's phba structure from the dev_id */ fcp_eq_hdl = (struct lpfc_fcp_eq_hdl *)dev_id; phba = fcp_eq_hdl->phba; - eqidx = fcp_eq_hdl->idx; if (unlikely(!phba)) return IRQ_NONE; @@ -12831,12 +12829,8 @@ out_fail: static void __iomem * lpfc_dual_chute_pci_bar_map(struct lpfc_hba *phba, uint16_t pci_barset) { - struct pci_dev *pdev; - if (!phba->pcidev) return NULL; - else - pdev = phba->pcidev; switch (pci_barset) { case WQ_PCI_BAR_0_AND_1: @@ -15920,7 +15914,6 @@ lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record) LPFC_MBOXQ_t *mboxq; uint8_t *bytep; void *virt_addr; - dma_addr_t phys_addr; struct lpfc_mbx_sge sge; uint32_t alloc_len, req_len; uint32_t fcfindex; @@ -15953,7 +15946,6 @@ lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record) * routine only uses a single SGE. */ lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); - phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); virt_addr = mboxq->sge_array->addr[0]; /* * Configure the FCF record for FCFI 0. This is the driver's diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index d1a5b057c..1e916e16c 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -454,7 +454,6 @@ struct lpfc_vector_map_info { uint16_t core_id; uint16_t irq; uint16_t channel_id; - struct cpumask maskbits; }; #define LPFC_VECTOR_MAP_EMPTY 0xffff diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 6258d3d77..ea53aa664 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "10.7.0.0." +#define LPFC_DRIVER_VERSION "11.0.0.0." #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 20c375419..c0f7c8ce5 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -35,8 +35,8 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "06.807.10.00-rc1" -#define MEGASAS_RELDATE "March 6, 2015" +#define MEGASAS_VERSION "06.808.16.00-rc1" +#define MEGASAS_RELDATE "Oct. 8, 2015" /* * Device IDs @@ -52,6 +52,10 @@ #define PCI_DEVICE_ID_LSI_PLASMA 0x002f #define PCI_DEVICE_ID_LSI_INVADER 0x005d #define PCI_DEVICE_ID_LSI_FURY 0x005f +#define PCI_DEVICE_ID_LSI_INTRUDER 0x00ce +#define PCI_DEVICE_ID_LSI_INTRUDER_24 0x00cf +#define PCI_DEVICE_ID_LSI_CUTLASS_52 0x0052 +#define PCI_DEVICE_ID_LSI_CUTLASS_53 0x0053 /* * Intel HBA SSDIDs @@ -62,6 +66,14 @@ #define MEGARAID_INTEL_RS3MC044_SSDID 0x9381 #define MEGARAID_INTEL_RS3WC080_SSDID 0x9341 #define MEGARAID_INTEL_RS3WC040_SSDID 0x9343 +#define MEGARAID_INTEL_RMS3BC160_SSDID 0x352B + +/* + * Intruder HBA SSDIDs + */ +#define MEGARAID_INTRUDER_SSDID1 0x9371 +#define MEGARAID_INTRUDER_SSDID2 0x9390 +#define MEGARAID_INTRUDER_SSDID3 0x9370 /* * Intel HBA branding @@ -78,6 +90,8 @@ "Intel(R) RAID Controller RS3WC080" #define MEGARAID_INTEL_RS3WC040_BRANDING \ "Intel(R) RAID Controller RS3WC040" +#define MEGARAID_INTEL_RMS3BC160_BRANDING \ + "Intel(R) Integrated RAID Module RMS3BC160" /* * ===================================== @@ -273,6 +287,16 @@ enum MFI_STAT { MFI_STAT_INVALID_STATUS = 0xFF }; +enum mfi_evt_class { + MFI_EVT_CLASS_DEBUG = -2, + MFI_EVT_CLASS_PROGRESS = -1, + MFI_EVT_CLASS_INFO = 0, + MFI_EVT_CLASS_WARNING = 1, + MFI_EVT_CLASS_CRITICAL = 2, + MFI_EVT_CLASS_FATAL = 3, + MFI_EVT_CLASS_DEAD = 4 +}; + /* * Crash dump related defines */ @@ -364,6 +388,8 @@ enum MR_EVT_ARGS { MR_EVT_ARGS_GENERIC, }; + +#define SGE_BUFFER_SIZE 4096 /* * define constants for device list query options */ @@ -394,6 +420,7 @@ enum MR_LD_QUERY_TYPE { #define MR_EVT_FOREIGN_CFG_IMPORTED 0x00db #define MR_EVT_LD_OFFLINE 0x00fc #define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152 +#define MR_EVT_CTRL_PROP_CHANGED 0x012f enum MR_PD_STATE { MR_PD_STATE_UNCONFIGURED_GOOD = 0x00, @@ -973,7 +1000,12 @@ struct megasas_ctrl_info { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved:12; + u32 reserved:7; + u32 useSeqNumJbodFP:1; + u32 supportExtendedSSCSize:1; + u32 supportDiskCacheSettingForSysPDs:1; + u32 supportCPLDUpdate:1; + u32 supportTTYLogCompression:1; u32 discardCacheDuringLDDelete:1; u32 supportSecurityonJBOD:1; u32 supportCacheBypassModes:1; @@ -1013,7 +1045,12 @@ struct megasas_ctrl_info { u32 supportCacheBypassModes:1; u32 supportSecurityonJBOD:1; u32 discardCacheDuringLDDelete:1; - u32 reserved:12; + u32 supportTTYLogCompression:1; + u32 supportCPLDUpdate:1; + u32 supportDiskCacheSettingForSysPDs:1; + u32 supportExtendedSSCSize:1; + u32 useSeqNumJbodFP:1; + u32 reserved:7; #endif } adapterOperations3; @@ -1229,7 +1266,9 @@ union megasas_sgl_frame { typedef union _MFI_CAPABILITIES { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved:25; + u32 reserved:23; + u32 support_ext_io_size:1; + u32 support_ext_queue_depth:1; u32 security_protocol_cmds_fw:1; u32 support_core_affinity:1; u32 support_ndrive_r1_lb:1; @@ -1245,7 +1284,9 @@ typedef union _MFI_CAPABILITIES { u32 support_ndrive_r1_lb:1; u32 support_core_affinity:1; u32 security_protocol_cmds_fw:1; - u32 reserved:25; + u32 support_ext_queue_depth:1; + u32 support_ext_io_size:1; + u32 reserved:23; #endif } mfi_capabilities; __le32 reg; @@ -1690,6 +1731,7 @@ struct megasas_instance { u32 crash_dump_drv_support; u32 crash_dump_app_support; u32 secure_jbod_support; + bool use_seqnum_jbod_fp; /* Added for PD sequence */ spinlock_t crashdump_lock; struct megasas_register_set __iomem *reg_set; @@ -1748,6 +1790,7 @@ struct megasas_instance { u8 UnevenSpanSupport; u8 supportmax256vd; + u8 allow_fw_scan; u16 fw_supported_vd_count; u16 fw_supported_pd_count; @@ -1769,7 +1812,9 @@ struct megasas_instance { struct msix_entry msixentry[MEGASAS_MAX_MSIX_QUEUES]; struct megasas_irq_context irq_context[MEGASAS_MAX_MSIX_QUEUES]; u64 map_id; + u64 pd_seq_map_id; struct megasas_cmd *map_update_cmd; + struct megasas_cmd *jbod_seq_cmd; unsigned long bar; long reset_flags; struct mutex reset_mutex; @@ -1780,6 +1825,7 @@ struct megasas_instance { char mpio; u16 throttlequeuedepth; u8 mask_interrupts; + u16 max_chain_frame_sz; u8 is_imr; bool dev_handle; }; @@ -1985,6 +2031,9 @@ __le16 get_updated_dev_handle(struct megasas_instance *instance, void mr_update_load_balance_params(struct MR_DRV_RAID_MAP_ALL *map, struct LD_LOAD_BALANCE_INFO *lbInfo); int megasas_get_ctrl_info(struct megasas_instance *instance); +/* PD sequence */ +int +megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend); int megasas_set_crash_dump_params(struct megasas_instance *instance, u8 crash_buf_state); void megasas_free_host_crash_buffer(struct megasas_instance *instance); @@ -2000,5 +2049,6 @@ void __megasas_return_cmd(struct megasas_instance *instance, void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance, struct megasas_cmd *cmd_mfi, struct megasas_cmd_fusion *cmd_fusion); int megasas_cmd_type(struct scsi_cmnd *cmd); +void megasas_setup_jbod_map(struct megasas_instance *instance); #endif /*LSI_MEGARAID_SAS_H */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index eaa81e552..97a1c1c33 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -135,6 +135,12 @@ static struct pci_device_id megasas_pci_table[] = { /* Invader */ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FURY)}, /* Fury */ + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER)}, + /* Intruder */ + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER_24)}, + /* Intruder 24 port*/ + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_52)}, + {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_53)}, {} }; @@ -260,6 +266,66 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) } +static const char * +format_timestamp(uint32_t timestamp) +{ + static char buffer[32]; + + if ((timestamp & 0xff000000) == 0xff000000) + snprintf(buffer, sizeof(buffer), "boot + %us", timestamp & + 0x00ffffff); + else + snprintf(buffer, sizeof(buffer), "%us", timestamp); + return buffer; +} + +static const char * +format_class(int8_t class) +{ + static char buffer[6]; + + switch (class) { + case MFI_EVT_CLASS_DEBUG: + return "debug"; + case MFI_EVT_CLASS_PROGRESS: + return "progress"; + case MFI_EVT_CLASS_INFO: + return "info"; + case MFI_EVT_CLASS_WARNING: + return "WARN"; + case MFI_EVT_CLASS_CRITICAL: + return "CRIT"; + case MFI_EVT_CLASS_FATAL: + return "FATAL"; + case MFI_EVT_CLASS_DEAD: + return "DEAD"; + default: + snprintf(buffer, sizeof(buffer), "%d", class); + return buffer; + } +} + +/** + * megasas_decode_evt: Decode FW AEN event and print critical event + * for information. + * @instance: Adapter soft state + */ +static void +megasas_decode_evt(struct megasas_instance *instance) +{ + struct megasas_evt_detail *evt_detail = instance->evt_detail; + union megasas_evt_class_locale class_locale; + class_locale.word = le32_to_cpu(evt_detail->cl.word); + + if (class_locale.members.class >= MFI_EVT_CLASS_CRITICAL) + dev_info(&instance->pdev->dev, "%d (%s/0x%04x/%s) - %s\n", + le32_to_cpu(evt_detail->seq_num), + format_timestamp(le32_to_cpu(evt_detail->time_stamp)), + (class_locale.members.locale), + format_class(class_locale.members.class), + evt_detail->description); +} + /** * The following functions are defined for xscale * (deviceid : 1064R, PERC5) controllers @@ -1659,8 +1725,56 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no) return NULL; } +/* +* megasas_set_dma_alignment - Set DMA alignment for PI enabled VD +* +* @sdev: OS provided scsi device +* +* Returns void +*/ +static void megasas_set_dma_alignment(struct scsi_device *sdev) +{ + u32 device_id, ld; + struct megasas_instance *instance; + struct fusion_context *fusion; + struct MR_LD_RAID *raid; + struct MR_DRV_RAID_MAP_ALL *local_map_ptr; + + instance = megasas_lookup_instance(sdev->host->host_no); + fusion = instance->ctrl_context; + + if (!fusion) + return; + + if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) { + device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + + sdev->id; + local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; + ld = MR_TargetIdToLdGet(device_id, local_map_ptr); + raid = MR_LdRaidGet(ld, local_map_ptr); + + if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) + blk_queue_update_dma_alignment(sdev->request_queue, 0x7); + } +} + static int megasas_slave_configure(struct scsi_device *sdev) { + u16 pd_index = 0; + struct megasas_instance *instance; + + instance = megasas_lookup_instance(sdev->host->host_no); + if (instance->allow_fw_scan) { + if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && + sdev->type == TYPE_DISK) { + pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + + sdev->id; + if (instance->pd_list[pd_index].driveState != + MR_PD_STATE_SYSTEM) + return -ENXIO; + } + } + megasas_set_dma_alignment(sdev); /* * The RAID firmware may require extended timeouts. */ @@ -1683,8 +1797,8 @@ static int megasas_slave_alloc(struct scsi_device *sdev) pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id; - if (instance->pd_list[pd_index].driveState == - MR_PD_STATE_SYSTEM) { + if ((instance->allow_fw_scan || instance->pd_list[pd_index].driveState == + MR_PD_STATE_SYSTEM)) { return 0; } return -ENXIO; @@ -1736,10 +1850,7 @@ void megaraid_sas_kill_hba(struct megasas_instance *instance) msleep(1000); if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + (instance->ctrl_context)) { writel(MFI_STOP_ADP, &instance->reg_set->doorbell); /* Flush */ readl(&instance->reg_set->doorbell); @@ -2506,10 +2617,7 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd) /* * First wait for all commands to complete */ - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) + if (instance->ctrl_context) ret = megasas_reset_fusion(scmd->device->host, 1); else ret = megasas_generic_reset(scmd); @@ -2837,7 +2945,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, struct megasas_header *hdr = &cmd->frame->hdr; unsigned long flags; struct fusion_context *fusion = instance->ctrl_context; - u32 opcode; + u32 opcode, status; /* flag for the retry reset */ cmd->retry_for_fw_reset = 0; @@ -2945,6 +3053,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, && (cmd->frame->dcmd.mbox.b[1] == 1)) { fusion->fast_path_io = 0; spin_lock_irqsave(instance->host->host_lock, flags); + instance->map_update_cmd = NULL; if (cmd->frame->hdr.cmd_status != 0) { if (cmd->frame->hdr.cmd_status != MFI_STAT_NOT_FOUND) @@ -2982,6 +3091,27 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, spin_unlock_irqrestore(&poll_aen_lock, flags); } + /* FW has an updated PD sequence */ + if ((opcode == MR_DCMD_SYSTEM_PD_MAP_GET_INFO) && + (cmd->frame->dcmd.mbox.b[0] == 1)) { + + spin_lock_irqsave(instance->host->host_lock, flags); + status = cmd->frame->hdr.cmd_status; + instance->jbod_seq_cmd = NULL; + megasas_return_cmd(instance, cmd); + + if (status == MFI_STAT_OK) { + instance->pd_seq_map_id++; + /* Re-register a pd sync seq num cmd */ + if (megasas_sync_pd_seq_num(instance, true)) + instance->use_seqnum_jbod_fp = false; + } else + instance->use_seqnum_jbod_fp = false; + + spin_unlock_irqrestore(instance->host->host_lock, flags); + break; + } + /* * See if got an event notification */ @@ -3348,22 +3478,14 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) PCI_DEVICE_ID_LSI_SAS0073SKINNY) || (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FURY)) { + (instance->ctrl_context)) writel( MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, &instance->reg_set->doorbell); - } else { + else writel( MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, &instance->reg_set->inbound_doorbell); - } max_wait = MEGASAS_RESET_WAIT_TIME; cur_state = MFI_STATE_WAIT_HANDSHAKE; @@ -3374,17 +3496,10 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) PCI_DEVICE_ID_LSI_SAS0073SKINNY) || (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FURY)) { + (instance->ctrl_context)) writel(MFI_INIT_HOTPLUG, &instance->reg_set->doorbell); - } else + else writel(MFI_INIT_HOTPLUG, &instance->reg_set->inbound_doorbell); @@ -3401,24 +3516,11 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) PCI_DEVICE_ID_LSI_SAS0073SKINNY) || (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device - == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device - == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device - == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device - == PCI_DEVICE_ID_LSI_FURY)) { + (instance->ctrl_context)) { writel(MFI_RESET_FLAGS, &instance->reg_set->doorbell); - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FURY)) { + + if (instance->ctrl_context) { for (i = 0; i < (10 * 1000); i += 20) { if (readl( &instance-> @@ -3639,11 +3741,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) memset(cmd->frame, 0, total_sz); cmd->frame->io.context = cpu_to_le32(cmd->index); cmd->frame->io.pad_0 = 0; - if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) && - (instance->pdev->device != PCI_DEVICE_ID_LSI_PLASMA) && - (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) && - (instance->pdev->device != PCI_DEVICE_ID_LSI_FURY) && - (reset_devices)) + if (!instance->ctrl_context && reset_devices) cmd->frame->hdr.cmd = MFI_CMD_INVALID; } @@ -4136,11 +4234,21 @@ megasas_get_ctrl_info(struct megasas_instance *instance) le32_to_cpus((u32 *)&ctrl_info->adapterOperations2); le32_to_cpus((u32 *)&ctrl_info->adapterOperations3); megasas_update_ext_vd_details(instance); + instance->use_seqnum_jbod_fp = + ctrl_info->adapterOperations3.useSeqNumJbodFP; instance->is_imr = (ctrl_info->memory_size ? 0 : 1); dev_info(&instance->pdev->dev, "controller type\t: %s(%dMB)\n", instance->is_imr ? "iMR" : "MR", le16_to_cpu(ctrl_info->memory_size)); + instance->disableOnlineCtrlReset = + ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset; + dev_info(&instance->pdev->dev, "Online Controller Reset(OCR)\t: %s\n", + instance->disableOnlineCtrlReset ? "Disabled" : "Enabled"); + instance->secure_jbod_support = + ctrl_info->adapterOperations3.supportSecurityonJBOD; + dev_info(&instance->pdev->dev, "Secure JBOD support\t: %s\n", + instance->secure_jbod_support ? "Yes" : "No"); } pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info), @@ -4480,6 +4588,62 @@ megasas_destroy_irqs(struct megasas_instance *instance) { free_irq(instance->pdev->irq, &instance->irq_context[0]); } +/** + * megasas_setup_jbod_map - setup jbod map for FP seq_number. + * @instance: Adapter soft state + * @is_probe: Driver probe check + * + * Return 0 on success. + */ +void +megasas_setup_jbod_map(struct megasas_instance *instance) +{ + int i; + struct fusion_context *fusion = instance->ctrl_context; + u32 pd_seq_map_sz; + + pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + + (sizeof(struct MR_PD_CFG_SEQ) * (MAX_PHYSICAL_DEVICES - 1)); + + if (reset_devices || !fusion || + !instance->ctrl_info->adapterOperations3.useSeqNumJbodFP) { + dev_info(&instance->pdev->dev, + "Jbod map is not supported %s %d\n", + __func__, __LINE__); + instance->use_seqnum_jbod_fp = false; + return; + } + + if (fusion->pd_seq_sync[0]) + goto skip_alloc; + + for (i = 0; i < JBOD_MAPS_COUNT; i++) { + fusion->pd_seq_sync[i] = dma_alloc_coherent + (&instance->pdev->dev, pd_seq_map_sz, + &fusion->pd_seq_phys[i], GFP_KERNEL); + if (!fusion->pd_seq_sync[i]) { + dev_err(&instance->pdev->dev, + "Failed to allocate memory from %s %d\n", + __func__, __LINE__); + if (i == 1) { + dma_free_coherent(&instance->pdev->dev, + pd_seq_map_sz, fusion->pd_seq_sync[0], + fusion->pd_seq_phys[0]); + fusion->pd_seq_sync[0] = NULL; + } + instance->use_seqnum_jbod_fp = false; + return; + } + } + +skip_alloc: + if (!megasas_sync_pd_seq_num(instance, false) && + !megasas_sync_pd_seq_num(instance, true)) + instance->use_seqnum_jbod_fp = true; + else + instance->use_seqnum_jbod_fp = false; +} + /** * megasas_init_fw - Initializes the FW * @instance: Adapter soft state @@ -4498,6 +4662,9 @@ static int megasas_init_fw(struct megasas_instance *instance) unsigned long bar_list; int i, loop, fw_msix_count = 0; struct IOV_111 *iovPtr; + struct fusion_context *fusion; + + fusion = instance->ctrl_context; /* Find first memory bar */ bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM); @@ -4523,6 +4690,10 @@ static int megasas_init_fw(struct megasas_instance *instance) case PCI_DEVICE_ID_LSI_PLASMA: case PCI_DEVICE_ID_LSI_INVADER: case PCI_DEVICE_ID_LSI_FURY: + case PCI_DEVICE_ID_LSI_INTRUDER: + case PCI_DEVICE_ID_LSI_INTRUDER_24: + case PCI_DEVICE_ID_LSI_CUTLASS_52: + case PCI_DEVICE_ID_LSI_CUTLASS_53: instance->instancet = &megasas_instance_template_fusion; break; case PCI_DEVICE_ID_LSI_SAS1078R: @@ -4541,6 +4712,7 @@ static int megasas_init_fw(struct megasas_instance *instance) case PCI_DEVICE_ID_DELL_PERC5: default: instance->instancet = &megasas_instance_template_xscale; + instance->allow_fw_scan = 1; break; } @@ -4575,37 +4747,32 @@ static int megasas_init_fw(struct megasas_instance *instance) scratch_pad_2 = readl (&instance->reg_set->outbound_scratch_pad_2); /* Check max MSI-X vectors */ - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA)) { - instance->msix_vectors = (scratch_pad_2 - & MR_MAX_REPLY_QUEUES_OFFSET) + 1; - fw_msix_count = instance->msix_vectors; - if (msix_vectors) - instance->msix_vectors = - min(msix_vectors, - instance->msix_vectors); - } else if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) - || (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { - /* Invader/Fury supports more than 8 MSI-X */ - instance->msix_vectors = ((scratch_pad_2 - & MR_MAX_REPLY_QUEUES_EXT_OFFSET) - >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1; - fw_msix_count = instance->msix_vectors; - /* Save 1-15 reply post index address to local memory - * Index 0 is already saved from reg offset - * MPI2_REPLY_POST_HOST_INDEX_OFFSET - */ - for (loop = 1; loop < MR_MAX_MSIX_REG_ARRAY; loop++) { - instance->reply_post_host_index_addr[loop] = - (u32 __iomem *) - ((u8 __iomem *)instance->reg_set + - MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET - + (loop * 0x10)); + if (fusion) { + if (fusion->adapter_type == THUNDERBOLT_SERIES) { /* Thunderbolt Series*/ + instance->msix_vectors = (scratch_pad_2 + & MR_MAX_REPLY_QUEUES_OFFSET) + 1; + fw_msix_count = instance->msix_vectors; + } else { /* Invader series supports more than 8 MSI-x vectors*/ + instance->msix_vectors = ((scratch_pad_2 + & MR_MAX_REPLY_QUEUES_EXT_OFFSET) + >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1; + fw_msix_count = instance->msix_vectors; + /* Save 1-15 reply post index address to local memory + * Index 0 is already saved from reg offset + * MPI2_REPLY_POST_HOST_INDEX_OFFSET + */ + for (loop = 1; loop < MR_MAX_MSIX_REG_ARRAY; loop++) { + instance->reply_post_host_index_addr[loop] = + (u32 __iomem *) + ((u8 __iomem *)instance->reg_set + + MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET + + (loop * 0x10)); + } } if (msix_vectors) instance->msix_vectors = min(msix_vectors, instance->msix_vectors); - } else + } else /* MFI adapters */ instance->msix_vectors = 1; /* Don't bother allocating more MSI-X vectors than cpus */ instance->msix_vectors = min(instance->msix_vectors, @@ -4626,6 +4793,9 @@ static int megasas_init_fw(struct megasas_instance *instance) "current msix/online cpus\t: (%d/%d)\n", instance->msix_vectors, (unsigned int)num_online_cpus()); + tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, + (unsigned long)instance); + if (instance->msix_vectors ? megasas_setup_irqs_msix(instance, 1) : megasas_setup_irqs_ioapic(instance)) @@ -4646,13 +4816,13 @@ static int megasas_init_fw(struct megasas_instance *instance) if (instance->instancet->init_adapter(instance)) goto fail_init_adapter; - tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, - (unsigned long)instance); instance->instancet->enable_intr(instance); dev_err(&instance->pdev->dev, "INIT adapter done\n"); + megasas_setup_jbod_map(instance); + /** for passthrough * the following function will get the PD LIST. */ @@ -4686,8 +4856,6 @@ static int megasas_init_fw(struct megasas_instance *instance) tmp_sectors = min_t(u32, max_sectors_1, max_sectors_2); - instance->disableOnlineCtrlReset = - ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset; instance->mpio = ctrl_info->adapterOperations2.mpio; instance->UnevenSpanSupport = ctrl_info->adapterOperations2.supportUnevenSpans; @@ -4700,18 +4868,22 @@ static int megasas_init_fw(struct megasas_instance *instance) } if (ctrl_info->host_interface.SRIOV) { - if (!ctrl_info->adapterOperations2.activePassive) - instance->PlasmaFW111 = 1; - - if (!instance->PlasmaFW111) - instance->requestorId = - ctrl_info->iov.requestorId; - else { - iovPtr = (struct IOV_111 *)((unsigned char *)ctrl_info + IOV_111_OFFSET); - instance->requestorId = iovPtr->requestorId; + instance->requestorId = ctrl_info->iov.requestorId; + if (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) { + if (!ctrl_info->adapterOperations2.activePassive) + instance->PlasmaFW111 = 1; + + dev_info(&instance->pdev->dev, "SR-IOV: firmware type: %s\n", + instance->PlasmaFW111 ? "1.11" : "new"); + + if (instance->PlasmaFW111) { + iovPtr = (struct IOV_111 *) + ((unsigned char *)ctrl_info + IOV_111_OFFSET); + instance->requestorId = iovPtr->requestorId; + } } - dev_warn(&instance->pdev->dev, "I am VF " - "requestorId %d\n", instance->requestorId); + dev_info(&instance->pdev->dev, "SRIOV: VF requestorId %d\n", + instance->requestorId); } instance->crash_dump_fw_support = @@ -4732,8 +4904,6 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->crash_dump_buf = NULL; } - instance->secure_jbod_support = - ctrl_info->adapterOperations3.supportSecurityonJBOD; dev_info(&instance->pdev->dev, "pci id\t\t: (0x%04x)/(0x%04x)/(0x%04x)/(0x%04x)\n", @@ -4743,16 +4913,14 @@ static int megasas_init_fw(struct megasas_instance *instance) le16_to_cpu(ctrl_info->pci.sub_device_id)); dev_info(&instance->pdev->dev, "unevenspan support : %s\n", instance->UnevenSpanSupport ? "yes" : "no"); - dev_info(&instance->pdev->dev, "disable ocr : %s\n", - instance->disableOnlineCtrlReset ? "yes" : "no"); dev_info(&instance->pdev->dev, "firmware crash dump : %s\n", instance->crash_dump_drv_support ? "yes" : "no"); - dev_info(&instance->pdev->dev, "secure jbod : %s\n", - instance->secure_jbod_support ? "yes" : "no"); + dev_info(&instance->pdev->dev, "jbod sync map : %s\n", + instance->use_seqnum_jbod_fp ? "yes" : "no"); instance->max_sectors_per_req = instance->max_num_sge * - PAGE_SIZE / 512; + SGE_BUFFER_SIZE / 512; if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors)) instance->max_sectors_per_req = tmp_sectors; @@ -5049,7 +5217,6 @@ static int megasas_start_aen(struct megasas_instance *instance) static int megasas_io_attach(struct megasas_instance *instance) { struct Scsi_Host *host = instance->host; - u32 error; /* * Export parameters required by SCSI mid-layer @@ -5092,20 +5259,10 @@ static int megasas_io_attach(struct megasas_instance *instance) host->max_cmd_len = 16; /* Fusion only supports host reset */ - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (instance->ctrl_context) { host->hostt->eh_device_reset_handler = NULL; host->hostt->eh_bus_reset_handler = NULL; } - error = scsi_init_shared_tag_map(host, host->can_queue); - if (error) { - dev_err(&instance->pdev->dev, - "Failed to shared tag from %s %d\n", - __func__, __LINE__); - return -ENODEV; - } /* * Notify the mid-layer about the new controller @@ -5218,6 +5375,10 @@ static int megasas_probe_one(struct pci_dev *pdev, case PCI_DEVICE_ID_LSI_PLASMA: case PCI_DEVICE_ID_LSI_INVADER: case PCI_DEVICE_ID_LSI_FURY: + case PCI_DEVICE_ID_LSI_INTRUDER: + case PCI_DEVICE_ID_LSI_INTRUDER_24: + case PCI_DEVICE_ID_LSI_CUTLASS_52: + case PCI_DEVICE_ID_LSI_CUTLASS_53: { instance->ctrl_context_pages = get_order(sizeof(struct fusion_context)); @@ -5231,6 +5392,11 @@ static int megasas_probe_one(struct pci_dev *pdev, fusion = instance->ctrl_context; memset(fusion, 0, ((1 << PAGE_SHIFT) << instance->ctrl_context_pages)); + if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || + (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA)) + fusion->adapter_type = THUNDERBOLT_SERIES; + else + fusion->adapter_type = INVADER_SERIES; } break; default: /* For all other supported controllers */ @@ -5333,10 +5499,7 @@ static int megasas_probe_one(struct pci_dev *pdev, instance->disableOnlineCtrlReset = 1; instance->UnevenSpanSupport = 0; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (instance->ctrl_context) { INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq); INIT_WORK(&instance->crash_init, megasas_fusion_crash_dump_wq); } else @@ -5416,10 +5579,7 @@ fail_io_attach: instance->instancet->disable_intr(instance); megasas_destroy_irqs(instance); - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) + if (instance->ctrl_context) megasas_release_fusion(instance); else megasas_release_mfi(instance); @@ -5506,10 +5666,14 @@ static void megasas_shutdown_controller(struct megasas_instance *instance, if (instance->aen_cmd) megasas_issue_blocked_abort_cmd(instance, - instance->aen_cmd, 30); + instance->aen_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT); if (instance->map_update_cmd) megasas_issue_blocked_abort_cmd(instance, - instance->map_update_cmd, 30); + instance->map_update_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT); + if (instance->jbod_seq_cmd) + megasas_issue_blocked_abort_cmd(instance, + instance->jbod_seq_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT); + dcmd = &cmd->frame->dcmd; memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); @@ -5628,12 +5792,7 @@ megasas_resume(struct pci_dev *pdev) instance->msix_vectors)) goto fail_reenable_msix; - switch (instance->pdev->device) { - case PCI_DEVICE_ID_LSI_FUSION: - case PCI_DEVICE_ID_LSI_PLASMA: - case PCI_DEVICE_ID_LSI_INVADER: - case PCI_DEVICE_ID_LSI_FURY: - { + if (instance->ctrl_context) { megasas_reset_reply_desc(instance); if (megasas_ioc_init_fusion(instance)) { megasas_free_cmds(instance); @@ -5642,14 +5801,11 @@ megasas_resume(struct pci_dev *pdev) } if (!megasas_get_map_info(instance)) megasas_sync_map_info(instance); - } - break; - default: + } else { *instance->producer = 0; *instance->consumer = 0; if (megasas_issue_init_mfi(instance)) goto fail_init_mfi; - break; } tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, @@ -5674,6 +5830,7 @@ megasas_resume(struct pci_dev *pdev) } instance->instancet->enable_intr(instance); + megasas_setup_jbod_map(instance); instance->unload = 0; /* @@ -5721,6 +5878,7 @@ static void megasas_detach_one(struct pci_dev *pdev) struct Scsi_Host *host; struct megasas_instance *instance; struct fusion_context *fusion; + u32 pd_seq_map_sz; instance = pci_get_drvdata(pdev); instance->unload = 1; @@ -5769,12 +5927,11 @@ static void megasas_detach_one(struct pci_dev *pdev) if (instance->msix_vectors) pci_disable_msix(instance->pdev); - switch (instance->pdev->device) { - case PCI_DEVICE_ID_LSI_FUSION: - case PCI_DEVICE_ID_LSI_PLASMA: - case PCI_DEVICE_ID_LSI_INVADER: - case PCI_DEVICE_ID_LSI_FURY: + if (instance->ctrl_context) { megasas_release_fusion(instance); + pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + + (sizeof(struct MR_PD_CFG_SEQ) * + (MAX_PHYSICAL_DEVICES - 1)); for (i = 0; i < 2 ; i++) { if (fusion->ld_map[i]) dma_free_coherent(&instance->pdev->dev, @@ -5784,11 +5941,15 @@ static void megasas_detach_one(struct pci_dev *pdev) if (fusion->ld_drv_map[i]) free_pages((ulong)fusion->ld_drv_map[i], fusion->drv_map_pages); + if (fusion->pd_seq_sync) + dma_free_coherent(&instance->pdev->dev, + pd_seq_map_sz, + fusion->pd_seq_sync[i], + fusion->pd_seq_phys[i]); } free_pages((ulong)instance->ctrl_context, instance->ctrl_context_pages); - break; - default: + } else { megasas_release_mfi(instance); pci_free_consistent(pdev, sizeof(u32), instance->producer, @@ -5796,7 +5957,6 @@ static void megasas_detach_one(struct pci_dev *pdev) pci_free_consistent(pdev, sizeof(u32), instance->consumer, instance->consumer_h); - break; } kfree(instance->ctrl_info); @@ -6316,6 +6476,9 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) int i; int error = 0; compat_uptr_t ptr; + unsigned long local_raw_ptr; + u32 local_sense_off; + u32 local_sense_len; if (clear_user(ioc, sizeof(*ioc))) return -EFAULT; @@ -6333,9 +6496,15 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) * sense_len is not null, so prepare the 64bit value under * the same condition. */ - if (ioc->sense_len) { + if (get_user(local_raw_ptr, ioc->frame.raw) || + get_user(local_sense_off, &ioc->sense_off) || + get_user(local_sense_len, &ioc->sense_len)) + return -EFAULT; + + + if (local_sense_len) { void __user **sense_ioc_ptr = - (void __user **)(ioc->frame.raw + ioc->sense_off); + (void __user **)((u8*)local_raw_ptr + local_sense_off); compat_uptr_t *sense_cioc_ptr = (compat_uptr_t *)(cioc->frame.raw + cioc->sense_off); if (get_user(ptr, sense_cioc_ptr) || @@ -6504,6 +6673,7 @@ megasas_aen_polling(struct work_struct *work) instance->ev = NULL; host = instance->host; if (instance->evt_detail) { + megasas_decode_evt(instance); switch (le32_to_cpu(instance->evt_detail->code)) { case MR_EVT_PD_INSERTED: @@ -6564,8 +6734,7 @@ megasas_aen_polling(struct work_struct *work) case MR_EVT_CFG_CLEARED: case MR_EVT_LD_DELETED: if (!instance->requestorId || - (instance->requestorId && - megasas_get_ld_vf_affiliation(instance, 0))) { + megasas_get_ld_vf_affiliation(instance, 0)) { if (megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) megasas_get_ld_list(instance); @@ -6596,8 +6765,7 @@ megasas_aen_polling(struct work_struct *work) break; case MR_EVT_LD_CREATED: if (!instance->requestorId || - (instance->requestorId && - megasas_get_ld_vf_affiliation(instance, 0))) { + megasas_get_ld_vf_affiliation(instance, 0)) { if (megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) megasas_get_ld_list(instance); @@ -6627,6 +6795,9 @@ megasas_aen_polling(struct work_struct *work) case MR_EVT_LD_STATE_CHANGE: doscan = 1; break; + case MR_EVT_CTRL_PROP_CHANGED: + megasas_get_ctrl_info(instance); + break; default: doscan = 0; break; @@ -6663,8 +6834,7 @@ megasas_aen_polling(struct work_struct *work) } if (!instance->requestorId || - (instance->requestorId && - megasas_get_ld_vf_affiliation(instance, 0))) { + megasas_get_ld_vf_affiliation(instance, 0)) { if (megasas_ld_list_query(instance, MR_LD_QUERY_TYPE_EXPOSED_TO_HOST)) megasas_get_ld_list(instance); diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index be57b1867..741509b35 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -741,14 +741,12 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, u8 physArm, span; u64 row; u8 retval = TRUE; - u8 do_invader = 0; u64 *pdBlock = &io_info->pdBlock; __le16 *pDevHandle = &io_info->devHandle; u32 logArm, rowMod, armQ, arm; + struct fusion_context *fusion; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER || - instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) - do_invader = 1; + fusion = instance->ctrl_context; /*Get row and span from io_info for Uneven Span IO.*/ row = io_info->start_row; @@ -779,7 +777,8 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, else { *pDevHandle = cpu_to_le16(MR_PD_INVALID); if ((raid->level >= 5) && - (!do_invader || (do_invader && + ((fusion->adapter_type == THUNDERBOLT_SERIES) || + ((fusion->adapter_type == INVADER_SERIES) && (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; else if (raid->level == 1) { @@ -823,13 +822,12 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, u8 physArm, span; u64 row; u8 retval = TRUE; - u8 do_invader = 0; u64 *pdBlock = &io_info->pdBlock; __le16 *pDevHandle = &io_info->devHandle; + struct fusion_context *fusion; + + fusion = instance->ctrl_context; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER || - instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) - do_invader = 1; row = mega_div64_32(stripRow, raid->rowDataSize); @@ -875,7 +873,8 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, /* set dev handle as invalid. */ *pDevHandle = cpu_to_le16(MR_PD_INVALID); if ((raid->level >= 5) && - (!do_invader || (do_invader && + ((fusion->adapter_type == THUNDERBOLT_SERIES) || + ((fusion->adapter_type == INVADER_SERIES) && (raid->regTypeReqOnRead != REGION_TYPE_UNUSED)))) pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; else if (raid->level == 1) { @@ -909,6 +908,7 @@ MR_BuildRaidContext(struct megasas_instance *instance, struct RAID_CONTEXT *pRAID_Context, struct MR_DRV_RAID_MAP_ALL *map, u8 **raidLUN) { + struct fusion_context *fusion; struct MR_LD_RAID *raid; u32 ld, stripSize, stripe_mask; u64 endLba, endStrip, endRow, start_row, start_strip; @@ -929,6 +929,7 @@ MR_BuildRaidContext(struct megasas_instance *instance, isRead = io_info->isRead; io_info->IoforUnevenSpan = 0; io_info->start_span = SPAN_INVALID; + fusion = instance->ctrl_context; ld = MR_TargetIdToLdGet(ldTgtId, map); raid = MR_LdRaidGet(ld, map); @@ -1092,8 +1093,7 @@ MR_BuildRaidContext(struct megasas_instance *instance, cpu_to_le16(raid->fpIoTimeoutForLd ? raid->fpIoTimeoutForLd : map->raidMap.fpPdIoTimeoutSec); - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) + if (fusion->adapter_type == INVADER_SERIES) pRAID_Context->regLockFlags = (isRead) ? raid->regTypeReqOnRead : raid->regTypeReqOnWrite; else @@ -1198,10 +1198,6 @@ void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map, span_row_width += MR_LdSpanPtrGet (ld, count, map)->spanRowDataSize; - printk(KERN_INFO "megasas:" - "span %x rowDataSize %x\n", - count, MR_LdSpanPtrGet - (ld, count, map)->spanRowDataSize); } } diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index f0837cc3b..8d630a552 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -316,26 +316,23 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) u32 max_cmd; struct fusion_context *fusion; struct megasas_cmd_fusion *cmd; - u32 total_sz_chain_frame; fusion = instance->ctrl_context; max_cmd = instance->max_fw_cmds; - total_sz_chain_frame = MEGASAS_MAX_SZ_CHAIN_FRAME; /* * Use DMA pool facility provided by PCI layer */ - fusion->sg_dma_pool = pci_pool_create("megasas sg pool fusion", - instance->pdev, - total_sz_chain_frame, 4, - 0); + fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance->pdev, + instance->max_chain_frame_sz, + 4, 0); if (!fusion->sg_dma_pool) { dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n"); return -ENOMEM; } - fusion->sense_dma_pool = pci_pool_create("megasas sense pool fusion", + fusion->sense_dma_pool = pci_pool_create("sense pool fusion", instance->pdev, SCSI_SENSE_BUFFERSIZE, 64, 0); @@ -605,6 +602,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) int i; struct megasas_header *frame_hdr; const char *sys_info; + MFI_CAPABILITIES *drv_ops; fusion = instance->ctrl_context; @@ -652,20 +650,21 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) init_frame->cmd = MFI_CMD_INIT; init_frame->cmd_status = 0xFF; + drv_ops = (MFI_CAPABILITIES *) &(init_frame->driver_operations); + /* driver support Extended MSIX */ - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) - init_frame->driver_operations. - mfi_capabilities.support_additional_msix = 1; + if (fusion->adapter_type == INVADER_SERIES) + drv_ops->mfi_capabilities.support_additional_msix = 1; /* driver supports HA / Remote LUN over Fast Path interface */ - init_frame->driver_operations.mfi_capabilities.support_fp_remote_lun - = 1; - init_frame->driver_operations.mfi_capabilities.support_max_255lds - = 1; - init_frame->driver_operations.mfi_capabilities.support_ndrive_r1_lb - = 1; - init_frame->driver_operations.mfi_capabilities.security_protocol_cmds_fw - = 1; + drv_ops->mfi_capabilities.support_fp_remote_lun = 1; + + drv_ops->mfi_capabilities.support_max_255lds = 1; + drv_ops->mfi_capabilities.support_ndrive_r1_lb = 1; + drv_ops->mfi_capabilities.security_protocol_cmds_fw = 1; + + if (instance->max_chain_frame_sz > MEGASAS_CHAIN_FRAME_SZ_MIN) + drv_ops->mfi_capabilities.support_ext_io_size = 1; + /* Convert capability to LE32 */ cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities); @@ -726,6 +725,83 @@ fail_get_cmd: return ret; } +/** + * megasas_sync_pd_seq_num - JBOD SEQ MAP + * @instance: Adapter soft state + * @pend: set to 1, if it is pended jbod map. + * + * Issue Jbod map to the firmware. If it is pended command, + * issue command and return. If it is first instance of jbod map + * issue and receive command. + */ +int +megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) { + int ret = 0; + u32 pd_seq_map_sz; + struct megasas_cmd *cmd; + struct megasas_dcmd_frame *dcmd; + struct fusion_context *fusion = instance->ctrl_context; + struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; + dma_addr_t pd_seq_h; + + pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id & 1)]; + pd_seq_h = fusion->pd_seq_phys[(instance->pd_seq_map_id & 1)]; + pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) + + (sizeof(struct MR_PD_CFG_SEQ) * + (MAX_PHYSICAL_DEVICES - 1)); + + cmd = megasas_get_cmd(instance); + if (!cmd) { + dev_err(&instance->pdev->dev, + "Could not get mfi cmd. Fail from %s %d\n", + __func__, __LINE__); + return -ENOMEM; + } + + dcmd = &cmd->frame->dcmd; + + memset(pd_sync, 0, pd_seq_map_sz); + memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); + dcmd->cmd = MFI_CMD_DCMD; + dcmd->cmd_status = 0xFF; + dcmd->sge_count = 1; + dcmd->timeout = 0; + dcmd->pad_0 = 0; + dcmd->data_xfer_len = cpu_to_le32(pd_seq_map_sz); + dcmd->opcode = cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO); + dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(pd_seq_h); + dcmd->sgl.sge32[0].length = cpu_to_le32(pd_seq_map_sz); + + if (pend) { + dcmd->mbox.b[0] = MEGASAS_DCMD_MBOX_PEND_FLAG; + dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_WRITE); + instance->jbod_seq_cmd = cmd; + instance->instancet->issue_dcmd(instance, cmd); + return 0; + } + + dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ); + + /* Below code is only for non pended DCMD */ + if (instance->ctrl_context && !instance->mask_interrupts) + ret = megasas_issue_blocked_cmd(instance, cmd, 60); + else + ret = megasas_issue_polled(instance, cmd); + + if (le32_to_cpu(pd_sync->count) > MAX_PHYSICAL_DEVICES) { + dev_warn(&instance->pdev->dev, + "driver supports max %d JBOD, but FW reports %d\n", + MAX_PHYSICAL_DEVICES, le32_to_cpu(pd_sync->count)); + ret = -EINVAL; + } + + if (!ret) + instance->pd_seq_map_id++; + + megasas_return_cmd(instance, cmd); + return ret; +} + /* * megasas_get_ld_map_info - Returns FW's ld_map structure * @instance: Adapter soft state @@ -961,6 +1037,18 @@ megasas_display_intel_branding(struct megasas_instance *instance) break; } break; + case PCI_DEVICE_ID_LSI_CUTLASS_52: + case PCI_DEVICE_ID_LSI_CUTLASS_53: + switch (instance->pdev->subsystem_device) { + case MEGARAID_INTEL_RMS3BC160_SSDID: + dev_info(&instance->pdev->dev, "scsi host %d: %s\n", + instance->host->host_no, + MEGARAID_INTEL_RMS3BC160_BRANDING); + break; + default: + break; + } + break; default: break; } @@ -977,7 +1065,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) { struct megasas_register_set __iomem *reg_set; struct fusion_context *fusion; - u32 max_cmd; + u32 max_cmd, scratch_pad_2; int i = 0, count; fusion = instance->ctrl_context; @@ -1016,15 +1104,40 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * (max_cmd + 1)); /* Extra 1 for SMID 0 */ + scratch_pad_2 = readl(&instance->reg_set->outbound_scratch_pad_2); + /* If scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK is set, + * Firmware support extended IO chain frame which is 4 times more than + * legacy Firmware. + * Legacy Firmware - Frame size is (8 * 128) = 1K + * 1M IO Firmware - Frame size is (8 * 128 * 4) = 4K + */ + if (scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK) + instance->max_chain_frame_sz = + ((scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_MASK) >> + MEGASAS_MAX_CHAIN_SHIFT) * MEGASAS_1MB_IO; + else + instance->max_chain_frame_sz = + ((scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_MASK) >> + MEGASAS_MAX_CHAIN_SHIFT) * MEGASAS_256K_IO; + + if (instance->max_chain_frame_sz < MEGASAS_CHAIN_FRAME_SZ_MIN) { + dev_warn(&instance->pdev->dev, "frame size %d invalid, fall back to legacy max frame size %d\n", + instance->max_chain_frame_sz, + MEGASAS_CHAIN_FRAME_SZ_MIN); + instance->max_chain_frame_sz = MEGASAS_CHAIN_FRAME_SZ_MIN; + } + fusion->max_sge_in_main_msg = - (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE - - offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16; + (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE + - offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16; fusion->max_sge_in_chain = - MEGASAS_MAX_SZ_CHAIN_FRAME / sizeof(union MPI2_SGE_IO_UNION); + instance->max_chain_frame_sz + / sizeof(union MPI2_SGE_IO_UNION); - instance->max_num_sge = rounddown_pow_of_two( - fusion->max_sge_in_main_msg + fusion->max_sge_in_chain - 2); + instance->max_num_sge = + rounddown_pow_of_two(fusion->max_sge_in_main_msg + + fusion->max_sge_in_chain - 2); /* Used for pass thru MFI frame (DCMD) */ fusion->chain_offset_mfi_pthru = @@ -1186,8 +1299,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, fusion = instance->ctrl_context; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (fusion->adapter_type == INVADER_SERIES) { struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = sgl_ptr; sgl_ptr_end += fusion->max_sge_in_main_msg - 1; sgl_ptr_end->Flags = 0; @@ -1204,11 +1316,9 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, sgl_ptr->Length = cpu_to_le32(sg_dma_len(os_sgl)); sgl_ptr->Address = cpu_to_le64(sg_dma_address(os_sgl)); sgl_ptr->Flags = 0; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (fusion->adapter_type == INVADER_SERIES) if (i == sge_count - 1) sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST; - } sgl_ptr++; sg_processed = i + 1; @@ -1217,10 +1327,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, (sge_count > fusion->max_sge_in_main_msg)) { struct MPI25_IEEE_SGE_CHAIN64 *sg_chain; - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FURY)) { + if (fusion->adapter_type == INVADER_SERIES) { if ((le16_to_cpu(cmd->io_request->IoFlags) & MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) != MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) @@ -1236,10 +1343,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, sg_chain = sgl_ptr; /* Prepare chain element */ sg_chain->NextChainOffset = 0; - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FURY)) + if (fusion->adapter_type == INVADER_SERIES) sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT; else sg_chain->Flags = @@ -1250,7 +1354,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance, sgl_ptr = (struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame; - memset(sgl_ptr, 0, MEGASAS_MAX_SZ_CHAIN_FRAME); + memset(sgl_ptr, 0, instance->max_chain_frame_sz); } } @@ -1556,8 +1660,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, cmd->request_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (fusion->adapter_type == INVADER_SERIES) { if (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED) cmd->request_desc->SCSIIO.RequestFlags = @@ -1582,7 +1685,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG; if ((raidLUN[0] == 1) && - (local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 2)) { + (local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 1)) { instance->dev_handle = !(instance->dev_handle); io_info.devHandle = local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].devHandle[instance->dev_handle]; @@ -1598,8 +1701,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance, cmd->request_desc->SCSIIO.RequestFlags = (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (fusion->adapter_type == INVADER_SERIES) { if (io_request->RaidContext.regLockFlags == REGION_TYPE_UNUSED) cmd->request_desc->SCSIIO.RequestFlags = @@ -1722,7 +1824,9 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, u16 timeout_limit; struct MR_DRV_RAID_MAP_ALL *local_map_ptr; struct RAID_CONTEXT *pRAID_Context; + struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync; struct fusion_context *fusion = instance->ctrl_context; + pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id - 1) & 1]; device_id = MEGASAS_DEV_INDEX(scmd); pd_index = MEGASAS_PD_INDEX(scmd); @@ -1731,16 +1835,38 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, io_request = cmd->io_request; /* get RAID_Context pointer */ pRAID_Context = &io_request->RaidContext; + pRAID_Context->regLockFlags = 0; + pRAID_Context->regLockRowLBA = 0; + pRAID_Context->regLockLength = 0; io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); io_request->LUN[1] = scmd->device->lun; pRAID_Context->RAIDFlags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; - pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); - pRAID_Context->configSeqNum = 0; - local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; - io_request->DevHandle = - local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; + /* If FW supports PD sequence number */ + if (instance->use_seqnum_jbod_fp && + instance->pd_list[pd_index].driveType == TYPE_DISK) { + /* TgtId must be incremented by 255 as jbod seq number is index + * below raid map + */ + pRAID_Context->VirtualDiskTgtId = + cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1)); + pRAID_Context->configSeqNum = pd_sync->seq[pd_index].seqNum; + io_request->DevHandle = pd_sync->seq[pd_index].devHandle; + pRAID_Context->regLockFlags |= + (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA); + } else if (fusion->fast_path_io) { + pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); + pRAID_Context->configSeqNum = 0; + local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)]; + io_request->DevHandle = + local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; + } else { + /* Want to send all IO via FW path */ + pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); + pRAID_Context->configSeqNum = 0; + io_request->DevHandle = cpu_to_le16(0xFFFF); + } cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle; cmd->request_desc->SCSIIO.MSIxIndex = @@ -1755,22 +1881,16 @@ megasas_build_syspd_fusion(struct megasas_instance *instance, (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); pRAID_Context->timeoutValue = cpu_to_le16(os_timeout_value); + pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id); } else { /* system pd Fast Path */ io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; - pRAID_Context->regLockFlags = 0; - pRAID_Context->regLockRowLBA = 0; - pRAID_Context->regLockLength = 0; timeout_limit = (scmd->device->type == TYPE_DISK) ? 255 : 0xFFFF; pRAID_Context->timeoutValue = cpu_to_le16((os_timeout_value > timeout_limit) ? timeout_limit : os_timeout_value); - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { - cmd->request_desc->SCSIIO.RequestFlags |= - (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); + if (fusion->adapter_type == INVADER_SERIES) { pRAID_Context->Type = MPI2_TYPE_CUDA; pRAID_Context->nseg = 0x1; io_request->IoFlags |= @@ -1796,7 +1916,7 @@ megasas_build_io_fusion(struct megasas_instance *instance, struct scsi_cmnd *scp, struct megasas_cmd_fusion *cmd) { - u32 sge_count; + u16 sge_count; u8 cmd_type; struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request; @@ -1854,7 +1974,11 @@ megasas_build_io_fusion(struct megasas_instance *instance, return 1; } + /* numSGE store lower 8 bit of sge_count. + * numSGEExt store higher 8 bit of sge_count + */ io_request->RaidContext.numSGE = sge_count; + io_request->RaidContext.numSGEExt = (u8)(sge_count >> 8); io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING); @@ -2084,10 +2208,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) * pending to be completed */ if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) { - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FURY)) + if (fusion->adapter_type == INVADER_SERIES) writel(((MSIxIndex & 0x7) << 24) | fusion->last_reply_idx[MSIxIndex], instance->reply_post_host_index_addr[MSIxIndex/8]); @@ -2103,8 +2224,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) return IRQ_NONE; wmb(); - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) + if (fusion->adapter_type == INVADER_SERIES) writel(((MSIxIndex & 0x7) << 24) | fusion->last_reply_idx[MSIxIndex], instance->reply_post_host_index_addr[MSIxIndex/8]); @@ -2227,8 +2347,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance, io_req = cmd->io_request; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { + if (fusion->adapter_type == INVADER_SERIES) { struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL; sgl_ptr_end += fusion->max_sge_in_main_msg - 1; @@ -2248,7 +2367,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance, mpi25_ieee_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT | MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR; - mpi25_ieee_chain->Length = cpu_to_le32(MEGASAS_MAX_SZ_CHAIN_FRAME); + mpi25_ieee_chain->Length = cpu_to_le32(instance->max_chain_frame_sz); return 0; } @@ -2384,6 +2503,70 @@ static int megasas_adp_reset_fusion(struct megasas_instance *instance, struct megasas_register_set __iomem *regs) { + u32 host_diag, abs_state, retry; + + /* Now try to reset the chip */ + writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + writel(MPI2_WRSEQ_1ST_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + writel(MPI2_WRSEQ_2ND_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + writel(MPI2_WRSEQ_3RD_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + writel(MPI2_WRSEQ_4TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + writel(MPI2_WRSEQ_5TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + writel(MPI2_WRSEQ_6TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset); + + /* Check that the diag write enable (DRWE) bit is on */ + host_diag = readl(&instance->reg_set->fusion_host_diag); + retry = 0; + while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) { + msleep(100); + host_diag = readl(&instance->reg_set->fusion_host_diag); + if (retry++ == 100) { + dev_warn(&instance->pdev->dev, + "Host diag unlock failed from %s %d\n", + __func__, __LINE__); + break; + } + } + if (!(host_diag & HOST_DIAG_WRITE_ENABLE)) + return -1; + + /* Send chip reset command */ + writel(host_diag | HOST_DIAG_RESET_ADAPTER, + &instance->reg_set->fusion_host_diag); + msleep(3000); + + /* Make sure reset adapter bit is cleared */ + host_diag = readl(&instance->reg_set->fusion_host_diag); + retry = 0; + while (host_diag & HOST_DIAG_RESET_ADAPTER) { + msleep(100); + host_diag = readl(&instance->reg_set->fusion_host_diag); + if (retry++ == 1000) { + dev_warn(&instance->pdev->dev, + "Diag reset adapter never cleared %s %d\n", + __func__, __LINE__); + break; + } + } + if (host_diag & HOST_DIAG_RESET_ADAPTER) + return -1; + + abs_state = instance->instancet->read_fw_status_reg(instance->reg_set) + & MFI_STATE_MASK; + retry = 0; + + while ((abs_state <= MFI_STATE_FW_INIT) && (retry++ < 1000)) { + msleep(100); + abs_state = instance->instancet-> + read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK; + } + if (abs_state <= MFI_STATE_FW_INIT) { + dev_warn(&instance->pdev->dev, + "fw state < MFI_STATE_FW_INIT, state = 0x%x %s %d\n", + abs_state, __func__, __LINE__); + return -1; + } + return 0; } @@ -2512,8 +2695,10 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance) continue; req_desc = megasas_get_request_descriptor (instance, smid - 1); - if (req_desc && (cmd_mfi->frame->dcmd.opcode != - cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO))) + if (req_desc && ((cmd_mfi->frame->dcmd.opcode != + cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO)) && + (cmd_mfi->frame->dcmd.opcode != + cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO)))) megasas_fire_cmd_fusion(instance, req_desc); else megasas_return_cmd(instance, cmd_mfi); @@ -2547,11 +2732,11 @@ out: /* Core fusion reset function */ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) { - int retval = SUCCESS, i, retry = 0, convert = 0; + int retval = SUCCESS, i, convert = 0; struct megasas_instance *instance; struct megasas_cmd_fusion *cmd_fusion; struct fusion_context *fusion; - u32 host_diag, abs_state, status_reg, reset_adapter; + u32 abs_state, status_reg, reset_adapter; u32 io_timeout_in_crash_mode = 0; struct scsi_cmnd *scmd_local = NULL; @@ -2705,82 +2890,11 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) /* Now try to reset the chip */ for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) { - writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_1ST_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_2ND_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_3RD_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_4TH_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_5TH_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_6TH_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - - /* Check that the diag write enable (DRWE) bit is on */ - host_diag = readl(&instance->reg_set->fusion_host_diag); - retry = 0; - while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) { - msleep(100); - host_diag = - readl(&instance->reg_set->fusion_host_diag); - if (retry++ == 100) { - dev_warn(&instance->pdev->dev, - "Host diag unlock failed! " - "for scsi%d\n", - instance->host->host_no); - break; - } - } - if (!(host_diag & HOST_DIAG_WRITE_ENABLE)) - continue; - /* Send chip reset command */ - writel(host_diag | HOST_DIAG_RESET_ADAPTER, - &instance->reg_set->fusion_host_diag); - msleep(3000); - - /* Make sure reset adapter bit is cleared */ - host_diag = readl(&instance->reg_set->fusion_host_diag); - retry = 0; - while (host_diag & HOST_DIAG_RESET_ADAPTER) { - msleep(100); - host_diag = - readl(&instance->reg_set->fusion_host_diag); - if (retry++ == 1000) { - dev_warn(&instance->pdev->dev, - "Diag reset adapter never " - "cleared for scsi%d!\n", - instance->host->host_no); - break; - } - } - if (host_diag & HOST_DIAG_RESET_ADAPTER) + if (instance->instancet->adp_reset + (instance, instance->reg_set)) continue; - abs_state = - instance->instancet->read_fw_status_reg( - instance->reg_set) & MFI_STATE_MASK; - retry = 0; - - while ((abs_state <= MFI_STATE_FW_INIT) && - (retry++ < 1000)) { - msleep(100); - abs_state = - instance->instancet->read_fw_status_reg( - instance->reg_set) & MFI_STATE_MASK; - } - if (abs_state <= MFI_STATE_FW_INIT) { - dev_warn(&instance->pdev->dev, "firmware " - "state < MFI_STATE_FW_INIT, state = " - "0x%x for scsi%d\n", abs_state, - instance->host->host_no); - continue; - } - /* Wait for FW to become ready */ if (megasas_transition_to_ready(instance, 1)) { dev_warn(&instance->pdev->dev, "Failed to " @@ -2816,6 +2930,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) if (!megasas_get_map_info(instance)) megasas_sync_map_info(instance); + megasas_setup_jbod_map(instance); + clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); instance->instancet->enable_intr(instance); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index ced6dc0cf..473005c99 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -35,8 +35,13 @@ #define _MEGARAID_SAS_FUSION_H_ /* Fusion defines */ -#define MEGASAS_MAX_SZ_CHAIN_FRAME 1024 +#define MEGASAS_CHAIN_FRAME_SZ_MIN 1024 #define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000009) +#define MEGASAS_MAX_CHAIN_SHIFT 5 +#define MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK 0x400000 +#define MEGASAS_MAX_CHAIN_SIZE_MASK 0x3E0 +#define MEGASAS_256K_IO 128 +#define MEGASAS_1MB_IO (MEGASAS_256K_IO * 4) #define MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE 256 #define MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST 0xF0 #define MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST 0xF1 @@ -89,6 +94,12 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE { #define MEGASAS_FP_CMD_LEN 16 #define MEGASAS_FUSION_IN_RESET 0 #define THRESHOLD_REPLY_COUNT 50 +#define JBOD_MAPS_COUNT 2 + +enum MR_FUSION_ADAPTER_TYPE { + THUNDERBOLT_SERIES = 0, + INVADER_SERIES = 1, +}; /* * Raid Context structure which describes MegaRAID specific IO Parameters @@ -117,7 +128,9 @@ struct RAID_CONTEXT { u8 numSGE; __le16 configSeqNum; u8 spanArm; - u8 resvd2[3]; + u8 priority; + u8 numSGEExt; + u8 resvd2; }; #define RAID_CTX_SPANARM_ARM_SHIFT (0) @@ -486,6 +499,7 @@ struct MPI2_IOC_INIT_REQUEST { #define MAX_PHYSICAL_DEVICES 256 #define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES) #define MR_DCMD_LD_MAP_GET_INFO 0x0300e101 +#define MR_DCMD_SYSTEM_PD_MAP_GET_INFO 0x0200e102 #define MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC 0x010e8485 /* SR-IOV HB alloc*/ #define MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111 0x03200200 #define MR_DCMD_LD_VF_MAP_GET_ALL_LDS 0x03150200 @@ -789,6 +803,21 @@ struct MR_FW_RAID_MAP_EXT { struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES_EXT]; }; +/* + * * define MR_PD_CFG_SEQ structure for system PDs + * */ +struct MR_PD_CFG_SEQ { + __le16 seqNum; + __le16 devHandle; + u8 reserved[4]; +} __packed; + +struct MR_PD_CFG_SEQ_NUM_SYNC { + __le32 size; + __le32 count; + struct MR_PD_CFG_SEQ seq[1]; +} __packed; + struct fusion_context { struct megasas_cmd_fusion **cmd_list; dma_addr_t req_frames_desc_phys; @@ -828,9 +857,12 @@ struct fusion_context { u32 current_map_sz; u32 drv_map_sz; u32 drv_map_pages; + struct MR_PD_CFG_SEQ_NUM_SYNC *pd_seq_sync[JBOD_MAPS_COUNT]; + dma_addr_t pd_seq_phys[JBOD_MAPS_COUNT]; u8 fast_path_io; struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES_EXT]; LD_SPAN_INFO log_to_span[MAX_LOGICAL_DRIVES_EXT]; + u8 adapter_type; }; union desc_value { diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig deleted file mode 100644 index 657b45ca0..000000000 --- a/drivers/scsi/mpt2sas/Kconfig +++ /dev/null @@ -1,67 +0,0 @@ -# -# Kernel configuration file for the MPT2SAS -# -# This code is based on drivers/scsi/mpt2sas/Kconfig -# Copyright (C) 2007-2014 LSI Corporation -# (mailto:DL-MPTFusionLinux@lsi.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. - -# 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. - -# NO WARRANTY -# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -# solely responsible for determining the appropriateness of using and -# distributing the Program and assumes all risks associated with its -# exercise of rights under this Agreement, including but not limited to -# the risks and costs of program errors, damage to or loss of data, -# programs or equipment, and unavailability or interruption of operations. - -# DISCLAIMER OF LIABILITY -# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. - -config SCSI_MPT2SAS - tristate "LSI MPT Fusion SAS 2.0 Device Driver" - depends on PCI && SCSI - select SCSI_SAS_ATTRS - select RAID_ATTRS - ---help--- - This driver supports PCI-Express SAS 6Gb/s Host Adapters. - -config SCSI_MPT2SAS_MAX_SGE - int "LSI MPT Fusion Max number of SG Entries (16 - 128)" - depends on PCI && SCSI && SCSI_MPT2SAS - default "128" - range 16 128 - ---help--- - This option allows you to specify the maximum number of scatter- - gather entries per I/O. The driver default is 128, which matches - SAFE_PHYS_SEGMENTS. However, it may decreased down to 16. - Decreasing this parameter will reduce memory requirements - on a per controller instance. - -config SCSI_MPT2SAS_LOGGING - bool "LSI MPT Fusion logging facility" - depends on PCI && SCSI && SCSI_MPT2SAS - ---help--- - This turns on a logging facility. diff --git a/drivers/scsi/mpt2sas/Makefile b/drivers/scsi/mpt2sas/Makefile deleted file mode 100644 index 728f04757..000000000 --- a/drivers/scsi/mpt2sas/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# mpt2sas makefile -obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas.o -mpt2sas-y += mpt2sas_base.o \ - mpt2sas_config.o \ - mpt2sas_scsih.o \ - mpt2sas_transport.o \ - mpt2sas_ctl.o diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h deleted file mode 100644 index 7fc6f23bd..000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2.h +++ /dev/null @@ -1,1170 +0,0 @@ -/* - * Copyright (c) 2000-2014 LSI Corporation. - * - * - * Name: mpi2.h - * Title: MPI Message independent structures and definitions - * including System Interface Register Set and - * scatter/gather formats. - * Creation Date: June 21, 2006 - * - * mpi2.h Version: 02.00.35 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT. - * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT. - * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT. - * Moved ReplyPostHostIndex register to offset 0x6C of the - * MPI2_SYSTEM_INTERFACE_REGS and modified the define for - * MPI2_REPLY_POST_HOST_INDEX_OFFSET. - * Added union of request descriptors. - * Added union of reply descriptors. - * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT. - * Added define for MPI2_VERSION_02_00. - * Fixed the size of the FunctionDependent5 field in the - * MPI2_DEFAULT_REPLY structure. - * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT. - * Removed the MPI-defined Fault Codes and extended the - * product specific codes up to 0xEFFF. - * Added a sixth key value for the WriteSequence register - * and changed the flush value to 0x0. - * Added message function codes for Diagnostic Buffer Post - * and Diagnsotic Release. - * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED - * Moved MPI2_VERSION_UNION from mpi2_ioc.h. - * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT. - * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT. - * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT. - * Added #defines for marking a reply descriptor as unused. - * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT. - * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT. - * Moved LUN field defines from mpi2_init.h. - * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT. - * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT. - * In all request and reply descriptors, replaced VF_ID - * field with MSIxIndex field. - * Removed DevHandle field from - * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those - * bytes reserved. - * Added RAID Accelerator functionality. - * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. - * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. - * Added MSI-x index mask and shift for Reply Post Host - * Index register. - * Added function code for Host Based Discovery Action. - * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT. - * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL. - * Added defines for product-specific range of message - * function codes, 0xF0 to 0xFF. - * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT. - * Added alternative defines for the SGE Direction bit. - * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT. - * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT. - * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define. - * 02-23-11 02.00.19 Bumped MPI2_HEADER_VERSION_UNIT. - * Added MPI2_FUNCTION_SEND_HOST_MESSAGE. - * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT. - * 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT. - * 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT. - * 11-18-11 02.00.23 Bumped MPI2_HEADER_VERSION_UNIT. - * 02-06-12 02.00.24 Bumped MPI2_HEADER_VERSION_UNIT. - * 03-29-12 02.00.25 Bumped MPI2_HEADER_VERSION_UNIT. - * Added Hard Reset delay timings. - * 07-10-12 02.00.26 Bumped MPI2_HEADER_VERSION_UNIT. - * 07-26-12 02.00.27 Bumped MPI2_HEADER_VERSION_UNIT. - * 11-27-12 02.00.28 Bumped MPI2_HEADER_VERSION_UNIT. - * 12-20-12 02.00.29 Bumped MPI2_HEADER_VERSION_UNIT. - * Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET. - * 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT. - * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT. - * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT. - * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT. - * 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT. - * 06-13-14 02.00.35 Bumped MPI2_HEADER_VERSION_UNIT. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_H -#define MPI2_H - - -/***************************************************************************** -* -* MPI Version Definitions -* -*****************************************************************************/ - -#define MPI2_VERSION_MAJOR (0x02) -#define MPI2_VERSION_MINOR (0x00) -#define MPI2_VERSION_MAJOR_MASK (0xFF00) -#define MPI2_VERSION_MAJOR_SHIFT (8) -#define MPI2_VERSION_MINOR_MASK (0x00FF) -#define MPI2_VERSION_MINOR_SHIFT (0) -#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ - MPI2_VERSION_MINOR) - -#define MPI2_VERSION_02_00 (0x0200) - -/* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x23) -#define MPI2_HEADER_VERSION_DEV (0x00) -#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) -#define MPI2_HEADER_VERSION_UNIT_SHIFT (8) -#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF) -#define MPI2_HEADER_VERSION_DEV_SHIFT (0) -#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | MPI2_HEADER_VERSION_DEV) - - -/***************************************************************************** -* -* IOC State Definitions -* -*****************************************************************************/ - -#define MPI2_IOC_STATE_RESET (0x00000000) -#define MPI2_IOC_STATE_READY (0x10000000) -#define MPI2_IOC_STATE_OPERATIONAL (0x20000000) -#define MPI2_IOC_STATE_FAULT (0x40000000) - -#define MPI2_IOC_STATE_MASK (0xF0000000) -#define MPI2_IOC_STATE_SHIFT (28) - -/* Fault state range for prodcut specific codes */ -#define MPI2_FAULT_PRODUCT_SPECIFIC_MIN (0x0000) -#define MPI2_FAULT_PRODUCT_SPECIFIC_MAX (0xEFFF) - - -/***************************************************************************** -* -* System Interface Register Definitions -* -*****************************************************************************/ - -typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS -{ - U32 Doorbell; /* 0x00 */ - U32 WriteSequence; /* 0x04 */ - U32 HostDiagnostic; /* 0x08 */ - U32 Reserved1; /* 0x0C */ - U32 DiagRWData; /* 0x10 */ - U32 DiagRWAddressLow; /* 0x14 */ - U32 DiagRWAddressHigh; /* 0x18 */ - U32 Reserved2[5]; /* 0x1C */ - U32 HostInterruptStatus; /* 0x30 */ - U32 HostInterruptMask; /* 0x34 */ - U32 DCRData; /* 0x38 */ - U32 DCRAddress; /* 0x3C */ - U32 Reserved3[2]; /* 0x40 */ - U32 ReplyFreeHostIndex; /* 0x48 */ - U32 Reserved4[8]; /* 0x4C */ - U32 ReplyPostHostIndex; /* 0x6C */ - U32 Reserved5; /* 0x70 */ - U32 HCBSize; /* 0x74 */ - U32 HCBAddressLow; /* 0x78 */ - U32 HCBAddressHigh; /* 0x7C */ - U32 Reserved6[16]; /* 0x80 */ - U32 RequestDescriptorPostLow; /* 0xC0 */ - U32 RequestDescriptorPostHigh; /* 0xC4 */ - U32 Reserved7[14]; /* 0xC8 */ -} MPI2_SYSTEM_INTERFACE_REGS, MPI2_POINTER PTR_MPI2_SYSTEM_INTERFACE_REGS, - Mpi2SystemInterfaceRegs_t, MPI2_POINTER pMpi2SystemInterfaceRegs_t; - -/* - * Defines for working with the Doorbell register. - */ -#define MPI2_DOORBELL_OFFSET (0x00000000) - -/* IOC --> System values */ -#define MPI2_DOORBELL_USED (0x08000000) -#define MPI2_DOORBELL_WHO_INIT_MASK (0x07000000) -#define MPI2_DOORBELL_WHO_INIT_SHIFT (24) -#define MPI2_DOORBELL_FAULT_CODE_MASK (0x0000FFFF) -#define MPI2_DOORBELL_DATA_MASK (0x0000FFFF) - -/* System --> IOC values */ -#define MPI2_DOORBELL_FUNCTION_MASK (0xFF000000) -#define MPI2_DOORBELL_FUNCTION_SHIFT (24) -#define MPI2_DOORBELL_ADD_DWORDS_MASK (0x00FF0000) -#define MPI2_DOORBELL_ADD_DWORDS_SHIFT (16) - - -/* - * Defines for the WriteSequence register - */ -#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004) -#define MPI2_WRSEQ_KEY_VALUE_MASK (0x0000000F) -#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0) -#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF) -#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4) -#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB) -#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2) -#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7) -#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD) - -/* - * Defines for the HostDiagnostic register - */ -#define MPI2_HOST_DIAGNOSTIC_OFFSET (0x00000008) - -#define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK (0x00001800) -#define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT (0x00000000) -#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800) - -#define MPI2_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400) -#define MPI2_DIAG_FORCE_HCB_ON_RESET (0x00000200) -#define MPI2_DIAG_HCB_MODE (0x00000100) -#define MPI2_DIAG_DIAG_WRITE_ENABLE (0x00000080) -#define MPI2_DIAG_FLASH_BAD_SIG (0x00000040) -#define MPI2_DIAG_RESET_HISTORY (0x00000020) -#define MPI2_DIAG_DIAG_RW_ENABLE (0x00000010) -#define MPI2_DIAG_RESET_ADAPTER (0x00000004) -#define MPI2_DIAG_HOLD_IOC_RESET (0x00000002) - -/* - * Offsets for DiagRWData and address - */ -#define MPI2_DIAG_RW_DATA_OFFSET (0x00000010) -#define MPI2_DIAG_RW_ADDRESS_LOW_OFFSET (0x00000014) -#define MPI2_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00000018) - -/* - * Defines for the HostInterruptStatus register - */ -#define MPI2_HOST_INTERRUPT_STATUS_OFFSET (0x00000030) -#define MPI2_HIS_SYS2IOC_DB_STATUS (0x80000000) -#define MPI2_HIS_IOP_DOORBELL_STATUS MPI2_HIS_SYS2IOC_DB_STATUS -#define MPI2_HIS_RESET_IRQ_STATUS (0x40000000) -#define MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT (0x00000008) -#define MPI2_HIS_IOC2SYS_DB_STATUS (0x00000001) -#define MPI2_HIS_DOORBELL_INTERRUPT MPI2_HIS_IOC2SYS_DB_STATUS - -/* - * Defines for the HostInterruptMask register - */ -#define MPI2_HOST_INTERRUPT_MASK_OFFSET (0x00000034) -#define MPI2_HIM_RESET_IRQ_MASK (0x40000000) -#define MPI2_HIM_REPLY_INT_MASK (0x00000008) -#define MPI2_HIM_RIM MPI2_HIM_REPLY_INT_MASK -#define MPI2_HIM_IOC2SYS_DB_MASK (0x00000001) -#define MPI2_HIM_DIM MPI2_HIM_IOC2SYS_DB_MASK - -/* - * Offsets for DCRData and address - */ -#define MPI2_DCR_DATA_OFFSET (0x00000038) -#define MPI2_DCR_ADDRESS_OFFSET (0x0000003C) - -/* - * Offset for the Reply Free Queue - */ -#define MPI2_REPLY_FREE_HOST_INDEX_OFFSET (0x00000048) - -/* - * Defines for the Reply Descriptor Post Queue - */ -#define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C) -#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF) -#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000) -#define MPI2_RPHI_MSIX_INDEX_SHIFT (24) -#define MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET (0x0000030C) /* MPI v2.5 only */ - -/* - * Defines for the HCBSize and address - */ -#define MPI2_HCB_SIZE_OFFSET (0x00000074) -#define MPI2_HCB_SIZE_SIZE_MASK (0xFFFFF000) -#define MPI2_HCB_SIZE_HCB_ENABLE (0x00000001) - -#define MPI2_HCB_ADDRESS_LOW_OFFSET (0x00000078) -#define MPI2_HCB_ADDRESS_HIGH_OFFSET (0x0000007C) - -/* - * Offsets for the Request Queue - */ -#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET (0x000000C0) -#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET (0x000000C4) - - -/* Hard Reset delay timings */ -#define MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC (50000) -#define MPI2_HARD_RESET_PCIE_RESET_READ_WINDOW_MICRO_SEC (255000) -#define MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC (256000) - -/***************************************************************************** -* -* Message Descriptors -* -*****************************************************************************/ - -/* Request Descriptors */ - -/* Default Request Descriptor */ -typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR -{ - U8 RequestFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 LMID; /* 0x04 */ - U16 DescriptorTypeDependent; /* 0x06 */ -} MPI2_DEFAULT_REQUEST_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_DEFAULT_REQUEST_DESCRIPTOR, - Mpi2DefaultRequestDescriptor_t, MPI2_POINTER pMpi2DefaultRequestDescriptor_t; - -/* defines for the RequestFlags field */ -#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E) -#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) -#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02) -#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06) -#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08) -#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A) - -#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01) - - -/* High Priority Request Descriptor */ -typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR -{ - U8 RequestFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 LMID; /* 0x04 */ - U16 Reserved1; /* 0x06 */ -} MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, - Mpi2HighPriorityRequestDescriptor_t, - MPI2_POINTER pMpi2HighPriorityRequestDescriptor_t; - - -/* SCSI IO Request Descriptor */ -typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR -{ - U8 RequestFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 LMID; /* 0x04 */ - U16 DevHandle; /* 0x06 */ -} MPI2_SCSI_IO_REQUEST_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST_DESCRIPTOR, - Mpi2SCSIIORequestDescriptor_t, MPI2_POINTER pMpi2SCSIIORequestDescriptor_t; - - -/* SCSI Target Request Descriptor */ -typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR -{ - U8 RequestFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 LMID; /* 0x04 */ - U16 IoIndex; /* 0x06 */ -} MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, - Mpi2SCSITargetRequestDescriptor_t, - MPI2_POINTER pMpi2SCSITargetRequestDescriptor_t; - - -/* RAID Accelerator Request Descriptor */ -typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR { - U8 RequestFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 LMID; /* 0x04 */ - U16 Reserved; /* 0x06 */ -} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, - Mpi2RAIDAcceleratorRequestDescriptor_t, - MPI2_POINTER pMpi2RAIDAcceleratorRequestDescriptor_t; - - -/* union of Request Descriptors */ -typedef union _MPI2_REQUEST_DESCRIPTOR_UNION -{ - MPI2_DEFAULT_REQUEST_DESCRIPTOR Default; - MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority; - MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO; - MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget; - MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator; - U64 Words; -} MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION, - Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t; - - -/* Reply Descriptors */ - -/* Default Reply Descriptor */ -typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR -{ - U8 ReplyFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 DescriptorTypeDependent1; /* 0x02 */ - U32 DescriptorTypeDependent2; /* 0x04 */ -} MPI2_DEFAULT_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR, - Mpi2DefaultReplyDescriptor_t, MPI2_POINTER pMpi2DefaultReplyDescriptor_t; - -/* defines for the ReplyFlags field */ -#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F) -#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00) -#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01) -#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02) -#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03) -#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS (0x05) -#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F) - -/* values for marking a reply descriptor as unused */ -#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK (0xFFFFFFFF) -#define MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK (0xFFFFFFFF) - -/* Address Reply Descriptor */ -typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR -{ - U8 ReplyFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U32 ReplyFrameAddress; /* 0x04 */ -} MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR, - Mpi2AddressReplyDescriptor_t, MPI2_POINTER pMpi2AddressReplyDescriptor_t; - -#define MPI2_ADDRESS_REPLY_SMID_INVALID (0x00) - - -/* SCSI IO Success Reply Descriptor */ -typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR -{ - U8 ReplyFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 TaskTag; /* 0x04 */ - U16 Reserved1; /* 0x06 */ -} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, - Mpi2SCSIIOSuccessReplyDescriptor_t, - MPI2_POINTER pMpi2SCSIIOSuccessReplyDescriptor_t; - - -/* TargetAssist Success Reply Descriptor */ -typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR -{ - U8 ReplyFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U8 SequenceNumber; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 IoIndex; /* 0x06 */ -} MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, - Mpi2TargetAssistSuccessReplyDescriptor_t, - MPI2_POINTER pMpi2TargetAssistSuccessReplyDescriptor_t; - - -/* Target Command Buffer Reply Descriptor */ -typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR -{ - U8 ReplyFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U8 VP_ID; /* 0x02 */ - U8 Flags; /* 0x03 */ - U16 InitiatorDevHandle; /* 0x04 */ - U16 IoIndex; /* 0x06 */ -} MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, - Mpi2TargetCommandBufferReplyDescriptor_t, - MPI2_POINTER pMpi2TargetCommandBufferReplyDescriptor_t; - -/* defines for Flags field */ -#define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK (0x3F) - - -/* RAID Accelerator Success Reply Descriptor */ -typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR { - U8 ReplyFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U32 Reserved; /* 0x04 */ -} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, - Mpi2RAIDAcceleratorSuccessReplyDescriptor_t, - MPI2_POINTER pMpi2RAIDAcceleratorSuccessReplyDescriptor_t; - - -/* union of Reply Descriptors */ -typedef union _MPI2_REPLY_DESCRIPTORS_UNION -{ - MPI2_DEFAULT_REPLY_DESCRIPTOR Default; - MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply; - MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess; - MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess; - MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; - MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess; - U64 Words; -} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION, -Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t; - - - -/***************************************************************************** -* -* Message Functions -* -*****************************************************************************/ - -#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ -#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) /* SCSI Task Management */ -#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */ -#define MPI2_FUNCTION_IOC_FACTS (0x03) /* IOC Facts */ -#define MPI2_FUNCTION_CONFIG (0x04) /* Configuration */ -#define MPI2_FUNCTION_PORT_FACTS (0x05) /* Port Facts */ -#define MPI2_FUNCTION_PORT_ENABLE (0x06) /* Port Enable */ -#define MPI2_FUNCTION_EVENT_NOTIFICATION (0x07) /* Event Notification */ -#define MPI2_FUNCTION_EVENT_ACK (0x08) /* Event Acknowledge */ -#define MPI2_FUNCTION_FW_DOWNLOAD (0x09) /* FW Download */ -#define MPI2_FUNCTION_TARGET_ASSIST (0x0B) /* Target Assist */ -#define MPI2_FUNCTION_TARGET_STATUS_SEND (0x0C) /* Target Status Send */ -#define MPI2_FUNCTION_TARGET_MODE_ABORT (0x0D) /* Target Mode Abort */ -#define MPI2_FUNCTION_FW_UPLOAD (0x12) /* FW Upload */ -#define MPI2_FUNCTION_RAID_ACTION (0x15) /* RAID Action */ -#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) /* SCSI IO RAID Passthrough */ -#define MPI2_FUNCTION_TOOLBOX (0x17) /* Toolbox */ -#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) /* SCSI Enclosure Processor */ -#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A) /* SMP Passthrough */ -#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) /* SAS IO Unit Control */ -#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C) /* SATA Passthrough */ -#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D) /* Diagnostic Buffer Post */ -#define MPI2_FUNCTION_DIAG_RELEASE (0x1E) /* Diagnostic Release */ -#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */ -#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */ -#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator*/ -/* Host Based Discovery Action */ -#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) -/* Power Management Control */ -#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) -/* Send Host Message */ -#define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31) -/* beginning of product-specific range */ -#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) -/* end of product-specific range */ -#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) - - - - -/* Doorbell functions */ -#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) -#define MPI2_FUNCTION_HANDSHAKE (0x42) - - -/***************************************************************************** -* -* IOC Status Values -* -*****************************************************************************/ - -/* mask for IOCStatus status value */ -#define MPI2_IOCSTATUS_MASK (0x7FFF) - -/**************************************************************************** -* Common IOCStatus values for all replies -****************************************************************************/ - -#define MPI2_IOCSTATUS_SUCCESS (0x0000) -#define MPI2_IOCSTATUS_INVALID_FUNCTION (0x0001) -#define MPI2_IOCSTATUS_BUSY (0x0002) -#define MPI2_IOCSTATUS_INVALID_SGL (0x0003) -#define MPI2_IOCSTATUS_INTERNAL_ERROR (0x0004) -#define MPI2_IOCSTATUS_INVALID_VPID (0x0005) -#define MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) -#define MPI2_IOCSTATUS_INVALID_FIELD (0x0007) -#define MPI2_IOCSTATUS_INVALID_STATE (0x0008) -#define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009) - -/**************************************************************************** -* Config IOCStatus values -****************************************************************************/ - -#define MPI2_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) -#define MPI2_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) -#define MPI2_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) -#define MPI2_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) -#define MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) -#define MPI2_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) - -/**************************************************************************** -* SCSI IO Reply -****************************************************************************/ - -#define MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) -#define MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE (0x0042) -#define MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) -#define MPI2_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) -#define MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) -#define MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) -#define MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) -#define MPI2_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) -#define MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) -#define MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) -#define MPI2_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) -#define MPI2_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) - -/**************************************************************************** -* For use by SCSI Initiator and SCSI Target end-to-end data protection -****************************************************************************/ - -#define MPI2_IOCSTATUS_EEDP_GUARD_ERROR (0x004D) -#define MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E) -#define MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) - -/**************************************************************************** -* SCSI Target values -****************************************************************************/ - -#define MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062) -#define MPI2_IOCSTATUS_TARGET_ABORTED (0x0063) -#define MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) -#define MPI2_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) -#define MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A) -#define MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006D) -#define MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E) -#define MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006F) -#define MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070) -#define MPI2_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071) - -/**************************************************************************** -* Serial Attached SCSI values -****************************************************************************/ - -#define MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) -#define MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091) - -/**************************************************************************** -* Diagnostic Buffer Post / Diagnostic Release values -****************************************************************************/ - -#define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) - -/**************************************************************************** -* RAID Accelerator values -****************************************************************************/ - -#define MPI2_IOCSTATUS_RAID_ACCEL_ERROR (0x00B0) - -/**************************************************************************** -* IOCStatus flag to indicate that log info is available -****************************************************************************/ - -#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000) - -/**************************************************************************** -* IOCLogInfo Types -****************************************************************************/ - -#define MPI2_IOCLOGINFO_TYPE_MASK (0xF0000000) -#define MPI2_IOCLOGINFO_TYPE_SHIFT (28) -#define MPI2_IOCLOGINFO_TYPE_NONE (0x0) -#define MPI2_IOCLOGINFO_TYPE_SCSI (0x1) -#define MPI2_IOCLOGINFO_TYPE_FC (0x2) -#define MPI2_IOCLOGINFO_TYPE_SAS (0x3) -#define MPI2_IOCLOGINFO_TYPE_ISCSI (0x4) -#define MPI2_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) - - -/***************************************************************************** -* -* Standard Message Structures -* -*****************************************************************************/ - -/**************************************************************************** -* Request Message Header for all request messages -****************************************************************************/ - -typedef struct _MPI2_REQUEST_HEADER -{ - U16 FunctionDependent1; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 FunctionDependent2; /* 0x04 */ - U8 FunctionDependent3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ -} MPI2_REQUEST_HEADER, MPI2_POINTER PTR_MPI2_REQUEST_HEADER, - MPI2RequestHeader_t, MPI2_POINTER pMPI2RequestHeader_t; - - -/**************************************************************************** -* Default Reply -****************************************************************************/ - -typedef struct _MPI2_DEFAULT_REPLY -{ - U16 FunctionDependent1; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 FunctionDependent2; /* 0x04 */ - U8 FunctionDependent3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U16 FunctionDependent5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_DEFAULT_REPLY, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY, - MPI2DefaultReply_t, MPI2_POINTER pMPI2DefaultReply_t; - - -/* common version structure/union used in messages and configuration pages */ - -typedef struct _MPI2_VERSION_STRUCT -{ - U8 Dev; /* 0x00 */ - U8 Unit; /* 0x01 */ - U8 Minor; /* 0x02 */ - U8 Major; /* 0x03 */ -} MPI2_VERSION_STRUCT; - -typedef union _MPI2_VERSION_UNION -{ - MPI2_VERSION_STRUCT Struct; - U32 Word; -} MPI2_VERSION_UNION; - - -/* LUN field defines, common to many structures */ -#define MPI2_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF) -#define MPI2_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000) -#define MPI2_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF) -#define MPI2_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000) -#define MPI2_LUN_LEVEL_1_WORD (0xFF00) -#define MPI2_LUN_LEVEL_1_DWORD (0x0000FF00) - - -/***************************************************************************** -* -* Fusion-MPT MPI Scatter Gather Elements -* -*****************************************************************************/ - -/**************************************************************************** -* MPI Simple Element structures -****************************************************************************/ - -typedef struct _MPI2_SGE_SIMPLE32 -{ - U32 FlagsLength; - U32 Address; -} MPI2_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_SGE_SIMPLE32, - Mpi2SGESimple32_t, MPI2_POINTER pMpi2SGESimple32_t; - -typedef struct _MPI2_SGE_SIMPLE64 -{ - U32 FlagsLength; - U64 Address; -} MPI2_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_SGE_SIMPLE64, - Mpi2SGESimple64_t, MPI2_POINTER pMpi2SGESimple64_t; - -typedef struct _MPI2_SGE_SIMPLE_UNION -{ - U32 FlagsLength; - union - { - U32 Address32; - U64 Address64; - } u; -} MPI2_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_SIMPLE_UNION, - Mpi2SGESimpleUnion_t, MPI2_POINTER pMpi2SGESimpleUnion_t; - - -/**************************************************************************** -* MPI Chain Element structures -****************************************************************************/ - -typedef struct _MPI2_SGE_CHAIN32 -{ - U16 Length; - U8 NextChainOffset; - U8 Flags; - U32 Address; -} MPI2_SGE_CHAIN32, MPI2_POINTER PTR_MPI2_SGE_CHAIN32, - Mpi2SGEChain32_t, MPI2_POINTER pMpi2SGEChain32_t; - -typedef struct _MPI2_SGE_CHAIN64 -{ - U16 Length; - U8 NextChainOffset; - U8 Flags; - U64 Address; -} MPI2_SGE_CHAIN64, MPI2_POINTER PTR_MPI2_SGE_CHAIN64, - Mpi2SGEChain64_t, MPI2_POINTER pMpi2SGEChain64_t; - -typedef struct _MPI2_SGE_CHAIN_UNION -{ - U16 Length; - U8 NextChainOffset; - U8 Flags; - union - { - U32 Address32; - U64 Address64; - } u; -} MPI2_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_SGE_CHAIN_UNION, - Mpi2SGEChainUnion_t, MPI2_POINTER pMpi2SGEChainUnion_t; - - -/**************************************************************************** -* MPI Transaction Context Element structures -****************************************************************************/ - -typedef struct _MPI2_SGE_TRANSACTION32 -{ - U8 Reserved; - U8 ContextSize; - U8 DetailsLength; - U8 Flags; - U32 TransactionContext[1]; - U32 TransactionDetails[1]; -} MPI2_SGE_TRANSACTION32, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION32, - Mpi2SGETransaction32_t, MPI2_POINTER pMpi2SGETransaction32_t; - -typedef struct _MPI2_SGE_TRANSACTION64 -{ - U8 Reserved; - U8 ContextSize; - U8 DetailsLength; - U8 Flags; - U32 TransactionContext[2]; - U32 TransactionDetails[1]; -} MPI2_SGE_TRANSACTION64, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION64, - Mpi2SGETransaction64_t, MPI2_POINTER pMpi2SGETransaction64_t; - -typedef struct _MPI2_SGE_TRANSACTION96 -{ - U8 Reserved; - U8 ContextSize; - U8 DetailsLength; - U8 Flags; - U32 TransactionContext[3]; - U32 TransactionDetails[1]; -} MPI2_SGE_TRANSACTION96, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION96, - Mpi2SGETransaction96_t, MPI2_POINTER pMpi2SGETransaction96_t; - -typedef struct _MPI2_SGE_TRANSACTION128 -{ - U8 Reserved; - U8 ContextSize; - U8 DetailsLength; - U8 Flags; - U32 TransactionContext[4]; - U32 TransactionDetails[1]; -} MPI2_SGE_TRANSACTION128, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION128, - Mpi2SGETransaction_t128, MPI2_POINTER pMpi2SGETransaction_t128; - -typedef struct _MPI2_SGE_TRANSACTION_UNION -{ - U8 Reserved; - U8 ContextSize; - U8 DetailsLength; - U8 Flags; - union - { - U32 TransactionContext32[1]; - U32 TransactionContext64[2]; - U32 TransactionContext96[3]; - U32 TransactionContext128[4]; - } u; - U32 TransactionDetails[1]; -} MPI2_SGE_TRANSACTION_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION_UNION, - Mpi2SGETransactionUnion_t, MPI2_POINTER pMpi2SGETransactionUnion_t; - - -/**************************************************************************** -* MPI SGE union for IO SGL's -****************************************************************************/ - -typedef struct _MPI2_MPI_SGE_IO_UNION -{ - union - { - MPI2_SGE_SIMPLE_UNION Simple; - MPI2_SGE_CHAIN_UNION Chain; - } u; -} MPI2_MPI_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_IO_UNION, - Mpi2MpiSGEIOUnion_t, MPI2_POINTER pMpi2MpiSGEIOUnion_t; - - -/**************************************************************************** -* MPI SGE union for SGL's with Simple and Transaction elements -****************************************************************************/ - -typedef struct _MPI2_SGE_TRANS_SIMPLE_UNION -{ - union - { - MPI2_SGE_SIMPLE_UNION Simple; - MPI2_SGE_TRANSACTION_UNION Transaction; - } u; -} MPI2_SGE_TRANS_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANS_SIMPLE_UNION, - Mpi2SGETransSimpleUnion_t, MPI2_POINTER pMpi2SGETransSimpleUnion_t; - - -/**************************************************************************** -* All MPI SGE types union -****************************************************************************/ - -typedef struct _MPI2_MPI_SGE_UNION -{ - union - { - MPI2_SGE_SIMPLE_UNION Simple; - MPI2_SGE_CHAIN_UNION Chain; - MPI2_SGE_TRANSACTION_UNION Transaction; - } u; -} MPI2_MPI_SGE_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_UNION, - Mpi2MpiSgeUnion_t, MPI2_POINTER pMpi2MpiSgeUnion_t; - - -/**************************************************************************** -* MPI SGE field definition and masks -****************************************************************************/ - -/* Flags field bit definitions */ - -#define MPI2_SGE_FLAGS_LAST_ELEMENT (0x80) -#define MPI2_SGE_FLAGS_END_OF_BUFFER (0x40) -#define MPI2_SGE_FLAGS_ELEMENT_TYPE_MASK (0x30) -#define MPI2_SGE_FLAGS_LOCAL_ADDRESS (0x08) -#define MPI2_SGE_FLAGS_DIRECTION (0x04) -#define MPI2_SGE_FLAGS_ADDRESS_SIZE (0x02) -#define MPI2_SGE_FLAGS_END_OF_LIST (0x01) - -#define MPI2_SGE_FLAGS_SHIFT (24) - -#define MPI2_SGE_LENGTH_MASK (0x00FFFFFF) -#define MPI2_SGE_CHAIN_LENGTH_MASK (0x0000FFFF) - -/* Element Type */ - -#define MPI2_SGE_FLAGS_TRANSACTION_ELEMENT (0x00) -#define MPI2_SGE_FLAGS_SIMPLE_ELEMENT (0x10) -#define MPI2_SGE_FLAGS_CHAIN_ELEMENT (0x30) -#define MPI2_SGE_FLAGS_ELEMENT_MASK (0x30) - -/* Address location */ - -#define MPI2_SGE_FLAGS_SYSTEM_ADDRESS (0x00) - -/* Direction */ - -#define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00) -#define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04) - -#define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST) -#define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC) - -/* Address Size */ - -#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00) -#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02) - -/* Context Size */ - -#define MPI2_SGE_FLAGS_32_BIT_CONTEXT (0x00) -#define MPI2_SGE_FLAGS_64_BIT_CONTEXT (0x02) -#define MPI2_SGE_FLAGS_96_BIT_CONTEXT (0x04) -#define MPI2_SGE_FLAGS_128_BIT_CONTEXT (0x06) - -#define MPI2_SGE_CHAIN_OFFSET_MASK (0x00FF0000) -#define MPI2_SGE_CHAIN_OFFSET_SHIFT (16) - -/**************************************************************************** -* MPI SGE operation Macros -****************************************************************************/ - -/* SIMPLE FlagsLength manipulations... */ -#define MPI2_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_SGE_FLAGS_SHIFT) -#define MPI2_SGE_GET_FLAGS(f) (((f) & ~MPI2_SGE_LENGTH_MASK) >> MPI2_SGE_FLAGS_SHIFT) -#define MPI2_SGE_LENGTH(f) ((f) & MPI2_SGE_LENGTH_MASK) -#define MPI2_SGE_CHAIN_LENGTH(f) ((f) & MPI2_SGE_CHAIN_LENGTH_MASK) - -#define MPI2_SGE_SET_FLAGS_LENGTH(f,l) (MPI2_SGE_SET_FLAGS(f) | MPI2_SGE_LENGTH(l)) - -#define MPI2_pSGE_GET_FLAGS(psg) MPI2_SGE_GET_FLAGS((psg)->FlagsLength) -#define MPI2_pSGE_GET_LENGTH(psg) MPI2_SGE_LENGTH((psg)->FlagsLength) -#define MPI2_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_SGE_SET_FLAGS_LENGTH(f,l) - -/* CAUTION - The following are READ-MODIFY-WRITE! */ -#define MPI2_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_SGE_SET_FLAGS(f) -#define MPI2_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_SGE_LENGTH(l) - -#define MPI2_GET_CHAIN_OFFSET(x) ((x & MPI2_SGE_CHAIN_OFFSET_MASK) >> MPI2_SGE_CHAIN_OFFSET_SHIFT) - - -/***************************************************************************** -* -* Fusion-MPT IEEE Scatter Gather Elements -* -*****************************************************************************/ - -/**************************************************************************** -* IEEE Simple Element structures -****************************************************************************/ - -typedef struct _MPI2_IEEE_SGE_SIMPLE32 -{ - U32 Address; - U32 FlagsLength; -} MPI2_IEEE_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE32, - Mpi2IeeeSgeSimple32_t, MPI2_POINTER pMpi2IeeeSgeSimple32_t; - -typedef struct _MPI2_IEEE_SGE_SIMPLE64 -{ - U64 Address; - U32 Length; - U16 Reserved1; - U8 Reserved2; - U8 Flags; -} MPI2_IEEE_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE64, - Mpi2IeeeSgeSimple64_t, MPI2_POINTER pMpi2IeeeSgeSimple64_t; - -typedef union _MPI2_IEEE_SGE_SIMPLE_UNION -{ - MPI2_IEEE_SGE_SIMPLE32 Simple32; - MPI2_IEEE_SGE_SIMPLE64 Simple64; -} MPI2_IEEE_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE_UNION, - Mpi2IeeeSgeSimpleUnion_t, MPI2_POINTER pMpi2IeeeSgeSimpleUnion_t; - - -/**************************************************************************** -* IEEE Chain Element structures -****************************************************************************/ - -typedef MPI2_IEEE_SGE_SIMPLE32 MPI2_IEEE_SGE_CHAIN32; - -typedef MPI2_IEEE_SGE_SIMPLE64 MPI2_IEEE_SGE_CHAIN64; - -typedef union _MPI2_IEEE_SGE_CHAIN_UNION -{ - MPI2_IEEE_SGE_CHAIN32 Chain32; - MPI2_IEEE_SGE_CHAIN64 Chain64; -} MPI2_IEEE_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_CHAIN_UNION, - Mpi2IeeeSgeChainUnion_t, MPI2_POINTER pMpi2IeeeSgeChainUnion_t; - - -/**************************************************************************** -* All IEEE SGE types union -****************************************************************************/ - -typedef struct _MPI2_IEEE_SGE_UNION -{ - union - { - MPI2_IEEE_SGE_SIMPLE_UNION Simple; - MPI2_IEEE_SGE_CHAIN_UNION Chain; - } u; -} MPI2_IEEE_SGE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_UNION, - Mpi2IeeeSgeUnion_t, MPI2_POINTER pMpi2IeeeSgeUnion_t; - - -/**************************************************************************** -* IEEE SGE field definitions and masks -****************************************************************************/ - -/* Flags field bit definitions */ - -#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK (0x80) - -#define MPI2_IEEE32_SGE_FLAGS_SHIFT (24) - -#define MPI2_IEEE32_SGE_LENGTH_MASK (0x00FFFFFF) - -/* Element Type */ - -#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT (0x00) -#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80) - -/* Data Location Address Space */ - -#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03) -#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) - /* IEEE Simple Element only */ -#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) - /* IEEE Simple Element only */ -#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) -#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) - /* IEEE Simple Element only */ -#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR (0x03) - /* IEEE Chain Element only */ -#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR \ - (MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR) /* typo in name */ - -/**************************************************************************** -* IEEE SGE operation Macros -****************************************************************************/ - -/* SIMPLE FlagsLength manipulations... */ -#define MPI2_IEEE32_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_IEEE32_SGE_FLAGS_SHIFT) -#define MPI2_IEEE32_SGE_GET_FLAGS(f) (((f) & ~MPI2_IEEE32_SGE_LENGTH_MASK) >> MPI2_IEEE32_SGE_FLAGS_SHIFT) -#define MPI2_IEEE32_SGE_LENGTH(f) ((f) & MPI2_IEEE32_SGE_LENGTH_MASK) - -#define MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f, l) (MPI2_IEEE32_SGE_SET_FLAGS(f) | MPI2_IEEE32_SGE_LENGTH(l)) - -#define MPI2_IEEE32_pSGE_GET_FLAGS(psg) MPI2_IEEE32_SGE_GET_FLAGS((psg)->FlagsLength) -#define MPI2_IEEE32_pSGE_GET_LENGTH(psg) MPI2_IEEE32_SGE_LENGTH((psg)->FlagsLength) -#define MPI2_IEEE32_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f,l) - -/* CAUTION - The following are READ-MODIFY-WRITE! */ -#define MPI2_IEEE32_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_IEEE32_SGE_SET_FLAGS(f) -#define MPI2_IEEE32_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_IEEE32_SGE_LENGTH(l) - - - - -/***************************************************************************** -* -* Fusion-MPT MPI/IEEE Scatter Gather Unions -* -*****************************************************************************/ - -typedef union _MPI2_SIMPLE_SGE_UNION -{ - MPI2_SGE_SIMPLE_UNION MpiSimple; - MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; -} MPI2_SIMPLE_SGE_UNION, MPI2_POINTER PTR_MPI2_SIMPLE_SGE_UNION, - Mpi2SimpleSgeUntion_t, MPI2_POINTER pMpi2SimpleSgeUntion_t; - - -typedef union _MPI2_SGE_IO_UNION -{ - MPI2_SGE_SIMPLE_UNION MpiSimple; - MPI2_SGE_CHAIN_UNION MpiChain; - MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; - MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; -} MPI2_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_SGE_IO_UNION, - Mpi2SGEIOUnion_t, MPI2_POINTER pMpi2SGEIOUnion_t; - - -/**************************************************************************** -* -* Values for SGLFlags field, used in many request messages with an SGL -* -****************************************************************************/ - -/* values for MPI SGL Data Location Address Space subfield */ -#define MPI2_SGLFLAGS_ADDRESS_SPACE_MASK (0x0C) -#define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE (0x00) -#define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE (0x04) -#define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08) -#define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE (0x0C) -/* values for SGL Type subfield */ -#define MPI2_SGLFLAGS_SGL_TYPE_MASK (0x03) -#define MPI2_SGLFLAGS_SGL_TYPE_MPI (0x00) -#define MPI2_SGLFLAGS_SGL_TYPE_IEEE32 (0x01) -#define MPI2_SGLFLAGS_SGL_TYPE_IEEE64 (0x02) - - -#endif - diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h deleted file mode 100644 index ee8d2d695..000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ /dev/null @@ -1,3068 +0,0 @@ -/* - * Copyright (c) 2000-2014 LSI Corporation. - * - * - * Name: mpi2_cnfg.h - * Title: MPI Configuration messages and pages - * Creation Date: November 10, 2006 - * - * mpi2_cnfg.h Version: 02.00.29 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags. - * Added Manufacturing Page 11. - * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE - * define. - * 06-26-07 02.00.02 Adding generic structure for product-specific - * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS. - * Rework of BIOS Page 2 configuration page. - * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the - * forms. - * Added configuration pages IOC Page 8 and Driver - * Persistent Mapping Page 0. - * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated - * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1, - * RAID Physical Disk Pages 0 and 1, RAID Configuration - * Page 0). - * Added new value for AccessStatus field of SAS Device - * Page 0 (_SATA_NEEDS_INITIALIZATION). - * 10-31-07 02.00.04 Added missing SEPDevHandle field to - * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. - * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for - * NVDATA. - * Modified IOC Page 7 to use masks and added field for - * SASBroadcastPrimitiveMasks. - * Added MPI2_CONFIG_PAGE_BIOS_4. - * Added MPI2_CONFIG_PAGE_LOG_0. - * 02-29-08 02.00.06 Modified various names to make them 32-character unique. - * Added SAS Device IDs. - * Updated Integrated RAID configuration pages including - * Manufacturing Page 4, IOC Page 6, and RAID Configuration - * Page 0. - * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA. - * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION. - * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING. - * Added missing MaxNumRoutedSasAddresses field to - * MPI2_CONFIG_PAGE_EXPANDER_0. - * Added SAS Port Page 0. - * Modified structure layout for - * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0. - * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use - * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array. - * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF - * to 0x000000FF. - * Added two new values for the Physical Disk Coercion Size - * bits in the Flags field of Manufacturing Page 4. - * Added product-specific Manufacturing pages 16 to 31. - * Modified Flags bits for controlling write cache on SATA - * drives in IO Unit Page 1. - * Added new bit to AdditionalControlFlags of SAS IO Unit - * Page 1 to control Invalid Topology Correction. - * Added additional defines for RAID Volume Page 0 - * VolumeStatusFlags field. - * Modified meaning of RAID Volume Page 0 VolumeSettings - * define for auto-configure of hot-swap drives. - * Added SupportedPhysDisks field to RAID Volume Page 1 and - * added related defines. - * Added PhysDiskAttributes field (and related defines) to - * RAID Physical Disk Page 0. - * Added MPI2_SAS_PHYINFO_PHY_VACANT define. - * Added three new DiscoveryStatus bits for SAS IO Unit - * Page 0 and SAS Expander Page 0. - * Removed multiplexing information from SAS IO Unit pages. - * Added BootDeviceWaitTime field to SAS IO Unit Page 4. - * Removed Zone Address Resolved bit from PhyInfo and from - * Expander Page 0 Flags field. - * Added two new AccessStatus values to SAS Device Page 0 - * for indicating routing problems. Added 3 reserved words - * to this page. - * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3. - * Inserted missing reserved field into structure for IOC - * Page 6. - * Added more pending task bits to RAID Volume Page 0 - * VolumeStatusFlags defines. - * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define. - * Added a new DiscoveryStatus bit for SAS IO Unit Page 0 - * and SAS Expander Page 0 to flag a downstream initiator - * when in simplified routing mode. - * Removed SATA Init Failure defines for DiscoveryStatus - * fields of SAS IO Unit Page 0 and SAS Expander Page 0. - * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define. - * Added PortGroups, DmaGroup, and ControlGroup fields to - * SAS Device Page 0. - * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO - * Unit Page 6. - * Added expander reduced functionality data to SAS - * Expander Page 0. - * Added SAS PHY Page 2 and SAS PHY Page 3. - * 07-30-09 02.00.12 Added IO Unit Page 7. - * Added new device ids. - * Added SAS IO Unit Page 5. - * Added partial and slumber power management capable flags - * to SAS Device Page 0 Flags field. - * Added PhyInfo defines for power condition. - * Added Ethernet configuration pages. - * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. - * Added SAS PHY Page 4 structure and defines. - * 02-10-10 02.00.14 Modified the comments for the configuration page - * structures that contain an array of data. The host - * should use the "count" field in the page data (e.g. the - * NumPhys field) to determine the number of valid elements - * in the array. - * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines. - * Added PowerManagementCapabilities to IO Unit Page 7. - * Added PortWidthModGroup field to - * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS. - * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines. - * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines. - * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines. - * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT - * define. - * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define. - * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define. - * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing) - * defines. - * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to - * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for - * the Pinout field. - * Added BoardTemperature and BoardTemperatureUnits fields - * to MPI2_CONFIG_PAGE_IO_UNIT_7. - * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define - * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure. - * 02-23-11 02.00.18 Added ProxyVF_ID field to MPI2_CONFIG_REQUEST. - * Added IO Unit Page 8, IO Unit Page 9, - * and IO Unit Page 10. - * Added SASNotifyPrimitiveMasks field to - * MPI2_CONFIG_PAGE_IOC_7. - * 03-09-11 02.00.19 Fixed IO Unit Page 10 (to match the spec). - * 05-25-11 02.00.20 Cleaned up a few comments. - * 08-24-11 02.00.21 Marked the IO Unit Page 7 PowerManagementCapabilities - * for PCIe link as obsolete. - * Added SpinupFlags field containing a Disable Spin-up - * bit to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of - * SAS IO Unit Page 4. - * 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT. - * Added UEFIVersion field to BIOS Page 1 and defined new - * BiosOptions bits. - * 11-27-12 02.00.23 Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER. - * Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID. - * 12-20-12 02.00.24 Marked MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION as - * obsolete for MPI v2.5 and later. - * Added some defines for 12G SAS speeds. - * 04-09-13 02.00.25 Added MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK. - * Fixed MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS to - * match the specification. - * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for - * MPI2_CONFIG_PAGE_MAN_7. - * Added EnclosureLevel and ConnectorName fields to - * MPI2_CONFIG_PAGE_SAS_DEV_0. - * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for - * MPI2_CONFIG_PAGE_SAS_DEV_0. - * Added EnclosureLevel field to - * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. - * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for - * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. - * 01-08-14 02.00.28 Added more defines for the BiosOptions field of - * MPI2_CONFIG_PAGE_BIOS_1. - * 06-13-14 02.00.29 Added SSUTimeout field to MPI2_CONFIG_PAGE_BIOS_1, and - * more defines for the BiosOptions field. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_CNFG_H -#define MPI2_CNFG_H - -/***************************************************************************** -* Configuration Page Header and defines -*****************************************************************************/ - -/* Config Page Header */ -typedef struct _MPI2_CONFIG_PAGE_HEADER -{ - U8 PageVersion; /* 0x00 */ - U8 PageLength; /* 0x01 */ - U8 PageNumber; /* 0x02 */ - U8 PageType; /* 0x03 */ -} MPI2_CONFIG_PAGE_HEADER, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER, - Mpi2ConfigPageHeader_t, MPI2_POINTER pMpi2ConfigPageHeader_t; - -typedef union _MPI2_CONFIG_PAGE_HEADER_UNION -{ - MPI2_CONFIG_PAGE_HEADER Struct; - U8 Bytes[4]; - U16 Word16[2]; - U32 Word32; -} MPI2_CONFIG_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER_UNION, - Mpi2ConfigPageHeaderUnion, MPI2_POINTER pMpi2ConfigPageHeaderUnion; - -/* Extended Config Page Header */ -typedef struct _MPI2_CONFIG_EXTENDED_PAGE_HEADER -{ - U8 PageVersion; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 PageNumber; /* 0x02 */ - U8 PageType; /* 0x03 */ - U16 ExtPageLength; /* 0x04 */ - U8 ExtPageType; /* 0x06 */ - U8 Reserved2; /* 0x07 */ -} MPI2_CONFIG_EXTENDED_PAGE_HEADER, - MPI2_POINTER PTR_MPI2_CONFIG_EXTENDED_PAGE_HEADER, - Mpi2ConfigExtendedPageHeader_t, MPI2_POINTER pMpi2ConfigExtendedPageHeader_t; - -typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION -{ - MPI2_CONFIG_PAGE_HEADER Struct; - MPI2_CONFIG_EXTENDED_PAGE_HEADER Ext; - U8 Bytes[8]; - U16 Word16[4]; - U32 Word32[2]; -} MPI2_CONFIG_EXT_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_EXT_PAGE_HEADER_UNION, - Mpi2ConfigPageExtendedHeaderUnion, MPI2_POINTER pMpi2ConfigPageExtendedHeaderUnion; - - -/* PageType field values */ -#define MPI2_CONFIG_PAGEATTR_READ_ONLY (0x00) -#define MPI2_CONFIG_PAGEATTR_CHANGEABLE (0x10) -#define MPI2_CONFIG_PAGEATTR_PERSISTENT (0x20) -#define MPI2_CONFIG_PAGEATTR_MASK (0xF0) - -#define MPI2_CONFIG_PAGETYPE_IO_UNIT (0x00) -#define MPI2_CONFIG_PAGETYPE_IOC (0x01) -#define MPI2_CONFIG_PAGETYPE_BIOS (0x02) -#define MPI2_CONFIG_PAGETYPE_RAID_VOLUME (0x08) -#define MPI2_CONFIG_PAGETYPE_MANUFACTURING (0x09) -#define MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A) -#define MPI2_CONFIG_PAGETYPE_EXTENDED (0x0F) -#define MPI2_CONFIG_PAGETYPE_MASK (0x0F) - -#define MPI2_CONFIG_TYPENUM_MASK (0x0FFF) - - -/* ExtPageType field values */ -#define MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT (0x10) -#define MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER (0x11) -#define MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE (0x12) -#define MPI2_CONFIG_EXTPAGETYPE_SAS_PHY (0x13) -#define MPI2_CONFIG_EXTPAGETYPE_LOG (0x14) -#define MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE (0x15) -#define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16) -#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) -#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) -#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19) -#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A) - - -/***************************************************************************** -* PageAddress defines -*****************************************************************************/ - -/* RAID Volume PageAddress format */ -#define MPI2_RAID_VOLUME_PGAD_FORM_MASK (0xF0000000) -#define MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) -#define MPI2_RAID_VOLUME_PGAD_FORM_HANDLE (0x10000000) - -#define MPI2_RAID_VOLUME_PGAD_HANDLE_MASK (0x0000FFFF) - - -/* RAID Physical Disk PageAddress format */ -#define MPI2_PHYSDISK_PGAD_FORM_MASK (0xF0000000) -#define MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM (0x00000000) -#define MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM (0x10000000) -#define MPI2_PHYSDISK_PGAD_FORM_DEVHANDLE (0x20000000) - -#define MPI2_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF) -#define MPI2_PHYSDISK_PGAD_DEVHANDLE_MASK (0x0000FFFF) - - -/* SAS Expander PageAddress format */ -#define MPI2_SAS_EXPAND_PGAD_FORM_MASK (0xF0000000) -#define MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL (0x00000000) -#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM (0x10000000) -#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL (0x20000000) - -#define MPI2_SAS_EXPAND_PGAD_HANDLE_MASK (0x0000FFFF) -#define MPI2_SAS_EXPAND_PGAD_PHYNUM_MASK (0x00FF0000) -#define MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT (16) - - -/* SAS Device PageAddress format */ -#define MPI2_SAS_DEVICE_PGAD_FORM_MASK (0xF0000000) -#define MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) -#define MPI2_SAS_DEVICE_PGAD_FORM_HANDLE (0x20000000) - -#define MPI2_SAS_DEVICE_PGAD_HANDLE_MASK (0x0000FFFF) - - -/* SAS PHY PageAddress format */ -#define MPI2_SAS_PHY_PGAD_FORM_MASK (0xF0000000) -#define MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER (0x00000000) -#define MPI2_SAS_PHY_PGAD_FORM_PHY_TBL_INDEX (0x10000000) - -#define MPI2_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x000000FF) -#define MPI2_SAS_PHY_PGAD_PHY_TBL_INDEX_MASK (0x0000FFFF) - - -/* SAS Port PageAddress format */ -#define MPI2_SASPORT_PGAD_FORM_MASK (0xF0000000) -#define MPI2_SASPORT_PGAD_FORM_GET_NEXT_PORT (0x00000000) -#define MPI2_SASPORT_PGAD_FORM_PORT_NUM (0x10000000) - -#define MPI2_SASPORT_PGAD_PORTNUMBER_MASK (0x00000FFF) - - -/* SAS Enclosure PageAddress format */ -#define MPI2_SAS_ENCLOS_PGAD_FORM_MASK (0xF0000000) -#define MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) -#define MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE (0x10000000) - -#define MPI2_SAS_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF) - - -/* RAID Configuration PageAddress format */ -#define MPI2_RAID_PGAD_FORM_MASK (0xF0000000) -#define MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM (0x00000000) -#define MPI2_RAID_PGAD_FORM_CONFIGNUM (0x10000000) -#define MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG (0x20000000) - -#define MPI2_RAID_PGAD_CONFIGNUM_MASK (0x000000FF) - - -/* Driver Persistent Mapping PageAddress format */ -#define MPI2_DPM_PGAD_FORM_MASK (0xF0000000) -#define MPI2_DPM_PGAD_FORM_ENTRY_RANGE (0x00000000) - -#define MPI2_DPM_PGAD_ENTRY_COUNT_MASK (0x0FFF0000) -#define MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT (16) -#define MPI2_DPM_PGAD_START_ENTRY_MASK (0x0000FFFF) - - -/* Ethernet PageAddress format */ -#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000) -#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000) - -#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF) - - - -/**************************************************************************** -* Configuration messages -****************************************************************************/ - -/* Configuration Request Message */ -typedef struct _MPI2_CONFIG_REQUEST -{ - U8 Action; /* 0x00 */ - U8 SGLFlags; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 ExtPageLength; /* 0x04 */ - U8 ExtPageType; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U8 Reserved2; /* 0x0C */ - U8 ProxyVF_ID; /* 0x0D */ - U16 Reserved4; /* 0x0E */ - U32 Reserved3; /* 0x10 */ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */ - U32 PageAddress; /* 0x18 */ - MPI2_SGE_IO_UNION PageBufferSGE; /* 0x1C */ -} MPI2_CONFIG_REQUEST, MPI2_POINTER PTR_MPI2_CONFIG_REQUEST, - Mpi2ConfigRequest_t, MPI2_POINTER pMpi2ConfigRequest_t; - -/* values for the Action field */ -#define MPI2_CONFIG_ACTION_PAGE_HEADER (0x00) -#define MPI2_CONFIG_ACTION_PAGE_READ_CURRENT (0x01) -#define MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT (0x02) -#define MPI2_CONFIG_ACTION_PAGE_DEFAULT (0x03) -#define MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM (0x04) -#define MPI2_CONFIG_ACTION_PAGE_READ_DEFAULT (0x05) -#define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06) -#define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07) - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -/* Config Reply Message */ -typedef struct _MPI2_CONFIG_REPLY -{ - U8 Action; /* 0x00 */ - U8 SGLFlags; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 ExtPageLength; /* 0x04 */ - U8 ExtPageType; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U16 Reserved2; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */ -} MPI2_CONFIG_REPLY, MPI2_POINTER PTR_MPI2_CONFIG_REPLY, - Mpi2ConfigReply_t, MPI2_POINTER pMpi2ConfigReply_t; - - - -/***************************************************************************** -* -* C o n f i g u r a t i o n P a g e s -* -*****************************************************************************/ - -/**************************************************************************** -* Manufacturing Config pages -****************************************************************************/ - -#define MPI2_MFGPAGE_VENDORID_LSI (0x1000) - -/* SAS */ -#define MPI2_MFGPAGE_DEVID_SAS2004 (0x0070) -#define MPI2_MFGPAGE_DEVID_SAS2008 (0x0072) -#define MPI2_MFGPAGE_DEVID_SAS2108_1 (0x0074) -#define MPI2_MFGPAGE_DEVID_SAS2108_2 (0x0076) -#define MPI2_MFGPAGE_DEVID_SAS2108_3 (0x0077) -#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064) -#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065) - -#define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E) - -#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080) -#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081) -#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082) -#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) -#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) -#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) -#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086) -#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087) -#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E) - - - - -/* Manufacturing Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_MAN_0 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 ChipName[16]; /* 0x04 */ - U8 ChipRevision[8]; /* 0x14 */ - U8 BoardName[16]; /* 0x1C */ - U8 BoardAssembly[16]; /* 0x2C */ - U8 BoardTracerNumber[16]; /* 0x3C */ -} MPI2_CONFIG_PAGE_MAN_0, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_0, - Mpi2ManufacturingPage0_t, MPI2_POINTER pMpi2ManufacturingPage0_t; - -#define MPI2_MANUFACTURING0_PAGEVERSION (0x00) - - -/* Manufacturing Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_MAN_1 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 VPD[256]; /* 0x04 */ -} MPI2_CONFIG_PAGE_MAN_1, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_1, - Mpi2ManufacturingPage1_t, MPI2_POINTER pMpi2ManufacturingPage1_t; - -#define MPI2_MANUFACTURING1_PAGEVERSION (0x00) - - -typedef struct _MPI2_CHIP_REVISION_ID -{ - U16 DeviceID; /* 0x00 */ - U8 PCIRevisionID; /* 0x02 */ - U8 Reserved; /* 0x03 */ -} MPI2_CHIP_REVISION_ID, MPI2_POINTER PTR_MPI2_CHIP_REVISION_ID, - Mpi2ChipRevisionId_t, MPI2_POINTER pMpi2ChipRevisionId_t; - - -/* Manufacturing Page 2 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength at runtime. - */ -#ifndef MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS -#define MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_MAN_2 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */ - U32 HwSettings[MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS];/* 0x08 */ -} MPI2_CONFIG_PAGE_MAN_2, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_2, - Mpi2ManufacturingPage2_t, MPI2_POINTER pMpi2ManufacturingPage2_t; - -#define MPI2_MANUFACTURING2_PAGEVERSION (0x00) - - -/* Manufacturing Page 3 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength at runtime. - */ -#ifndef MPI2_MAN_PAGE_3_INFO_WORDS -#define MPI2_MAN_PAGE_3_INFO_WORDS (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_MAN_3 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */ - U32 Info[MPI2_MAN_PAGE_3_INFO_WORDS];/* 0x08 */ -} MPI2_CONFIG_PAGE_MAN_3, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_3, - Mpi2ManufacturingPage3_t, MPI2_POINTER pMpi2ManufacturingPage3_t; - -#define MPI2_MANUFACTURING3_PAGEVERSION (0x00) - - -/* Manufacturing Page 4 */ - -typedef struct _MPI2_MANPAGE4_PWR_SAVE_SETTINGS -{ - U8 PowerSaveFlags; /* 0x00 */ - U8 InternalOperationsSleepTime; /* 0x01 */ - U8 InternalOperationsRunTime; /* 0x02 */ - U8 HostIdleTime; /* 0x03 */ -} MPI2_MANPAGE4_PWR_SAVE_SETTINGS, - MPI2_POINTER PTR_MPI2_MANPAGE4_PWR_SAVE_SETTINGS, - Mpi2ManPage4PwrSaveSettings_t, MPI2_POINTER pMpi2ManPage4PwrSaveSettings_t; - -/* defines for the PowerSaveFlags field */ -#define MPI2_MANPAGE4_MASK_POWERSAVE_MODE (0x03) -#define MPI2_MANPAGE4_POWERSAVE_MODE_DISABLED (0x00) -#define MPI2_MANPAGE4_CUSTOM_POWERSAVE_MODE (0x01) -#define MPI2_MANPAGE4_FULL_POWERSAVE_MODE (0x02) - -typedef struct _MPI2_CONFIG_PAGE_MAN_4 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Flags; /* 0x08 */ - U8 InquirySize; /* 0x0C */ - U8 Reserved2; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - U8 InquiryData[56]; /* 0x10 */ - U32 RAID0VolumeSettings; /* 0x48 */ - U32 RAID1EVolumeSettings; /* 0x4C */ - U32 RAID1VolumeSettings; /* 0x50 */ - U32 RAID10VolumeSettings; /* 0x54 */ - U32 Reserved4; /* 0x58 */ - U32 Reserved5; /* 0x5C */ - MPI2_MANPAGE4_PWR_SAVE_SETTINGS PowerSaveSettings; /* 0x60 */ - U8 MaxOCEDisks; /* 0x64 */ - U8 ResyncRate; /* 0x65 */ - U16 DataScrubDuration; /* 0x66 */ - U8 MaxHotSpares; /* 0x68 */ - U8 MaxPhysDisksPerVol; /* 0x69 */ - U8 MaxPhysDisks; /* 0x6A */ - U8 MaxVolumes; /* 0x6B */ -} MPI2_CONFIG_PAGE_MAN_4, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_4, - Mpi2ManufacturingPage4_t, MPI2_POINTER pMpi2ManufacturingPage4_t; - -#define MPI2_MANUFACTURING4_PAGEVERSION (0x0A) - -/* Manufacturing Page 4 Flags field */ -#define MPI2_MANPAGE4_METADATA_SIZE_MASK (0x00030000) -#define MPI2_MANPAGE4_METADATA_512MB (0x00000000) - -#define MPI2_MANPAGE4_MIX_SSD_SAS_SATA (0x00008000) -#define MPI2_MANPAGE4_MIX_SSD_AND_NON_SSD (0x00004000) -#define MPI2_MANPAGE4_HIDE_PHYSDISK_NON_IR (0x00002000) - -#define MPI2_MANPAGE4_MASK_PHYSDISK_COERCION (0x00001C00) -#define MPI2_MANPAGE4_PHYSDISK_COERCION_1GB (0x00000000) -#define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION (0x00000400) -#define MPI2_MANPAGE4_PHYSDISK_ADAPTIVE_COERCION (0x00000800) -#define MPI2_MANPAGE4_PHYSDISK_ZERO_COERCION (0x00000C00) - -#define MPI2_MANPAGE4_MASK_BAD_BLOCK_MARKING (0x00000300) -#define MPI2_MANPAGE4_DEFAULT_BAD_BLOCK_MARKING (0x00000000) -#define MPI2_MANPAGE4_TABLE_BAD_BLOCK_MARKING (0x00000100) -#define MPI2_MANPAGE4_WRITE_LONG_BAD_BLOCK_MARKING (0x00000200) - -#define MPI2_MANPAGE4_FORCE_OFFLINE_FAILOVER (0x00000080) -#define MPI2_MANPAGE4_RAID10_DISABLE (0x00000040) -#define MPI2_MANPAGE4_RAID1E_DISABLE (0x00000020) -#define MPI2_MANPAGE4_RAID1_DISABLE (0x00000010) -#define MPI2_MANPAGE4_RAID0_DISABLE (0x00000008) -#define MPI2_MANPAGE4_IR_MODEPAGE8_DISABLE (0x00000004) -#define MPI2_MANPAGE4_IM_RESYNC_CACHE_ENABLE (0x00000002) -#define MPI2_MANPAGE4_IR_NO_MIX_SAS_SATA (0x00000001) - - -/* Manufacturing Page 5 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES -#define MPI2_MAN_PAGE_5_PHY_ENTRIES (1) -#endif - -typedef struct _MPI2_MANUFACTURING5_ENTRY -{ - U64 WWID; /* 0x00 */ - U64 DeviceName; /* 0x08 */ -} MPI2_MANUFACTURING5_ENTRY, MPI2_POINTER PTR_MPI2_MANUFACTURING5_ENTRY, - Mpi2Manufacturing5Entry_t, MPI2_POINTER pMpi2Manufacturing5Entry_t; - -typedef struct _MPI2_CONFIG_PAGE_MAN_5 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 NumPhys; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - U32 Reserved3; /* 0x08 */ - U32 Reserved4; /* 0x0C */ - MPI2_MANUFACTURING5_ENTRY Phy[MPI2_MAN_PAGE_5_PHY_ENTRIES];/* 0x08 */ -} MPI2_CONFIG_PAGE_MAN_5, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_5, - Mpi2ManufacturingPage5_t, MPI2_POINTER pMpi2ManufacturingPage5_t; - -#define MPI2_MANUFACTURING5_PAGEVERSION (0x03) - - -/* Manufacturing Page 6 */ - -typedef struct _MPI2_CONFIG_PAGE_MAN_6 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 ProductSpecificInfo;/* 0x04 */ -} MPI2_CONFIG_PAGE_MAN_6, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_6, - Mpi2ManufacturingPage6_t, MPI2_POINTER pMpi2ManufacturingPage6_t; - -#define MPI2_MANUFACTURING6_PAGEVERSION (0x00) - - -/* Manufacturing Page 7 */ - -typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO -{ - U32 Pinout; /* 0x00 */ - U8 Connector[16]; /* 0x04 */ - U8 Location; /* 0x14 */ - U8 ReceptacleID; /* 0x15 */ - U16 Slot; /* 0x16 */ - U32 Reserved2; /* 0x18 */ -} MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO, - Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t; - -/* defines for the Pinout field */ -#define MPI2_MANPAGE7_PINOUT_LANE_MASK (0x0000FF00) -#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT (8) - -#define MPI2_MANPAGE7_PINOUT_TYPE_MASK (0x000000FF) -#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN (0x00) -#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE (0x01) -#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x02) -#define MPI2_MANPAGE7_PINOUT_SFF_8486 (0x03) -#define MPI2_MANPAGE7_PINOUT_SFF_8484 (0x04) -#define MPI2_MANPAGE7_PINOUT_SFF_8087 (0x05) -#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I (0x06) -#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I (0x07) -#define MPI2_MANPAGE7_PINOUT_SFF_8470 (0x08) -#define MPI2_MANPAGE7_PINOUT_SFF_8088 (0x09) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X (0x0A) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C) -#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D) - -/* defines for the Location field */ -#define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01) -#define MPI2_MANPAGE7_LOCATION_INTERNAL (0x02) -#define MPI2_MANPAGE7_LOCATION_EXTERNAL (0x04) -#define MPI2_MANPAGE7_LOCATION_SWITCHABLE (0x08) -#define MPI2_MANPAGE7_LOCATION_AUTO (0x10) -#define MPI2_MANPAGE7_LOCATION_NOT_PRESENT (0x20) -#define MPI2_MANPAGE7_LOCATION_NOT_CONNECTED (0x80) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX -#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_MAN_7 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U32 Flags; /* 0x0C */ - U8 EnclosureName[16]; /* 0x10 */ - U8 NumPhys; /* 0x20 */ - U8 Reserved3; /* 0x21 */ - U16 Reserved4; /* 0x22 */ - MPI2_MANPAGE7_CONNECTOR_INFO ConnectorInfo[MPI2_MANPAGE7_CONNECTOR_INFO_MAX]; /* 0x24 */ -} MPI2_CONFIG_PAGE_MAN_7, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7, - Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t; - -#define MPI2_MANUFACTURING7_PAGEVERSION (0x01) - -/* defines for the Flags field */ -#define MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL (0x00000008) -#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002) -#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) - - -/* - * Generic structure to use for product-specific manufacturing pages - * (currently Manufacturing Page 8 through Manufacturing Page 31). - */ - -typedef struct _MPI2_CONFIG_PAGE_MAN_PS -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 ProductSpecificInfo;/* 0x04 */ -} MPI2_CONFIG_PAGE_MAN_PS, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_PS, - Mpi2ManufacturingPagePS_t, MPI2_POINTER pMpi2ManufacturingPagePS_t; - -#define MPI2_MANUFACTURING8_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING9_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING10_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING11_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING12_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING13_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING14_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING15_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING16_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING17_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING18_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING19_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING20_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING21_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING22_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING23_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING24_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING25_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING26_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING27_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING28_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING29_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING30_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING31_PAGEVERSION (0x00) - - -/**************************************************************************** -* IO Unit Config Pages -****************************************************************************/ - -/* IO Unit Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_0 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U64 UniqueValue; /* 0x04 */ - MPI2_VERSION_UNION NvdataVersionDefault; /* 0x08 */ - MPI2_VERSION_UNION NvdataVersionPersistent; /* 0x0A */ -} MPI2_CONFIG_PAGE_IO_UNIT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_0, - Mpi2IOUnitPage0_t, MPI2_POINTER pMpi2IOUnitPage0_t; - -#define MPI2_IOUNITPAGE0_PAGEVERSION (0x02) - - -/* IO Unit Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Flags; /* 0x04 */ -} MPI2_CONFIG_PAGE_IO_UNIT_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_1, - Mpi2IOUnitPage1_t, MPI2_POINTER pMpi2IOUnitPage1_t; - -#define MPI2_IOUNITPAGE1_PAGEVERSION (0x04) - -/* IO Unit Page 1 Flags defines */ -#define MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK (0x00004000) -#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800) -#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600) -#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9) -#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000) -#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200) -#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400) -#define MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE (0x00000100) -#define MPI2_IOUNITPAGE1_DISABLE_IR (0x00000040) -#define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020) -#define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004) - - -/* IO Unit Page 3 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for GPIOCount at runtime. - */ -#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX -#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 GPIOCount; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - U16 GPIOVal[MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX];/* 0x08 */ -} MPI2_CONFIG_PAGE_IO_UNIT_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_3, - Mpi2IOUnitPage3_t, MPI2_POINTER pMpi2IOUnitPage3_t; - -#define MPI2_IOUNITPAGE3_PAGEVERSION (0x01) - -/* defines for IO Unit Page 3 GPIOVal field */ -#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_MASK (0xFFFC) -#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_SHIFT (2) -#define MPI2_IOUNITPAGE3_GPIO_SETTING_OFF (0x0000) -#define MPI2_IOUNITPAGE3_GPIO_SETTING_ON (0x0001) - - -/* IO Unit Page 5 */ - -/* - * Upper layer code (drivers, utilities, etc.) should leave this define set to - * one and check the value returned for NumDmaEngines at runtime. - */ -#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES -#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U64 RaidAcceleratorBufferBaseAddress; /* 0x04 */ - U64 RaidAcceleratorBufferSize; /* 0x0C */ - U64 RaidAcceleratorControlBaseAddress; /* 0x14 */ - U8 RAControlSize; /* 0x1C */ - U8 NumDmaEngines; /* 0x1D */ - U8 RAMinControlSize; /* 0x1E */ - U8 RAMaxControlSize; /* 0x1F */ - U32 Reserved1; /* 0x20 */ - U32 Reserved2; /* 0x24 */ - U32 Reserved3; /* 0x28 */ - U32 DmaEngineCapabilities - [MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /* 0x2C */ -} MPI2_CONFIG_PAGE_IO_UNIT_5, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_5, - Mpi2IOUnitPage5_t, MPI2_POINTER pMpi2IOUnitPage5_t; - -#define MPI2_IOUNITPAGE5_PAGEVERSION (0x00) - -/* defines for IO Unit Page 5 DmaEngineCapabilities field */ -#define MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS (0xFFFF0000) -#define MPI2_IOUNITPAGE5_DMA_CAP_SHIFT_MAX_REQUESTS (16) - -#define MPI2_IOUNITPAGE5_DMA_CAP_EEDP (0x0008) -#define MPI2_IOUNITPAGE5_DMA_CAP_PARITY_GENERATION (0x0004) -#define MPI2_IOUNITPAGE5_DMA_CAP_HASHING (0x0002) -#define MPI2_IOUNITPAGE5_DMA_CAP_ENCRYPTION (0x0001) - - -/* IO Unit Page 6 */ - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U16 Flags; /* 0x04 */ - U8 RAHostControlSize; /* 0x06 */ - U8 Reserved0; /* 0x07 */ - U64 RaidAcceleratorHostControlBaseAddress; /* 0x08 */ - U32 Reserved1; /* 0x10 */ - U32 Reserved2; /* 0x14 */ - U32 Reserved3; /* 0x18 */ -} MPI2_CONFIG_PAGE_IO_UNIT_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_6, - Mpi2IOUnitPage6_t, MPI2_POINTER pMpi2IOUnitPage6_t; - -#define MPI2_IOUNITPAGE6_PAGEVERSION (0x00) - -/* defines for IO Unit Page 6 Flags field */ -#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001) - - -/* IO Unit Page 7 */ - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U16 Reserved1; /* 0x04 */ - U8 PCIeWidth; /* 0x06 */ - U8 PCIeSpeed; /* 0x07 */ - U32 ProcessorState; /* 0x08 */ - U32 PowerManagementCapabilities; /* 0x0C */ - U16 IOCTemperature; /* 0x10 */ - U8 IOCTemperatureUnits; /* 0x12 */ - U8 IOCSpeed; /* 0x13 */ - U16 BoardTemperature; /* 0x14 */ - U8 BoardTemperatureUnits; /* 0x16 */ - U8 Reserved3; /* 0x17 */ - U32 Reserved4; /* 0x18 */ - U32 Reserved5; /* 0x1C */ - U32 Reserved6; /* 0x20 */ - U32 Reserved7; /* 0x24 */ -} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, - Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t; - -#define MPI2_IOUNITPAGE7_PAGEVERSION (0x04) - -/* defines for IO Unit Page 7 PCIeWidth field */ -#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) -#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02) -#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04) -#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08) - -/* defines for IO Unit Page 7 PCIeSpeed field */ -#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00) -#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01) -#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02) - -/* defines for IO Unit Page 7 ProcessorState field */ -#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F) -#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0) - -#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00) -#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01) -#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02) - -/* defines for IO Unit Page 7 PowerManagementCapabilities field */ -#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400) -#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200) -#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100) -#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) /* obsolete */ -#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) /* obsolete */ - -/* defines for IO Unit Page 7 IOCTemperatureUnits field */ -#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) -#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01) -#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02) - -/* defines for IO Unit Page 7 IOCSpeed field */ -#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01) -#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02) -#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04) -#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08) - -/* defines for IO Unit Page 7 BoardTemperatureUnits field */ -#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT (0x00) -#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01) -#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02) - -/* IO Unit Page 8 */ - -#define MPI2_IOUNIT8_NUM_THRESHOLDS (4) - -typedef struct _MPI2_IOUNIT8_SENSOR { - U16 Flags; /* 0x00 */ - U16 Reserved1; /* 0x02 */ - U16 - Threshold[MPI2_IOUNIT8_NUM_THRESHOLDS]; /* 0x04 */ - U32 Reserved2; /* 0x0C */ - U32 Reserved3; /* 0x10 */ - U32 Reserved4; /* 0x14 */ -} MPI2_IOUNIT8_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT8_SENSOR, -Mpi2IOUnit8Sensor_t, MPI2_POINTER pMpi2IOUnit8Sensor_t; - -/* defines for IO Unit Page 8 Sensor Flags field */ -#define MPI2_IOUNIT8_SENSOR_FLAGS_T3_ENABLE (0x0008) -#define MPI2_IOUNIT8_SENSOR_FLAGS_T2_ENABLE (0x0004) -#define MPI2_IOUNIT8_SENSOR_FLAGS_T1_ENABLE (0x0002) -#define MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE (0x0001) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumSensors at runtime. - */ -#ifndef MPI2_IOUNITPAGE8_SENSOR_ENTRIES -#define MPI2_IOUNITPAGE8_SENSOR_ENTRIES (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U8 NumSensors; /* 0x0C */ - U8 PollingInterval; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_IOUNIT8_SENSOR - Sensor[MPI2_IOUNITPAGE8_SENSOR_ENTRIES];/* 0x10 */ -} MPI2_CONFIG_PAGE_IO_UNIT_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_8, -Mpi2IOUnitPage8_t, MPI2_POINTER pMpi2IOUnitPage8_t; - -#define MPI2_IOUNITPAGE8_PAGEVERSION (0x00) - - -/* IO Unit Page 9 */ - -typedef struct _MPI2_IOUNIT9_SENSOR { - U16 CurrentTemperature; /* 0x00 */ - U16 Reserved1; /* 0x02 */ - U8 Flags; /* 0x04 */ - U8 Reserved2; /* 0x05 */ - U16 Reserved3; /* 0x06 */ - U32 Reserved4; /* 0x08 */ - U32 Reserved5; /* 0x0C */ -} MPI2_IOUNIT9_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT9_SENSOR, -Mpi2IOUnit9Sensor_t, MPI2_POINTER pMpi2IOUnit9Sensor_t; - -/* defines for IO Unit Page 9 Sensor Flags field */ -#define MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID (0x01) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumSensors at runtime. - */ -#ifndef MPI2_IOUNITPAGE9_SENSOR_ENTRIES -#define MPI2_IOUNITPAGE9_SENSOR_ENTRIES (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U8 NumSensors; /* 0x0C */ - U8 Reserved4; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_IOUNIT9_SENSOR - Sensor[MPI2_IOUNITPAGE9_SENSOR_ENTRIES];/* 0x10 */ -} MPI2_CONFIG_PAGE_IO_UNIT_9, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_9, -Mpi2IOUnitPage9_t, MPI2_POINTER pMpi2IOUnitPage9_t; - -#define MPI2_IOUNITPAGE9_PAGEVERSION (0x00) - - -/* IO Unit Page 10 */ - -typedef struct _MPI2_IOUNIT10_FUNCTION { - U8 CreditPercent; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ -} MPI2_IOUNIT10_FUNCTION, MPI2_POINTER PTR_MPI2_IOUNIT10_FUNCTION, -Mpi2IOUnit10Function_t, MPI2_POINTER pMpi2IOUnit10Function_t; - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumFunctions at runtime. - */ -#ifndef MPI2_IOUNITPAGE10_FUNCTION_ENTRIES -#define MPI2_IOUNITPAGE10_FUNCTION_ENTRIES (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 NumFunctions; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - U32 Reserved3; /* 0x08 */ - U32 Reserved4; /* 0x0C */ - MPI2_IOUNIT10_FUNCTION - Function[MPI2_IOUNITPAGE10_FUNCTION_ENTRIES];/* 0x10 */ -} MPI2_CONFIG_PAGE_IO_UNIT_10, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_10, -Mpi2IOUnitPage10_t, MPI2_POINTER pMpi2IOUnitPage10_t; - -#define MPI2_IOUNITPAGE10_PAGEVERSION (0x01) - - - -/**************************************************************************** -* IOC Config Pages -****************************************************************************/ - -/* IOC Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_IOC_0 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U16 VendorID; /* 0x0C */ - U16 DeviceID; /* 0x0E */ - U8 RevisionID; /* 0x10 */ - U8 Reserved3; /* 0x11 */ - U16 Reserved4; /* 0x12 */ - U32 ClassCode; /* 0x14 */ - U16 SubsystemVendorID; /* 0x18 */ - U16 SubsystemID; /* 0x1A */ -} MPI2_CONFIG_PAGE_IOC_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_0, - Mpi2IOCPage0_t, MPI2_POINTER pMpi2IOCPage0_t; - -#define MPI2_IOCPAGE0_PAGEVERSION (0x02) - - -/* IOC Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_IOC_1 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Flags; /* 0x04 */ - U32 CoalescingTimeout; /* 0x08 */ - U8 CoalescingDepth; /* 0x0C */ - U8 PCISlotNum; /* 0x0D */ - U8 PCIBusNum; /* 0x0E */ - U8 PCIDomainSegment; /* 0x0F */ - U32 Reserved1; /* 0x10 */ - U32 Reserved2; /* 0x14 */ -} MPI2_CONFIG_PAGE_IOC_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_1, - Mpi2IOCPage1_t, MPI2_POINTER pMpi2IOCPage1_t; - -#define MPI2_IOCPAGE1_PAGEVERSION (0x05) - -/* defines for IOC Page 1 Flags field */ -#define MPI2_IOCPAGE1_REPLY_COALESCING (0x00000001) - -#define MPI2_IOCPAGE1_PCISLOTNUM_UNKNOWN (0xFF) -#define MPI2_IOCPAGE1_PCIBUSNUM_UNKNOWN (0xFF) -#define MPI2_IOCPAGE1_PCIDOMAIN_UNKNOWN (0xFF) - -/* IOC Page 6 */ - -typedef struct _MPI2_CONFIG_PAGE_IOC_6 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 CapabilitiesFlags; /* 0x04 */ - U8 MaxDrivesRAID0; /* 0x08 */ - U8 MaxDrivesRAID1; /* 0x09 */ - U8 MaxDrivesRAID1E; /* 0x0A */ - U8 MaxDrivesRAID10; /* 0x0B */ - U8 MinDrivesRAID0; /* 0x0C */ - U8 MinDrivesRAID1; /* 0x0D */ - U8 MinDrivesRAID1E; /* 0x0E */ - U8 MinDrivesRAID10; /* 0x0F */ - U32 Reserved1; /* 0x10 */ - U8 MaxGlobalHotSpares; /* 0x14 */ - U8 MaxPhysDisks; /* 0x15 */ - U8 MaxVolumes; /* 0x16 */ - U8 MaxConfigs; /* 0x17 */ - U8 MaxOCEDisks; /* 0x18 */ - U8 Reserved2; /* 0x19 */ - U16 Reserved3; /* 0x1A */ - U32 SupportedStripeSizeMapRAID0; /* 0x1C */ - U32 SupportedStripeSizeMapRAID1E; /* 0x20 */ - U32 SupportedStripeSizeMapRAID10; /* 0x24 */ - U32 Reserved4; /* 0x28 */ - U32 Reserved5; /* 0x2C */ - U16 DefaultMetadataSize; /* 0x30 */ - U16 Reserved6; /* 0x32 */ - U16 MaxBadBlockTableEntries; /* 0x34 */ - U16 Reserved7; /* 0x36 */ - U32 IRNvsramVersion; /* 0x38 */ -} MPI2_CONFIG_PAGE_IOC_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_6, - Mpi2IOCPage6_t, MPI2_POINTER pMpi2IOCPage6_t; - -#define MPI2_IOCPAGE6_PAGEVERSION (0x05) - -/* defines for IOC Page 6 CapabilitiesFlags */ -#define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT (0x00000020) -#define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT (0x00000010) -#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT (0x00000008) -#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT (0x00000004) -#define MPI2_IOCPAGE6_CAP_FLAGS_RAID0_SUPPORT (0x00000002) -#define MPI2_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001) - - -/* IOC Page 7 */ - -#define MPI2_IOCPAGE7_EVENTMASK_WORDS (4) - -typedef struct _MPI2_CONFIG_PAGE_IOC_7 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 EventMasks[MPI2_IOCPAGE7_EVENTMASK_WORDS];/* 0x08 */ - U16 SASBroadcastPrimitiveMasks; /* 0x18 */ - U16 SASNotifyPrimitiveMasks; /* 0x1A */ - U32 Reserved3; /* 0x1C */ -} MPI2_CONFIG_PAGE_IOC_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_7, - Mpi2IOCPage7_t, MPI2_POINTER pMpi2IOCPage7_t; - -#define MPI2_IOCPAGE7_PAGEVERSION (0x02) - - -/* IOC Page 8 */ - -typedef struct _MPI2_CONFIG_PAGE_IOC_8 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 NumDevsPerEnclosure; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - U16 MaxPersistentEntries; /* 0x08 */ - U16 MaxNumPhysicalMappedIDs; /* 0x0A */ - U16 Flags; /* 0x0C */ - U16 Reserved3; /* 0x0E */ - U16 IRVolumeMappingFlags; /* 0x10 */ - U16 Reserved4; /* 0x12 */ - U32 Reserved5; /* 0x14 */ -} MPI2_CONFIG_PAGE_IOC_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_8, - Mpi2IOCPage8_t, MPI2_POINTER pMpi2IOCPage8_t; - -#define MPI2_IOCPAGE8_PAGEVERSION (0x00) - -/* defines for IOC Page 8 Flags field */ -#define MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1 (0x00000020) -#define MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0 (0x00000010) - -#define MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE (0x0000000E) -#define MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING (0x00000000) -#define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING (0x00000002) - -#define MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING (0x00000001) -#define MPI2_IOCPAGE8_FLAGS_ENABLE_PERSISTENT_MAPPING (0x00000000) - -/* defines for IOC Page 8 IRVolumeMappingFlags */ -#define MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE (0x00000003) -#define MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING (0x00000000) -#define MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING (0x00000001) - - -/**************************************************************************** -* BIOS Config Pages -****************************************************************************/ - -/* BIOS Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_BIOS_1 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 BiosOptions; /* 0x04 */ - U32 IOCSettings; /* 0x08 */ - U8 SSUTimeout; /* 0x0C */ - U8 Reserved1; /* 0x0D */ - U16 Reserved2; /* 0x0E */ - U32 DeviceSettings; /* 0x10 */ - U16 NumberOfDevices; /* 0x14 */ - U16 UEFIVersion; /* 0x16 */ - U16 IOTimeoutBlockDevicesNonRM; /* 0x18 */ - U16 IOTimeoutSequential; /* 0x1A */ - U16 IOTimeoutOther; /* 0x1C */ - U16 IOTimeoutBlockDevicesRM; /* 0x1E */ -} MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1, - Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t; - -#define MPI2_BIOSPAGE1_PAGEVERSION (0x07) - -/* values for BIOS Page 1 BiosOptions field */ -#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800) -#define MPI2_BIOSPAGE1_OPTIONS_PNS_PBDHL (0x00000000) -#define MPI2_BIOSPAGE1_OPTIONS_PNS_ENCSLOSURE (0x00000800) -#define MPI2_BIOSPAGE1_OPTIONS_PNS_LWWID (0x00001000) -#define MPI2_BIOSPAGE1_OPTIONS_PNS_PSENS (0x00001800) -#define MPI2_BIOSPAGE1_OPTIONS_PNS_ESPHY (0x00002000) - -#define MPI2_BIOSPAGE1_OPTIONS_X86_DISABLE_BIOS (0x00000400) - -#define MPI2_BIOSPAGE1_OPTIONS_MASK_REGISTRATION_UEFI_BSD (0x00000300) -#define MPI2_BIOSPAGE1_OPTIONS_USE_BIT0_REGISTRATION_UEFI_BSD (0x00000000) -#define MPI2_BIOSPAGE1_OPTIONS_FULL_REGISTRATION_UEFI_BSD (0x00000100) -#define MPI2_BIOSPAGE1_OPTIONS_ADAPTER_REGISTRATION_UEFI_BSD (0x00000200) -#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_REGISTRATION_UEFI_BSD (0x00000300) - -#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0) -#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000) - -#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION (0x00000006) -#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII (0x00000000) -#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII (0x00000002) -#define MPI2_BIOSPAGE1_OPTIONS_VERSION_CHECK_UEFI_HII (0x00000004) - -#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) - -/* values for BIOS Page 1 IOCSettings field */ -#define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000) -#define MPI2_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT (0x00000000) -#define MPI2_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT (0x00010000) - -#define MPI2_BIOSPAGE1_IOCSET_MASK_RM_SETTING (0x000000C0) -#define MPI2_BIOSPAGE1_IOCSET_NONE_RM_SETTING (0x00000000) -#define MPI2_BIOSPAGE1_IOCSET_BOOT_RM_SETTING (0x00000040) -#define MPI2_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING (0x00000080) - -#define MPI2_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT (0x00000030) -#define MPI2_BIOSPAGE1_IOCSET_NO_SUPPORT (0x00000000) -#define MPI2_BIOSPAGE1_IOCSET_BIOS_SUPPORT (0x00000010) -#define MPI2_BIOSPAGE1_IOCSET_OS_SUPPORT (0x00000020) -#define MPI2_BIOSPAGE1_IOCSET_ALL_SUPPORT (0x00000030) - -#define MPI2_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008) - -/* values for BIOS Page 1 DeviceSettings field */ -#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING (0x00000010) -#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008) -#define MPI2_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004) -#define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002) -#define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001) - -/* defines for BIOS Page 1 UEFIVersion field */ -#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_MASK (0xFF00) -#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_SHIFT (8) -#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_MASK (0x00FF) -#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_SHIFT (0) - - - -/* BIOS Page 2 */ - -typedef struct _MPI2_BOOT_DEVICE_ADAPTER_ORDER -{ - U32 Reserved1; /* 0x00 */ - U32 Reserved2; /* 0x04 */ - U32 Reserved3; /* 0x08 */ - U32 Reserved4; /* 0x0C */ - U32 Reserved5; /* 0x10 */ - U32 Reserved6; /* 0x14 */ -} MPI2_BOOT_DEVICE_ADAPTER_ORDER, - MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ADAPTER_ORDER, - Mpi2BootDeviceAdapterOrder_t, MPI2_POINTER pMpi2BootDeviceAdapterOrder_t; - -typedef struct _MPI2_BOOT_DEVICE_SAS_WWID -{ - U64 SASAddress; /* 0x00 */ - U8 LUN[8]; /* 0x08 */ - U32 Reserved1; /* 0x10 */ - U32 Reserved2; /* 0x14 */ -} MPI2_BOOT_DEVICE_SAS_WWID, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_SAS_WWID, - Mpi2BootDeviceSasWwid_t, MPI2_POINTER pMpi2BootDeviceSasWwid_t; - -typedef struct _MPI2_BOOT_DEVICE_ENCLOSURE_SLOT -{ - U64 EnclosureLogicalID; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 Reserved2; /* 0x0C */ - U16 SlotNumber; /* 0x10 */ - U16 Reserved3; /* 0x12 */ - U32 Reserved4; /* 0x14 */ -} MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, - MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, - Mpi2BootDeviceEnclosureSlot_t, MPI2_POINTER pMpi2BootDeviceEnclosureSlot_t; - -typedef struct _MPI2_BOOT_DEVICE_DEVICE_NAME -{ - U64 DeviceName; /* 0x00 */ - U8 LUN[8]; /* 0x08 */ - U32 Reserved1; /* 0x10 */ - U32 Reserved2; /* 0x14 */ -} MPI2_BOOT_DEVICE_DEVICE_NAME, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_DEVICE_NAME, - Mpi2BootDeviceDeviceName_t, MPI2_POINTER pMpi2BootDeviceDeviceName_t; - -typedef union _MPI2_MPI2_BIOSPAGE2_BOOT_DEVICE -{ - MPI2_BOOT_DEVICE_ADAPTER_ORDER AdapterOrder; - MPI2_BOOT_DEVICE_SAS_WWID SasWwid; - MPI2_BOOT_DEVICE_ENCLOSURE_SLOT EnclosureSlot; - MPI2_BOOT_DEVICE_DEVICE_NAME DeviceName; -} MPI2_BIOSPAGE2_BOOT_DEVICE, MPI2_POINTER PTR_MPI2_BIOSPAGE2_BOOT_DEVICE, - Mpi2BiosPage2BootDevice_t, MPI2_POINTER pMpi2BiosPage2BootDevice_t; - -typedef struct _MPI2_CONFIG_PAGE_BIOS_2 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U32 Reserved3; /* 0x0C */ - U32 Reserved4; /* 0x10 */ - U32 Reserved5; /* 0x14 */ - U32 Reserved6; /* 0x18 */ - U8 ReqBootDeviceForm; /* 0x1C */ - U8 Reserved7; /* 0x1D */ - U16 Reserved8; /* 0x1E */ - MPI2_BIOSPAGE2_BOOT_DEVICE RequestedBootDevice; /* 0x20 */ - U8 ReqAltBootDeviceForm; /* 0x38 */ - U8 Reserved9; /* 0x39 */ - U16 Reserved10; /* 0x3A */ - MPI2_BIOSPAGE2_BOOT_DEVICE RequestedAltBootDevice; /* 0x3C */ - U8 CurrentBootDeviceForm; /* 0x58 */ - U8 Reserved11; /* 0x59 */ - U16 Reserved12; /* 0x5A */ - MPI2_BIOSPAGE2_BOOT_DEVICE CurrentBootDevice; /* 0x58 */ -} MPI2_CONFIG_PAGE_BIOS_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_2, - Mpi2BiosPage2_t, MPI2_POINTER pMpi2BiosPage2_t; - -#define MPI2_BIOSPAGE2_PAGEVERSION (0x04) - -/* values for BIOS Page 2 BootDeviceForm fields */ -#define MPI2_BIOSPAGE2_FORM_MASK (0x0F) -#define MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED (0x00) -#define MPI2_BIOSPAGE2_FORM_SAS_WWID (0x05) -#define MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06) -#define MPI2_BIOSPAGE2_FORM_DEVICE_NAME (0x07) - - -/* BIOS Page 3 */ - -typedef struct _MPI2_ADAPTER_INFO -{ - U8 PciBusNumber; /* 0x00 */ - U8 PciDeviceAndFunctionNumber; /* 0x01 */ - U16 AdapterFlags; /* 0x02 */ -} MPI2_ADAPTER_INFO, MPI2_POINTER PTR_MPI2_ADAPTER_INFO, - Mpi2AdapterInfo_t, MPI2_POINTER pMpi2AdapterInfo_t; - -#define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001) -#define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002) - -typedef struct _MPI2_CONFIG_PAGE_BIOS_3 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 GlobalFlags; /* 0x04 */ - U32 BiosVersion; /* 0x08 */ - MPI2_ADAPTER_INFO AdapterOrder[4]; /* 0x0C */ - U32 Reserved1; /* 0x1C */ -} MPI2_CONFIG_PAGE_BIOS_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_3, - Mpi2BiosPage3_t, MPI2_POINTER pMpi2BiosPage3_t; - -#define MPI2_BIOSPAGE3_PAGEVERSION (0x00) - -/* values for BIOS Page 3 GlobalFlags */ -#define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR (0x00000002) -#define MPI2_BIOSPAGE3_FLAGS_VERBOSE_ENABLE (0x00000004) -#define MPI2_BIOSPAGE3_FLAGS_HOOK_INT_40_DISABLE (0x00000010) - -#define MPI2_BIOSPAGE3_FLAGS_DEV_LIST_DISPLAY_MASK (0x000000E0) -#define MPI2_BIOSPAGE3_FLAGS_INSTALLED_DEV_DISPLAY (0x00000000) -#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DISPLAY (0x00000020) -#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DEV_DISPLAY (0x00000040) - - -/* BIOS Page 4 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES -#define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1) -#endif - -typedef struct _MPI2_BIOS4_ENTRY -{ - U64 ReassignmentWWID; /* 0x00 */ - U64 ReassignmentDeviceName; /* 0x08 */ -} MPI2_BIOS4_ENTRY, MPI2_POINTER PTR_MPI2_BIOS4_ENTRY, - Mpi2MBios4Entry_t, MPI2_POINTER pMpi2Bios4Entry_t; - -typedef struct _MPI2_CONFIG_PAGE_BIOS_4 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 NumPhys; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - MPI2_BIOS4_ENTRY Phy[MPI2_BIOS_PAGE_4_PHY_ENTRIES]; /* 0x08 */ -} MPI2_CONFIG_PAGE_BIOS_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_4, - Mpi2BiosPage4_t, MPI2_POINTER pMpi2BiosPage4_t; - -#define MPI2_BIOSPAGE4_PAGEVERSION (0x01) - - -/**************************************************************************** -* RAID Volume Config Pages -****************************************************************************/ - -/* RAID Volume Page 0 */ - -typedef struct _MPI2_RAIDVOL0_PHYS_DISK -{ - U8 RAIDSetNum; /* 0x00 */ - U8 PhysDiskMap; /* 0x01 */ - U8 PhysDiskNum; /* 0x02 */ - U8 Reserved; /* 0x03 */ -} MPI2_RAIDVOL0_PHYS_DISK, MPI2_POINTER PTR_MPI2_RAIDVOL0_PHYS_DISK, - Mpi2RaidVol0PhysDisk_t, MPI2_POINTER pMpi2RaidVol0PhysDisk_t; - -/* defines for the PhysDiskMap field */ -#define MPI2_RAIDVOL0_PHYSDISK_PRIMARY (0x01) -#define MPI2_RAIDVOL0_PHYSDISK_SECONDARY (0x02) - -typedef struct _MPI2_RAIDVOL0_SETTINGS -{ - U16 Settings; /* 0x00 */ - U8 HotSparePool; /* 0x01 */ - U8 Reserved; /* 0x02 */ -} MPI2_RAIDVOL0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDVOL0_SETTINGS, - Mpi2RaidVol0Settings_t, MPI2_POINTER pMpi2RaidVol0Settings_t; - -/* RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */ -#define MPI2_RAID_HOT_SPARE_POOL_0 (0x01) -#define MPI2_RAID_HOT_SPARE_POOL_1 (0x02) -#define MPI2_RAID_HOT_SPARE_POOL_2 (0x04) -#define MPI2_RAID_HOT_SPARE_POOL_3 (0x08) -#define MPI2_RAID_HOT_SPARE_POOL_4 (0x10) -#define MPI2_RAID_HOT_SPARE_POOL_5 (0x20) -#define MPI2_RAID_HOT_SPARE_POOL_6 (0x40) -#define MPI2_RAID_HOT_SPARE_POOL_7 (0x80) - -/* RAID Volume Page 0 VolumeSettings defines */ -#define MPI2_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0008) -#define MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE (0x0004) - -#define MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING (0x0003) -#define MPI2_RAIDVOL0_SETTING_UNCHANGED (0x0000) -#define MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING (0x0001) -#define MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING (0x0002) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhysDisks at runtime. - */ -#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX -#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U16 DevHandle; /* 0x04 */ - U8 VolumeState; /* 0x06 */ - U8 VolumeType; /* 0x07 */ - U32 VolumeStatusFlags; /* 0x08 */ - MPI2_RAIDVOL0_SETTINGS VolumeSettings; /* 0x0C */ - U64 MaxLBA; /* 0x10 */ - U32 StripeSize; /* 0x18 */ - U16 BlockSize; /* 0x1C */ - U16 Reserved1; /* 0x1E */ - U8 SupportedPhysDisks; /* 0x20 */ - U8 ResyncRate; /* 0x21 */ - U16 DataScrubDuration; /* 0x22 */ - U8 NumPhysDisks; /* 0x24 */ - U8 Reserved2; /* 0x25 */ - U8 Reserved3; /* 0x26 */ - U8 InactiveStatus; /* 0x27 */ - MPI2_RAIDVOL0_PHYS_DISK PhysDisk[MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX]; /* 0x28 */ -} MPI2_CONFIG_PAGE_RAID_VOL_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_0, - Mpi2RaidVolPage0_t, MPI2_POINTER pMpi2RaidVolPage0_t; - -#define MPI2_RAIDVOLPAGE0_PAGEVERSION (0x0A) - -/* values for RAID VolumeState */ -#define MPI2_RAID_VOL_STATE_MISSING (0x00) -#define MPI2_RAID_VOL_STATE_FAILED (0x01) -#define MPI2_RAID_VOL_STATE_INITIALIZING (0x02) -#define MPI2_RAID_VOL_STATE_ONLINE (0x03) -#define MPI2_RAID_VOL_STATE_DEGRADED (0x04) -#define MPI2_RAID_VOL_STATE_OPTIMAL (0x05) - -/* values for RAID VolumeType */ -#define MPI2_RAID_VOL_TYPE_RAID0 (0x00) -#define MPI2_RAID_VOL_TYPE_RAID1E (0x01) -#define MPI2_RAID_VOL_TYPE_RAID1 (0x02) -#define MPI2_RAID_VOL_TYPE_RAID10 (0x05) -#define MPI2_RAID_VOL_TYPE_UNKNOWN (0xFF) - -/* values for RAID Volume Page 0 VolumeStatusFlags field */ -#define MPI2_RAIDVOL0_STATUS_FLAG_PENDING_RESYNC (0x02000000) -#define MPI2_RAIDVOL0_STATUS_FLAG_BACKG_INIT_PENDING (0x01000000) -#define MPI2_RAIDVOL0_STATUS_FLAG_MDC_PENDING (0x00800000) -#define MPI2_RAIDVOL0_STATUS_FLAG_USER_CONSIST_PENDING (0x00400000) -#define MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT (0x00200000) -#define MPI2_RAIDVOL0_STATUS_FLAG_DATA_SCRUB (0x00100000) -#define MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK (0x00080000) -#define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000) -#define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000) -#define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000) -#define MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT (0x00000080) -#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040) -#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020) -#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000) -#define MPI2_RAIDVOL0_STATUS_FLAG_1E_ADJACENT_MIRROR (0x00000010) -#define MPI2_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL (0x00000008) -#define MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE (0x00000004) -#define MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED (0x00000002) -#define MPI2_RAIDVOL0_STATUS_FLAG_ENABLED (0x00000001) - -/* values for RAID Volume Page 0 SupportedPhysDisks field */ -#define MPI2_RAIDVOL0_SUPPORT_SOLID_STATE_DISKS (0x08) -#define MPI2_RAIDVOL0_SUPPORT_HARD_DISKS (0x04) -#define MPI2_RAIDVOL0_SUPPORT_SAS_PROTOCOL (0x02) -#define MPI2_RAIDVOL0_SUPPORT_SATA_PROTOCOL (0x01) - -/* values for RAID Volume Page 0 InactiveStatus field */ -#define MPI2_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00) -#define MPI2_RAIDVOLPAGE0_STALE_METADATA_INACTIVE (0x01) -#define MPI2_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE (0x02) -#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE (0x03) -#define MPI2_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE (0x04) -#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE (0x05) -#define MPI2_RAIDVOLPAGE0_PREVIOUSLY_DELETED (0x06) - - -/* RAID Volume Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_1 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U16 DevHandle; /* 0x04 */ - U16 Reserved0; /* 0x06 */ - U8 GUID[24]; /* 0x08 */ - U8 Name[16]; /* 0x20 */ - U64 WWID; /* 0x30 */ - U32 Reserved1; /* 0x38 */ - U32 Reserved2; /* 0x3C */ -} MPI2_CONFIG_PAGE_RAID_VOL_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_1, - Mpi2RaidVolPage1_t, MPI2_POINTER pMpi2RaidVolPage1_t; - -#define MPI2_RAIDVOLPAGE1_PAGEVERSION (0x03) - - -/**************************************************************************** -* RAID Physical Disk Config Pages -****************************************************************************/ - -/* RAID Physical Disk Page 0 */ - -typedef struct _MPI2_RAIDPHYSDISK0_SETTINGS -{ - U16 Reserved1; /* 0x00 */ - U8 HotSparePool; /* 0x02 */ - U8 Reserved2; /* 0x03 */ -} MPI2_RAIDPHYSDISK0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_SETTINGS, - Mpi2RaidPhysDisk0Settings_t, MPI2_POINTER pMpi2RaidPhysDisk0Settings_t; - -/* use MPI2_RAID_HOT_SPARE_POOL_ defines for the HotSparePool field */ - -typedef struct _MPI2_RAIDPHYSDISK0_INQUIRY_DATA -{ - U8 VendorID[8]; /* 0x00 */ - U8 ProductID[16]; /* 0x08 */ - U8 ProductRevLevel[4]; /* 0x18 */ - U8 SerialNum[32]; /* 0x1C */ -} MPI2_RAIDPHYSDISK0_INQUIRY_DATA, - MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_INQUIRY_DATA, - Mpi2RaidPhysDisk0InquiryData_t, MPI2_POINTER pMpi2RaidPhysDisk0InquiryData_t; - -typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U16 DevHandle; /* 0x04 */ - U8 Reserved1; /* 0x06 */ - U8 PhysDiskNum; /* 0x07 */ - MPI2_RAIDPHYSDISK0_SETTINGS PhysDiskSettings; /* 0x08 */ - U32 Reserved2; /* 0x0C */ - MPI2_RAIDPHYSDISK0_INQUIRY_DATA InquiryData; /* 0x10 */ - U32 Reserved3; /* 0x4C */ - U8 PhysDiskState; /* 0x50 */ - U8 OfflineReason; /* 0x51 */ - U8 IncompatibleReason; /* 0x52 */ - U8 PhysDiskAttributes; /* 0x53 */ - U32 PhysDiskStatusFlags; /* 0x54 */ - U64 DeviceMaxLBA; /* 0x58 */ - U64 HostMaxLBA; /* 0x60 */ - U64 CoercedMaxLBA; /* 0x68 */ - U16 BlockSize; /* 0x70 */ - U16 Reserved5; /* 0x72 */ - U32 Reserved6; /* 0x74 */ -} MPI2_CONFIG_PAGE_RD_PDISK_0, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_0, - Mpi2RaidPhysDiskPage0_t, MPI2_POINTER pMpi2RaidPhysDiskPage0_t; - -#define MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION (0x05) - -/* PhysDiskState defines */ -#define MPI2_RAID_PD_STATE_NOT_CONFIGURED (0x00) -#define MPI2_RAID_PD_STATE_NOT_COMPATIBLE (0x01) -#define MPI2_RAID_PD_STATE_OFFLINE (0x02) -#define MPI2_RAID_PD_STATE_ONLINE (0x03) -#define MPI2_RAID_PD_STATE_HOT_SPARE (0x04) -#define MPI2_RAID_PD_STATE_DEGRADED (0x05) -#define MPI2_RAID_PD_STATE_REBUILDING (0x06) -#define MPI2_RAID_PD_STATE_OPTIMAL (0x07) - -/* OfflineReason defines */ -#define MPI2_PHYSDISK0_ONLINE (0x00) -#define MPI2_PHYSDISK0_OFFLINE_MISSING (0x01) -#define MPI2_PHYSDISK0_OFFLINE_FAILED (0x03) -#define MPI2_PHYSDISK0_OFFLINE_INITIALIZING (0x04) -#define MPI2_PHYSDISK0_OFFLINE_REQUESTED (0x05) -#define MPI2_PHYSDISK0_OFFLINE_FAILED_REQUESTED (0x06) -#define MPI2_PHYSDISK0_OFFLINE_OTHER (0xFF) - -/* IncompatibleReason defines */ -#define MPI2_PHYSDISK0_COMPATIBLE (0x00) -#define MPI2_PHYSDISK0_INCOMPATIBLE_PROTOCOL (0x01) -#define MPI2_PHYSDISK0_INCOMPATIBLE_BLOCKSIZE (0x02) -#define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03) -#define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04) -#define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05) -#define MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE (0x06) -#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF) - -/* PhysDiskAttributes defines */ -#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C) -#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08) -#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04) - -#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03) -#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02) -#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01) - -/* PhysDiskStatusFlags defines */ -#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED (0x00000040) -#define MPI2_PHYSDISK0_STATUS_FLAG_OCE_TARGET (0x00000020) -#define MPI2_PHYSDISK0_STATUS_FLAG_WRITE_CACHE_ENABLED (0x00000010) -#define MPI2_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS (0x00000000) -#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x00000008) -#define MPI2_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME (0x00000004) -#define MPI2_PHYSDISK0_STATUS_FLAG_QUIESCED (0x00000002) -#define MPI2_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x00000001) - - -/* RAID Physical Disk Page 1 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhysDiskPaths at runtime. - */ -#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX -#define MPI2_RAID_PHYS_DISK1_PATH_MAX (1) -#endif - -typedef struct _MPI2_RAIDPHYSDISK1_PATH -{ - U16 DevHandle; /* 0x00 */ - U16 Reserved1; /* 0x02 */ - U64 WWID; /* 0x04 */ - U64 OwnerWWID; /* 0x0C */ - U8 OwnerIdentifier; /* 0x14 */ - U8 Reserved2; /* 0x15 */ - U16 Flags; /* 0x16 */ -} MPI2_RAIDPHYSDISK1_PATH, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK1_PATH, - Mpi2RaidPhysDisk1Path_t, MPI2_POINTER pMpi2RaidPhysDisk1Path_t; - -/* RAID Physical Disk Page 1 Physical Disk Path Flags field defines */ -#define MPI2_RAID_PHYSDISK1_FLAG_PRIMARY (0x0004) -#define MPI2_RAID_PHYSDISK1_FLAG_BROKEN (0x0002) -#define MPI2_RAID_PHYSDISK1_FLAG_INVALID (0x0001) - -typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 NumPhysDiskPaths; /* 0x04 */ - U8 PhysDiskNum; /* 0x05 */ - U16 Reserved1; /* 0x06 */ - U32 Reserved2; /* 0x08 */ - MPI2_RAIDPHYSDISK1_PATH PhysicalDiskPath[MPI2_RAID_PHYS_DISK1_PATH_MAX];/* 0x0C */ -} MPI2_CONFIG_PAGE_RD_PDISK_1, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_1, - Mpi2RaidPhysDiskPage1_t, MPI2_POINTER pMpi2RaidPhysDiskPage1_t; - -#define MPI2_RAIDPHYSDISKPAGE1_PAGEVERSION (0x02) - - -/**************************************************************************** -* values for fields used by several types of SAS Config Pages -****************************************************************************/ - -/* values for NegotiatedLinkRates fields */ -#define MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL (0xF0) -#define MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL (4) -#define MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL (0x0F) -/* link rates used for Negotiated Physical and Logical Link Rate */ -#define MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE (0x00) -#define MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED (0x01) -#define MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED (0x02) -#define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03) -#define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04) -#define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05) -#define MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06) -#define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08) -#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09) -#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A) - - -/* values for AttachedPhyInfo fields */ -#define MPI2_SAS_APHYINFO_INSIDE_ZPSDS_PERSISTENT (0x00000040) -#define MPI2_SAS_APHYINFO_REQUESTED_INSIDE_ZPSDS (0x00000020) -#define MPI2_SAS_APHYINFO_BREAK_REPLY_CAPABLE (0x00000010) - -#define MPI2_SAS_APHYINFO_REASON_MASK (0x0000000F) -#define MPI2_SAS_APHYINFO_REASON_UNKNOWN (0x00000000) -#define MPI2_SAS_APHYINFO_REASON_POWER_ON (0x00000001) -#define MPI2_SAS_APHYINFO_REASON_HARD_RESET (0x00000002) -#define MPI2_SAS_APHYINFO_REASON_SMP_PHY_CONTROL (0x00000003) -#define MPI2_SAS_APHYINFO_REASON_LOSS_OF_SYNC (0x00000004) -#define MPI2_SAS_APHYINFO_REASON_MULTIPLEXING_SEQ (0x00000005) -#define MPI2_SAS_APHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00000006) -#define MPI2_SAS_APHYINFO_REASON_BREAK_TIMEOUT (0x00000007) -#define MPI2_SAS_APHYINFO_REASON_PHY_TEST_STOPPED (0x00000008) - - -/* values for PhyInfo fields */ -#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000) - -#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000) -#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27) -#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000) -#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000) -#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000) - -#define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS (0x04000000) -#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT (0x02000000) -#define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS (0x01000000) -#define MPI2_SAS_PHYINFO_ZONE_GROUP_PERSISTENT (0x00400000) -#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS (0x00200000) -#define MPI2_SAS_PHYINFO_ZONING_ENABLED (0x00100000) - -#define MPI2_SAS_PHYINFO_REASON_MASK (0x000F0000) -#define MPI2_SAS_PHYINFO_REASON_UNKNOWN (0x00000000) -#define MPI2_SAS_PHYINFO_REASON_POWER_ON (0x00010000) -#define MPI2_SAS_PHYINFO_REASON_HARD_RESET (0x00020000) -#define MPI2_SAS_PHYINFO_REASON_SMP_PHY_CONTROL (0x00030000) -#define MPI2_SAS_PHYINFO_REASON_LOSS_OF_SYNC (0x00040000) -#define MPI2_SAS_PHYINFO_REASON_MULTIPLEXING_SEQ (0x00050000) -#define MPI2_SAS_PHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00060000) -#define MPI2_SAS_PHYINFO_REASON_BREAK_TIMEOUT (0x00070000) -#define MPI2_SAS_PHYINFO_REASON_PHY_TEST_STOPPED (0x00080000) - -#define MPI2_SAS_PHYINFO_MULTIPLEXING_SUPPORTED (0x00008000) -#define MPI2_SAS_PHYINFO_SATA_PORT_ACTIVE (0x00004000) -#define MPI2_SAS_PHYINFO_SATA_PORT_SELECTOR_PRESENT (0x00002000) -#define MPI2_SAS_PHYINFO_VIRTUAL_PHY (0x00001000) - -#define MPI2_SAS_PHYINFO_MASK_PARTIAL_PATHWAY_TIME (0x00000F00) -#define MPI2_SAS_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME (8) - -#define MPI2_SAS_PHYINFO_MASK_ROUTING_ATTRIBUTE (0x000000F0) -#define MPI2_SAS_PHYINFO_DIRECT_ROUTING (0x00000000) -#define MPI2_SAS_PHYINFO_SUBTRACTIVE_ROUTING (0x00000010) -#define MPI2_SAS_PHYINFO_TABLE_ROUTING (0x00000020) - - -/* values for SAS ProgrammedLinkRate fields */ -#define MPI2_SAS_PRATE_MAX_RATE_MASK (0xF0) -#define MPI2_SAS_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00) -#define MPI2_SAS_PRATE_MAX_RATE_1_5 (0x80) -#define MPI2_SAS_PRATE_MAX_RATE_3_0 (0x90) -#define MPI2_SAS_PRATE_MAX_RATE_6_0 (0xA0) -#define MPI25_SAS_PRATE_MAX_RATE_12_0 (0xB0) -#define MPI2_SAS_PRATE_MIN_RATE_MASK (0x0F) -#define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00) -#define MPI2_SAS_PRATE_MIN_RATE_1_5 (0x08) -#define MPI2_SAS_PRATE_MIN_RATE_3_0 (0x09) -#define MPI2_SAS_PRATE_MIN_RATE_6_0 (0x0A) - - -/* values for SAS HwLinkRate fields */ -#define MPI2_SAS_HWRATE_MAX_RATE_MASK (0xF0) -#define MPI2_SAS_HWRATE_MAX_RATE_1_5 (0x80) -#define MPI2_SAS_HWRATE_MAX_RATE_3_0 (0x90) -#define MPI2_SAS_HWRATE_MAX_RATE_6_0 (0xA0) -#define MPI25_SAS_HWRATE_MAX_RATE_12_0 (0xB0) -#define MPI2_SAS_HWRATE_MIN_RATE_MASK (0x0F) -#define MPI2_SAS_HWRATE_MIN_RATE_1_5 (0x08) -#define MPI2_SAS_HWRATE_MIN_RATE_3_0 (0x09) -#define MPI2_SAS_HWRATE_MIN_RATE_6_0 (0x0A) - - - -/**************************************************************************** -* SAS IO Unit Config Pages -****************************************************************************/ - -/* SAS IO Unit Page 0 */ - -typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA -{ - U8 Port; /* 0x00 */ - U8 PortFlags; /* 0x01 */ - U8 PhyFlags; /* 0x02 */ - U8 NegotiatedLinkRate; /* 0x03 */ - U32 ControllerPhyDeviceInfo;/* 0x04 */ - U16 AttachedDevHandle; /* 0x08 */ - U16 ControllerDevHandle; /* 0x0A */ - U32 DiscoveryStatus; /* 0x0C */ - U32 Reserved; /* 0x10 */ -} MPI2_SAS_IO_UNIT0_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT0_PHY_DATA, - Mpi2SasIOUnit0PhyData_t, MPI2_POINTER pMpi2SasIOUnit0PhyData_t; - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_SAS_IOUNIT0_PHY_MAX -#define MPI2_SAS_IOUNIT0_PHY_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U8 NumPhys; /* 0x0C */ - U8 Reserved2; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_SAS_IO_UNIT0_PHY_DATA PhyData[MPI2_SAS_IOUNIT0_PHY_MAX]; /* 0x10 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_0, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_0, - Mpi2SasIOUnitPage0_t, MPI2_POINTER pMpi2SasIOUnitPage0_t; - -#define MPI2_SASIOUNITPAGE0_PAGEVERSION (0x05) - -/* values for SAS IO Unit Page 0 PortFlags */ -#define MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS (0x08) -#define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG (0x01) - -/* values for SAS IO Unit Page 0 PhyFlags */ -#define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED (0x10) -#define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08) - -/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ - -/* see mpi2_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */ - -/* values for SAS IO Unit Page 0 DiscoveryStatus */ -#define MPI2_SASIOUNIT0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) -#define MPI2_SASIOUNIT0_DS_MAX_EXPANDERS_EXCEED (0x40000000) -#define MPI2_SASIOUNIT0_DS_MAX_DEVICES_EXCEED (0x20000000) -#define MPI2_SASIOUNIT0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) -#define MPI2_SASIOUNIT0_DS_DOWNSTREAM_INITIATOR (0x08000000) -#define MPI2_SASIOUNIT0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) -#define MPI2_SASIOUNIT0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) -#define MPI2_SASIOUNIT0_DS_MULTI_PORT_DOMAIN (0x00002000) -#define MPI2_SASIOUNIT0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) -#define MPI2_SASIOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800) -#define MPI2_SASIOUNIT0_DS_TABLE_LINK (0x00000400) -#define MPI2_SASIOUNIT0_DS_SUBTRACTIVE_LINK (0x00000200) -#define MPI2_SASIOUNIT0_DS_SMP_CRC_ERROR (0x00000100) -#define MPI2_SASIOUNIT0_DS_SMP_FUNCTION_FAILED (0x00000080) -#define MPI2_SASIOUNIT0_DS_INDEX_NOT_EXIST (0x00000040) -#define MPI2_SASIOUNIT0_DS_OUT_ROUTE_ENTRIES (0x00000020) -#define MPI2_SASIOUNIT0_DS_SMP_TIMEOUT (0x00000010) -#define MPI2_SASIOUNIT0_DS_MULTIPLE_PORTS (0x00000004) -#define MPI2_SASIOUNIT0_DS_UNADDRESSABLE_DEVICE (0x00000002) -#define MPI2_SASIOUNIT0_DS_LOOP_DETECTED (0x00000001) - - -/* SAS IO Unit Page 1 */ - -typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA -{ - U8 Port; /* 0x00 */ - U8 PortFlags; /* 0x01 */ - U8 PhyFlags; /* 0x02 */ - U8 MaxMinLinkRate; /* 0x03 */ - U32 ControllerPhyDeviceInfo; /* 0x04 */ - U16 MaxTargetPortConnectTime; /* 0x08 */ - U16 Reserved1; /* 0x0A */ -} MPI2_SAS_IO_UNIT1_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT1_PHY_DATA, - Mpi2SasIOUnit1PhyData_t, MPI2_POINTER pMpi2SasIOUnit1PhyData_t; - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_SAS_IOUNIT1_PHY_MAX -#define MPI2_SAS_IOUNIT1_PHY_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U16 ControlFlags; /* 0x08 */ - U16 SASNarrowMaxQueueDepth; /* 0x0A */ - U16 AdditionalControlFlags; /* 0x0C */ - U16 SASWideMaxQueueDepth; /* 0x0E */ - U8 NumPhys; /* 0x10 */ - U8 SATAMaxQDepth; /* 0x11 */ - U8 ReportDeviceMissingDelay; /* 0x12 */ - U8 IODeviceMissingDelay; /* 0x13 */ - MPI2_SAS_IO_UNIT1_PHY_DATA PhyData[MPI2_SAS_IOUNIT1_PHY_MAX]; /* 0x14 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_1, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_1, - Mpi2SasIOUnitPage1_t, MPI2_POINTER pMpi2SasIOUnitPage1_t; - -#define MPI2_SASIOUNITPAGE1_PAGEVERSION (0x09) - -/* values for SAS IO Unit Page 1 ControlFlags */ -#define MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000) -#define MPI2_SASIOUNIT1_CONTROL_SATA_3_0_MAX (0x4000) -#define MPI2_SASIOUNIT1_CONTROL_SATA_1_5_MAX (0x2000) -#define MPI2_SASIOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000) - -#define MPI2_SASIOUNIT1_CONTROL_MASK_DEV_SUPPORT (0x0600) -#define MPI2_SASIOUNIT1_CONTROL_SHIFT_DEV_SUPPORT (9) -#define MPI2_SASIOUNIT1_CONTROL_DEV_SUPPORT_BOTH (0x0) -#define MPI2_SASIOUNIT1_CONTROL_DEV_SAS_SUPPORT (0x1) -#define MPI2_SASIOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x2) - -#define MPI2_SASIOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080) -#define MPI2_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040) -#define MPI2_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020) -#define MPI2_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED (0x0010) -#define MPI2_SASIOUNIT1_CONTROL_TABLE_SUBTRACTIVE_ILLEGAL (0x0008) -#define MPI2_SASIOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL (0x0004) -#define MPI2_SASIOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002) -#define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) - -/* values for SAS IO Unit Page 1 AdditionalControlFlags */ -#define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080) -#define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040) -#define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION (0x0020) -#define MPI2_SASIOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010) -#define MPI2_SASIOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008) -#define MPI2_SASIOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004) -#define MPI2_SASIOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002) -#define MPI2_SASIOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) - -/* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */ -#define MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F) -#define MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16 (0x80) - -/* values for SAS IO Unit Page 1 PortFlags */ -#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) - -/* values for SAS IO Unit Page 1 PhyFlags */ -#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10) -#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) - -/* values for SAS IO Unit Page 1 MaxMinLinkRate */ -#define MPI2_SASIOUNIT1_MAX_RATE_MASK (0xF0) -#define MPI2_SASIOUNIT1_MAX_RATE_1_5 (0x80) -#define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90) -#define MPI2_SASIOUNIT1_MAX_RATE_6_0 (0xA0) -#define MPI2_SASIOUNIT1_MIN_RATE_MASK (0x0F) -#define MPI2_SASIOUNIT1_MIN_RATE_1_5 (0x08) -#define MPI2_SASIOUNIT1_MIN_RATE_3_0 (0x09) -#define MPI2_SASIOUNIT1_MIN_RATE_6_0 (0x0A) - -/* see mpi2_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */ - - -/* SAS IO Unit Page 4 */ - -typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP -{ - U8 MaxTargetSpinup; /* 0x00 */ - U8 SpinupDelay; /* 0x01 */ - U8 SpinupFlags; /* 0x02 */ - U8 Reserved1; /* 0x03 */ -} MPI2_SAS_IOUNIT4_SPINUP_GROUP, MPI2_POINTER PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP, - Mpi2SasIOUnit4SpinupGroup_t, MPI2_POINTER pMpi2SasIOUnit4SpinupGroup_t; - -/* defines for SAS IO Unit Page 4 SpinupFlags */ -#define MPI2_SASIOUNIT4_SPINUP_DISABLE_FLAG (0x01) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_SAS_IOUNIT4_PHY_MAX -#define MPI2_SAS_IOUNIT4_PHY_MAX (4) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - MPI2_SAS_IOUNIT4_SPINUP_GROUP SpinupGroupParameters[4]; /* 0x08 */ - U32 Reserved1; /* 0x18 */ - U32 Reserved2; /* 0x1C */ - U32 Reserved3; /* 0x20 */ - U8 BootDeviceWaitTime; /* 0x24 */ - U8 Reserved4; /* 0x25 */ - U16 Reserved5; /* 0x26 */ - U8 NumPhys; /* 0x28 */ - U8 PEInitialSpinupDelay; /* 0x29 */ - U8 PEReplyDelay; /* 0x2A */ - U8 Flags; /* 0x2B */ - U8 PHY[MPI2_SAS_IOUNIT4_PHY_MAX]; /* 0x2C */ -} MPI2_CONFIG_PAGE_SASIOUNIT_4, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_4, - Mpi2SasIOUnitPage4_t, MPI2_POINTER pMpi2SasIOUnitPage4_t; - -#define MPI2_SASIOUNITPAGE4_PAGEVERSION (0x02) - -/* defines for Flags field */ -#define MPI2_SASIOUNIT4_FLAGS_AUTO_PORTENABLE (0x01) - -/* defines for PHY field */ -#define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK (0x03) - - -/* SAS IO Unit Page 5 */ - -typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { - U8 ControlFlags; /* 0x00 */ - U8 PortWidthModGroup; /* 0x01 */ - U16 InactivityTimerExponent; /* 0x02 */ - U8 SATAPartialTimeout; /* 0x04 */ - U8 Reserved2; /* 0x05 */ - U8 SATASlumberTimeout; /* 0x06 */ - U8 Reserved3; /* 0x07 */ - U8 SASPartialTimeout; /* 0x08 */ - U8 Reserved4; /* 0x09 */ - U8 SASSlumberTimeout; /* 0x0A */ - U8 Reserved5; /* 0x0B */ -} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, - MPI2_POINTER PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, - Mpi2SasIOUnit5PhyPmSettings_t, MPI2_POINTER pMpi2SasIOUnit5PhyPmSettings_t; - -/* defines for ControlFlags field */ -#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08) -#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04) -#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02) -#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01) - -/* defines for PortWidthModeGroup field */ -#define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF) - -/* defines for InactivityTimerExponent field */ -#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000) -#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12) -#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700) -#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8) -#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070) -#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4) -#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007) -#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0) - -#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7) -#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6) -#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5) -#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4) -#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3) -#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2) -#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1) -#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_SAS_IOUNIT5_PHY_MAX -#define MPI2_SAS_IOUNIT5_PHY_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 NumPhys; /* 0x08 */ - U8 Reserved1; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U32 Reserved3; /* 0x0C */ - MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS SASPhyPowerManagementSettings - [MPI2_SAS_IOUNIT5_PHY_MAX]; /* 0x10 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_5, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, - Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t; - -#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01) - - -/* SAS IO Unit Page 6 */ - -typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS { - U8 CurrentStatus; /* 0x00 */ - U8 CurrentModulation; /* 0x01 */ - U8 CurrentUtilization; /* 0x02 */ - U8 Reserved1; /* 0x03 */ - U32 Reserved2; /* 0x04 */ -} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, - MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, - Mpi2SasIOUnit6PortWidthModGroupStatus_t, - MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t; - -/* defines for CurrentStatus field */ -#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00) -#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01) -#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02) -#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03) -#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04) -#define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05) -#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06) -#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07) - -/* defines for CurrentModulation field */ -#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00) -#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01) -#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02) -#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumGroups at runtime. - */ -#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX -#define MPI2_SAS_IOUNIT6_GROUP_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 Reserved2; /* 0x0C */ - U8 NumGroups; /* 0x10 */ - U8 Reserved3; /* 0x11 */ - U16 Reserved4; /* 0x12 */ - MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS - PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_6, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6, - Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t; - -#define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00) - - -/* SAS IO Unit Page 7 */ - -typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS { - U8 Flags; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U8 Threshold75Pct; /* 0x04 */ - U8 Threshold50Pct; /* 0x05 */ - U8 Threshold25Pct; /* 0x06 */ - U8 Reserved3; /* 0x07 */ -} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, - MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, - Mpi2SasIOUnit7PortWidthModGroupSettings_t, - MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t; - -/* defines for Flags field */ -#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01) - - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumGroups at runtime. - */ -#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX -#define MPI2_SAS_IOUNIT7_GROUP_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 SamplingInterval; /* 0x08 */ - U8 WindowLength; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U32 Reserved2; /* 0x0C */ - U32 Reserved3; /* 0x10 */ - U8 NumGroups; /* 0x14 */ - U8 Reserved4; /* 0x15 */ - U16 Reserved5; /* 0x16 */ - MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS - PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_7, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7, - Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t; - -#define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00) - - -/* SAS IO Unit Page 8 */ - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 PowerManagementCapabilities;/* 0x0C */ - U32 Reserved2; /* 0x10 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_8, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8, - Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t; - -#define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00) - -/* defines for PowerManagementCapabilities field */ -#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x00001000) -#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x00000800) -#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x00000400) -#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x00000200) -#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x00000100) -#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x00000010) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x00000008) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x00000004) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x00000002) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x00000001) - - - -/* SAS IO Unit Page 16 */ - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT16 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U64 TimeStamp; /* 0x08 */ - U32 Reserved1; /* 0x10 */ - U32 Reserved2; /* 0x14 */ - U32 FastPathPendedRequests; /* 0x18 */ - U32 FastPathUnPendedRequests; /* 0x1C */ - U32 FastPathHostRequestStarts; /* 0x20 */ - U32 FastPathFirmwareRequestStarts; /* 0x24 */ - U32 FastPathHostCompletions; /* 0x28 */ - U32 FastPathFirmwareCompletions; /* 0x2C */ - U32 NonFastPathRequestStarts; /* 0x30 */ - U32 NonFastPathHostCompletions; /* 0x30 */ -} MPI2_CONFIG_PAGE_SASIOUNIT16, -MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT16, -Mpi2SasIOUnitPage16_t, MPI2_POINTER pMpi2SasIOUnitPage16_t; - -#define MPI2_SASIOUNITPAGE16_PAGEVERSION (0x00) - - -/**************************************************************************** -* SAS Expander Config Pages -****************************************************************************/ - -/* SAS Expander Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 PhysicalPort; /* 0x08 */ - U8 ReportGenLength; /* 0x09 */ - U16 EnclosureHandle; /* 0x0A */ - U64 SASAddress; /* 0x0C */ - U32 DiscoveryStatus; /* 0x14 */ - U16 DevHandle; /* 0x18 */ - U16 ParentDevHandle; /* 0x1A */ - U16 ExpanderChangeCount; /* 0x1C */ - U16 ExpanderRouteIndexes; /* 0x1E */ - U8 NumPhys; /* 0x20 */ - U8 SASLevel; /* 0x21 */ - U16 Flags; /* 0x22 */ - U16 STPBusInactivityTimeLimit; /* 0x24 */ - U16 STPMaxConnectTimeLimit; /* 0x26 */ - U16 STP_SMP_NexusLossTime; /* 0x28 */ - U16 MaxNumRoutedSasAddresses; /* 0x2A */ - U64 ActiveZoneManagerSASAddress;/* 0x2C */ - U16 ZoneLockInactivityLimit; /* 0x34 */ - U16 Reserved1; /* 0x36 */ - U8 TimeToReducedFunc; /* 0x38 */ - U8 InitialTimeToReducedFunc; /* 0x39 */ - U8 MaxReducedFuncTime; /* 0x3A */ - U8 Reserved2; /* 0x3B */ -} MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0, - Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t; - -#define MPI2_SASEXPANDER0_PAGEVERSION (0x06) - -/* values for SAS Expander Page 0 DiscoveryStatus field */ -#define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) -#define MPI2_SAS_EXPANDER0_DS_MAX_EXPANDERS_EXCEED (0x40000000) -#define MPI2_SAS_EXPANDER0_DS_MAX_DEVICES_EXCEED (0x20000000) -#define MPI2_SAS_EXPANDER0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) -#define MPI2_SAS_EXPANDER0_DS_DOWNSTREAM_INITIATOR (0x08000000) -#define MPI2_SAS_EXPANDER0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) -#define MPI2_SAS_EXPANDER0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) -#define MPI2_SAS_EXPANDER0_DS_MULTI_PORT_DOMAIN (0x00002000) -#define MPI2_SAS_EXPANDER0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) -#define MPI2_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE (0x00000800) -#define MPI2_SAS_EXPANDER0_DS_TABLE_LINK (0x00000400) -#define MPI2_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK (0x00000200) -#define MPI2_SAS_EXPANDER0_DS_SMP_CRC_ERROR (0x00000100) -#define MPI2_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED (0x00000080) -#define MPI2_SAS_EXPANDER0_DS_INDEX_NOT_EXIST (0x00000040) -#define MPI2_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES (0x00000020) -#define MPI2_SAS_EXPANDER0_DS_SMP_TIMEOUT (0x00000010) -#define MPI2_SAS_EXPANDER0_DS_MULTIPLE_PORTS (0x00000004) -#define MPI2_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE (0x00000002) -#define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED (0x00000001) - -/* values for SAS Expander Page 0 Flags field */ -#define MPI2_SAS_EXPANDER0_FLAGS_REDUCED_FUNCTIONALITY (0x2000) -#define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED (0x1000) -#define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES (0x0800) -#define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES (0x0400) -#define MPI2_SAS_EXPANDER0_FLAGS_ZONING_SUPPORT (0x0200) -#define MPI2_SAS_EXPANDER0_FLAGS_ENABLED_ZONING (0x0100) -#define MPI2_SAS_EXPANDER0_FLAGS_TABLE_TO_TABLE_SUPPORT (0x0080) -#define MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x0010) -#define MPI2_SAS_EXPANDER0_FLAGS_OTHERS_CONFIG (0x0004) -#define MPI2_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x0002) -#define MPI2_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x0001) - - -/* SAS Expander Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_EXPANDER_1 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 PhysicalPort; /* 0x08 */ - U8 Reserved1; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U8 NumPhys; /* 0x0C */ - U8 Phy; /* 0x0D */ - U16 NumTableEntriesProgrammed; /* 0x0E */ - U8 ProgrammedLinkRate; /* 0x10 */ - U8 HwLinkRate; /* 0x11 */ - U16 AttachedDevHandle; /* 0x12 */ - U32 PhyInfo; /* 0x14 */ - U32 AttachedDeviceInfo; /* 0x18 */ - U16 ExpanderDevHandle; /* 0x1C */ - U8 ChangeCount; /* 0x1E */ - U8 NegotiatedLinkRate; /* 0x1F */ - U8 PhyIdentifier; /* 0x20 */ - U8 AttachedPhyIdentifier; /* 0x21 */ - U8 Reserved3; /* 0x22 */ - U8 DiscoveryInfo; /* 0x23 */ - U32 AttachedPhyInfo; /* 0x24 */ - U8 ZoneGroup; /* 0x28 */ - U8 SelfConfigStatus; /* 0x29 */ - U16 Reserved4; /* 0x2A */ -} MPI2_CONFIG_PAGE_EXPANDER_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_1, - Mpi2ExpanderPage1_t, MPI2_POINTER pMpi2ExpanderPage1_t; - -#define MPI2_SASEXPANDER1_PAGEVERSION (0x02) - -/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ - -/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ - -/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */ - -/* see mpi2_sas.h for the MPI2_SAS_DEVICE_INFO_ defines used for the AttachedDeviceInfo field */ - -/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ - -/* values for SAS Expander Page 1 DiscoveryInfo field */ -#define MPI2_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04) -#define MPI2_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02) -#define MPI2_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01) - -/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ - -/**************************************************************************** -* SAS Device Config Pages -****************************************************************************/ - -/* SAS Device Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U16 Slot; /* 0x08 */ - U16 EnclosureHandle; /* 0x0A */ - U64 SASAddress; /* 0x0C */ - U16 ParentDevHandle; /* 0x14 */ - U8 PhyNum; /* 0x16 */ - U8 AccessStatus; /* 0x17 */ - U16 DevHandle; /* 0x18 */ - U8 AttachedPhyIdentifier; /* 0x1A */ - U8 ZoneGroup; /* 0x1B */ - U32 DeviceInfo; /* 0x1C */ - U16 Flags; /* 0x20 */ - U8 PhysicalPort; /* 0x22 */ - U8 MaxPortConnections; /* 0x23 */ - U64 DeviceName; /* 0x24 */ - U8 PortGroups; /* 0x2C */ - U8 DmaGroup; /* 0x2D */ - U8 ControlGroup; /* 0x2E */ - U8 EnclosureLevel; /* 0x2F */ - U8 ConnectorName[4]; /* 0x30 */ - U32 Reserved3; /* 0x34 */ -} MPI2_CONFIG_PAGE_SAS_DEV_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_0, - Mpi2SasDevicePage0_t, MPI2_POINTER pMpi2SasDevicePage0_t; - -#define MPI2_SASDEVICE0_PAGEVERSION (0x09) - -/* values for SAS Device Page 0 AccessStatus field */ -#define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) -#define MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) -#define MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) -#define MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03) -#define MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04) -#define MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE (0x05) -#define MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE (0x06) -#define MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED (0x07) -/* specific values for SATA Init failures */ -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG (0x12) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x13) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x14) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN (0x15) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN (0x16) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN (0x17) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x18) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x19) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX (0x1F) - -/* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */ - -/* values for SAS Device Page 0 Flags field */ -#define MPI2_SAS_DEVICE0_FLAGS_UNAUTHORIZED_DEVICE (0x8000) -#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000) -#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800) -#define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400) -#define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) -#define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) -#define MPI2_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080) -#define MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040) -#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) -#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) -#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) -#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002) -#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) - - -/* SAS Device Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_1 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U64 SASAddress; /* 0x0C */ - U32 Reserved2; /* 0x14 */ - U16 DevHandle; /* 0x18 */ - U16 Reserved3; /* 0x1A */ - U8 InitialRegDeviceFIS[20];/* 0x1C */ -} MPI2_CONFIG_PAGE_SAS_DEV_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_1, - Mpi2SasDevicePage1_t, MPI2_POINTER pMpi2SasDevicePage1_t; - -#define MPI2_SASDEVICE1_PAGEVERSION (0x01) - - -/**************************************************************************** -* SAS PHY Config Pages -****************************************************************************/ - -/* SAS PHY Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U16 OwnerDevHandle; /* 0x08 */ - U16 Reserved1; /* 0x0A */ - U16 AttachedDevHandle; /* 0x0C */ - U8 AttachedPhyIdentifier; /* 0x0E */ - U8 Reserved2; /* 0x0F */ - U32 AttachedPhyInfo; /* 0x10 */ - U8 ProgrammedLinkRate; /* 0x14 */ - U8 HwLinkRate; /* 0x15 */ - U8 ChangeCount; /* 0x16 */ - U8 Flags; /* 0x17 */ - U32 PhyInfo; /* 0x18 */ - U8 NegotiatedLinkRate; /* 0x1C */ - U8 Reserved3; /* 0x1D */ - U16 Reserved4; /* 0x1E */ -} MPI2_CONFIG_PAGE_SAS_PHY_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_0, - Mpi2SasPhyPage0_t, MPI2_POINTER pMpi2SasPhyPage0_t; - -#define MPI2_SASPHY0_PAGEVERSION (0x03) - -/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ - -/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ - -/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ - -/* values for SAS PHY Page 0 Flags field */ -#define MPI2_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01) - -/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */ - -/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ - - -/* SAS PHY Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 InvalidDwordCount; /* 0x0C */ - U32 RunningDisparityErrorCount; /* 0x10 */ - U32 LossDwordSynchCount; /* 0x14 */ - U32 PhyResetProblemCount; /* 0x18 */ -} MPI2_CONFIG_PAGE_SAS_PHY_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_1, - Mpi2SasPhyPage1_t, MPI2_POINTER pMpi2SasPhyPage1_t; - -#define MPI2_SASPHY1_PAGEVERSION (0x01) - - -/* SAS PHY Page 2 */ - -typedef struct _MPI2_SASPHY2_PHY_EVENT { - U8 PhyEventCode; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 PhyEventInfo; /* 0x04 */ -} MPI2_SASPHY2_PHY_EVENT, MPI2_POINTER PTR_MPI2_SASPHY2_PHY_EVENT, - Mpi2SasPhy2PhyEvent_t, MPI2_POINTER pMpi2SasPhy2PhyEvent_t; - -/* use MPI2_SASPHY3_EVENT_CODE_ for the PhyEventCode field */ - - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhyEvents at runtime. - */ -#ifndef MPI2_SASPHY2_PHY_EVENT_MAX -#define MPI2_SASPHY2_PHY_EVENT_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U8 NumPhyEvents; /* 0x0C */ - U8 Reserved2; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_SASPHY2_PHY_EVENT PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX]; - /* 0x10 */ -} MPI2_CONFIG_PAGE_SAS_PHY_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_2, - Mpi2SasPhyPage2_t, MPI2_POINTER pMpi2SasPhyPage2_t; - -#define MPI2_SASPHY2_PAGEVERSION (0x00) - - -/* SAS PHY Page 3 */ - -typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG { - U8 PhyEventCode; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U8 CounterType; /* 0x04 */ - U8 ThresholdWindow; /* 0x05 */ - U8 TimeUnits; /* 0x06 */ - U8 Reserved3; /* 0x07 */ - U32 EventThreshold; /* 0x08 */ - U16 ThresholdFlags; /* 0x0C */ - U16 Reserved4; /* 0x0E */ -} MPI2_SASPHY3_PHY_EVENT_CONFIG, MPI2_POINTER PTR_MPI2_SASPHY3_PHY_EVENT_CONFIG, - Mpi2SasPhy3PhyEventConfig_t, MPI2_POINTER pMpi2SasPhy3PhyEventConfig_t; - -/* values for PhyEventCode field */ -#define MPI2_SASPHY3_EVENT_CODE_NO_EVENT (0x00) -#define MPI2_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01) -#define MPI2_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02) -#define MPI2_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03) -#define MPI2_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04) -#define MPI2_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05) -#define MPI2_SASPHY3_EVENT_CODE_RX_ERROR (0x06) -#define MPI2_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20) -#define MPI2_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21) -#define MPI2_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22) -#define MPI2_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23) -#define MPI2_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24) -#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25) -#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26) -#define MPI2_SASPHY3_EVENT_CODE_TX_BREAK (0x27) -#define MPI2_SASPHY3_EVENT_CODE_RX_BREAK (0x28) -#define MPI2_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29) -#define MPI2_SASPHY3_EVENT_CODE_CONNECTION (0x2A) -#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2B) -#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2C) -#define MPI2_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2D) -#define MPI2_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2E) -#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40) -#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41) -#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42) -#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43) -#define MPI2_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44) -#define MPI2_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45) -#define MPI2_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50) -#define MPI2_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51) -#define MPI2_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52) -#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60) -#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61) -#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63) -#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0) -#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1) -#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2) - -/* values for the CounterType field */ -#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00) -#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01) -#define MPI2_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02) - -/* values for the TimeUnits field */ -#define MPI2_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00) -#define MPI2_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01) -#define MPI2_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02) -#define MPI2_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03) - -/* values for the ThresholdFlags field */ -#define MPI2_SASPHY3_TFLAGS_PHY_RESET (0x0002) -#define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhyEvents at runtime. - */ -#ifndef MPI2_SASPHY3_PHY_EVENT_MAX -#define MPI2_SASPHY3_PHY_EVENT_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U8 NumPhyEvents; /* 0x0C */ - U8 Reserved2; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_SASPHY3_PHY_EVENT_CONFIG PhyEventConfig - [MPI2_SASPHY3_PHY_EVENT_MAX]; /* 0x10 */ -} MPI2_CONFIG_PAGE_SAS_PHY_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_3, - Mpi2SasPhyPage3_t, MPI2_POINTER pMpi2SasPhyPage3_t; - -#define MPI2_SASPHY3_PAGEVERSION (0x00) - - -/* SAS PHY Page 4 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U16 Reserved1; /* 0x08 */ - U8 Reserved2; /* 0x0A */ - U8 Flags; /* 0x0B */ - U8 InitialFrame[28]; /* 0x0C */ -} MPI2_CONFIG_PAGE_SAS_PHY_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_4, - Mpi2SasPhyPage4_t, MPI2_POINTER pMpi2SasPhyPage4_t; - -#define MPI2_SASPHY4_PAGEVERSION (0x00) - -/* values for the Flags field */ -#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02) -#define MPI2_SASPHY4_FLAGS_SATA_FRAME (0x01) - - - - -/**************************************************************************** -* SAS Port Config Pages -****************************************************************************/ - -/* SAS Port Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_PORT_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 PortNumber; /* 0x08 */ - U8 PhysicalPort; /* 0x09 */ - U8 PortWidth; /* 0x0A */ - U8 PhysicalPortWidth; /* 0x0B */ - U8 ZoneGroup; /* 0x0C */ - U8 Reserved1; /* 0x0D */ - U16 Reserved2; /* 0x0E */ - U64 SASAddress; /* 0x10 */ - U32 DeviceInfo; /* 0x18 */ - U32 Reserved3; /* 0x1C */ - U32 Reserved4; /* 0x20 */ -} MPI2_CONFIG_PAGE_SAS_PORT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PORT_0, - Mpi2SasPortPage0_t, MPI2_POINTER pMpi2SasPortPage0_t; - -#define MPI2_SASPORT0_PAGEVERSION (0x00) - -/* see mpi2_sas.h for values for SAS Port Page 0 DeviceInfo values */ - - -/**************************************************************************** -* SAS Enclosure Config Pages -****************************************************************************/ - -/* SAS Enclosure Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U64 EnclosureLogicalID; /* 0x0C */ - U16 Flags; /* 0x14 */ - U16 EnclosureHandle; /* 0x16 */ - U16 NumSlots; /* 0x18 */ - U16 StartSlot; /* 0x1A */ - U8 Reserved2; /* 0x1C */ - U8 EnclosureLevel; /* 0x1D */ - U16 SEPDevHandle; /* 0x1E */ - U32 Reserved3; /* 0x20 */ - U32 Reserved4; /* 0x24 */ -} MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, - Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t; - -#define MPI2_SASENCLOSURE0_PAGEVERSION (0x04) - -/* values for SAS Enclosure Page 0 Flags field */ -#define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010) -#define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F) -#define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000) -#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001) -#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002) -#define MPI2_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003) -#define MPI2_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004) -#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005) - - -/**************************************************************************** -* Log Config Page -****************************************************************************/ - -/* Log Page 0 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumLogEntries at runtime. - */ -#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES -#define MPI2_LOG_0_NUM_LOG_ENTRIES (1) -#endif - -#define MPI2_LOG_0_LOG_DATA_LENGTH (0x1C) - -typedef struct _MPI2_LOG_0_ENTRY -{ - U64 TimeStamp; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U16 LogSequence; /* 0x0C */ - U16 LogEntryQualifier; /* 0x0E */ - U8 VP_ID; /* 0x10 */ - U8 VF_ID; /* 0x11 */ - U16 Reserved2; /* 0x12 */ - U8 LogData[MPI2_LOG_0_LOG_DATA_LENGTH];/* 0x14 */ -} MPI2_LOG_0_ENTRY, MPI2_POINTER PTR_MPI2_LOG_0_ENTRY, - Mpi2Log0Entry_t, MPI2_POINTER pMpi2Log0Entry_t; - -/* values for Log Page 0 LogEntry LogEntryQualifier field */ -#define MPI2_LOG_0_ENTRY_QUAL_ENTRY_UNUSED (0x0000) -#define MPI2_LOG_0_ENTRY_QUAL_POWER_ON_RESET (0x0001) -#define MPI2_LOG_0_ENTRY_QUAL_TIMESTAMP_UPDATE (0x0002) -#define MPI2_LOG_0_ENTRY_QUAL_MIN_IMPLEMENT_SPEC (0x8000) -#define MPI2_LOG_0_ENTRY_QUAL_MAX_IMPLEMENT_SPEC (0xFFFF) - -typedef struct _MPI2_CONFIG_PAGE_LOG_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 Reserved2; /* 0x0C */ - U16 NumLogEntries; /* 0x10 */ - U16 Reserved3; /* 0x12 */ - MPI2_LOG_0_ENTRY LogEntry[MPI2_LOG_0_NUM_LOG_ENTRIES]; /* 0x14 */ -} MPI2_CONFIG_PAGE_LOG_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_LOG_0, - Mpi2LogPage0_t, MPI2_POINTER pMpi2LogPage0_t; - -#define MPI2_LOG_0_PAGEVERSION (0x02) - - -/**************************************************************************** -* RAID Config Page -****************************************************************************/ - -/* RAID Page 0 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumElements at runtime. - */ -#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS -#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1) -#endif - -typedef struct _MPI2_RAIDCONFIG0_CONFIG_ELEMENT -{ - U16 ElementFlags; /* 0x00 */ - U16 VolDevHandle; /* 0x02 */ - U8 HotSparePool; /* 0x04 */ - U8 PhysDiskNum; /* 0x05 */ - U16 PhysDiskDevHandle; /* 0x06 */ -} MPI2_RAIDCONFIG0_CONFIG_ELEMENT, - MPI2_POINTER PTR_MPI2_RAIDCONFIG0_CONFIG_ELEMENT, - Mpi2RaidConfig0ConfigElement_t, MPI2_POINTER pMpi2RaidConfig0ConfigElement_t; - -/* values for the ElementFlags field */ -#define MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE (0x000F) -#define MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT (0x0000) -#define MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT (0x0001) -#define MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT (0x0002) -#define MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT (0x0003) - - -typedef struct _MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 NumHotSpares; /* 0x08 */ - U8 NumPhysDisks; /* 0x09 */ - U8 NumVolumes; /* 0x0A */ - U8 ConfigNum; /* 0x0B */ - U32 Flags; /* 0x0C */ - U8 ConfigGUID[24]; /* 0x10 */ - U32 Reserved1; /* 0x28 */ - U8 NumElements; /* 0x2C */ - U8 Reserved2; /* 0x2D */ - U16 Reserved3; /* 0x2E */ - MPI2_RAIDCONFIG0_CONFIG_ELEMENT ConfigElement[MPI2_RAIDCONFIG0_MAX_ELEMENTS]; /* 0x30 */ -} MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, - Mpi2RaidConfigurationPage0_t, MPI2_POINTER pMpi2RaidConfigurationPage0_t; - -#define MPI2_RAIDCONFIG0_PAGEVERSION (0x00) - -/* values for RAID Configuration Page 0 Flags field */ -#define MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG (0x00000001) - - -/**************************************************************************** -* Driver Persistent Mapping Config Pages -****************************************************************************/ - -/* Driver Persistent Mapping Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY -{ - U64 PhysicalIdentifier; /* 0x00 */ - U16 MappingInformation; /* 0x08 */ - U16 DeviceIndex; /* 0x0A */ - U32 PhysicalBitsMapping; /* 0x0C */ - U32 Reserved1; /* 0x10 */ -} MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, - Mpi2DriverMap0Entry_t, MPI2_POINTER pMpi2DriverMap0Entry_t; - -typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY Entry; /* 0x08 */ -} MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, - Mpi2DriverMappingPage0_t, MPI2_POINTER pMpi2DriverMappingPage0_t; - -#define MPI2_DRIVERMAPPING0_PAGEVERSION (0x00) - -/* values for Driver Persistent Mapping Page 0 MappingInformation field */ -#define MPI2_DRVMAP0_MAPINFO_SLOT_MASK (0x07F0) -#define MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT (4) -#define MPI2_DRVMAP0_MAPINFO_MISSING_MASK (0x000F) - - -/**************************************************************************** -* Ethernet Config Pages -****************************************************************************/ - -/* Ethernet Page 0 */ - -/* IP address (union of IPv4 and IPv6) */ -typedef union _MPI2_ETHERNET_IP_ADDR { - U32 IPv4Addr; - U32 IPv6Addr[4]; -} MPI2_ETHERNET_IP_ADDR, MPI2_POINTER PTR_MPI2_ETHERNET_IP_ADDR, - Mpi2EthernetIpAddr_t, MPI2_POINTER pMpi2EthernetIpAddr_t; - -#define MPI2_ETHERNET_HOST_NAME_LENGTH (32) - -typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 NumInterfaces; /* 0x08 */ - U8 Reserved0; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U32 Status; /* 0x0C */ - U8 MediaState; /* 0x10 */ - U8 Reserved2; /* 0x11 */ - U16 Reserved3; /* 0x12 */ - U8 MacAddress[6]; /* 0x14 */ - U8 Reserved4; /* 0x1A */ - U8 Reserved5; /* 0x1B */ - MPI2_ETHERNET_IP_ADDR IpAddress; /* 0x1C */ - MPI2_ETHERNET_IP_ADDR SubnetMask; /* 0x2C */ - MPI2_ETHERNET_IP_ADDR GatewayIpAddress; /* 0x3C */ - MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /* 0x4C */ - MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /* 0x5C */ - MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /* 0x6C */ - U8 HostName - [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ -} MPI2_CONFIG_PAGE_ETHERNET_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_0, - Mpi2EthernetPage0_t, MPI2_POINTER pMpi2EthernetPage0_t; - -#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00) - -/* values for Ethernet Page 0 Status field */ -#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000) -#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000) -#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000) -#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100) -#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080) -#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040) -#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020) -#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010) -#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008) -#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004) -#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002) -#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001) - -/* values for Ethernet Page 0 MediaState field */ -#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80) -#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00) -#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80) - -#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07) -#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00) -#define MPI2_ETHPG0_MS_10MBIT (0x01) -#define MPI2_ETHPG0_MS_100MBIT (0x02) -#define MPI2_ETHPG0_MS_1GBIT (0x03) - - -/* Ethernet Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved0; /* 0x08 */ - U32 Flags; /* 0x0C */ - U8 MediaState; /* 0x10 */ - U8 Reserved1; /* 0x11 */ - U16 Reserved2; /* 0x12 */ - U8 MacAddress[6]; /* 0x14 */ - U8 Reserved3; /* 0x1A */ - U8 Reserved4; /* 0x1B */ - MPI2_ETHERNET_IP_ADDR StaticIpAddress; /* 0x1C */ - MPI2_ETHERNET_IP_ADDR StaticSubnetMask; /* 0x2C */ - MPI2_ETHERNET_IP_ADDR StaticGatewayIpAddress; /* 0x3C */ - MPI2_ETHERNET_IP_ADDR StaticDNS1IpAddress; /* 0x4C */ - MPI2_ETHERNET_IP_ADDR StaticDNS2IpAddress; /* 0x5C */ - U32 Reserved5; /* 0x6C */ - U32 Reserved6; /* 0x70 */ - U32 Reserved7; /* 0x74 */ - U32 Reserved8; /* 0x78 */ - U8 HostName - [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ -} MPI2_CONFIG_PAGE_ETHERNET_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_1, - Mpi2EthernetPage1_t, MPI2_POINTER pMpi2EthernetPage1_t; - -#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00) - -/* values for Ethernet Page 1 Flags field */ -#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100) -#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080) -#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040) -#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020) -#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010) -#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008) -#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004) -#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002) -#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001) - -/* values for Ethernet Page 1 MediaState field */ -#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80) -#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00) -#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80) - -#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07) -#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00) -#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01) -#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02) -#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03) - - -/**************************************************************************** -* Extended Manufacturing Config Pages -****************************************************************************/ - -/* - * Generic structure to use for product-specific extended manufacturing pages - * (currently Extended Manufacturing Page 40 through Extended Manufacturing - * Page 60). - */ - -typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 ProductSpecificInfo; /* 0x08 */ -} MPI2_CONFIG_PAGE_EXT_MAN_PS, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS, - Mpi2ExtManufacturingPagePS_t, - MPI2_POINTER pMpi2ExtManufacturingPagePS_t; - -/* PageVersion should be provided by product-specific code */ - -#endif - diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h deleted file mode 100644 index eea1a16b1..000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright (c) 2000-2014 LSI Corporation. - * - * - * Name: mpi2_init.h - * Title: MPI SCSI initiator mode messages and structures - * Creation Date: June 23, 2006 - * - * mpi2_init.h Version: 02.00.15 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t. - * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines. - * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention. - * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY. - * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t. - * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO - * Control field Task Attribute flags. - * Moved LUN field defines to mpi2.h because they are - * common to many structures. - * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to - * Query Asynchronous Event. - * Defined two new bits in the SlotStatus field of the SCSI - * Enclosure Processor Request and Reply. - * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for - * both SCSI IO Error Reply and SCSI Task Management Reply. - * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. - * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. - * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it. - * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request. - * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define. - * 02-06-12 02.00.13 Added alternate defines for Task Priority / Command - * Priority to match SAM-4. - * 07-10-12 02.00.14 Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION. - * 04-09-13 02.00.15 Added SCSIStatusQualifier field to MPI2_SCSI_IO_REPLY, - * replacing the Reserved4 field. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_INIT_H -#define MPI2_INIT_H - -/***************************************************************************** -* -* SCSI Initiator Messages -* -*****************************************************************************/ - -/**************************************************************************** -* SCSI IO messages and associated structures -****************************************************************************/ - -typedef struct -{ - U8 CDB[20]; /* 0x00 */ - U32 PrimaryReferenceTag; /* 0x14 */ - U16 PrimaryApplicationTag; /* 0x18 */ - U16 PrimaryApplicationTagMask; /* 0x1A */ - U32 TransferLength; /* 0x1C */ -} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32, - Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t; - -typedef union -{ - U8 CDB32[32]; - MPI2_SCSI_IO_CDB_EEDP32 EEDP32; - MPI2_SGE_SIMPLE_UNION SGE; -} MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION, - Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t; - -/* SCSI IO Request Message */ -typedef struct _MPI2_SCSI_IO_REQUEST -{ - U16 DevHandle; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved1; /* 0x04 */ - U8 Reserved2; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U32 SenseBufferLowAddress; /* 0x0C */ - U16 SGLFlags; /* 0x10 */ - U8 SenseBufferLength; /* 0x12 */ - U8 Reserved4; /* 0x13 */ - U8 SGLOffset0; /* 0x14 */ - U8 SGLOffset1; /* 0x15 */ - U8 SGLOffset2; /* 0x16 */ - U8 SGLOffset3; /* 0x17 */ - U32 SkipCount; /* 0x18 */ - U32 DataLength; /* 0x1C */ - U32 BidirectionalDataLength; /* 0x20 */ - U16 IoFlags; /* 0x24 */ - U16 EEDPFlags; /* 0x26 */ - U32 EEDPBlockSize; /* 0x28 */ - U32 SecondaryReferenceTag; /* 0x2C */ - U16 SecondaryApplicationTag; /* 0x30 */ - U16 ApplicationTagTranslationMask; /* 0x32 */ - U8 LUN[8]; /* 0x34 */ - U32 Control; /* 0x3C */ - MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */ - -#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */ - MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion; -#endif - - MPI2_SGE_IO_UNION SGL; /* 0x60 */ - -} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST, - Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t; - -/* SCSI IO MsgFlags bits */ - -/* MsgFlags for SenseBufferAddressSpace */ -#define MPI2_SCSIIO_MSGFLAGS_MASK_SENSE_ADDR (0x0C) -#define MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR (0x00) -#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR (0x04) -#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR (0x08) -#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR (0x0C) - -/* SCSI IO SGLFlags bits */ - -/* base values for Data Location Address Space */ -#define MPI2_SCSIIO_SGLFLAGS_ADDR_MASK (0x0C) -#define MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR (0x00) -#define MPI2_SCSIIO_SGLFLAGS_IOCDDR_ADDR (0x04) -#define MPI2_SCSIIO_SGLFLAGS_IOCPLB_ADDR (0x08) -#define MPI2_SCSIIO_SGLFLAGS_IOCPLBNTA_ADDR (0x0C) - -/* base values for Type */ -#define MPI2_SCSIIO_SGLFLAGS_TYPE_MASK (0x03) -#define MPI2_SCSIIO_SGLFLAGS_TYPE_MPI (0x00) -#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE32 (0x01) -#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE64 (0x02) - -/* shift values for each sub-field */ -#define MPI2_SCSIIO_SGLFLAGS_SGL3_SHIFT (12) -#define MPI2_SCSIIO_SGLFLAGS_SGL2_SHIFT (8) -#define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4) -#define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0) - -/* number of SGLOffset fields */ -#define MPI2_SCSIIO_NUM_SGLOFFSETS (4) - -/* SCSI IO IoFlags bits */ - -/* Large CDB Address Space */ -#define MPI2_SCSIIO_CDB_ADDR_MASK (0x6000) -#define MPI2_SCSIIO_CDB_ADDR_SYSTEM (0x0000) -#define MPI2_SCSIIO_CDB_ADDR_IOCDDR (0x2000) -#define MPI2_SCSIIO_CDB_ADDR_IOCPLB (0x4000) -#define MPI2_SCSIIO_CDB_ADDR_IOCPLBNTA (0x6000) - -#define MPI2_SCSIIO_IOFLAGS_LARGE_CDB (0x1000) -#define MPI2_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800) -#define MPI2_SCSIIO_IOFLAGS_MULTICAST (0x0400) -#define MPI2_SCSIIO_IOFLAGS_CMD_DETERMINES_DATA_DIR (0x0200) -#define MPI2_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF) - -/* SCSI IO EEDPFlags bits */ - -#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000) -#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_REFTAG (0x4000) -#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG (0x2000) -#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_APPTAG (0x1000) - -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) - -#define MPI2_SCSIIO_EEDPFLAGS_PASSTHRU_REFTAG (0x0008) - -#define MPI2_SCSIIO_EEDPFLAGS_MASK_OP (0x0007) -#define MPI2_SCSIIO_EEDPFLAGS_NOOP_OP (0x0000) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_OP (0x0001) -#define MPI2_SCSIIO_EEDPFLAGS_STRIP_OP (0x0002) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003) -#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) -#define MPI2_SCSIIO_EEDPFLAGS_REPLACE_OP (0x0006) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REGEN_OP (0x0007) - -/* SCSI IO LUN fields: use MPI2_LUN_ from mpi2.h */ - -/* SCSI IO Control bits */ -#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK (0xFC000000) -#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26) - -#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000) -#define MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION (24) -#define MPI2_SCSIIO_CONTROL_NODATATRANSFER (0x00000000) -#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000) -#define MPI2_SCSIIO_CONTROL_READ (0x02000000) -#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL (0x03000000) - -#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK (0x00007800) -#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT (11) -/* alternate name for the previous field; called Command Priority in SAM-4 */ -#define MPI2_SCSIIO_CONTROL_CMDPRI_MASK (0x00007800) -#define MPI2_SCSIIO_CONTROL_CMDPRI_SHIFT (11) - -#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700) -#define MPI2_SCSIIO_CONTROL_SIMPLEQ (0x00000000) -#define MPI2_SCSIIO_CONTROL_HEADOFQ (0x00000100) -#define MPI2_SCSIIO_CONTROL_ORDEREDQ (0x00000200) -#define MPI2_SCSIIO_CONTROL_ACAQ (0x00000400) - -#define MPI2_SCSIIO_CONTROL_TLR_MASK (0x000000C0) -#define MPI2_SCSIIO_CONTROL_NO_TLR (0x00000000) -#define MPI2_SCSIIO_CONTROL_TLR_ON (0x00000040) -#define MPI2_SCSIIO_CONTROL_TLR_OFF (0x00000080) - - -/* SCSI IO Error Reply Message */ -typedef struct _MPI2_SCSI_IO_REPLY -{ - U16 DevHandle; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved1; /* 0x04 */ - U8 Reserved2; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U8 SCSIStatus; /* 0x0C */ - U8 SCSIState; /* 0x0D */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 TransferCount; /* 0x14 */ - U32 SenseCount; /* 0x18 */ - U32 ResponseInfo; /* 0x1C */ - U16 TaskTag; /* 0x20 */ - U16 SCSIStatusQualifier; /* 0x22 */ - U32 BidirectionalTransferCount; /* 0x24 */ - U32 Reserved5; /* 0x28 */ - U32 Reserved6; /* 0x2C */ -} MPI2_SCSI_IO_REPLY, MPI2_POINTER PTR_MPI2_SCSI_IO_REPLY, - Mpi2SCSIIOReply_t, MPI2_POINTER pMpi2SCSIIOReply_t; - -/* SCSI IO Reply SCSIStatus values (SAM-4 status codes) */ - -#define MPI2_SCSI_STATUS_GOOD (0x00) -#define MPI2_SCSI_STATUS_CHECK_CONDITION (0x02) -#define MPI2_SCSI_STATUS_CONDITION_MET (0x04) -#define MPI2_SCSI_STATUS_BUSY (0x08) -#define MPI2_SCSI_STATUS_INTERMEDIATE (0x10) -#define MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14) -#define MPI2_SCSI_STATUS_RESERVATION_CONFLICT (0x18) -#define MPI2_SCSI_STATUS_COMMAND_TERMINATED (0x22) /* obsolete */ -#define MPI2_SCSI_STATUS_TASK_SET_FULL (0x28) -#define MPI2_SCSI_STATUS_ACA_ACTIVE (0x30) -#define MPI2_SCSI_STATUS_TASK_ABORTED (0x40) - -/* SCSI IO Reply SCSIState flags */ - -#define MPI2_SCSI_STATE_RESPONSE_INFO_VALID (0x10) -#define MPI2_SCSI_STATE_TERMINATED (0x08) -#define MPI2_SCSI_STATE_NO_SCSI_STATUS (0x04) -#define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02) -#define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01) - -/* masks and shifts for the ResponseInfo field */ - -#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF) -#define MPI2_SCSI_RI_SHIFT_REASONCODE (0) - -#define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF) - - -/**************************************************************************** -* SCSI Task Management messages -****************************************************************************/ - -/* SCSI Task Management Request Message */ -typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST -{ - U16 DevHandle; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U8 Reserved1; /* 0x04 */ - U8 TaskType; /* 0x05 */ - U8 Reserved2; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U8 LUN[8]; /* 0x0C */ - U32 Reserved4[7]; /* 0x14 */ - U16 TaskMID; /* 0x30 */ - U16 Reserved5; /* 0x32 */ -} MPI2_SCSI_TASK_MANAGE_REQUEST, - MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REQUEST, - Mpi2SCSITaskManagementRequest_t, - MPI2_POINTER pMpi2SCSITaskManagementRequest_t; - -/* TaskType values */ - -#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01) -#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02) -#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) -#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) -#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) -#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) -#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08) -#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09) -#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A) - -/* obsolete TaskType name */ -#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION \ - (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT) - -/* MsgFlags bits */ - -#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET (0x18) -#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET (0x00) -#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08) -#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10) - -#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01) - - - -/* SCSI Task Management Reply Message */ -typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY -{ - U16 DevHandle; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U8 ResponseCode; /* 0x04 */ - U8 TaskType; /* 0x05 */ - U8 Reserved1; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U16 Reserved3; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 TerminationCount; /* 0x14 */ - U32 ResponseInfo; /* 0x18 */ -} MPI2_SCSI_TASK_MANAGE_REPLY, - MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY, - Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t; - -/* ResponseCode values */ - -#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00) -#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02) -#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04) -#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) -#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) -#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) -#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A) -#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) - -/* masks and shifts for the ResponseInfo field */ - -#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF) -#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0) -#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00) -#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8) -#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000) -#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16) -#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000) -#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24) - - -/**************************************************************************** -* SCSI Enclosure Processor messages -****************************************************************************/ - -/* SCSI Enclosure Processor Request Message */ -typedef struct _MPI2_SEP_REQUEST -{ - U16 DevHandle; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U8 Action; /* 0x04 */ - U8 Flags; /* 0x05 */ - U8 Reserved1; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U32 SlotStatus; /* 0x0C */ - U32 Reserved3; /* 0x10 */ - U32 Reserved4; /* 0x14 */ - U32 Reserved5; /* 0x18 */ - U16 Slot; /* 0x1C */ - U16 EnclosureHandle; /* 0x1E */ -} MPI2_SEP_REQUEST, MPI2_POINTER PTR_MPI2_SEP_REQUEST, - Mpi2SepRequest_t, MPI2_POINTER pMpi2SepRequest_t; - -/* Action defines */ -#define MPI2_SEP_REQ_ACTION_WRITE_STATUS (0x00) -#define MPI2_SEP_REQ_ACTION_READ_STATUS (0x01) - -/* Flags defines */ -#define MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS (0x00) -#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS (0x01) - -/* SlotStatus defines */ -#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000) -#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) -#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200) -#define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100) -#define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080) -#define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT (0x00000040) -#define MPI2_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) -#define MPI2_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) -#define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING (0x00000004) -#define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002) -#define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001) - - -/* SCSI Enclosure Processor Reply Message */ -typedef struct _MPI2_SEP_REPLY -{ - U16 DevHandle; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U8 Action; /* 0x04 */ - U8 Flags; /* 0x05 */ - U8 Reserved1; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U16 Reserved3; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 SlotStatus; /* 0x14 */ - U32 Reserved4; /* 0x18 */ - U16 Slot; /* 0x1C */ - U16 EnclosureHandle; /* 0x1E */ -} MPI2_SEP_REPLY, MPI2_POINTER PTR_MPI2_SEP_REPLY, - Mpi2SepReply_t, MPI2_POINTER pMpi2SepReply_t; - -/* SlotStatus defines */ -#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000) -#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) -#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200) -#define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100) -#define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080) -#define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT (0x00000040) -#define MPI2_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) -#define MPI2_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) -#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING (0x00000004) -#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002) -#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001) - - -#endif - - diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h deleted file mode 100644 index b02de48be..000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ /dev/null @@ -1,1708 +0,0 @@ -/* - * Copyright (c) 2000-2014 LSI Corporation. - * - * - * Name: mpi2_ioc.h - * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages - * Creation Date: October 11, 2006 - * - * mpi2_ioc.h Version: 02.00.24 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to - * MaxTargets. - * Added TotalImageSize field to FWDownload Request. - * Added reserved words to FWUpload Request. - * 06-26-07 02.00.02 Added IR Configuration Change List Event. - * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit - * request and replaced it with - * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth. - * Replaced the MinReplyQueueDepth field of the IOCFacts - * reply with MaxReplyDescriptorPostQueueDepth. - * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum - * depth for the Reply Descriptor Post Queue. - * Added SASAddress field to Initiator Device Table - * Overflow Event data. - * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING - * for SAS Initiator Device Status Change Event data. - * Modified Reason Code defines for SAS Topology Change - * List Event data, including adding a bit for PHY Vacant - * status, and adding a mask for the Reason Code. - * Added define for - * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING. - * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID. - * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of - * the IOCFacts Reply. - * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. - * Moved MPI2_VERSION_UNION to mpi2.h. - * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks - * instead of enables, and added SASBroadcastPrimitiveMasks - * field. - * Added Log Entry Added Event and related structure. - * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID. - * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET. - * Added MaxVolumes and MaxPersistentEntries fields to - * IOCFacts reply. - * Added ProtocalFlags and IOCCapabilities fields to - * MPI2_FW_IMAGE_HEADER. - * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT. - * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to - * a U16 (from a U32). - * Removed extra 's' from EventMasks name. - * 06-27-08 02.00.08 Fixed an offset in a comment. - * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST. - * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and - * renamed MinReplyFrameSize to ReplyFrameSize. - * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX. - * Added two new RAIDOperation values for Integrated RAID - * Operations Status Event data. - * Added four new IR Configuration Change List Event data - * ReasonCode values. - * Added two new ReasonCode defines for SAS Device Status - * Change Event data. - * Added three new DiscoveryStatus bits for the SAS - * Discovery event data. - * Added Multiplexing Status Change bit to the PhyStatus - * field of the SAS Topology Change List event data. - * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY. - * BootFlags are now product-specific. - * Added defines for the indivdual signature bytes - * for MPI2_INIT_IMAGE_FOOTER. - * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define. - * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR - * define. - * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE - * define. - * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define. - * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define. - * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define. - * Added two new reason codes for SAS Device Status Change - * Event. - * Added new event: SAS PHY Counter. - * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. - * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. - * Added new product id family for 2208. - * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. - * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. - * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. - * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. - * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. - * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. - * Added Host Based Discovery Phy Event data. - * Added defines for ProductID Product field - * (MPI2_FW_HEADER_PID_). - * Modified values for SAS ProductID Family - * (MPI2_FW_HEADER_PID_FAMILY_). - * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines. - * Added PowerManagementControl Request structures and - * defines. - * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete. - * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. - * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC. - * 02-23-11 02.00.17 Added SAS NOTIFY Primitive event, and added - * SASNotifyPrimitiveMasks field to - * MPI2_EVENT_NOTIFICATION_REQUEST. - * Added Temperature Threshold Event. - * Added Host Message Event. - * Added Send Host Message request and reply. - * 05-25-11 02.00.18 For Extended Image Header, added - * MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC and - * MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC defines. - * Deprecated MPI2_EXT_IMAGE_TYPE_MAX define. - * 08-24-11 02.00.19 Added PhysicalPort field to - * MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure. - * Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete. - * 03-29-12 02.00.21 Added a product specific range to event values. - * 07-26-12 02.00.22 Added MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE. - * Added ElapsedSeconds field to - * MPI2_EVENT_DATA_IR_OPERATION_STATUS. - * 08-19-13 02.00.23 For IOCInit, added MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE - * and MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY. - * Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE. - * Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY. - * Added Encrypted Hash Extended Image. - * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_IOC_H -#define MPI2_IOC_H - -/***************************************************************************** -* -* IOC Messages -* -*****************************************************************************/ - -/**************************************************************************** -* IOCInit message -****************************************************************************/ - -/* IOCInit Request message */ -typedef struct _MPI2_IOC_INIT_REQUEST -{ - U8 WhoInit; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 MsgVersion; /* 0x0C */ - U16 HeaderVersion; /* 0x0E */ - U32 Reserved5; /* 0x10 */ - U16 Reserved6; /* 0x14 */ - U8 Reserved7; /* 0x16 */ - U8 HostMSIxVectors; /* 0x17 */ - U16 Reserved8; /* 0x18 */ - U16 SystemRequestFrameSize; /* 0x1A */ - U16 ReplyDescriptorPostQueueDepth; /* 0x1C */ - U16 ReplyFreeQueueDepth; /* 0x1E */ - U32 SenseBufferAddressHigh; /* 0x20 */ - U32 SystemReplyAddressHigh; /* 0x24 */ - U64 SystemRequestFrameBaseAddress; /* 0x28 */ - U64 ReplyDescriptorPostQueueAddress;/* 0x30 */ - U64 ReplyFreeQueueAddress; /* 0x38 */ - U64 TimeStamp; /* 0x40 */ -} MPI2_IOC_INIT_REQUEST, MPI2_POINTER PTR_MPI2_IOC_INIT_REQUEST, - Mpi2IOCInitRequest_t, MPI2_POINTER pMpi2IOCInitRequest_t; - -/* WhoInit values */ -#define MPI2_WHOINIT_NOT_INITIALIZED (0x00) -#define MPI2_WHOINIT_SYSTEM_BIOS (0x01) -#define MPI2_WHOINIT_ROM_BIOS (0x02) -#define MPI2_WHOINIT_PCI_PEER (0x03) -#define MPI2_WHOINIT_HOST_DRIVER (0x04) -#define MPI2_WHOINIT_MANUFACTURER (0x05) - -/* MsgFlags */ -#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01) - -/* MsgVersion */ -#define MPI2_IOCINIT_MSGVERSION_MAJOR_MASK (0xFF00) -#define MPI2_IOCINIT_MSGVERSION_MAJOR_SHIFT (8) -#define MPI2_IOCINIT_MSGVERSION_MINOR_MASK (0x00FF) -#define MPI2_IOCINIT_MSGVERSION_MINOR_SHIFT (0) - -/* HeaderVersion */ -#define MPI2_IOCINIT_HDRVERSION_UNIT_MASK (0xFF00) -#define MPI2_IOCINIT_HDRVERSION_UNIT_SHIFT (8) -#define MPI2_IOCINIT_HDRVERSION_DEV_MASK (0x00FF) -#define MPI2_IOCINIT_HDRVERSION_DEV_SHIFT (0) - -/* minimum depth for a Reply Descriptor Post Queue */ -#define MPI2_RDPQ_DEPTH_MIN (16) - -/* Reply Descriptor Post Queue Array Entry */ -typedef struct _MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY { - U64 RDPQBaseAddress; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 Reserved2; /* 0x0C */ -} MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY, -MPI2_POINTER PTR_MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY, -Mpi2IOCInitRDPQArrayEntry, MPI2_POINTER pMpi2IOCInitRDPQArrayEntry; - -/* IOCInit Reply message */ -typedef struct _MPI2_IOC_INIT_REPLY -{ - U8 WhoInit; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_IOC_INIT_REPLY, MPI2_POINTER PTR_MPI2_IOC_INIT_REPLY, - Mpi2IOCInitReply_t, MPI2_POINTER pMpi2IOCInitReply_t; - - -/**************************************************************************** -* IOCFacts message -****************************************************************************/ - -/* IOCFacts Request message */ -typedef struct _MPI2_IOC_FACTS_REQUEST -{ - U16 Reserved1; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ -} MPI2_IOC_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_IOC_FACTS_REQUEST, - Mpi2IOCFactsRequest_t, MPI2_POINTER pMpi2IOCFactsRequest_t; - - -/* IOCFacts Reply message */ -typedef struct _MPI2_IOC_FACTS_REPLY -{ - U16 MsgVersion; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 HeaderVersion; /* 0x04 */ - U8 IOCNumber; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U16 IOCExceptions; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U8 MaxChainDepth; /* 0x14 */ - U8 WhoInit; /* 0x15 */ - U8 NumberOfPorts; /* 0x16 */ - U8 MaxMSIxVectors; /* 0x17 */ - U16 RequestCredit; /* 0x18 */ - U16 ProductID; /* 0x1A */ - U32 IOCCapabilities; /* 0x1C */ - MPI2_VERSION_UNION FWVersion; /* 0x20 */ - U16 IOCRequestFrameSize; /* 0x24 */ - U16 Reserved3; /* 0x26 */ - U16 MaxInitiators; /* 0x28 */ - U16 MaxTargets; /* 0x2A */ - U16 MaxSasExpanders; /* 0x2C */ - U16 MaxEnclosures; /* 0x2E */ - U16 ProtocolFlags; /* 0x30 */ - U16 HighPriorityCredit; /* 0x32 */ - U16 MaxReplyDescriptorPostQueueDepth; /* 0x34 */ - U8 ReplyFrameSize; /* 0x36 */ - U8 MaxVolumes; /* 0x37 */ - U16 MaxDevHandle; /* 0x38 */ - U16 MaxPersistentEntries; /* 0x3A */ - U16 MinDevHandle; /* 0x3C */ - U16 Reserved4; /* 0x3E */ -} MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY, - Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t; - -/* MsgVersion */ -#define MPI2_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00) -#define MPI2_IOCFACTS_MSGVERSION_MAJOR_SHIFT (8) -#define MPI2_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF) -#define MPI2_IOCFACTS_MSGVERSION_MINOR_SHIFT (0) - -/* HeaderVersion */ -#define MPI2_IOCFACTS_HDRVERSION_UNIT_MASK (0xFF00) -#define MPI2_IOCFACTS_HDRVERSION_UNIT_SHIFT (8) -#define MPI2_IOCFACTS_HDRVERSION_DEV_MASK (0x00FF) -#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT (0) - -/* IOCExceptions */ -#define MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE (0x0200) -#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX (0x0100) - -#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x00E0) -#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_GOOD (0x0000) -#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_BACKUP (0x0020) -#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_RESTORED (0x0040) -#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_CORRUPT_BACKUP (0x0060) - -#define MPI2_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (0x0010) -#define MPI2_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (0x0008) -#define MPI2_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004) -#define MPI2_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002) -#define MPI2_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001) - -/* defines for WhoInit field are after the IOCInit Request */ - -/* ProductID field uses MPI2_FW_HEADER_PID_ */ - -/* IOCCapabilities */ -#define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE (0x00040000) -#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000) -#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000) -#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000) -#define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000) -#define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID (0x00001000) -#define MPI2_IOCFACTS_CAPABILITY_TLR (0x00000800) -#define MPI2_IOCFACTS_CAPABILITY_MULTICAST (0x00000100) -#define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (0x00000080) -#define MPI2_IOCFACTS_CAPABILITY_EEDP (0x00000040) -#define MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020) -#define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) -#define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) -#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004) - -/* ProtocolFlags */ -#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001) -#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002) - - -/**************************************************************************** -* PortFacts message -****************************************************************************/ - -/* PortFacts Request message */ -typedef struct _MPI2_PORT_FACTS_REQUEST -{ - U16 Reserved1; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 PortNumber; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ -} MPI2_PORT_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_PORT_FACTS_REQUEST, - Mpi2PortFactsRequest_t, MPI2_POINTER pMpi2PortFactsRequest_t; - -/* PortFacts Reply message */ -typedef struct _MPI2_PORT_FACTS_REPLY -{ - U16 Reserved1; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 PortNumber; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U16 Reserved4; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U8 Reserved5; /* 0x14 */ - U8 PortType; /* 0x15 */ - U16 Reserved6; /* 0x16 */ - U16 MaxPostedCmdBuffers; /* 0x18 */ - U16 Reserved7; /* 0x1A */ -} MPI2_PORT_FACTS_REPLY, MPI2_POINTER PTR_MPI2_PORT_FACTS_REPLY, - Mpi2PortFactsReply_t, MPI2_POINTER pMpi2PortFactsReply_t; - -/* PortType values */ -#define MPI2_PORTFACTS_PORTTYPE_INACTIVE (0x00) -#define MPI2_PORTFACTS_PORTTYPE_FC (0x10) -#define MPI2_PORTFACTS_PORTTYPE_ISCSI (0x20) -#define MPI2_PORTFACTS_PORTTYPE_SAS_PHYSICAL (0x30) -#define MPI2_PORTFACTS_PORTTYPE_SAS_VIRTUAL (0x31) - - -/**************************************************************************** -* PortEnable message -****************************************************************************/ - -/* PortEnable Request message */ -typedef struct _MPI2_PORT_ENABLE_REQUEST -{ - U16 Reserved1; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U8 Reserved2; /* 0x04 */ - U8 PortFlags; /* 0x05 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ -} MPI2_PORT_ENABLE_REQUEST, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REQUEST, - Mpi2PortEnableRequest_t, MPI2_POINTER pMpi2PortEnableRequest_t; - - -/* PortEnable Reply message */ -typedef struct _MPI2_PORT_ENABLE_REPLY -{ - U16 Reserved1; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U8 Reserved2; /* 0x04 */ - U8 PortFlags; /* 0x05 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_PORT_ENABLE_REPLY, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REPLY, - Mpi2PortEnableReply_t, MPI2_POINTER pMpi2PortEnableReply_t; - - -/**************************************************************************** -* EventNotification message -****************************************************************************/ - -/* EventNotification Request message */ -#define MPI2_EVENT_NOTIFY_EVENTMASK_WORDS (4) - -typedef struct _MPI2_EVENT_NOTIFICATION_REQUEST -{ - U16 Reserved1; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U32 Reserved5; /* 0x0C */ - U32 Reserved6; /* 0x10 */ - U32 EventMasks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];/* 0x14 */ - U16 SASBroadcastPrimitiveMasks; /* 0x24 */ - U16 SASNotifyPrimitiveMasks; /* 0x26 */ - U32 Reserved8; /* 0x28 */ -} MPI2_EVENT_NOTIFICATION_REQUEST, - MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REQUEST, - Mpi2EventNotificationRequest_t, MPI2_POINTER pMpi2EventNotificationRequest_t; - - -/* EventNotification Reply message */ -typedef struct _MPI2_EVENT_NOTIFICATION_REPLY -{ - U16 EventDataLength; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved1; /* 0x04 */ - U8 AckRequired; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U16 Reserved3; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U16 Event; /* 0x14 */ - U16 Reserved4; /* 0x16 */ - U32 EventContext; /* 0x18 */ - U32 EventData[1]; /* 0x1C */ -} MPI2_EVENT_NOTIFICATION_REPLY, MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REPLY, - Mpi2EventNotificationReply_t, MPI2_POINTER pMpi2EventNotificationReply_t; - -/* AckRequired */ -#define MPI2_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00) -#define MPI2_EVENT_NOTIFICATION_ACK_REQUIRED (0x01) - -/* Event */ -#define MPI2_EVENT_LOG_DATA (0x0001) -#define MPI2_EVENT_STATE_CHANGE (0x0002) -#define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005) -#define MPI2_EVENT_EVENT_CHANGE (0x000A) -#define MPI2_EVENT_TASK_SET_FULL (0x000E) /* obsolete */ -#define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F) -#define MPI2_EVENT_IR_OPERATION_STATUS (0x0014) -#define MPI2_EVENT_SAS_DISCOVERY (0x0016) -#define MPI2_EVENT_SAS_BROADCAST_PRIMITIVE (0x0017) -#define MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x0018) -#define MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW (0x0019) -#define MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST (0x001C) -#define MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE (0x001D) -#define MPI2_EVENT_IR_VOLUME (0x001E) -#define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F) -#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020) -#define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021) -#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022) -#define MPI2_EVENT_GPIO_INTERRUPT (0x0023) -#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024) -#define MPI2_EVENT_SAS_QUIESCE (0x0025) -#define MPI2_EVENT_SAS_NOTIFY_PRIMITIVE (0x0026) -#define MPI2_EVENT_TEMP_THRESHOLD (0x0027) -#define MPI2_EVENT_HOST_MESSAGE (0x0028) -#define MPI2_EVENT_MIN_PRODUCT_SPECIFIC (0x006E) -#define MPI2_EVENT_MAX_PRODUCT_SPECIFIC (0x007F) - -/* Log Entry Added Event data */ - -/* the following structure matches MPI2_LOG_0_ENTRY in mpi2_cnfg.h */ -#define MPI2_EVENT_DATA_LOG_DATA_LENGTH (0x1C) - -typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED -{ - U64 TimeStamp; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U16 LogSequence; /* 0x0C */ - U16 LogEntryQualifier; /* 0x0E */ - U8 VP_ID; /* 0x10 */ - U8 VF_ID; /* 0x11 */ - U16 Reserved2; /* 0x12 */ - U8 LogData[MPI2_EVENT_DATA_LOG_DATA_LENGTH];/* 0x14 */ -} MPI2_EVENT_DATA_LOG_ENTRY_ADDED, - MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED, - Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t; - -/* GPIO Interrupt Event data */ - -typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT { - U8 GPIONum; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ -} MPI2_EVENT_DATA_GPIO_INTERRUPT, - MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT, - Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t; - -/* Temperature Threshold Event data */ - -typedef struct _MPI2_EVENT_DATA_TEMPERATURE { - U16 Status; /* 0x00 */ - U8 SensorNum; /* 0x02 */ - U8 Reserved1; /* 0x03 */ - U16 CurrentTemperature; /* 0x04 */ - U16 Reserved2; /* 0x06 */ - U32 Reserved3; /* 0x08 */ - U32 Reserved4; /* 0x0C */ -} MPI2_EVENT_DATA_TEMPERATURE, -MPI2_POINTER PTR_MPI2_EVENT_DATA_TEMPERATURE, -Mpi2EventDataTemperature_t, MPI2_POINTER pMpi2EventDataTemperature_t; - -/* Temperature Threshold Event data Status bits */ -#define MPI2_EVENT_TEMPERATURE3_EXCEEDED (0x0008) -#define MPI2_EVENT_TEMPERATURE2_EXCEEDED (0x0004) -#define MPI2_EVENT_TEMPERATURE1_EXCEEDED (0x0002) -#define MPI2_EVENT_TEMPERATURE0_EXCEEDED (0x0001) - - -/* Host Message Event data */ - -typedef struct _MPI2_EVENT_DATA_HOST_MESSAGE { - U8 SourceVF_ID; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 Reserved3; /* 0x04 */ - U32 HostData[1]; /* 0x08 */ -} MPI2_EVENT_DATA_HOST_MESSAGE, MPI2_POINTER PTR_MPI2_EVENT_DATA_HOST_MESSAGE, -Mpi2EventDataHostMessage_t, MPI2_POINTER pMpi2EventDataHostMessage_t; - - -/* Hard Reset Received Event data */ - -typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED -{ - U8 Reserved1; /* 0x00 */ - U8 Port; /* 0x01 */ - U16 Reserved2; /* 0x02 */ -} MPI2_EVENT_DATA_HARD_RESET_RECEIVED, - MPI2_POINTER PTR_MPI2_EVENT_DATA_HARD_RESET_RECEIVED, - Mpi2EventDataHardResetReceived_t, - MPI2_POINTER pMpi2EventDataHardResetReceived_t; - -/* Task Set Full Event data */ -/* this event is obsolete */ - -typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL -{ - U16 DevHandle; /* 0x00 */ - U16 CurrentDepth; /* 0x02 */ -} MPI2_EVENT_DATA_TASK_SET_FULL, MPI2_POINTER PTR_MPI2_EVENT_DATA_TASK_SET_FULL, - Mpi2EventDataTaskSetFull_t, MPI2_POINTER pMpi2EventDataTaskSetFull_t; - - -/* SAS Device Status Change Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE -{ - U16 TaskTag; /* 0x00 */ - U8 ReasonCode; /* 0x02 */ - U8 PhysicalPort; /* 0x03 */ - U8 ASC; /* 0x04 */ - U8 ASCQ; /* 0x05 */ - U16 DevHandle; /* 0x06 */ - U32 Reserved2; /* 0x08 */ - U64 SASAddress; /* 0x0C */ - U8 LUN[8]; /* 0x14 */ -} MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, - Mpi2EventDataSasDeviceStatusChange_t, - MPI2_POINTER pMpi2EventDataSasDeviceStatusChange_t; - -/* SAS Device Status Change Event data ReasonCode values */ -#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) -#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07) -#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08) -#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09) -#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A) -#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) -#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) -#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D) -#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E) -#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F) -#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE (0x10) -#define MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY (0x11) -#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY (0x12) - - -/* Integrated RAID Operation Status Event data */ - -typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS -{ - U16 VolDevHandle; /* 0x00 */ - U16 Reserved1; /* 0x02 */ - U8 RAIDOperation; /* 0x04 */ - U8 PercentComplete; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - U32 ElapsedSeconds; /* 0x08 */ -} MPI2_EVENT_DATA_IR_OPERATION_STATUS, - MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS, - Mpi2EventDataIrOperationStatus_t, - MPI2_POINTER pMpi2EventDataIrOperationStatus_t; - -/* Integrated RAID Operation Status Event data RAIDOperation values */ -#define MPI2_EVENT_IR_RAIDOP_RESYNC (0x00) -#define MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION (0x01) -#define MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK (0x02) -#define MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT (0x03) -#define MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT (0x04) - - -/* Integrated RAID Volume Event data */ - -typedef struct _MPI2_EVENT_DATA_IR_VOLUME -{ - U16 VolDevHandle; /* 0x00 */ - U8 ReasonCode; /* 0x02 */ - U8 Reserved1; /* 0x03 */ - U32 NewValue; /* 0x04 */ - U32 PreviousValue; /* 0x08 */ -} MPI2_EVENT_DATA_IR_VOLUME, MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_VOLUME, - Mpi2EventDataIrVolume_t, MPI2_POINTER pMpi2EventDataIrVolume_t; - -/* Integrated RAID Volume Event data ReasonCode values */ -#define MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED (0x01) -#define MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED (0x02) -#define MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED (0x03) - - -/* Integrated RAID Physical Disk Event data */ - -typedef struct _MPI2_EVENT_DATA_IR_PHYSICAL_DISK -{ - U16 Reserved1; /* 0x00 */ - U8 ReasonCode; /* 0x02 */ - U8 PhysDiskNum; /* 0x03 */ - U16 PhysDiskDevHandle; /* 0x04 */ - U16 Reserved2; /* 0x06 */ - U16 Slot; /* 0x08 */ - U16 EnclosureHandle; /* 0x0A */ - U32 NewValue; /* 0x0C */ - U32 PreviousValue; /* 0x10 */ -} MPI2_EVENT_DATA_IR_PHYSICAL_DISK, - MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_PHYSICAL_DISK, - Mpi2EventDataIrPhysicalDisk_t, MPI2_POINTER pMpi2EventDataIrPhysicalDisk_t; - -/* Integrated RAID Physical Disk Event data ReasonCode values */ -#define MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED (0x01) -#define MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED (0x02) -#define MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED (0x03) - - -/* Integrated RAID Configuration Change List Event data */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check NumElements at runtime. - */ -#ifndef MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT -#define MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT (1) -#endif - -typedef struct _MPI2_EVENT_IR_CONFIG_ELEMENT -{ - U16 ElementFlags; /* 0x00 */ - U16 VolDevHandle; /* 0x02 */ - U8 ReasonCode; /* 0x04 */ - U8 PhysDiskNum; /* 0x05 */ - U16 PhysDiskDevHandle; /* 0x06 */ -} MPI2_EVENT_IR_CONFIG_ELEMENT, MPI2_POINTER PTR_MPI2_EVENT_IR_CONFIG_ELEMENT, - Mpi2EventIrConfigElement_t, MPI2_POINTER pMpi2EventIrConfigElement_t; - -/* IR Configuration Change List Event data ElementFlags values */ -#define MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK (0x000F) -#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT (0x0000) -#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT (0x0001) -#define MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT (0x0002) - -/* IR Configuration Change List Event data ReasonCode values */ -#define MPI2_EVENT_IR_CHANGE_RC_ADDED (0x01) -#define MPI2_EVENT_IR_CHANGE_RC_REMOVED (0x02) -#define MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE (0x03) -#define MPI2_EVENT_IR_CHANGE_RC_HIDE (0x04) -#define MPI2_EVENT_IR_CHANGE_RC_UNHIDE (0x05) -#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED (0x06) -#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED (0x07) -#define MPI2_EVENT_IR_CHANGE_RC_PD_CREATED (0x08) -#define MPI2_EVENT_IR_CHANGE_RC_PD_DELETED (0x09) - -typedef struct _MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST -{ - U8 NumElements; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 Reserved2; /* 0x02 */ - U8 ConfigNum; /* 0x03 */ - U32 Flags; /* 0x04 */ - MPI2_EVENT_IR_CONFIG_ELEMENT ConfigElement[MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT]; /* 0x08 */ -} MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, - MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, - Mpi2EventDataIrConfigChangeList_t, - MPI2_POINTER pMpi2EventDataIrConfigChangeList_t; - -/* IR Configuration Change List Event data Flags values */ -#define MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG (0x00000001) - - -/* SAS Discovery Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_DISCOVERY -{ - U8 Flags; /* 0x00 */ - U8 ReasonCode; /* 0x01 */ - U8 PhysicalPort; /* 0x02 */ - U8 Reserved1; /* 0x03 */ - U32 DiscoveryStatus; /* 0x04 */ -} MPI2_EVENT_DATA_SAS_DISCOVERY, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DISCOVERY, - Mpi2EventDataSasDiscovery_t, MPI2_POINTER pMpi2EventDataSasDiscovery_t; - -/* SAS Discovery Event data Flags values */ -#define MPI2_EVENT_SAS_DISC_DEVICE_CHANGE (0x02) -#define MPI2_EVENT_SAS_DISC_IN_PROGRESS (0x01) - -/* SAS Discovery Event data ReasonCode values */ -#define MPI2_EVENT_SAS_DISC_RC_STARTED (0x01) -#define MPI2_EVENT_SAS_DISC_RC_COMPLETED (0x02) - -/* SAS Discovery Event data DiscoveryStatus values */ -#define MPI2_EVENT_SAS_DISC_DS_MAX_ENCLOSURES_EXCEED (0x80000000) -#define MPI2_EVENT_SAS_DISC_DS_MAX_EXPANDERS_EXCEED (0x40000000) -#define MPI2_EVENT_SAS_DISC_DS_MAX_DEVICES_EXCEED (0x20000000) -#define MPI2_EVENT_SAS_DISC_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) -#define MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR (0x08000000) -#define MPI2_EVENT_SAS_DISC_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) -#define MPI2_EVENT_SAS_DISC_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) -#define MPI2_EVENT_SAS_DISC_DS_MULTI_PORT_DOMAIN (0x00002000) -#define MPI2_EVENT_SAS_DISC_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) -#define MPI2_EVENT_SAS_DISC_DS_UNSUPPORTED_DEVICE (0x00000800) -#define MPI2_EVENT_SAS_DISC_DS_TABLE_LINK (0x00000400) -#define MPI2_EVENT_SAS_DISC_DS_SUBTRACTIVE_LINK (0x00000200) -#define MPI2_EVENT_SAS_DISC_DS_SMP_CRC_ERROR (0x00000100) -#define MPI2_EVENT_SAS_DISC_DS_SMP_FUNCTION_FAILED (0x00000080) -#define MPI2_EVENT_SAS_DISC_DS_INDEX_NOT_EXIST (0x00000040) -#define MPI2_EVENT_SAS_DISC_DS_OUT_ROUTE_ENTRIES (0x00000020) -#define MPI2_EVENT_SAS_DISC_DS_SMP_TIMEOUT (0x00000010) -#define MPI2_EVENT_SAS_DISC_DS_MULTIPLE_PORTS (0x00000004) -#define MPI2_EVENT_SAS_DISC_DS_UNADDRESSABLE_DEVICE (0x00000002) -#define MPI2_EVENT_SAS_DISC_DS_LOOP_DETECTED (0x00000001) - - -/* SAS Broadcast Primitive Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE -{ - U8 PhyNum; /* 0x00 */ - U8 Port; /* 0x01 */ - U8 PortWidth; /* 0x02 */ - U8 Primitive; /* 0x03 */ -} MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, - Mpi2EventDataSasBroadcastPrimitive_t, - MPI2_POINTER pMpi2EventDataSasBroadcastPrimitive_t; - -/* defines for the Primitive field */ -#define MPI2_EVENT_PRIMITIVE_CHANGE (0x01) -#define MPI2_EVENT_PRIMITIVE_SES (0x02) -#define MPI2_EVENT_PRIMITIVE_EXPANDER (0x03) -#define MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04) -#define MPI2_EVENT_PRIMITIVE_RESERVED3 (0x05) -#define MPI2_EVENT_PRIMITIVE_RESERVED4 (0x06) -#define MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07) -#define MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED (0x08) - -/* SAS Notify Primitive Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE { - U8 PhyNum; /* 0x00 */ - U8 Port; /* 0x01 */ - U8 Reserved1; /* 0x02 */ - U8 Primitive; /* 0x03 */ -} MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, -MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, -Mpi2EventDataSasNotifyPrimitive_t, -MPI2_POINTER pMpi2EventDataSasNotifyPrimitive_t; - -/* defines for the Primitive field */ -#define MPI2_EVENT_NOTIFY_ENABLE_SPINUP (0x01) -#define MPI2_EVENT_NOTIFY_POWER_LOSS_EXPECTED (0x02) -#define MPI2_EVENT_NOTIFY_RESERVED1 (0x03) -#define MPI2_EVENT_NOTIFY_RESERVED2 (0x04) - - -/* SAS Initiator Device Status Change Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE -{ - U8 ReasonCode; /* 0x00 */ - U8 PhysicalPort; /* 0x01 */ - U16 DevHandle; /* 0x02 */ - U64 SASAddress; /* 0x04 */ -} MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, - Mpi2EventDataSasInitDevStatusChange_t, - MPI2_POINTER pMpi2EventDataSasInitDevStatusChange_t; - -/* SAS Initiator Device Status Change event ReasonCode values */ -#define MPI2_EVENT_SAS_INIT_RC_ADDED (0x01) -#define MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING (0x02) - - -/* SAS Initiator Device Table Overflow Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW -{ - U16 MaxInit; /* 0x00 */ - U16 CurrentInit; /* 0x02 */ - U64 SASAddress; /* 0x04 */ -} MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, - Mpi2EventDataSasInitTableOverflow_t, - MPI2_POINTER pMpi2EventDataSasInitTableOverflow_t; - - -/* SAS Topology Change List Event data */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check NumEntries at runtime. - */ -#ifndef MPI2_EVENT_SAS_TOPO_PHY_COUNT -#define MPI2_EVENT_SAS_TOPO_PHY_COUNT (1) -#endif - -typedef struct _MPI2_EVENT_SAS_TOPO_PHY_ENTRY -{ - U16 AttachedDevHandle; /* 0x00 */ - U8 LinkRate; /* 0x02 */ - U8 PhyStatus; /* 0x03 */ -} MPI2_EVENT_SAS_TOPO_PHY_ENTRY, MPI2_POINTER PTR_MPI2_EVENT_SAS_TOPO_PHY_ENTRY, - Mpi2EventSasTopoPhyEntry_t, MPI2_POINTER pMpi2EventSasTopoPhyEntry_t; - -typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST -{ - U16 EnclosureHandle; /* 0x00 */ - U16 ExpanderDevHandle; /* 0x02 */ - U8 NumPhys; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - U8 NumEntries; /* 0x08 */ - U8 StartPhyNum; /* 0x09 */ - U8 ExpStatus; /* 0x0A */ - U8 PhysicalPort; /* 0x0B */ - MPI2_EVENT_SAS_TOPO_PHY_ENTRY PHY[MPI2_EVENT_SAS_TOPO_PHY_COUNT]; /* 0x0C*/ -} MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, - Mpi2EventDataSasTopologyChangeList_t, - MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t; - -/* values for the ExpStatus field */ -#define MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00) -#define MPI2_EVENT_SAS_TOPO_ES_ADDED (0x01) -#define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02) -#define MPI2_EVENT_SAS_TOPO_ES_RESPONDING (0x03) -#define MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING (0x04) - -/* defines for the LinkRate field */ -#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK (0xF0) -#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT (4) -#define MPI2_EVENT_SAS_TOPO_LR_PREV_MASK (0x0F) -#define MPI2_EVENT_SAS_TOPO_LR_PREV_SHIFT (0) - -#define MPI2_EVENT_SAS_TOPO_LR_UNKNOWN_LINK_RATE (0x00) -#define MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED (0x01) -#define MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED (0x02) -#define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03) -#define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04) -#define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05) -#define MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06) -#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08) -#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09) -#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A) - -/* values for the PhyStatus field */ -#define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT (0x80) -#define MPI2_EVENT_SAS_TOPO_PS_MULTIPLEX_CHANGE (0x10) -/* values for the PhyStatus ReasonCode sub-field */ -#define MPI2_EVENT_SAS_TOPO_RC_MASK (0x0F) -#define MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED (0x01) -#define MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING (0x02) -#define MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED (0x03) -#define MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE (0x04) -#define MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING (0x05) - - -/* SAS Enclosure Device Status Change Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE -{ - U16 EnclosureHandle; /* 0x00 */ - U8 ReasonCode; /* 0x02 */ - U8 PhysicalPort; /* 0x03 */ - U64 EnclosureLogicalID; /* 0x04 */ - U16 NumSlots; /* 0x0C */ - U16 StartSlot; /* 0x0E */ - U32 PhyBits; /* 0x10 */ -} MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, - Mpi2EventDataSasEnclDevStatusChange_t, - MPI2_POINTER pMpi2EventDataSasEnclDevStatusChange_t; - -/* SAS Enclosure Device Status Change event ReasonCode values */ -#define MPI2_EVENT_SAS_ENCL_RC_ADDED (0x01) -#define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING (0x02) - - -/* SAS PHY Counter Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER { - U64 TimeStamp; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U8 PhyEventCode; /* 0x0C */ - U8 PhyNum; /* 0x0D */ - U16 Reserved2; /* 0x0E */ - U32 PhyEventInfo; /* 0x10 */ - U8 CounterType; /* 0x14 */ - U8 ThresholdWindow; /* 0x15 */ - U8 TimeUnits; /* 0x16 */ - U8 Reserved3; /* 0x17 */ - U32 EventThreshold; /* 0x18 */ - U16 ThresholdFlags; /* 0x1C */ - U16 Reserved4; /* 0x1E */ -} MPI2_EVENT_DATA_SAS_PHY_COUNTER, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_PHY_COUNTER, - Mpi2EventDataSasPhyCounter_t, MPI2_POINTER pMpi2EventDataSasPhyCounter_t; - -/* use MPI2_SASPHY3_EVENT_CODE_ values from mpi2_cnfg.h for the - * PhyEventCode field - * use MPI2_SASPHY3_COUNTER_TYPE_ values from mpi2_cnfg.h for the - * CounterType field - * use MPI2_SASPHY3_TIME_UNITS_ values from mpi2_cnfg.h for the - * TimeUnits field - * use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the - * ThresholdFlags field - * */ - - -/* SAS Quiesce Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE { - U8 ReasonCode; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 Reserved3; /* 0x04 */ -} MPI2_EVENT_DATA_SAS_QUIESCE, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE, - Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t; - -/* SAS Quiesce Event data ReasonCode values */ -#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01) -#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02) - - -/* Host Based Discovery Phy Event data */ - -typedef struct _MPI2_EVENT_HBD_PHY_SAS { - U8 Flags; /* 0x00 */ - U8 NegotiatedLinkRate; /* 0x01 */ - U8 PhyNum; /* 0x02 */ - U8 PhysicalPort; /* 0x03 */ - U32 Reserved1; /* 0x04 */ - U8 InitialFrame[28]; /* 0x08 */ -} MPI2_EVENT_HBD_PHY_SAS, MPI2_POINTER PTR_MPI2_EVENT_HBD_PHY_SAS, - Mpi2EventHbdPhySas_t, MPI2_POINTER pMpi2EventHbdPhySas_t; - -/* values for the Flags field */ -#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02) -#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01) - -/* use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h for - * the NegotiatedLinkRate field */ - -typedef union _MPI2_EVENT_HBD_DESCRIPTOR { - MPI2_EVENT_HBD_PHY_SAS Sas; -} MPI2_EVENT_HBD_DESCRIPTOR, MPI2_POINTER PTR_MPI2_EVENT_HBD_DESCRIPTOR, - Mpi2EventHbdDescriptor_t, MPI2_POINTER pMpi2EventHbdDescriptor_t; - -typedef struct _MPI2_EVENT_DATA_HBD_PHY { - U8 DescriptorType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 Reserved3; /* 0x04 */ - MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /* 0x08 */ -} MPI2_EVENT_DATA_HBD_PHY, MPI2_POINTER PTR_MPI2_EVENT_DATA_HBD_PHY, - Mpi2EventDataHbdPhy_t, MPI2_POINTER pMpi2EventDataMpi2EventDataHbdPhy_t; - -/* values for the DescriptorType field */ -#define MPI2_EVENT_HBD_DT_SAS (0x01) - - - -/**************************************************************************** -* EventAck message -****************************************************************************/ - -/* EventAck Request message */ -typedef struct _MPI2_EVENT_ACK_REQUEST -{ - U16 Reserved1; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Event; /* 0x0C */ - U16 Reserved5; /* 0x0E */ - U32 EventContext; /* 0x10 */ -} MPI2_EVENT_ACK_REQUEST, MPI2_POINTER PTR_MPI2_EVENT_ACK_REQUEST, - Mpi2EventAckRequest_t, MPI2_POINTER pMpi2EventAckRequest_t; - - -/* EventAck Reply message */ -typedef struct _MPI2_EVENT_ACK_REPLY -{ - U16 Reserved1; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_EVENT_ACK_REPLY, MPI2_POINTER PTR_MPI2_EVENT_ACK_REPLY, - Mpi2EventAckReply_t, MPI2_POINTER pMpi2EventAckReply_t; - - -/**************************************************************************** -* SendHostMessage message -****************************************************************************/ - -/* SendHostMessage Request message */ -typedef struct _MPI2_SEND_HOST_MESSAGE_REQUEST { - U16 HostDataLength; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved1; /* 0x04 */ - U8 Reserved2; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U8 Reserved4; /* 0x0C */ - U8 DestVF_ID; /* 0x0D */ - U16 Reserved5; /* 0x0E */ - U32 Reserved6; /* 0x10 */ - U32 Reserved7; /* 0x14 */ - U32 Reserved8; /* 0x18 */ - U32 Reserved9; /* 0x1C */ - U32 Reserved10; /* 0x20 */ - U32 HostData[1]; /* 0x24 */ -} MPI2_SEND_HOST_MESSAGE_REQUEST, -MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REQUEST, -Mpi2SendHostMessageRequest_t, MPI2_POINTER pMpi2SendHostMessageRequest_t; - - -/* SendHostMessage Reply message */ -typedef struct _MPI2_SEND_HOST_MESSAGE_REPLY { - U16 HostDataLength; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved1; /* 0x04 */ - U8 Reserved2; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U16 Reserved4; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_SEND_HOST_MESSAGE_REPLY, MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REPLY, -Mpi2SendHostMessageReply_t, MPI2_POINTER pMpi2SendHostMessageReply_t; - - -/**************************************************************************** -* FWDownload message -****************************************************************************/ - -/* FWDownload Request message */ -typedef struct _MPI2_FW_DOWNLOAD_REQUEST -{ - U8 ImageType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U32 TotalImageSize; /* 0x0C */ - U32 Reserved5; /* 0x10 */ - MPI2_MPI_SGE_UNION SGL; /* 0x14 */ -} MPI2_FW_DOWNLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REQUEST, - Mpi2FWDownloadRequest, MPI2_POINTER pMpi2FWDownloadRequest; - -#define MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT (0x01) - -#define MPI2_FW_DOWNLOAD_ITYPE_FW (0x01) -#define MPI2_FW_DOWNLOAD_ITYPE_BIOS (0x02) -#define MPI2_FW_DOWNLOAD_ITYPE_MANUFACTURING (0x06) -#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07) -#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08) -#define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) -#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A) -#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) -#define MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY (0x0C) -#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0) - -/* FWDownload TransactionContext Element */ -typedef struct _MPI2_FW_DOWNLOAD_TCSGE -{ - U8 Reserved1; /* 0x00 */ - U8 ContextSize; /* 0x01 */ - U8 DetailsLength; /* 0x02 */ - U8 Flags; /* 0x03 */ - U32 Reserved2; /* 0x04 */ - U32 ImageOffset; /* 0x08 */ - U32 ImageSize; /* 0x0C */ -} MPI2_FW_DOWNLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_TCSGE, - Mpi2FWDownloadTCSGE_t, MPI2_POINTER pMpi2FWDownloadTCSGE_t; - -/* FWDownload Reply message */ -typedef struct _MPI2_FW_DOWNLOAD_REPLY -{ - U8 ImageType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_FW_DOWNLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REPLY, - Mpi2FWDownloadReply_t, MPI2_POINTER pMpi2FWDownloadReply_t; - - -/**************************************************************************** -* FWUpload message -****************************************************************************/ - -/* FWUpload Request message */ -typedef struct _MPI2_FW_UPLOAD_REQUEST -{ - U8 ImageType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U32 Reserved5; /* 0x0C */ - U32 Reserved6; /* 0x10 */ - MPI2_MPI_SGE_UNION SGL; /* 0x14 */ -} MPI2_FW_UPLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REQUEST, - Mpi2FWUploadRequest_t, MPI2_POINTER pMpi2FWUploadRequest_t; - -#define MPI2_FW_UPLOAD_ITYPE_FW_CURRENT (0x00) -#define MPI2_FW_UPLOAD_ITYPE_FW_FLASH (0x01) -#define MPI2_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) -#define MPI2_FW_UPLOAD_ITYPE_FW_BACKUP (0x05) -#define MPI2_FW_UPLOAD_ITYPE_MANUFACTURING (0x06) -#define MPI2_FW_UPLOAD_ITYPE_CONFIG_1 (0x07) -#define MPI2_FW_UPLOAD_ITYPE_CONFIG_2 (0x08) -#define MPI2_FW_UPLOAD_ITYPE_MEGARAID (0x09) -#define MPI2_FW_UPLOAD_ITYPE_COMPLETE (0x0A) -#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) - -typedef struct _MPI2_FW_UPLOAD_TCSGE -{ - U8 Reserved1; /* 0x00 */ - U8 ContextSize; /* 0x01 */ - U8 DetailsLength; /* 0x02 */ - U8 Flags; /* 0x03 */ - U32 Reserved2; /* 0x04 */ - U32 ImageOffset; /* 0x08 */ - U32 ImageSize; /* 0x0C */ -} MPI2_FW_UPLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_UPLOAD_TCSGE, - Mpi2FWUploadTCSGE_t, MPI2_POINTER pMpi2FWUploadTCSGE_t; - -/* FWUpload Reply message */ -typedef struct _MPI2_FW_UPLOAD_REPLY -{ - U8 ImageType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 ActualImageSize; /* 0x14 */ -} MPI2_FW_UPLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REPLY, - Mpi2FWUploadReply_t, MPI2_POINTER pMPi2FWUploadReply_t; - - -/* FW Image Header */ -typedef struct _MPI2_FW_IMAGE_HEADER -{ - U32 Signature; /* 0x00 */ - U32 Signature0; /* 0x04 */ - U32 Signature1; /* 0x08 */ - U32 Signature2; /* 0x0C */ - MPI2_VERSION_UNION MPIVersion; /* 0x10 */ - MPI2_VERSION_UNION FWVersion; /* 0x14 */ - MPI2_VERSION_UNION NVDATAVersion; /* 0x18 */ - MPI2_VERSION_UNION PackageVersion; /* 0x1C */ - U16 VendorID; /* 0x20 */ - U16 ProductID; /* 0x22 */ - U16 ProtocolFlags; /* 0x24 */ - U16 Reserved26; /* 0x26 */ - U32 IOCCapabilities; /* 0x28 */ - U32 ImageSize; /* 0x2C */ - U32 NextImageHeaderOffset; /* 0x30 */ - U32 Checksum; /* 0x34 */ - U32 Reserved38; /* 0x38 */ - U32 Reserved3C; /* 0x3C */ - U32 Reserved40; /* 0x40 */ - U32 Reserved44; /* 0x44 */ - U32 Reserved48; /* 0x48 */ - U32 Reserved4C; /* 0x4C */ - U32 Reserved50; /* 0x50 */ - U32 Reserved54; /* 0x54 */ - U32 Reserved58; /* 0x58 */ - U32 Reserved5C; /* 0x5C */ - U32 Reserved60; /* 0x60 */ - U32 FirmwareVersionNameWhat; /* 0x64 */ - U8 FirmwareVersionName[32]; /* 0x68 */ - U32 VendorNameWhat; /* 0x88 */ - U8 VendorName[32]; /* 0x8C */ - U32 PackageNameWhat; /* 0x88 */ - U8 PackageName[32]; /* 0x8C */ - U32 ReservedD0; /* 0xD0 */ - U32 ReservedD4; /* 0xD4 */ - U32 ReservedD8; /* 0xD8 */ - U32 ReservedDC; /* 0xDC */ - U32 ReservedE0; /* 0xE0 */ - U32 ReservedE4; /* 0xE4 */ - U32 ReservedE8; /* 0xE8 */ - U32 ReservedEC; /* 0xEC */ - U32 ReservedF0; /* 0xF0 */ - U32 ReservedF4; /* 0xF4 */ - U32 ReservedF8; /* 0xF8 */ - U32 ReservedFC; /* 0xFC */ -} MPI2_FW_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_FW_IMAGE_HEADER, - Mpi2FWImageHeader_t, MPI2_POINTER pMpi2FWImageHeader_t; - -/* Signature field */ -#define MPI2_FW_HEADER_SIGNATURE_OFFSET (0x00) -#define MPI2_FW_HEADER_SIGNATURE_MASK (0xFF000000) -#define MPI2_FW_HEADER_SIGNATURE (0xEA000000) - -/* Signature0 field */ -#define MPI2_FW_HEADER_SIGNATURE0_OFFSET (0x04) -#define MPI2_FW_HEADER_SIGNATURE0 (0x5AFAA55A) - -/* Signature1 field */ -#define MPI2_FW_HEADER_SIGNATURE1_OFFSET (0x08) -#define MPI2_FW_HEADER_SIGNATURE1 (0xA55AFAA5) - -/* Signature2 field */ -#define MPI2_FW_HEADER_SIGNATURE2_OFFSET (0x0C) -#define MPI2_FW_HEADER_SIGNATURE2 (0x5AA55AFA) - - -/* defines for using the ProductID field */ -#define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000) -#define MPI2_FW_HEADER_PID_TYPE_SAS (0x2000) - -#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) -#define MPI2_FW_HEADER_PID_PROD_A (0x0000) -#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200) -#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700) - - -#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF) -/* SAS */ -#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013) -#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014) - -/* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */ - -/* use MPI2_IOCFACTS_CAPABILITY_ defines for IOCCapabilities field */ - - -#define MPI2_FW_HEADER_IMAGESIZE_OFFSET (0x2C) -#define MPI2_FW_HEADER_NEXTIMAGE_OFFSET (0x30) -#define MPI2_FW_HEADER_VERNMHWAT_OFFSET (0x64) - -#define MPI2_FW_HEADER_WHAT_SIGNATURE (0x29232840) - -#define MPI2_FW_HEADER_SIZE (0x100) - - -/* Extended Image Header */ -typedef struct _MPI2_EXT_IMAGE_HEADER - -{ - U8 ImageType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 Checksum; /* 0x04 */ - U32 ImageSize; /* 0x08 */ - U32 NextImageHeaderOffset; /* 0x0C */ - U32 PackageVersion; /* 0x10 */ - U32 Reserved3; /* 0x14 */ - U32 Reserved4; /* 0x18 */ - U32 Reserved5; /* 0x1C */ - U8 IdentifyString[32]; /* 0x20 */ -} MPI2_EXT_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_EXT_IMAGE_HEADER, - Mpi2ExtImageHeader_t, MPI2_POINTER pMpi2ExtImageHeader_t; - -/* useful offsets */ -#define MPI2_EXT_IMAGE_IMAGETYPE_OFFSET (0x00) -#define MPI2_EXT_IMAGE_IMAGESIZE_OFFSET (0x08) -#define MPI2_EXT_IMAGE_NEXTIMAGE_OFFSET (0x0C) - -#define MPI2_EXT_IMAGE_HEADER_SIZE (0x40) - -/* defines for the ImageType field */ -#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) -#define MPI2_EXT_IMAGE_TYPE_FW (0x01) -#define MPI2_EXT_IMAGE_TYPE_NVDATA (0x03) -#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER (0x04) -#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION (0x05) -#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT (0x06) -#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES (0x07) -#define MPI2_EXT_IMAGE_TYPE_MEGARAID (0x08) -#define MPI2_EXT_IMAGE_TYPE_ENCRYPTED_HASH (0x09) -#define MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC (0x80) -#define MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC (0xFF) -#define MPI2_EXT_IMAGE_TYPE_MAX \ - (MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC) /* deprecated */ - - - -/* FLASH Layout Extended Image Data */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check RegionsPerLayout at runtime. - */ -#ifndef MPI2_FLASH_NUMBER_OF_REGIONS -#define MPI2_FLASH_NUMBER_OF_REGIONS (1) -#endif - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check NumberOfLayouts at runtime. - */ -#ifndef MPI2_FLASH_NUMBER_OF_LAYOUTS -#define MPI2_FLASH_NUMBER_OF_LAYOUTS (1) -#endif - -typedef struct _MPI2_FLASH_REGION -{ - U8 RegionType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 RegionOffset; /* 0x04 */ - U32 RegionSize; /* 0x08 */ - U32 Reserved3; /* 0x0C */ -} MPI2_FLASH_REGION, MPI2_POINTER PTR_MPI2_FLASH_REGION, - Mpi2FlashRegion_t, MPI2_POINTER pMpi2FlashRegion_t; - -typedef struct _MPI2_FLASH_LAYOUT -{ - U32 FlashSize; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U32 Reserved3; /* 0x0C */ - MPI2_FLASH_REGION Region[MPI2_FLASH_NUMBER_OF_REGIONS];/* 0x10 */ -} MPI2_FLASH_LAYOUT, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT, - Mpi2FlashLayout_t, MPI2_POINTER pMpi2FlashLayout_t; - -typedef struct _MPI2_FLASH_LAYOUT_DATA -{ - U8 ImageRevision; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 SizeOfRegion; /* 0x02 */ - U8 Reserved2; /* 0x03 */ - U16 NumberOfLayouts; /* 0x04 */ - U16 RegionsPerLayout; /* 0x06 */ - U16 MinimumSectorAlignment; /* 0x08 */ - U16 Reserved3; /* 0x0A */ - U32 Reserved4; /* 0x0C */ - MPI2_FLASH_LAYOUT Layout[MPI2_FLASH_NUMBER_OF_LAYOUTS];/* 0x10 */ -} MPI2_FLASH_LAYOUT_DATA, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT_DATA, - Mpi2FlashLayoutData_t, MPI2_POINTER pMpi2FlashLayoutData_t; - -/* defines for the RegionType field */ -#define MPI2_FLASH_REGION_UNUSED (0x00) -#define MPI2_FLASH_REGION_FIRMWARE (0x01) -#define MPI2_FLASH_REGION_BIOS (0x02) -#define MPI2_FLASH_REGION_NVDATA (0x03) -#define MPI2_FLASH_REGION_FIRMWARE_BACKUP (0x05) -#define MPI2_FLASH_REGION_MFG_INFORMATION (0x06) -#define MPI2_FLASH_REGION_CONFIG_1 (0x07) -#define MPI2_FLASH_REGION_CONFIG_2 (0x08) -#define MPI2_FLASH_REGION_MEGARAID (0x09) -#define MPI2_FLASH_REGION_INIT (0x0A) - -/* ImageRevision */ -#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00) - - - -/* Supported Devices Extended Image Data */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check NumberOfDevices at runtime. - */ -#ifndef MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES -#define MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES (1) -#endif - -typedef struct _MPI2_SUPPORTED_DEVICE -{ - U16 DeviceID; /* 0x00 */ - U16 VendorID; /* 0x02 */ - U16 DeviceIDMask; /* 0x04 */ - U16 Reserved1; /* 0x06 */ - U8 LowPCIRev; /* 0x08 */ - U8 HighPCIRev; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U32 Reserved3; /* 0x0C */ -} MPI2_SUPPORTED_DEVICE, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICE, - Mpi2SupportedDevice_t, MPI2_POINTER pMpi2SupportedDevice_t; - -typedef struct _MPI2_SUPPORTED_DEVICES_DATA -{ - U8 ImageRevision; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 NumberOfDevices; /* 0x02 */ - U8 Reserved2; /* 0x03 */ - U32 Reserved3; /* 0x04 */ - MPI2_SUPPORTED_DEVICE SupportedDevice[MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES]; /* 0x08 */ -} MPI2_SUPPORTED_DEVICES_DATA, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICES_DATA, - Mpi2SupportedDevicesData_t, MPI2_POINTER pMpi2SupportedDevicesData_t; - -/* ImageRevision */ -#define MPI2_SUPPORTED_DEVICES_IMAGE_REVISION (0x00) - - -/* Init Extended Image Data */ - -typedef struct _MPI2_INIT_IMAGE_FOOTER - -{ - U32 BootFlags; /* 0x00 */ - U32 ImageSize; /* 0x04 */ - U32 Signature0; /* 0x08 */ - U32 Signature1; /* 0x0C */ - U32 Signature2; /* 0x10 */ - U32 ResetVector; /* 0x14 */ -} MPI2_INIT_IMAGE_FOOTER, MPI2_POINTER PTR_MPI2_INIT_IMAGE_FOOTER, - Mpi2InitImageFooter_t, MPI2_POINTER pMpi2InitImageFooter_t; - -/* defines for the BootFlags field */ -#define MPI2_INIT_IMAGE_BOOTFLAGS_OFFSET (0x00) - -/* defines for the ImageSize field */ -#define MPI2_INIT_IMAGE_IMAGESIZE_OFFSET (0x04) - -/* defines for the Signature0 field */ -#define MPI2_INIT_IMAGE_SIGNATURE0_OFFSET (0x08) -#define MPI2_INIT_IMAGE_SIGNATURE0 (0x5AA55AEA) - -/* defines for the Signature1 field */ -#define MPI2_INIT_IMAGE_SIGNATURE1_OFFSET (0x0C) -#define MPI2_INIT_IMAGE_SIGNATURE1 (0xA55AEAA5) - -/* defines for the Signature2 field */ -#define MPI2_INIT_IMAGE_SIGNATURE2_OFFSET (0x10) -#define MPI2_INIT_IMAGE_SIGNATURE2 (0x5AEAA55A) - -/* Signature fields as individual bytes */ -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_0 (0xEA) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_1 (0x5A) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_2 (0xA5) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_3 (0x5A) - -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_4 (0xA5) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_5 (0xEA) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_6 (0x5A) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_7 (0xA5) - -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_8 (0x5A) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_9 (0xA5) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_A (0xEA) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_B (0x5A) - -/* defines for the ResetVector field */ -#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14) - - -/* Encrypted Hash Extended Image Data */ - -typedef struct _MPI25_ENCRYPTED_HASH_ENTRY { - U8 HashImageType; /* 0x00 */ - U8 HashAlgorithm; /* 0x01 */ - U8 EncryptionAlgorithm; /* 0x02 */ - U8 Reserved1; /* 0x03 */ - U32 Reserved2; /* 0x04 */ - U32 EncryptedHash[1]; /* 0x08 */ -} MPI25_ENCRYPTED_HASH_ENTRY, MPI2_POINTER PTR_MPI25_ENCRYPTED_HASH_ENTRY, -Mpi25EncryptedHashEntry_t, MPI2_POINTER pMpi25EncryptedHashEntry_t; - -/* values for HashImageType */ -#define MPI25_HASH_IMAGE_TYPE_UNUSED (0x00) -#define MPI25_HASH_IMAGE_TYPE_FIRMWARE (0x01) -#define MPI25_HASH_IMAGE_TYPE_BIOS (0x02) - -/* values for HashAlgorithm */ -#define MPI25_HASH_ALGORITHM_UNUSED (0x00) -#define MPI25_HASH_ALGORITHM_SHA256 (0x01) - -/* values for EncryptionAlgorithm */ -#define MPI25_ENCRYPTION_ALG_UNUSED (0x00) -#define MPI25_ENCRYPTION_ALG_RSA256 (0x01) - -typedef struct _MPI25_ENCRYPTED_HASH_DATA { - U8 ImageVersion; /* 0x00 */ - U8 NumHash; /* 0x01 */ - U16 Reserved1; /* 0x02 */ - U32 Reserved2; /* 0x04 */ - MPI25_ENCRYPTED_HASH_ENTRY EncryptedHashEntry[1]; /* 0x08 */ -} MPI25_ENCRYPTED_HASH_DATA, MPI2_POINTER PTR_MPI25_ENCRYPTED_HASH_DATA, -Mpi25EncryptedHashData_t, MPI2_POINTER pMpi25EncryptedHashData_t; - -/**************************************************************************** -* PowerManagementControl message -****************************************************************************/ - -/* PowerManagementControl Request message */ -typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST { - U8 Feature; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U8 Parameter1; /* 0x0C */ - U8 Parameter2; /* 0x0D */ - U8 Parameter3; /* 0x0E */ - U8 Parameter4; /* 0x0F */ - U32 Reserved5; /* 0x10 */ - U32 Reserved6; /* 0x14 */ -} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST, - Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t; - -/* defines for the Feature field */ -#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01) -#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02) -#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) /* obsolete */ -#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04) -#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80) -#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF) - -/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */ -/* Parameter1 contains a PHY number */ -/* Parameter2 indicates power condition action using these defines */ -#define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01) -#define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02) -#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03) -/* Parameter3 and Parameter4 are reserved */ - -/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION - * Feature */ -/* Parameter1 contains SAS port width modulation group number */ -/* Parameter2 indicates IOC action using these defines */ -#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01) -#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02) -#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03) -/* Parameter3 indicates desired modulation level using these defines */ -#define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00) -#define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01) -#define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02) -#define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03) -/* Parameter4 is reserved */ - -/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */ -/* Parameter1 indicates desired PCIe link speed using these defines */ -#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) /* obsolete */ -/* Parameter2 indicates desired PCIe link width using these defines */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) /* obsolete */ -/* Parameter3 and Parameter4 are reserved */ - -/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */ -/* Parameter1 indicates desired IOC hardware clock speed using these defines */ -#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01) -#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02) -#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04) -#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08) -/* Parameter2, Parameter3, and Parameter4 are reserved */ - - -/* PowerManagementControl Reply message */ -typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY { - U8 Feature; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY, - Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t; - - -#endif - diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h deleted file mode 100644 index 7efa58ff0..000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (c) 2000-2014 LSI Corporation. - * - * - * Name: mpi2_raid.h - * Title: MPI Integrated RAID messages and structures - * Creation Date: April 26, 2007 - * - * mpi2_raid.h Version: 02.00.10 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 08-31-07 02.00.01 Modifications to RAID Action request and reply, - * including the Actions and ActionData. - * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD. - * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that - * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT - * can be sized by the build environment. - * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of - * VolumeCreationFlags and marked the old one as obsolete. - * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define. - * 08-24-10 02.00.06 Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with - * related structures and defines. - * Added product-specific range to RAID Action values. - * 02-06-12 02.00.08 Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN. - * 07-26-12 02.00.09 Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR. - * Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define. - * 04-17-13 02.00.10 Added MPI25_RAID_ACTION_ADATA_ALLOW_PI. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_RAID_H -#define MPI2_RAID_H - -/***************************************************************************** -* -* Integrated RAID Messages -* -*****************************************************************************/ - -/**************************************************************************** -* RAID Action messages -****************************************************************************/ - -/* ActionDataWord defines for use with MPI2_RAID_ACTION_CREATE_VOLUME action */ -#define MPI25_RAID_ACTION_ADATA_ALLOW_PI (0x80000000) - -/* ActionDataWord defines for use with MPI2_RAID_ACTION_DELETE_VOLUME action */ -#define MPI2_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000) -#define MPI2_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000001) - -/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ - -/* ActionDataWord defines for use with MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES action */ -#define MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD (0x00000001) - -/* ActionDataWord for MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE Action */ -typedef struct _MPI2_RAID_ACTION_RATE_DATA -{ - U8 RateToChange; /* 0x00 */ - U8 RateOrMode; /* 0x01 */ - U16 DataScrubDuration; /* 0x02 */ -} MPI2_RAID_ACTION_RATE_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_RATE_DATA, - Mpi2RaidActionRateData_t, MPI2_POINTER pMpi2RaidActionRateData_t; - -#define MPI2_RAID_ACTION_SET_RATE_RESYNC (0x00) -#define MPI2_RAID_ACTION_SET_RATE_DATA_SCRUB (0x01) -#define MPI2_RAID_ACTION_SET_RATE_POWERSAVE_MODE (0x02) - -/* ActionDataWord for MPI2_RAID_ACTION_START_RAID_FUNCTION Action */ -typedef struct _MPI2_RAID_ACTION_START_RAID_FUNCTION -{ - U8 RAIDFunction; /* 0x00 */ - U8 Flags; /* 0x01 */ - U16 Reserved1; /* 0x02 */ -} MPI2_RAID_ACTION_START_RAID_FUNCTION, - MPI2_POINTER PTR_MPI2_RAID_ACTION_START_RAID_FUNCTION, - Mpi2RaidActionStartRaidFunction_t, - MPI2_POINTER pMpi2RaidActionStartRaidFunction_t; - -/* defines for the RAIDFunction field */ -#define MPI2_RAID_ACTION_START_BACKGROUND_INIT (0x00) -#define MPI2_RAID_ACTION_START_ONLINE_CAP_EXPANSION (0x01) -#define MPI2_RAID_ACTION_START_CONSISTENCY_CHECK (0x02) - -/* defines for the Flags field */ -#define MPI2_RAID_ACTION_START_NEW (0x00) -#define MPI2_RAID_ACTION_START_RESUME (0x01) - -/* ActionDataWord for MPI2_RAID_ACTION_STOP_RAID_FUNCTION Action */ -typedef struct _MPI2_RAID_ACTION_STOP_RAID_FUNCTION -{ - U8 RAIDFunction; /* 0x00 */ - U8 Flags; /* 0x01 */ - U16 Reserved1; /* 0x02 */ -} MPI2_RAID_ACTION_STOP_RAID_FUNCTION, - MPI2_POINTER PTR_MPI2_RAID_ACTION_STOP_RAID_FUNCTION, - Mpi2RaidActionStopRaidFunction_t, - MPI2_POINTER pMpi2RaidActionStopRaidFunction_t; - -/* defines for the RAIDFunction field */ -#define MPI2_RAID_ACTION_STOP_BACKGROUND_INIT (0x00) -#define MPI2_RAID_ACTION_STOP_ONLINE_CAP_EXPANSION (0x01) -#define MPI2_RAID_ACTION_STOP_CONSISTENCY_CHECK (0x02) - -/* defines for the Flags field */ -#define MPI2_RAID_ACTION_STOP_ABORT (0x00) -#define MPI2_RAID_ACTION_STOP_PAUSE (0x01) - -/* ActionDataWord for MPI2_RAID_ACTION_CREATE_HOT_SPARE Action */ -typedef struct _MPI2_RAID_ACTION_HOT_SPARE -{ - U8 HotSparePool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 DevHandle; /* 0x02 */ -} MPI2_RAID_ACTION_HOT_SPARE, MPI2_POINTER PTR_MPI2_RAID_ACTION_HOT_SPARE, - Mpi2RaidActionHotSpare_t, MPI2_POINTER pMpi2RaidActionHotSpare_t; - -/* ActionDataWord for MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE Action */ -typedef struct _MPI2_RAID_ACTION_FW_UPDATE_MODE -{ - U8 Flags; /* 0x00 */ - U8 DeviceFirmwareUpdateModeTimeout; /* 0x01 */ - U16 Reserved1; /* 0x02 */ -} MPI2_RAID_ACTION_FW_UPDATE_MODE, - MPI2_POINTER PTR_MPI2_RAID_ACTION_FW_UPDATE_MODE, - Mpi2RaidActionFwUpdateMode_t, MPI2_POINTER pMpi2RaidActionFwUpdateMode_t; - -/* ActionDataWord defines for use with MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */ -#define MPI2_RAID_ACTION_ADATA_DISABLE_FW_UPDATE (0x00) -#define MPI2_RAID_ACTION_ADATA_ENABLE_FW_UPDATE (0x01) - -typedef union _MPI2_RAID_ACTION_DATA -{ - U32 Word; - MPI2_RAID_ACTION_RATE_DATA Rates; - MPI2_RAID_ACTION_START_RAID_FUNCTION StartRaidFunction; - MPI2_RAID_ACTION_STOP_RAID_FUNCTION StopRaidFunction; - MPI2_RAID_ACTION_HOT_SPARE HotSpare; - MPI2_RAID_ACTION_FW_UPDATE_MODE FwUpdateMode; -} MPI2_RAID_ACTION_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_DATA, - Mpi2RaidActionData_t, MPI2_POINTER pMpi2RaidActionData_t; - - -/* RAID Action Request Message */ -typedef struct _MPI2_RAID_ACTION_REQUEST -{ - U8 Action; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 VolDevHandle; /* 0x04 */ - U8 PhysDiskNum; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U32 Reserved3; /* 0x0C */ - MPI2_RAID_ACTION_DATA ActionDataWord; /* 0x10 */ - MPI2_SGE_SIMPLE_UNION ActionDataSGE; /* 0x14 */ -} MPI2_RAID_ACTION_REQUEST, MPI2_POINTER PTR_MPI2_RAID_ACTION_REQUEST, - Mpi2RaidActionRequest_t, MPI2_POINTER pMpi2RaidActionRequest_t; - -/* RAID Action request Action values */ - -#define MPI2_RAID_ACTION_INDICATOR_STRUCT (0x01) -#define MPI2_RAID_ACTION_CREATE_VOLUME (0x02) -#define MPI2_RAID_ACTION_DELETE_VOLUME (0x03) -#define MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES (0x04) -#define MPI2_RAID_ACTION_ENABLE_ALL_VOLUMES (0x05) -#define MPI2_RAID_ACTION_PHYSDISK_OFFLINE (0x0A) -#define MPI2_RAID_ACTION_PHYSDISK_ONLINE (0x0B) -#define MPI2_RAID_ACTION_FAIL_PHYSDISK (0x0F) -#define MPI2_RAID_ACTION_ACTIVATE_VOLUME (0x11) -#define MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15) -#define MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE (0x17) -#define MPI2_RAID_ACTION_SET_VOLUME_NAME (0x18) -#define MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE (0x19) -#define MPI2_RAID_ACTION_ENABLE_FAILED_VOLUME (0x1C) -#define MPI2_RAID_ACTION_CREATE_HOT_SPARE (0x1D) -#define MPI2_RAID_ACTION_DELETE_HOT_SPARE (0x1E) -#define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED (0x20) -#define MPI2_RAID_ACTION_START_RAID_FUNCTION (0x21) -#define MPI2_RAID_ACTION_STOP_RAID_FUNCTION (0x22) -#define MPI2_RAID_ACTION_COMPATIBILITY_CHECK (0x23) -#define MPI2_RAID_ACTION_PHYSDISK_HIDDEN (0x24) -#define MPI2_RAID_ACTION_MIN_PRODUCT_SPECIFIC (0x80) -#define MPI2_RAID_ACTION_MAX_PRODUCT_SPECIFIC (0xFF) - -/* RAID Volume Creation Structure */ - -/* - * The following define can be customized for the targeted product. - */ -#ifndef MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS -#define MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS (1) -#endif - -typedef struct _MPI2_RAID_VOLUME_PHYSDISK -{ - U8 RAIDSetNum; /* 0x00 */ - U8 PhysDiskMap; /* 0x01 */ - U16 PhysDiskDevHandle; /* 0x02 */ -} MPI2_RAID_VOLUME_PHYSDISK, MPI2_POINTER PTR_MPI2_RAID_VOLUME_PHYSDISK, - Mpi2RaidVolumePhysDisk_t, MPI2_POINTER pMpi2RaidVolumePhysDisk_t; - -/* defines for the PhysDiskMap field */ -#define MPI2_RAIDACTION_PHYSDISK_PRIMARY (0x01) -#define MPI2_RAIDACTION_PHYSDISK_SECONDARY (0x02) - -typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT -{ - U8 NumPhysDisks; /* 0x00 */ - U8 VolumeType; /* 0x01 */ - U16 Reserved1; /* 0x02 */ - U32 VolumeCreationFlags; /* 0x04 */ - U32 VolumeSettings; /* 0x08 */ - U8 Reserved2; /* 0x0C */ - U8 ResyncRate; /* 0x0D */ - U16 DataScrubDuration; /* 0x0E */ - U64 VolumeMaxLBA; /* 0x10 */ - U32 StripeSize; /* 0x18 */ - U8 Name[16]; /* 0x1C */ - MPI2_RAID_VOLUME_PHYSDISK PhysDisk[MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS];/* 0x2C */ -} MPI2_RAID_VOLUME_CREATION_STRUCT, - MPI2_POINTER PTR_MPI2_RAID_VOLUME_CREATION_STRUCT, - Mpi2RaidVolumeCreationStruct_t, MPI2_POINTER pMpi2RaidVolumeCreationStruct_t; - -/* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */ - -/* defines for the VolumeCreationFlags field */ -#define MPI2_RAID_VOL_CREATION_DEFAULT_SETTINGS (0x80000000) -#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004) -#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002) -#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001) -/* The following is an obsolete define. - * It must be shifted left 24 bits in order to set the proper bit. - */ -#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80) - - -/* RAID Online Capacity Expansion Structure */ - -typedef struct _MPI2_RAID_ONLINE_CAPACITY_EXPANSION -{ - U32 Flags; /* 0x00 */ - U16 DevHandle0; /* 0x04 */ - U16 Reserved1; /* 0x06 */ - U16 DevHandle1; /* 0x08 */ - U16 Reserved2; /* 0x0A */ -} MPI2_RAID_ONLINE_CAPACITY_EXPANSION, - MPI2_POINTER PTR_MPI2_RAID_ONLINE_CAPACITY_EXPANSION, - Mpi2RaidOnlineCapacityExpansion_t, - MPI2_POINTER pMpi2RaidOnlineCapacityExpansion_t; - -/* RAID Compatibility Input Structure */ - -typedef struct _MPI2_RAID_COMPATIBILITY_INPUT_STRUCT { - U16 SourceDevHandle; /* 0x00 */ - U16 CandidateDevHandle; /* 0x02 */ - U32 Flags; /* 0x04 */ - U32 Reserved1; /* 0x08 */ - U32 Reserved2; /* 0x0C */ -} MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, -MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, -Mpi2RaidCompatibilityInputStruct_t, -MPI2_POINTER pMpi2RaidCompatibilityInputStruct_t; - -/* defines for RAID Compatibility Structure Flags field */ -#define MPI2_RAID_COMPAT_SOURCE_IS_VOLUME_FLAG (0x00000002) -#define MPI2_RAID_COMPAT_REPORT_SOURCE_INFO_FLAG (0x00000001) - - -/* RAID Volume Indicator Structure */ - -typedef struct _MPI2_RAID_VOL_INDICATOR -{ - U64 TotalBlocks; /* 0x00 */ - U64 BlocksRemaining; /* 0x08 */ - U32 Flags; /* 0x10 */ - U32 ElapsedSeconds; /* 0x14 */ -} MPI2_RAID_VOL_INDICATOR, MPI2_POINTER PTR_MPI2_RAID_VOL_INDICATOR, - Mpi2RaidVolIndicator_t, MPI2_POINTER pMpi2RaidVolIndicator_t; - -/* defines for RAID Volume Indicator Flags field */ -#define MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID (0x80000000) - -#define MPI2_RAID_VOL_FLAGS_OP_MASK (0x0000000F) -#define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT (0x00000000) -#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001) -#define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002) -#define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003) -#define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004) - -/* RAID Compatibility Result Structure */ - -typedef struct _MPI2_RAID_COMPATIBILITY_RESULT_STRUCT { - U8 State; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 GenericAttributes; /* 0x04 */ - U32 OEMSpecificAttributes; /* 0x08 */ - U32 Reserved3; /* 0x0C */ - U32 Reserved4; /* 0x10 */ -} MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, -MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, -Mpi2RaidCompatibilityResultStruct_t, -MPI2_POINTER pMpi2RaidCompatibilityResultStruct_t; - -/* defines for RAID Compatibility Result Structure State field */ -#define MPI2_RAID_COMPAT_STATE_COMPATIBLE (0x00) -#define MPI2_RAID_COMPAT_STATE_NOT_COMPATIBLE (0x01) - -/* defines for RAID Compatibility Result Structure GenericAttributes field */ -#define MPI2_RAID_COMPAT_GENATTRIB_4K_SECTOR (0x00000010) - -#define MPI2_RAID_COMPAT_GENATTRIB_MEDIA_MASK (0x0000000C) -#define MPI2_RAID_COMPAT_GENATTRIB_SOLID_STATE_DRIVE (0x00000008) -#define MPI2_RAID_COMPAT_GENATTRIB_HARD_DISK_DRIVE (0x00000004) - -#define MPI2_RAID_COMPAT_GENATTRIB_PROTOCOL_MASK (0x00000003) -#define MPI2_RAID_COMPAT_GENATTRIB_SAS_PROTOCOL (0x00000002) -#define MPI2_RAID_COMPAT_GENATTRIB_SATA_PROTOCOL (0x00000001) - -/* RAID Action Reply ActionData union */ -typedef union _MPI2_RAID_ACTION_REPLY_DATA -{ - U32 Word[6]; - MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator; - U16 VolDevHandle; - U8 VolumeState; - U8 PhysDiskNum; - MPI2_RAID_COMPATIBILITY_RESULT_STRUCT RaidCompatibilityResult; -} MPI2_RAID_ACTION_REPLY_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY_DATA, - Mpi2RaidActionReplyData_t, MPI2_POINTER pMpi2RaidActionReplyData_t; - -/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ - - -/* RAID Action Reply Message */ -typedef struct _MPI2_RAID_ACTION_REPLY -{ - U8 Action; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 VolDevHandle; /* 0x04 */ - U8 PhysDiskNum; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U16 Reserved3; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - MPI2_RAID_ACTION_REPLY_DATA ActionData; /* 0x14 */ -} MPI2_RAID_ACTION_REPLY, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY, - Mpi2RaidActionReply_t, MPI2_POINTER pMpi2RaidActionReply_t; - - -#endif - diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h deleted file mode 100644 index 45b6fa10b..000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (c) 2000-2014 LSI Corporation. - * - * - * Name: mpi2_sas.h - * Title: MPI Serial Attached SCSI structures and definitions - * Creation Date: February 9, 2007 - * - * mpi2_sas.h Version: 02.00.05 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit - * Control Request. - * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control - * Request. - * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST - * to MPI2_SGE_IO_UNION since it supports chained SGLs. - * 05-12-10 02.00.04 Modified some comments. - * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_SAS_H -#define MPI2_SAS_H - -/* - * Values for SASStatus. - */ -#define MPI2_SASSTATUS_SUCCESS (0x00) -#define MPI2_SASSTATUS_UNKNOWN_ERROR (0x01) -#define MPI2_SASSTATUS_INVALID_FRAME (0x02) -#define MPI2_SASSTATUS_UTC_BAD_DEST (0x03) -#define MPI2_SASSTATUS_UTC_BREAK_RECEIVED (0x04) -#define MPI2_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED (0x05) -#define MPI2_SASSTATUS_UTC_PORT_LAYER_REQUEST (0x06) -#define MPI2_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED (0x07) -#define MPI2_SASSTATUS_UTC_STP_RESOURCES_BUSY (0x08) -#define MPI2_SASSTATUS_UTC_WRONG_DESTINATION (0x09) -#define MPI2_SASSTATUS_SHORT_INFORMATION_UNIT (0x0A) -#define MPI2_SASSTATUS_LONG_INFORMATION_UNIT (0x0B) -#define MPI2_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA (0x0C) -#define MPI2_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR (0x0D) -#define MPI2_SASSTATUS_XFER_RDY_NOT_EXPECTED (0x0E) -#define MPI2_SASSTATUS_DATA_INCORRECT_DATA_LENGTH (0x0F) -#define MPI2_SASSTATUS_DATA_TOO_MUCH_READ_DATA (0x10) -#define MPI2_SASSTATUS_DATA_OFFSET_ERROR (0x11) -#define MPI2_SASSTATUS_SDSF_NAK_RECEIVED (0x12) -#define MPI2_SASSTATUS_SDSF_CONNECTION_FAILED (0x13) -#define MPI2_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT (0x14) - - -/* - * Values for the SAS DeviceInfo field used in SAS Device Status Change Event - * data and SAS Configuration pages. - */ -#define MPI2_SAS_DEVICE_INFO_SEP (0x00004000) -#define MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000) -#define MPI2_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000) -#define MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH (0x00000800) -#define MPI2_SAS_DEVICE_INFO_SSP_TARGET (0x00000400) -#define MPI2_SAS_DEVICE_INFO_STP_TARGET (0x00000200) -#define MPI2_SAS_DEVICE_INFO_SMP_TARGET (0x00000100) -#define MPI2_SAS_DEVICE_INFO_SATA_DEVICE (0x00000080) -#define MPI2_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000040) -#define MPI2_SAS_DEVICE_INFO_STP_INITIATOR (0x00000020) -#define MPI2_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000010) -#define MPI2_SAS_DEVICE_INFO_SATA_HOST (0x00000008) - -#define MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007) -#define MPI2_SAS_DEVICE_INFO_NO_DEVICE (0x00000000) -#define MPI2_SAS_DEVICE_INFO_END_DEVICE (0x00000001) -#define MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER (0x00000002) -#define MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER (0x00000003) - - -/***************************************************************************** -* -* SAS Messages -* -*****************************************************************************/ - -/**************************************************************************** -* SMP Passthrough messages -****************************************************************************/ - -/* SMP Passthrough Request Message */ -typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST -{ - U8 PassthroughFlags; /* 0x00 */ - U8 PhysicalPort; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 RequestDataLength; /* 0x04 */ - U8 SGLFlags; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U32 Reserved2; /* 0x0C */ - U64 SASAddress; /* 0x10 */ - U32 Reserved3; /* 0x18 */ - U32 Reserved4; /* 0x1C */ - MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */ -} MPI2_SMP_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REQUEST, - Mpi2SmpPassthroughRequest_t, MPI2_POINTER pMpi2SmpPassthroughRequest_t; - -/* values for PassthroughFlags field */ -#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80) - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -/* SMP Passthrough Reply Message */ -typedef struct _MPI2_SMP_PASSTHROUGH_REPLY -{ - U8 PassthroughFlags; /* 0x00 */ - U8 PhysicalPort; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 ResponseDataLength; /* 0x04 */ - U8 SGLFlags; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U8 Reserved2; /* 0x0C */ - U8 SASStatus; /* 0x0D */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 Reserved3; /* 0x14 */ - U8 ResponseData[4]; /* 0x18 */ -} MPI2_SMP_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REPLY, - Mpi2SmpPassthroughReply_t, MPI2_POINTER pMpi2SmpPassthroughReply_t; - -/* values for PassthroughFlags field */ -#define MPI2_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE (0x80) - -/* values for SASStatus field are at the top of this file */ - - -/**************************************************************************** -* SATA Passthrough messages -****************************************************************************/ - -/* SATA Passthrough Request Message */ -typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST -{ - U16 DevHandle; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 PassthroughFlags; /* 0x04 */ - U8 SGLFlags; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U32 Reserved2; /* 0x0C */ - U32 Reserved3; /* 0x10 */ - U32 Reserved4; /* 0x14 */ - U32 DataLength; /* 0x18 */ - U8 CommandFIS[20]; /* 0x1C */ - MPI2_SGE_IO_UNION SGL; /* 0x30 */ -} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST, - Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t; - -/* values for PassthroughFlags field */ -#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG (0x0100) -#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA (0x0020) -#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO (0x0010) -#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU (0x0004) -#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002) -#define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001) - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -/* SATA Passthrough Reply Message */ -typedef struct _MPI2_SATA_PASSTHROUGH_REPLY -{ - U16 DevHandle; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 PassthroughFlags; /* 0x04 */ - U8 SGLFlags; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U8 Reserved2; /* 0x0C */ - U8 SASStatus; /* 0x0D */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U8 StatusFIS[20]; /* 0x14 */ - U32 StatusControlRegisters; /* 0x28 */ - U32 TransferCount; /* 0x2C */ -} MPI2_SATA_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REPLY, - Mpi2SataPassthroughReply_t, MPI2_POINTER pMpi2SataPassthroughReply_t; - -/* values for SASStatus field are at the top of this file */ - - -/**************************************************************************** -* SAS IO Unit Control messages -****************************************************************************/ - -/* SAS IO Unit Control Request Message */ -typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST -{ - U8 Operation; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 DevHandle; /* 0x04 */ - U8 IOCParameter; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U16 Reserved4; /* 0x0C */ - U8 PhyNum; /* 0x0E */ - U8 PrimFlags; /* 0x0F */ - U32 Primitive; /* 0x10 */ - U8 LookupMethod; /* 0x14 */ - U8 Reserved5; /* 0x15 */ - U16 SlotNumber; /* 0x16 */ - U64 LookupAddress; /* 0x18 */ - U32 IOCParameterValue; /* 0x20 */ - U32 Reserved7; /* 0x24 */ - U32 Reserved8; /* 0x28 */ -} MPI2_SAS_IOUNIT_CONTROL_REQUEST, - MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REQUEST, - Mpi2SasIoUnitControlRequest_t, MPI2_POINTER pMpi2SasIoUnitControlRequest_t; - -/* values for the Operation field */ -#define MPI2_SAS_OP_CLEAR_ALL_PERSISTENT (0x02) -#define MPI2_SAS_OP_PHY_LINK_RESET (0x06) -#define MPI2_SAS_OP_PHY_HARD_RESET (0x07) -#define MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08) -#define MPI2_SAS_OP_SEND_PRIMITIVE (0x0A) -#define MPI2_SAS_OP_FORCE_FULL_DISCOVERY (0x0B) -#define MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C) -#define MPI2_SAS_OP_REMOVE_DEVICE (0x0D) -#define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E) -#define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F) -#define MPI2_SAS_OP_DEV_ENABLE_NCQ (0x14) -#define MPI2_SAS_OP_DEV_DISABLE_NCQ (0x15) -#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80) - -/* values for the PrimFlags field */ -#define MPI2_SAS_PRIMFLAGS_SINGLE (0x08) -#define MPI2_SAS_PRIMFLAGS_TRIPLE (0x02) -#define MPI2_SAS_PRIMFLAGS_REDUNDANT (0x01) - -/* values for the LookupMethod field */ -#define MPI2_SAS_LOOKUP_METHOD_SAS_ADDRESS (0x01) -#define MPI2_SAS_LOOKUP_METHOD_SAS_ENCLOSURE_SLOT (0x02) -#define MPI2_SAS_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03) - - -/* SAS IO Unit Control Reply Message */ -typedef struct _MPI2_SAS_IOUNIT_CONTROL_REPLY -{ - U8 Operation; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 DevHandle; /* 0x04 */ - U8 IOCParameter; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U16 Reserved4; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_SAS_IOUNIT_CONTROL_REPLY, - MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REPLY, - Mpi2SasIoUnitControlReply_t, MPI2_POINTER pMpi2SasIoUnitControlReply_t; - - -#endif - - diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h deleted file mode 100644 index 659b8ac83..000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright (c) 2000-2014 LSI Corporation. - * - * - * Name: mpi2_tool.h - * Title: MPI diagnostic tool structures and definitions - * Creation Date: March 26, 2007 - * - * mpi2_tool.h Version: 02.00.12 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release - * structures and defines. - * 02-29-08 02.00.02 Modified various names to make them 32-character unique. - * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. - * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request - * and reply messages. - * Added MPI2_DIAG_BUF_TYPE_EXTENDED. - * Incremented MPI2_DIAG_BUF_TYPE_COUNT. - * 05-12-10 02.00.05 Added Diagnostic Data Upload tool. - * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer - * Post Request. - * 05-25-11 02.00.07 Added Flags field and related defines to - * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST. - * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that - * it uses MPI Chain SGE as well as MPI Simple SGE. - * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info. - * 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_TOOL_H -#define MPI2_TOOL_H - -/***************************************************************************** -* -* Toolbox Messages -* -*****************************************************************************/ - -/* defines for the Tools */ -#define MPI2_TOOLBOX_CLEAN_TOOL (0x00) -#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01) -#define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02) -#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03) -#define MPI2_TOOLBOX_BEACON_TOOL (0x05) -#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06) -#define MPI2_TOOLBOX_TEXT_DISPLAY_TOOL (0x07) - - -/**************************************************************************** -* Toolbox reply -****************************************************************************/ - -typedef struct _MPI2_TOOLBOX_REPLY -{ - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_TOOLBOX_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_REPLY, - Mpi2ToolboxReply_t, MPI2_POINTER pMpi2ToolboxReply_t; - - -/**************************************************************************** -* Toolbox Clean Tool request -****************************************************************************/ - -typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST -{ - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U32 Flags; /* 0x0C */ - } MPI2_TOOLBOX_CLEAN_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_CLEAN_REQUEST, - Mpi2ToolboxCleanRequest_t, MPI2_POINTER pMpi2ToolboxCleanRequest_t; - -/* values for the Flags field */ -#define MPI2_TOOLBOX_CLEAN_BOOT_SERVICES (0x80000000) -#define MPI2_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES (0x40000000) -#define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000) -#define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000) -#define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000) -#define MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC (0x04000000) -#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000) -#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000) -#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004) -#define MPI2_TOOLBOX_CLEAN_SEEPROM (0x00000002) -#define MPI2_TOOLBOX_CLEAN_NVSRAM (0x00000001) - - -/**************************************************************************** -* Toolbox Memory Move request -****************************************************************************/ - -typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST { - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - MPI2_SGE_SIMPLE_UNION SGL; /* 0x0C */ -} MPI2_TOOLBOX_MEM_MOVE_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_MEM_MOVE_REQUEST, - Mpi2ToolboxMemMoveRequest_t, MPI2_POINTER pMpi2ToolboxMemMoveRequest_t; - - -/**************************************************************************** -* Toolbox Diagnostic Data Upload request -****************************************************************************/ - -typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST { - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U8 SGLFlags; /* 0x0C */ - U8 Reserved5; /* 0x0D */ - U16 Reserved6; /* 0x0E */ - U32 Flags; /* 0x10 */ - U32 DataLength; /* 0x14 */ - MPI2_SGE_SIMPLE_UNION SGL; /* 0x18 */ -} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, -MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, -Mpi2ToolboxDiagDataUploadRequest_t, -MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t; - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER { - U32 DiagDataLength; /* 00h */ - U8 FormatCode; /* 04h */ - U8 Reserved1; /* 05h */ - U16 Reserved2; /* 06h */ -} MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER, -Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t; - - -/**************************************************************************** -* Toolbox ISTWI Read Write Tool -****************************************************************************/ - -/* Toolbox ISTWI Read Write Tool request message */ -typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST { - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U32 Reserved5; /* 0x0C */ - U32 Reserved6; /* 0x10 */ - U8 DevIndex; /* 0x14 */ - U8 Action; /* 0x15 */ - U8 SGLFlags; /* 0x16 */ - U8 Flags; /* 0x17 */ - U16 TxDataLength; /* 0x18 */ - U16 RxDataLength; /* 0x1A */ - U32 Reserved8; /* 0x1C */ - U32 Reserved9; /* 0x20 */ - U32 Reserved10; /* 0x24 */ - U32 Reserved11; /* 0x28 */ - U32 Reserved12; /* 0x2C */ - MPI2_SGE_SIMPLE_UNION SGL; /* 0x30 */ -} MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, - MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, - Mpi2ToolboxIstwiReadWriteRequest_t, - MPI2_POINTER pMpi2ToolboxIstwiReadWriteRequest_t; - -/* values for the Action field */ -#define MPI2_TOOL_ISTWI_ACTION_READ_DATA (0x01) -#define MPI2_TOOL_ISTWI_ACTION_WRITE_DATA (0x02) -#define MPI2_TOOL_ISTWI_ACTION_SEQUENCE (0x03) -#define MPI2_TOOL_ISTWI_ACTION_RESERVE_BUS (0x10) -#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11) -#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12) - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - -/* values for the Flags field */ -#define MPI2_TOOL_ISTWI_FLAG_AUTO_RESERVE_RELEASE (0x80) -#define MPI2_TOOL_ISTWI_FLAG_PAGE_ADDR_MASK (0x07) - -/* Toolbox ISTWI Read Write Tool reply message */ -typedef struct _MPI2_TOOLBOX_ISTWI_REPLY { - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U8 DevIndex; /* 0x14 */ - U8 Action; /* 0x15 */ - U8 IstwiStatus; /* 0x16 */ - U8 Reserved6; /* 0x17 */ - U16 TxDataCount; /* 0x18 */ - U16 RxDataCount; /* 0x1A */ -} MPI2_TOOLBOX_ISTWI_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_REPLY, - Mpi2ToolboxIstwiReply_t, MPI2_POINTER pMpi2ToolboxIstwiReply_t; - - -/**************************************************************************** -* Toolbox Beacon Tool request -****************************************************************************/ - -typedef struct _MPI2_TOOLBOX_BEACON_REQUEST -{ - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U8 Reserved5; /* 0x0C */ - U8 PhysicalPort; /* 0x0D */ - U8 Reserved6; /* 0x0E */ - U8 Flags; /* 0x0F */ -} MPI2_TOOLBOX_BEACON_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_BEACON_REQUEST, - Mpi2ToolboxBeaconRequest_t, MPI2_POINTER pMpi2ToolboxBeaconRequest_t; - -/* values for the Flags field */ -#define MPI2_TOOLBOX_FLAGS_BEACONMODE_OFF (0x00) -#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01) - - -/**************************************************************************** -* Toolbox Diagnostic CLI Tool -****************************************************************************/ - -#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH (0x5C) - -/* MPI v2.0 Toolbox Diagnostic CLI Tool request message */ -typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST { - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U8 SGLFlags; /* 0x0C */ - U8 Reserved5; /* 0x0D */ - U16 Reserved6; /* 0x0E */ - U32 DataLength; /* 0x10 */ - U8 DiagnosticCliCommand - [MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH]; /* 0x14 */ - MPI2_MPI_SGE_IO_UNION SGL; /* 0x70 */ -} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, - MPI2_POINTER PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, - Mpi2ToolboxDiagnosticCliRequest_t, - MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t; - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -/* Toolbox Diagnostic CLI Tool reply message */ -typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY { - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 ReturnedDataLength; /* 0x14 */ -} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY, - MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_CLI_REPLY, - Mpi2ToolboxDiagnosticCliReply_t, - MPI2_POINTER pMpi2ToolboxDiagnosticCliReply_t; - - -/**************************************************************************** -* Toolbox Console Text Display Tool -****************************************************************************/ - -/* Toolbox Console Text Display Tool request message */ -typedef struct _MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST { - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U8 Console; /* 0x0C */ - U8 Flags; /* 0x0D */ - U16 Reserved6; /* 0x0E */ - U8 TextToDisplay[4]; /* 0x10 */ -} MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST, -MPI2_POINTER PTR_MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST, -Mpi2ToolboxTextDisplayRequest_t, -MPI2_POINTER pMpi2ToolboxTextDisplayRequest_t; - -/* defines for the Console field */ -#define MPI2_TOOLBOX_CONSOLE_TYPE_MASK (0xF0) -#define MPI2_TOOLBOX_CONSOLE_TYPE_DEFAULT (0x00) -#define MPI2_TOOLBOX_CONSOLE_TYPE_UART (0x10) -#define MPI2_TOOLBOX_CONSOLE_TYPE_ETHERNET (0x20) - -#define MPI2_TOOLBOX_CONSOLE_NUMBER_MASK (0x0F) - -/* defines for the Flags field */ -#define MPI2_TOOLBOX_CONSOLE_FLAG_TIMESTAMP (0x01) - - - -/***************************************************************************** -* -* Diagnostic Buffer Messages -* -*****************************************************************************/ - - -/**************************************************************************** -* Diagnostic Buffer Post request -****************************************************************************/ - -typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST -{ - U8 ExtendedType; /* 0x00 */ - U8 BufferType; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U64 BufferAddress; /* 0x0C */ - U32 BufferLength; /* 0x14 */ - U32 Reserved5; /* 0x18 */ - U32 Reserved6; /* 0x1C */ - U32 Flags; /* 0x20 */ - U32 ProductSpecific[23]; /* 0x24 */ -} MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST, - Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t; - -/* values for the ExtendedType field */ -#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02) - -/* values for the BufferType field */ -#define MPI2_DIAG_BUF_TYPE_TRACE (0x00) -#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01) -#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02) -/* count of the number of buffer types */ -#define MPI2_DIAG_BUF_TYPE_COUNT (0x03) - -/* values for the Flags field */ -#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL (0x00000002) -#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE (0x00000001) - - -/**************************************************************************** -* Diagnostic Buffer Post reply -****************************************************************************/ - -typedef struct _MPI2_DIAG_BUFFER_POST_REPLY -{ - U8 ExtendedType; /* 0x00 */ - U8 BufferType; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 TransferLength; /* 0x14 */ -} MPI2_DIAG_BUFFER_POST_REPLY, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REPLY, - Mpi2DiagBufferPostReply_t, MPI2_POINTER pMpi2DiagBufferPostReply_t; - - -/**************************************************************************** -* Diagnostic Release request -****************************************************************************/ - -typedef struct _MPI2_DIAG_RELEASE_REQUEST -{ - U8 Reserved1; /* 0x00 */ - U8 BufferType; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ -} MPI2_DIAG_RELEASE_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REQUEST, - Mpi2DiagReleaseRequest_t, MPI2_POINTER pMpi2DiagReleaseRequest_t; - - -/**************************************************************************** -* Diagnostic Buffer Post reply -****************************************************************************/ - -typedef struct _MPI2_DIAG_RELEASE_REPLY -{ - U8 Reserved1; /* 0x00 */ - U8 BufferType; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_DIAG_RELEASE_REPLY, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REPLY, - Mpi2DiagReleaseReply_t, MPI2_POINTER pMpi2DiagReleaseReply_t; - - -#endif - diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_type.h b/drivers/scsi/mpt2sas/mpi/mpi2_type.h deleted file mode 100644 index 6b0dcdd02..000000000 --- a/drivers/scsi/mpt2sas/mpi/mpi2_type.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2000-2014 LSI Corporation. - * - * - * Name: mpi2_type.h - * Title: MPI basic type definitions - * Creation Date: August 16, 2006 - * - * mpi2_type.h Version: 02.00.00 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_TYPE_H -#define MPI2_TYPE_H - - -/******************************************************************************* - * Define MPI2_POINTER if it hasn't already been defined. By default - * MPI2_POINTER is defined to be a near pointer. MPI2_POINTER can be defined as - * a far pointer by defining MPI2_POINTER as "far *" before this header file is - * included. - */ -#ifndef MPI2_POINTER -#define MPI2_POINTER * -#endif - -/* the basic types may have already been included by mpi_type.h */ -#ifndef MPI_TYPE_H -/***************************************************************************** -* -* Basic Types -* -*****************************************************************************/ - -typedef u8 U8; -typedef __le16 U16; -typedef __le32 U32; -typedef __le64 U64 __attribute__((aligned(4))); - -/***************************************************************************** -* -* Pointer Types -* -*****************************************************************************/ - -typedef U8 *PU8; -typedef U16 *PU16; -typedef U32 *PU32; -typedef U64 *PU64; - -#endif - -#endif - diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c deleted file mode 100644 index c16791122..000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ /dev/null @@ -1,4899 +0,0 @@ -/* - * This is the Fusion MPT base driver providing common API layer interface - * for access to MPT (Message Passing Technology) firmware. - * - * This code is based on drivers/scsi/mpt2sas/mpt2_base.c - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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. - * - * 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. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mpt2sas_base.h" - -static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS]; - -#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */ - -#define MAX_HBA_QUEUE_DEPTH 30000 -#define MAX_CHAIN_DEPTH 100000 -static int max_queue_depth = -1; -module_param(max_queue_depth, int, 0); -MODULE_PARM_DESC(max_queue_depth, " max controller queue depth "); - -static int max_sgl_entries = -1; -module_param(max_sgl_entries, int, 0); -MODULE_PARM_DESC(max_sgl_entries, " max sg entries "); - -static int msix_disable = -1; -module_param(msix_disable, int, 0); -MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); - -static int max_msix_vectors = -1; -module_param(max_msix_vectors, int, 0); -MODULE_PARM_DESC(max_msix_vectors, " max msix vectors "); - -static int mpt2sas_fwfault_debug; -MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " - "and halt firmware - (default=0)"); - -static int disable_discovery = -1; -module_param(disable_discovery, int, 0); -MODULE_PARM_DESC(disable_discovery, " disable discovery "); - -static int -_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag); - -static int -_base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag); - -/** - * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug. - * - */ -static int -_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) -{ - int ret = param_set_int(val, kp); - struct MPT2SAS_ADAPTER *ioc; - - if (ret) - return ret; - - /* global ioc spinlock to protect controller list on list operations */ - printk(KERN_INFO "setting fwfault_debug(%d)\n", mpt2sas_fwfault_debug); - spin_lock(&gioc_lock); - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) - ioc->fwfault_debug = mpt2sas_fwfault_debug; - spin_unlock(&gioc_lock); - return 0; -} - -module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug, - param_get_int, &mpt2sas_fwfault_debug, 0644); - -/** - * mpt2sas_remove_dead_ioc_func - kthread context to remove dead ioc - * @arg: input argument, used to derive ioc - * - * Return 0 if controller is removed from pci subsystem. - * Return -1 for other case. - */ -static int mpt2sas_remove_dead_ioc_func(void *arg) -{ - struct MPT2SAS_ADAPTER *ioc = (struct MPT2SAS_ADAPTER *)arg; - struct pci_dev *pdev; - - if ((ioc == NULL)) - return -1; - - pdev = ioc->pdev; - if ((pdev == NULL)) - return -1; - pci_stop_and_remove_bus_device_locked(pdev); - return 0; -} - - -/** - * _base_fault_reset_work - workq handling ioc fault conditions - * @work: input argument, used to derive ioc - * Context: sleep. - * - * Return nothing. - */ -static void -_base_fault_reset_work(struct work_struct *work) -{ - struct MPT2SAS_ADAPTER *ioc = - container_of(work, struct MPT2SAS_ADAPTER, fault_reset_work.work); - unsigned long flags; - u32 doorbell; - int rc; - struct task_struct *p; - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->shost_recovery || ioc->pci_error_recovery) - goto rearm_timer; - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); - - doorbell = mpt2sas_base_get_iocstate(ioc, 0); - if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_MASK) { - printk(MPT2SAS_INFO_FMT "%s : SAS host is non-operational !!!!\n", - ioc->name, __func__); - - /* It may be possible that EEH recovery can resolve some of - * pci bus failure issues rather removing the dead ioc function - * by considering controller is in a non-operational state. So - * here priority is given to the EEH recovery. If it doesn't - * not resolve this issue, mpt2sas driver will consider this - * controller to non-operational state and remove the dead ioc - * function. - */ - if (ioc->non_operational_loop++ < 5) { - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, - flags); - goto rearm_timer; - } - - /* - * Call _scsih_flush_pending_cmds callback so that we flush all - * pending commands back to OS. This call is required to aovid - * deadlock at block layer. Dead IOC will fail to do diag reset, - * and this call is safe since dead ioc will never return any - * command back from HW. - */ - ioc->schedule_dead_ioc_flush_running_cmds(ioc); - /* - * Set remove_host flag early since kernel thread will - * take some time to execute. - */ - ioc->remove_host = 1; - /*Remove the Dead Host */ - p = kthread_run(mpt2sas_remove_dead_ioc_func, ioc, - "mpt2sas_dead_ioc_%d", ioc->id); - if (IS_ERR(p)) { - printk(MPT2SAS_ERR_FMT - "%s: Running mpt2sas_dead_ioc thread failed !!!!\n", - ioc->name, __func__); - } else { - printk(MPT2SAS_ERR_FMT - "%s: Running mpt2sas_dead_ioc thread success !!!!\n", - ioc->name, __func__); - } - - return; /* don't rearm timer */ - } - - ioc->non_operational_loop = 0; - - if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - printk(MPT2SAS_WARN_FMT "%s: hard reset: %s\n", ioc->name, - __func__, (rc == 0) ? "success" : "failed"); - doorbell = mpt2sas_base_get_iocstate(ioc, 0); - if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) - mpt2sas_base_fault_info(ioc, doorbell & - MPI2_DOORBELL_DATA_MASK); - } - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - rearm_timer: - if (ioc->fault_reset_work_q) - queue_delayed_work(ioc->fault_reset_work_q, - &ioc->fault_reset_work, - msecs_to_jiffies(FAULT_POLLING_INTERVAL)); - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -} - -/** - * mpt2sas_base_start_watchdog - start the fault_reset_work_q - * @ioc: per adapter object - * Context: sleep. - * - * Return nothing. - */ -void -mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc) -{ - unsigned long flags; - - if (ioc->fault_reset_work_q) - return; - - /* initialize fault polling */ - INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); - snprintf(ioc->fault_reset_work_q_name, - sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id); - ioc->fault_reset_work_q = - create_singlethread_workqueue(ioc->fault_reset_work_q_name); - if (!ioc->fault_reset_work_q) { - printk(MPT2SAS_ERR_FMT "%s: failed (line=%d)\n", - ioc->name, __func__, __LINE__); - return; - } - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->fault_reset_work_q) - queue_delayed_work(ioc->fault_reset_work_q, - &ioc->fault_reset_work, - msecs_to_jiffies(FAULT_POLLING_INTERVAL)); - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -} - -/** - * mpt2sas_base_stop_watchdog - stop the fault_reset_work_q - * @ioc: per adapter object - * Context: sleep. - * - * Return nothing. - */ -void -mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc) -{ - unsigned long flags; - struct workqueue_struct *wq; - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - wq = ioc->fault_reset_work_q; - ioc->fault_reset_work_q = NULL; - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); - if (wq) { - if (!cancel_delayed_work_sync(&ioc->fault_reset_work)) - flush_workqueue(wq); - destroy_workqueue(wq); - } -} - -/** - * mpt2sas_base_fault_info - verbose translation of firmware FAULT code - * @ioc: per adapter object - * @fault_code: fault code - * - * Return nothing. - */ -void -mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code) -{ - printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n", - ioc->name, fault_code); -} - -/** - * mpt2sas_halt_firmware - halt's mpt controller firmware - * @ioc: per adapter object - * - * For debugging timeout related issues. Writing 0xCOFFEE00 - * to the doorbell register will halt controller firmware. With - * the purpose to stop both driver and firmware, the enduser can - * obtain a ring buffer from controller UART. - */ -void -mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc) -{ - u32 doorbell; - - if (!ioc->fwfault_debug) - return; - - dump_stack(); - - doorbell = readl(&ioc->chip->Doorbell); - if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) - mpt2sas_base_fault_info(ioc , doorbell); - else { - writel(0xC0FFEE00, &ioc->chip->Doorbell); - printk(MPT2SAS_ERR_FMT "Firmware is halted due to command " - "timeout\n", ioc->name); - } - - panic("panic in %s\n", __func__); -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _base_sas_ioc_info - verbose translation of the ioc status - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @request_hdr: request mf - * - * Return nothing. - */ -static void -_base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, - MPI2RequestHeader_t *request_hdr) -{ - u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & - MPI2_IOCSTATUS_MASK; - char *desc = NULL; - u16 frame_sz; - char *func_str = NULL; - - /* SCSI_IO, RAID_PASS are handled from _scsih_scsi_ioc_info */ - if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || - request_hdr->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || - request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION) - return; - - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - return; - - switch (ioc_status) { - -/**************************************************************************** -* Common IOCStatus values for all replies -****************************************************************************/ - - case MPI2_IOCSTATUS_INVALID_FUNCTION: - desc = "invalid function"; - break; - case MPI2_IOCSTATUS_BUSY: - desc = "busy"; - break; - case MPI2_IOCSTATUS_INVALID_SGL: - desc = "invalid sgl"; - break; - case MPI2_IOCSTATUS_INTERNAL_ERROR: - desc = "internal error"; - break; - case MPI2_IOCSTATUS_INVALID_VPID: - desc = "invalid vpid"; - break; - case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: - desc = "insufficient resources"; - break; - case MPI2_IOCSTATUS_INVALID_FIELD: - desc = "invalid field"; - break; - case MPI2_IOCSTATUS_INVALID_STATE: - desc = "invalid state"; - break; - case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED: - desc = "op state not supported"; - break; - -/**************************************************************************** -* Config IOCStatus values -****************************************************************************/ - - case MPI2_IOCSTATUS_CONFIG_INVALID_ACTION: - desc = "config invalid action"; - break; - case MPI2_IOCSTATUS_CONFIG_INVALID_TYPE: - desc = "config invalid type"; - break; - case MPI2_IOCSTATUS_CONFIG_INVALID_PAGE: - desc = "config invalid page"; - break; - case MPI2_IOCSTATUS_CONFIG_INVALID_DATA: - desc = "config invalid data"; - break; - case MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS: - desc = "config no defaults"; - break; - case MPI2_IOCSTATUS_CONFIG_CANT_COMMIT: - desc = "config cant commit"; - break; - -/**************************************************************************** -* SCSI IO Reply -****************************************************************************/ - - case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: - case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: - case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: - case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: - case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: - case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: - case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: - case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: - case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: - case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: - case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: - case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: - break; - -/**************************************************************************** -* For use by SCSI Initiator and SCSI Target end-to-end data protection -****************************************************************************/ - - case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: - desc = "eedp guard error"; - break; - case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: - desc = "eedp ref tag error"; - break; - case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: - desc = "eedp app tag error"; - break; - -/**************************************************************************** -* SCSI Target values -****************************************************************************/ - - case MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX: - desc = "target invalid io index"; - break; - case MPI2_IOCSTATUS_TARGET_ABORTED: - desc = "target aborted"; - break; - case MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: - desc = "target no conn retryable"; - break; - case MPI2_IOCSTATUS_TARGET_NO_CONNECTION: - desc = "target no connection"; - break; - case MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: - desc = "target xfer count mismatch"; - break; - case MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: - desc = "target data offset error"; - break; - case MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: - desc = "target too much write data"; - break; - case MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT: - desc = "target iu too short"; - break; - case MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: - desc = "target ack nak timeout"; - break; - case MPI2_IOCSTATUS_TARGET_NAK_RECEIVED: - desc = "target nak received"; - break; - -/**************************************************************************** -* Serial Attached SCSI values -****************************************************************************/ - - case MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED: - desc = "smp request failed"; - break; - case MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN: - desc = "smp data overrun"; - break; - -/**************************************************************************** -* Diagnostic Buffer Post / Diagnostic Release values -****************************************************************************/ - - case MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED: - desc = "diagnostic released"; - break; - default: - break; - } - - if (!desc) - return; - - switch (request_hdr->Function) { - case MPI2_FUNCTION_CONFIG: - frame_sz = sizeof(Mpi2ConfigRequest_t) + ioc->sge_size; - func_str = "config_page"; - break; - case MPI2_FUNCTION_SCSI_TASK_MGMT: - frame_sz = sizeof(Mpi2SCSITaskManagementRequest_t); - func_str = "task_mgmt"; - break; - case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: - frame_sz = sizeof(Mpi2SasIoUnitControlRequest_t); - func_str = "sas_iounit_ctl"; - break; - case MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR: - frame_sz = sizeof(Mpi2SepRequest_t); - func_str = "enclosure"; - break; - case MPI2_FUNCTION_IOC_INIT: - frame_sz = sizeof(Mpi2IOCInitRequest_t); - func_str = "ioc_init"; - break; - case MPI2_FUNCTION_PORT_ENABLE: - frame_sz = sizeof(Mpi2PortEnableRequest_t); - func_str = "port_enable"; - break; - case MPI2_FUNCTION_SMP_PASSTHROUGH: - frame_sz = sizeof(Mpi2SmpPassthroughRequest_t) + ioc->sge_size; - func_str = "smp_passthru"; - break; - default: - frame_sz = 32; - func_str = "unknown"; - break; - } - - printk(MPT2SAS_WARN_FMT "ioc_status: %s(0x%04x), request(0x%p)," - " (%s)\n", ioc->name, desc, ioc_status, request_hdr, func_str); - - _debug_dump_mf(request_hdr, frame_sz/4); -} - -/** - * _base_display_event_data - verbose translation of firmware asyn events - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * - * Return nothing. - */ -static void -_base_display_event_data(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventNotificationReply_t *mpi_reply) -{ - char *desc = NULL; - u16 event; - - if (!(ioc->logging_level & MPT_DEBUG_EVENTS)) - return; - - event = le16_to_cpu(mpi_reply->Event); - - switch (event) { - case MPI2_EVENT_LOG_DATA: - desc = "Log Data"; - break; - case MPI2_EVENT_STATE_CHANGE: - desc = "Status Change"; - break; - case MPI2_EVENT_HARD_RESET_RECEIVED: - desc = "Hard Reset Received"; - break; - case MPI2_EVENT_EVENT_CHANGE: - desc = "Event Change"; - break; - case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: - desc = "Device Status Change"; - break; - case MPI2_EVENT_IR_OPERATION_STATUS: - if (!ioc->hide_ir_msg) - desc = "IR Operation Status"; - break; - case MPI2_EVENT_SAS_DISCOVERY: - { - Mpi2EventDataSasDiscovery_t *event_data = - (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData; - printk(MPT2SAS_INFO_FMT "Discovery: (%s)", ioc->name, - (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? - "start" : "stop"); - if (event_data->DiscoveryStatus) - printk("discovery_status(0x%08x)", - le32_to_cpu(event_data->DiscoveryStatus)); - printk("\n"); - return; - } - case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: - desc = "SAS Broadcast Primitive"; - break; - case MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: - desc = "SAS Init Device Status Change"; - break; - case MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW: - desc = "SAS Init Table Overflow"; - break; - case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: - desc = "SAS Topology Change List"; - break; - case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: - desc = "SAS Enclosure Device Status Change"; - break; - case MPI2_EVENT_IR_VOLUME: - if (!ioc->hide_ir_msg) - desc = "IR Volume"; - break; - case MPI2_EVENT_IR_PHYSICAL_DISK: - if (!ioc->hide_ir_msg) - desc = "IR Physical Disk"; - break; - case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - if (!ioc->hide_ir_msg) - desc = "IR Configuration Change List"; - break; - case MPI2_EVENT_LOG_ENTRY_ADDED: - if (!ioc->hide_ir_msg) - desc = "Log Entry Added"; - break; - case MPI2_EVENT_TEMP_THRESHOLD: - desc = "Temperature Threshold"; - break; - } - - if (!desc) - return; - - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, desc); -} -#endif - -/** - * _base_sas_log_info - verbose translation of firmware log info - * @ioc: per adapter object - * @log_info: log info - * - * Return nothing. - */ -static void -_base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info) -{ - union loginfo_type { - u32 loginfo; - struct { - u32 subcode:16; - u32 code:8; - u32 originator:4; - u32 bus_type:4; - } dw; - }; - union loginfo_type sas_loginfo; - char *originator_str = NULL; - - sas_loginfo.loginfo = log_info; - if (sas_loginfo.dw.bus_type != 3 /*SAS*/) - return; - - /* each nexus loss loginfo */ - if (log_info == 0x31170000) - return; - - /* eat the loginfos associated with task aborts */ - if (ioc->ignore_loginfos && (log_info == 0x30050000 || log_info == - 0x31140000 || log_info == 0x31130000)) - return; - - switch (sas_loginfo.dw.originator) { - case 0: - originator_str = "IOP"; - break; - case 1: - originator_str = "PL"; - break; - case 2: - if (!ioc->hide_ir_msg) - originator_str = "IR"; - else - originator_str = "WarpDrive"; - break; - } - - printk(MPT2SAS_WARN_FMT "log_info(0x%08x): originator(%s), " - "code(0x%02x), sub_code(0x%04x)\n", ioc->name, log_info, - originator_str, sas_loginfo.dw.code, - sas_loginfo.dw.subcode); -} - -/** - * _base_display_reply_info - - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Return nothing. - */ -static void -_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - u16 ioc_status; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (unlikely(!mpi_reply)) { - printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - ioc_status = le16_to_cpu(mpi_reply->IOCStatus); -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if ((ioc_status & MPI2_IOCSTATUS_MASK) && - (ioc->logging_level & MPT_DEBUG_REPLY)) { - _base_sas_ioc_info(ioc , mpi_reply, - mpt2sas_base_get_msg_frame(ioc, smid)); - } -#endif - if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) - _base_sas_log_info(ioc, le32_to_cpu(mpi_reply->IOCLogInfo)); -} - -/** - * mpt2sas_base_done - base internal command completion routine - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) - return 1; - - if (ioc->base_cmds.status == MPT2_CMD_NOT_USED) - return 1; - - ioc->base_cmds.status |= MPT2_CMD_COMPLETE; - if (mpi_reply) { - ioc->base_cmds.status |= MPT2_CMD_REPLY_VALID; - memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); - } - ioc->base_cmds.status &= ~MPT2_CMD_PENDING; - - complete(&ioc->base_cmds.done); - return 1; -} - -/** - * _base_async_event - main callback handler for firmware asyn events - * @ioc: per adapter object - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Returns void. - */ -static void -_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply) -{ - Mpi2EventNotificationReply_t *mpi_reply; - Mpi2EventAckRequest_t *ack_request; - u16 smid; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (!mpi_reply) - return; - if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION) - return; -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - _base_display_event_data(ioc, mpi_reply); -#endif - if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED)) - goto out; - smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - goto out; - } - - ack_request = mpt2sas_base_get_msg_frame(ioc, smid); - memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t)); - ack_request->Function = MPI2_FUNCTION_EVENT_ACK; - ack_request->Event = mpi_reply->Event; - ack_request->EventContext = mpi_reply->EventContext; - ack_request->VF_ID = 0; /* TODO */ - ack_request->VP_ID = 0; - mpt2sas_base_put_smid_default(ioc, smid); - - out: - - /* scsih callback handler */ - mpt2sas_scsih_event_callback(ioc, msix_index, reply); - - /* ctl callback handler */ - mpt2sas_ctl_event_callback(ioc, msix_index, reply); - - return; -} - -/** - * _base_get_cb_idx - obtain the callback index - * @ioc: per adapter object - * @smid: system request message index - * - * Return callback index. - */ -static u8 -_base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - int i; - u8 cb_idx; - - if (smid < ioc->hi_priority_smid) { - i = smid - 1; - cb_idx = ioc->scsi_lookup[i].cb_idx; - } else if (smid < ioc->internal_smid) { - i = smid - ioc->hi_priority_smid; - cb_idx = ioc->hpr_lookup[i].cb_idx; - } else if (smid <= ioc->hba_queue_depth) { - i = smid - ioc->internal_smid; - cb_idx = ioc->internal_lookup[i].cb_idx; - } else - cb_idx = 0xFF; - return cb_idx; -} - -/** - * _base_mask_interrupts - disable interrupts - * @ioc: per adapter object - * - * Disabling ResetIRQ, Reply and Doorbell Interrupts - * - * Return nothing. - */ -static void -_base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc) -{ - u32 him_register; - - ioc->mask_interrupts = 1; - him_register = readl(&ioc->chip->HostInterruptMask); - him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + MPI2_HIM_RESET_IRQ_MASK; - writel(him_register, &ioc->chip->HostInterruptMask); - readl(&ioc->chip->HostInterruptMask); -} - -/** - * _base_unmask_interrupts - enable interrupts - * @ioc: per adapter object - * - * Enabling only Reply Interrupts - * - * Return nothing. - */ -static void -_base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc) -{ - u32 him_register; - - him_register = readl(&ioc->chip->HostInterruptMask); - him_register &= ~MPI2_HIM_RIM; - writel(him_register, &ioc->chip->HostInterruptMask); - ioc->mask_interrupts = 0; -} - -union reply_descriptor { - u64 word; - struct { - u32 low; - u32 high; - } u; -}; - -/** - * _base_interrupt - MPT adapter (IOC) specific interrupt handler. - * @irq: irq number (not used) - * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure - * @r: pt_regs pointer (not used) - * - * Return IRQ_HANDLE if processed, else IRQ_NONE. - */ -static irqreturn_t -_base_interrupt(int irq, void *bus_id) -{ - struct adapter_reply_queue *reply_q = bus_id; - union reply_descriptor rd; - u32 completed_cmds; - u8 request_desript_type; - u16 smid; - u8 cb_idx; - u32 reply; - u8 msix_index = reply_q->msix_index; - struct MPT2SAS_ADAPTER *ioc = reply_q->ioc; - Mpi2ReplyDescriptorsUnion_t *rpf; - u8 rc; - - if (ioc->mask_interrupts) - return IRQ_NONE; - - if (!atomic_add_unless(&reply_q->busy, 1, 1)) - return IRQ_NONE; - - rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index]; - request_desript_type = rpf->Default.ReplyFlags - & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; - if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) { - atomic_dec(&reply_q->busy); - return IRQ_NONE; - } - - completed_cmds = 0; - cb_idx = 0xFF; - do { - rd.word = le64_to_cpu(rpf->Words); - if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX) - goto out; - reply = 0; - smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1); - if (request_desript_type == - MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { - reply = le32_to_cpu - (rpf->AddressReply.ReplyFrameAddress); - if (reply > ioc->reply_dma_max_address || - reply < ioc->reply_dma_min_address) - reply = 0; - } else if (request_desript_type == - MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER) - goto next; - else if (request_desript_type == - MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS) - goto next; - if (smid) { - cb_idx = _base_get_cb_idx(ioc, smid); - if ((likely(cb_idx < MPT_MAX_CALLBACKS)) - && (likely(mpt_callbacks[cb_idx] != NULL))) { - rc = mpt_callbacks[cb_idx](ioc, smid, - msix_index, reply); - if (reply) - _base_display_reply_info(ioc, smid, - msix_index, reply); - if (rc) - mpt2sas_base_free_smid(ioc, smid); - } - } - if (!smid) - _base_async_event(ioc, msix_index, reply); - - /* reply free queue handling */ - if (reply) { - ioc->reply_free_host_index = - (ioc->reply_free_host_index == - (ioc->reply_free_queue_depth - 1)) ? - 0 : ioc->reply_free_host_index + 1; - ioc->reply_free[ioc->reply_free_host_index] = - cpu_to_le32(reply); - wmb(); - writel(ioc->reply_free_host_index, - &ioc->chip->ReplyFreeHostIndex); - } - - next: - - rpf->Words = cpu_to_le64(ULLONG_MAX); - reply_q->reply_post_host_index = - (reply_q->reply_post_host_index == - (ioc->reply_post_queue_depth - 1)) ? 0 : - reply_q->reply_post_host_index + 1; - request_desript_type = - reply_q->reply_post_free[reply_q->reply_post_host_index]. - Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; - completed_cmds++; - if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) - goto out; - if (!reply_q->reply_post_host_index) - rpf = reply_q->reply_post_free; - else - rpf++; - } while (1); - - out: - - if (!completed_cmds) { - atomic_dec(&reply_q->busy); - return IRQ_NONE; - } - wmb(); - if (ioc->is_warpdrive) { - writel(reply_q->reply_post_host_index, - ioc->reply_post_host_index[msix_index]); - atomic_dec(&reply_q->busy); - return IRQ_HANDLED; - } - writel(reply_q->reply_post_host_index | (msix_index << - MPI2_RPHI_MSIX_INDEX_SHIFT), &ioc->chip->ReplyPostHostIndex); - atomic_dec(&reply_q->busy); - return IRQ_HANDLED; -} - -/** - * _base_is_controller_msix_enabled - is controller support muli-reply queues - * @ioc: per adapter object - * - */ -static inline int -_base_is_controller_msix_enabled(struct MPT2SAS_ADAPTER *ioc) -{ - return (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable; -} - -/** - * mpt2sas_base_flush_reply_queues - flushing the MSIX reply queues - * @ioc: per adapter object - * Context: ISR conext - * - * Called when a Task Management request has completed. We want - * to flush the other reply queues so all the outstanding IO has been - * completed back to OS before we process the TM completetion. - * - * Return nothing. - */ -void -mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc) -{ - struct adapter_reply_queue *reply_q; - - /* If MSIX capability is turned off - * then multi-queues are not enabled - */ - if (!_base_is_controller_msix_enabled(ioc)) - return; - - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - if (ioc->shost_recovery) - return; - /* TMs are on msix_index == 0 */ - if (reply_q->msix_index == 0) - continue; - _base_interrupt(reply_q->vector, (void *)reply_q); - } -} - -/** - * mpt2sas_base_release_callback_handler - clear interrupt callback handler - * @cb_idx: callback index - * - * Return nothing. - */ -void -mpt2sas_base_release_callback_handler(u8 cb_idx) -{ - mpt_callbacks[cb_idx] = NULL; -} - -/** - * mpt2sas_base_register_callback_handler - obtain index for the interrupt callback handler - * @cb_func: callback function - * - * Returns cb_func. - */ -u8 -mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func) -{ - u8 cb_idx; - - for (cb_idx = MPT_MAX_CALLBACKS-1; cb_idx; cb_idx--) - if (mpt_callbacks[cb_idx] == NULL) - break; - - mpt_callbacks[cb_idx] = cb_func; - return cb_idx; -} - -/** - * mpt2sas_base_initialize_callback_handler - initialize the interrupt callback handler - * - * Return nothing. - */ -void -mpt2sas_base_initialize_callback_handler(void) -{ - u8 cb_idx; - - for (cb_idx = 0; cb_idx < MPT_MAX_CALLBACKS; cb_idx++) - mpt2sas_base_release_callback_handler(cb_idx); -} - -/** - * mpt2sas_base_build_zero_len_sge - build zero length sg entry - * @ioc: per adapter object - * @paddr: virtual address for SGE - * - * Create a zero length scatter gather entry to insure the IOCs hardware has - * something to use if the target device goes brain dead and tries - * to send data even when none is asked for. - * - * Return nothing. - */ -void -mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr) -{ - u32 flags_length = (u32)((MPI2_SGE_FLAGS_LAST_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST | - MPI2_SGE_FLAGS_SIMPLE_ELEMENT) << - MPI2_SGE_FLAGS_SHIFT); - ioc->base_add_sg_single(paddr, flags_length, -1); -} - -/** - * _base_add_sg_single_32 - Place a simple 32 bit SGE at address pAddr. - * @paddr: virtual address for SGE - * @flags_length: SGE flags and data transfer length - * @dma_addr: Physical address - * - * Return nothing. - */ -static void -_base_add_sg_single_32(void *paddr, u32 flags_length, dma_addr_t dma_addr) -{ - Mpi2SGESimple32_t *sgel = paddr; - - flags_length |= (MPI2_SGE_FLAGS_32_BIT_ADDRESSING | - MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT; - sgel->FlagsLength = cpu_to_le32(flags_length); - sgel->Address = cpu_to_le32(dma_addr); -} - - -/** - * _base_add_sg_single_64 - Place a simple 64 bit SGE at address pAddr. - * @paddr: virtual address for SGE - * @flags_length: SGE flags and data transfer length - * @dma_addr: Physical address - * - * Return nothing. - */ -static void -_base_add_sg_single_64(void *paddr, u32 flags_length, dma_addr_t dma_addr) -{ - Mpi2SGESimple64_t *sgel = paddr; - - flags_length |= (MPI2_SGE_FLAGS_64_BIT_ADDRESSING | - MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT; - sgel->FlagsLength = cpu_to_le32(flags_length); - sgel->Address = cpu_to_le64(dma_addr); -} - -#define convert_to_kb(x) ((x) << (PAGE_SHIFT - 10)) - -/** - * _base_config_dma_addressing - set dma addressing - * @ioc: per adapter object - * @pdev: PCI device struct - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev) -{ - struct sysinfo s; - u64 consistent_dma_mask; - - if (ioc->dma_mask) - consistent_dma_mask = DMA_BIT_MASK(64); - else - consistent_dma_mask = DMA_BIT_MASK(32); - - if (sizeof(dma_addr_t) > 4) { - const uint64_t required_mask = - dma_get_required_mask(&pdev->dev); - if ((required_mask > DMA_BIT_MASK(32)) && - !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) && - !pci_set_consistent_dma_mask(pdev, consistent_dma_mask)) { - ioc->base_add_sg_single = &_base_add_sg_single_64; - ioc->sge_size = sizeof(Mpi2SGESimple64_t); - ioc->dma_mask = 64; - goto out; - } - } - - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - ioc->base_add_sg_single = &_base_add_sg_single_32; - ioc->sge_size = sizeof(Mpi2SGESimple32_t); - ioc->dma_mask = 32; - } else - return -ENODEV; - - out: - si_meminfo(&s); - printk(MPT2SAS_INFO_FMT - "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n", - ioc->name, ioc->dma_mask, convert_to_kb(s.totalram)); - - return 0; -} - -static int -_base_change_consistent_dma_mask(struct MPT2SAS_ADAPTER *ioc, - struct pci_dev *pdev) -{ - if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) { - if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) - return -ENODEV; - } - return 0; -} -/** - * _base_check_enable_msix - checks MSIX capabable. - * @ioc: per adapter object - * - * Check to see if card is capable of MSIX, and set number - * of available msix vectors - */ -static int -_base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc) -{ - int base; - u16 message_control; - - - /* Check whether controller SAS2008 B0 controller, - if it is SAS2008 B0 controller use IO-APIC instead of MSIX */ - if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 && - ioc->pdev->revision == 0x01) { - return -EINVAL; - } - - base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); - if (!base) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not " - "supported\n", ioc->name)); - return -EINVAL; - } - - /* get msix vector count */ - /* NUMA_IO not supported for older controllers */ - if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2) - ioc->msix_vector_count = 1; - else { - pci_read_config_word(ioc->pdev, base + 2, &message_control); - ioc->msix_vector_count = (message_control & 0x3FF) + 1; - } - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, " - "vector_count(%d)\n", ioc->name, ioc->msix_vector_count)); - - return 0; -} - -/** - * _base_free_irq - free irq - * @ioc: per adapter object - * - * Freeing respective reply_queue from the list. - */ -static void -_base_free_irq(struct MPT2SAS_ADAPTER *ioc) -{ - struct adapter_reply_queue *reply_q, *next; - - if (list_empty(&ioc->reply_queue_list)) - return; - - list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { - list_del(&reply_q->list); - irq_set_affinity_hint(reply_q->vector, NULL); - free_cpumask_var(reply_q->affinity_hint); - synchronize_irq(reply_q->vector); - free_irq(reply_q->vector, reply_q); - kfree(reply_q); - } -} - -/** - * _base_request_irq - request irq - * @ioc: per adapter object - * @index: msix index into vector table - * @vector: irq vector - * - * Inserting respective reply_queue into the list. - */ -static int -_base_request_irq(struct MPT2SAS_ADAPTER *ioc, u8 index, u32 vector) -{ - struct adapter_reply_queue *reply_q; - int r; - - reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL); - if (!reply_q) { - printk(MPT2SAS_ERR_FMT "unable to allocate memory %d!\n", - ioc->name, (int)sizeof(struct adapter_reply_queue)); - return -ENOMEM; - } - reply_q->ioc = ioc; - reply_q->msix_index = index; - reply_q->vector = vector; - - if (!alloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL)) - return -ENOMEM; - cpumask_clear(reply_q->affinity_hint); - - atomic_set(&reply_q->busy, 0); - if (ioc->msix_enable) - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", - MPT2SAS_DRIVER_NAME, ioc->id, index); - else - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", - MPT2SAS_DRIVER_NAME, ioc->id); - r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name, - reply_q); - if (r) { - printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n", - reply_q->name, vector); - kfree(reply_q); - return -EBUSY; - } - - INIT_LIST_HEAD(&reply_q->list); - list_add_tail(&reply_q->list, &ioc->reply_queue_list); - return 0; -} - -/** - * _base_assign_reply_queues - assigning msix index for each cpu - * @ioc: per adapter object - * - * The enduser would need to set the affinity via /proc/irq/#/smp_affinity - * - * It would nice if we could call irq_set_affinity, however it is not - * an exported symbol - */ -static void -_base_assign_reply_queues(struct MPT2SAS_ADAPTER *ioc) -{ - unsigned int cpu, nr_cpus, nr_msix, index = 0; - struct adapter_reply_queue *reply_q; - - if (!_base_is_controller_msix_enabled(ioc)) - return; - - memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz); - - nr_cpus = num_online_cpus(); - nr_msix = ioc->reply_queue_count = min(ioc->reply_queue_count, - ioc->facts.MaxMSIxVectors); - if (!nr_msix) - return; - - cpu = cpumask_first(cpu_online_mask); - - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - - unsigned int i, group = nr_cpus / nr_msix; - - if (cpu >= nr_cpus) - break; - - if (index < nr_cpus % nr_msix) - group++; - - for (i = 0 ; i < group ; i++) { - ioc->cpu_msix_table[cpu] = index; - cpumask_or(reply_q->affinity_hint, - reply_q->affinity_hint, get_cpu_mask(cpu)); - cpu = cpumask_next(cpu, cpu_online_mask); - } - - if (irq_set_affinity_hint(reply_q->vector, - reply_q->affinity_hint)) - dinitprintk(ioc, pr_info(MPT2SAS_FMT - "error setting affinity hint for irq vector %d\n", - ioc->name, reply_q->vector)); - index++; - } -} - -/** - * _base_disable_msix - disables msix - * @ioc: per adapter object - * - */ -static void -_base_disable_msix(struct MPT2SAS_ADAPTER *ioc) -{ - if (ioc->msix_enable) { - pci_disable_msix(ioc->pdev); - ioc->msix_enable = 0; - } -} - -/** - * _base_enable_msix - enables msix, failback to io_apic - * @ioc: per adapter object - * - */ -static int -_base_enable_msix(struct MPT2SAS_ADAPTER *ioc) -{ - struct msix_entry *entries, *a; - int r; - int i; - u8 try_msix = 0; - - if (msix_disable == -1 || msix_disable == 0) - try_msix = 1; - - if (!try_msix) - goto try_ioapic; - - if (_base_check_enable_msix(ioc) != 0) - goto try_ioapic; - - ioc->reply_queue_count = min_t(int, ioc->cpu_count, - ioc->msix_vector_count); - - if (!ioc->rdpq_array_enable && max_msix_vectors == -1) - max_msix_vectors = 8; - - if (max_msix_vectors > 0) { - ioc->reply_queue_count = min_t(int, max_msix_vectors, - ioc->reply_queue_count); - ioc->msix_vector_count = ioc->reply_queue_count; - } else if (max_msix_vectors == 0) - goto try_ioapic; - - printk(MPT2SAS_INFO_FMT - "MSI-X vectors supported: %d, no of cores: %d, max_msix_vectors: %d\n", - ioc->name, ioc->msix_vector_count, ioc->cpu_count, max_msix_vectors); - - entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry), - GFP_KERNEL); - if (!entries) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "kcalloc " - "failed @ at %s:%d/%s() !!!\n", ioc->name, __FILE__, - __LINE__, __func__)); - goto try_ioapic; - } - - for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) - a->entry = i; - - r = pci_enable_msix_exact(ioc->pdev, entries, ioc->reply_queue_count); - if (r) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT - "pci_enable_msix_exact failed (r=%d) !!!\n", ioc->name, r)); - kfree(entries); - goto try_ioapic; - } - - ioc->msix_enable = 1; - for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) { - r = _base_request_irq(ioc, i, a->vector); - if (r) { - _base_free_irq(ioc); - _base_disable_msix(ioc); - kfree(entries); - goto try_ioapic; - } - } - - kfree(entries); - return 0; - -/* failback to io_apic interrupt routing */ - try_ioapic: - - ioc->reply_queue_count = 1; - r = _base_request_irq(ioc, 0, ioc->pdev->irq); - - return r; -} - -/** - * mpt2sas_base_map_resources - map in controller resources (io/irq/memap) - * @ioc: per adapter object - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) -{ - struct pci_dev *pdev = ioc->pdev; - u32 memap_sz; - u32 pio_sz; - int i, r = 0; - u64 pio_chip = 0; - u64 chip_phys = 0; - struct adapter_reply_queue *reply_q; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", - ioc->name, __func__)); - - ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); - if (pci_enable_device_mem(pdev)) { - printk(MPT2SAS_WARN_FMT "pci_enable_device_mem: " - "failed\n", ioc->name); - ioc->bars = 0; - return -ENODEV; - } - - - if (pci_request_selected_regions(pdev, ioc->bars, - MPT2SAS_DRIVER_NAME)) { - printk(MPT2SAS_WARN_FMT "pci_request_selected_regions: " - "failed\n", ioc->name); - ioc->bars = 0; - r = -ENODEV; - goto out_fail; - } - - /* AER (Advanced Error Reporting) hooks */ - pci_enable_pcie_error_reporting(pdev); - - pci_set_master(pdev); - - if (_base_config_dma_addressing(ioc, pdev) != 0) { - printk(MPT2SAS_WARN_FMT "no suitable DMA mask for %s\n", - ioc->name, pci_name(pdev)); - r = -ENODEV; - goto out_fail; - } - - for (i = 0, memap_sz = 0, pio_sz = 0; (i < DEVICE_COUNT_RESOURCE) && - (!memap_sz || !pio_sz); i++) { - if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { - if (pio_sz) - continue; - pio_chip = (u64)pci_resource_start(pdev, i); - pio_sz = pci_resource_len(pdev, i); - } else { - if (memap_sz) - continue; - /* verify memory resource is valid before using */ - if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { - ioc->chip_phys = pci_resource_start(pdev, i); - chip_phys = (u64)ioc->chip_phys; - memap_sz = pci_resource_len(pdev, i); - ioc->chip = ioremap(ioc->chip_phys, memap_sz); - } - } - } - - if (ioc->chip == NULL) { - printk(MPT2SAS_ERR_FMT "unable to map adapter memory! " - "or resource not found\n", ioc->name); - r = -EINVAL; - goto out_fail; - } - - _base_mask_interrupts(ioc); - - r = _base_get_ioc_facts(ioc, CAN_SLEEP); - if (r) - goto out_fail; - - if (!ioc->rdpq_array_enable_assigned) { - ioc->rdpq_array_enable = ioc->rdpq_array_capable; - ioc->rdpq_array_enable_assigned = 1; - } - - r = _base_enable_msix(ioc); - if (r) - goto out_fail; - - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) - printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n", - reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" : - "IO-APIC enabled"), reply_q->vector); - - printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n", - ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz); - printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n", - ioc->name, (unsigned long long)pio_chip, pio_sz); - - /* Save PCI configuration state for recovery from PCI AER/EEH errors */ - pci_save_state(pdev); - - return 0; - - out_fail: - if (ioc->chip_phys) - iounmap(ioc->chip); - ioc->chip_phys = 0; - pci_release_selected_regions(ioc->pdev, ioc->bars); - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); - return r; -} - -/** - * mpt2sas_base_get_msg_frame - obtain request mf pointer - * @ioc: per adapter object - * @smid: system request message index(smid zero is invalid) - * - * Returns virt pointer to message frame. - */ -void * -mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return (void *)(ioc->request + (smid * ioc->request_sz)); -} - -/** - * mpt2sas_base_get_sense_buffer - obtain a sense buffer assigned to a mf request - * @ioc: per adapter object - * @smid: system request message index - * - * Returns virt pointer to sense buffer. - */ -void * -mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return (void *)(ioc->sense + ((smid - 1) * SCSI_SENSE_BUFFERSIZE)); -} - -/** - * mpt2sas_base_get_sense_buffer_dma - obtain a sense buffer assigned to a mf request - * @ioc: per adapter object - * @smid: system request message index - * - * Returns phys pointer to the low 32bit address of the sense buffer. - */ -__le32 -mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return cpu_to_le32(ioc->sense_dma + - ((smid - 1) * SCSI_SENSE_BUFFERSIZE)); -} - -/** - * mpt2sas_base_get_reply_virt_addr - obtain reply frames virt address - * @ioc: per adapter object - * @phys_addr: lower 32 physical addr of the reply - * - * Converts 32bit lower physical addr into a virt address. - */ -void * -mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr) -{ - if (!phys_addr) - return NULL; - return ioc->reply + (phys_addr - (u32)ioc->reply_dma); -} - -/** - * mpt2sas_base_get_smid - obtain a free smid from internal queue - * @ioc: per adapter object - * @cb_idx: callback index - * - * Returns smid (zero is invalid) - */ -u16 -mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx) -{ - unsigned long flags; - struct request_tracker *request; - u16 smid; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - if (list_empty(&ioc->internal_free_list)) { - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - printk(MPT2SAS_ERR_FMT "%s: smid not available\n", - ioc->name, __func__); - return 0; - } - - request = list_entry(ioc->internal_free_list.next, - struct request_tracker, tracker_list); - request->cb_idx = cb_idx; - smid = request->smid; - list_del(&request->tracker_list); - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return smid; -} - -/** - * mpt2sas_base_get_smid_scsiio - obtain a free smid from scsiio queue - * @ioc: per adapter object - * @cb_idx: callback index - * @scmd: pointer to scsi command object - * - * Returns smid (zero is invalid) - */ -u16 -mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx, - struct scsi_cmnd *scmd) -{ - unsigned long flags; - struct scsiio_tracker *request; - u16 smid; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - if (list_empty(&ioc->free_list)) { - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - printk(MPT2SAS_ERR_FMT "%s: smid not available\n", - ioc->name, __func__); - return 0; - } - - request = list_entry(ioc->free_list.next, - struct scsiio_tracker, tracker_list); - request->scmd = scmd; - request->cb_idx = cb_idx; - smid = request->smid; - list_del(&request->tracker_list); - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return smid; -} - -/** - * mpt2sas_base_get_smid_hpr - obtain a free smid from hi-priority queue - * @ioc: per adapter object - * @cb_idx: callback index - * - * Returns smid (zero is invalid) - */ -u16 -mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx) -{ - unsigned long flags; - struct request_tracker *request; - u16 smid; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - if (list_empty(&ioc->hpr_free_list)) { - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return 0; - } - - request = list_entry(ioc->hpr_free_list.next, - struct request_tracker, tracker_list); - request->cb_idx = cb_idx; - smid = request->smid; - list_del(&request->tracker_list); - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return smid; -} - - -/** - * mpt2sas_base_free_smid - put smid back on free_list - * @ioc: per adapter object - * @smid: system request message index - * - * Return nothing. - */ -void -mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - unsigned long flags; - int i; - struct chain_tracker *chain_req, *next; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - if (smid < ioc->hi_priority_smid) { - /* scsiio queue */ - i = smid - 1; - if (!list_empty(&ioc->scsi_lookup[i].chain_list)) { - list_for_each_entry_safe(chain_req, next, - &ioc->scsi_lookup[i].chain_list, tracker_list) { - list_del_init(&chain_req->tracker_list); - list_add(&chain_req->tracker_list, - &ioc->free_chain_list); - } - } - ioc->scsi_lookup[i].cb_idx = 0xFF; - ioc->scsi_lookup[i].scmd = NULL; - ioc->scsi_lookup[i].direct_io = 0; - list_add(&ioc->scsi_lookup[i].tracker_list, - &ioc->free_list); - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - - /* - * See _wait_for_commands_to_complete() call with regards - * to this code. - */ - if (ioc->shost_recovery && ioc->pending_io_count) { - if (ioc->pending_io_count == 1) - wake_up(&ioc->reset_wq); - ioc->pending_io_count--; - } - return; - } else if (smid < ioc->internal_smid) { - /* hi-priority */ - i = smid - ioc->hi_priority_smid; - ioc->hpr_lookup[i].cb_idx = 0xFF; - list_add(&ioc->hpr_lookup[i].tracker_list, - &ioc->hpr_free_list); - } else if (smid <= ioc->hba_queue_depth) { - /* internal queue */ - i = smid - ioc->internal_smid; - ioc->internal_lookup[i].cb_idx = 0xFF; - list_add(&ioc->internal_lookup[i].tracker_list, - &ioc->internal_free_list); - } - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -} - -/** - * _base_writeq - 64 bit write to MMIO - * @ioc: per adapter object - * @b: data payload - * @addr: address in MMIO space - * @writeq_lock: spin lock - * - * Glue for handling an atomic 64 bit word to MMIO. This special handling takes - * care of 32 bit environment where its not quarenteed to send the entire word - * in one transfer. - */ -#ifndef writeq -static inline void _base_writeq(__u64 b, volatile void __iomem *addr, - spinlock_t *writeq_lock) -{ - unsigned long flags; - __u64 data_out = cpu_to_le64(b); - - spin_lock_irqsave(writeq_lock, flags); - writel((u32)(data_out), addr); - writel((u32)(data_out >> 32), (addr + 4)); - spin_unlock_irqrestore(writeq_lock, flags); -} -#else -static inline void _base_writeq(__u64 b, volatile void __iomem *addr, - spinlock_t *writeq_lock) -{ - writeq(cpu_to_le64(b), addr); -} -#endif - -static inline u8 -_base_get_msix_index(struct MPT2SAS_ADAPTER *ioc) -{ - return ioc->cpu_msix_table[raw_smp_processor_id()]; -} - -/** - * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware - * @ioc: per adapter object - * @smid: system request message index - * @handle: device handle - * - * Return nothing. - */ -void -mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle) -{ - Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; - - - descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; - descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); - descriptor.SCSIIO.SMID = cpu_to_le16(smid); - descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); - descriptor.SCSIIO.LMID = 0; - _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, - &ioc->scsi_lookup_lock); -} - - -/** - * mpt2sas_base_put_smid_hi_priority - send Task Management request to firmware - * @ioc: per adapter object - * @smid: system request message index - * - * Return nothing. - */ -void -mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; - - descriptor.HighPriority.RequestFlags = - MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; - descriptor.HighPriority.MSIxIndex = 0; - descriptor.HighPriority.SMID = cpu_to_le16(smid); - descriptor.HighPriority.LMID = 0; - descriptor.HighPriority.Reserved1 = 0; - _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, - &ioc->scsi_lookup_lock); -} - -/** - * mpt2sas_base_put_smid_default - Default, primarily used for config pages - * @ioc: per adapter object - * @smid: system request message index - * - * Return nothing. - */ -void -mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; - - descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; - descriptor.Default.MSIxIndex = _base_get_msix_index(ioc); - descriptor.Default.SMID = cpu_to_le16(smid); - descriptor.Default.LMID = 0; - descriptor.Default.DescriptorTypeDependent = 0; - _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, - &ioc->scsi_lookup_lock); -} - -/** - * mpt2sas_base_put_smid_target_assist - send Target Assist/Status to firmware - * @ioc: per adapter object - * @smid: system request message index - * @io_index: value used to track the IO - * - * Return nothing. - */ -void -mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u16 io_index) -{ - Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; - - descriptor.SCSITarget.RequestFlags = - MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET; - descriptor.SCSITarget.MSIxIndex = _base_get_msix_index(ioc); - descriptor.SCSITarget.SMID = cpu_to_le16(smid); - descriptor.SCSITarget.LMID = 0; - descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index); - _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, - &ioc->scsi_lookup_lock); -} - -/** - * _base_display_dell_branding - Disply branding string - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_dell_branding(struct MPT2SAS_ADAPTER *ioc) -{ - char dell_branding[MPT2SAS_DELL_BRANDING_SIZE]; - - if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_DELL) - return; - - memset(dell_branding, 0, MPT2SAS_DELL_BRANDING_SIZE); - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID: - strncpy(dell_branding, MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID: - strncpy(dell_branding, MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID: - strncpy(dell_branding, - MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID: - strncpy(dell_branding, - MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID: - strncpy(dell_branding, - MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_SSDID: - strncpy(dell_branding, MPT2SAS_DELL_PERC_H200_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_6GBPS_SAS_SSDID: - strncpy(dell_branding, MPT2SAS_DELL_6GBPS_SAS_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - default: - sprintf(dell_branding, "0x%4X", ioc->pdev->subsystem_device); - break; - } - - printk(MPT2SAS_INFO_FMT "%s: Vendor(0x%04X), Device(0x%04X)," - " SSVID(0x%04X), SSDID(0x%04X)\n", ioc->name, dell_branding, - ioc->pdev->vendor, ioc->pdev->device, ioc->pdev->subsystem_vendor, - ioc->pdev->subsystem_device); -} - -/** - * _base_display_intel_branding - Display branding string - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc) -{ - if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL) - return; - - switch (ioc->pdev->device) { - case MPI2_MFGPAGE_DEVID_SAS2008: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_INTEL_RMS2LL080_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS2LL080_BRANDING); - break; - case MPT2SAS_INTEL_RMS2LL040_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS2LL040_BRANDING); - break; - case MPT2SAS_INTEL_SSD910_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_SSD910_BRANDING); - break; - default: - break; - } - case MPI2_MFGPAGE_DEVID_SAS2308_2: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_INTEL_RS25GB008_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RS25GB008_BRANDING); - break; - case MPT2SAS_INTEL_RMS25JB080_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25JB080_BRANDING); - break; - case MPT2SAS_INTEL_RMS25JB040_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25JB040_BRANDING); - break; - case MPT2SAS_INTEL_RMS25KB080_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25KB080_BRANDING); - break; - case MPT2SAS_INTEL_RMS25KB040_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25KB040_BRANDING); - break; - case MPT2SAS_INTEL_RMS25LB040_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25LB040_BRANDING); - break; - case MPT2SAS_INTEL_RMS25LB080_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25LB080_BRANDING); - break; - default: - break; - } - default: - break; - } -} - -/** - * _base_display_hp_branding - Display branding string - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_hp_branding(struct MPT2SAS_ADAPTER *ioc) -{ - if (ioc->pdev->subsystem_vendor != MPT2SAS_HP_3PAR_SSVID) - return; - - switch (ioc->pdev->device) { - case MPI2_MFGPAGE_DEVID_SAS2004: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING); - break; - default: - break; - } - case MPI2_MFGPAGE_DEVID_SAS2308_2: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_HP_2_4_INTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_2_4_INTERNAL_BRANDING); - break; - case MPT2SAS_HP_2_4_EXTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_2_4_EXTERNAL_BRANDING); - break; - case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING); - break; - case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING); - break; - default: - break; - } - default: - break; - } -} - -/** - * _base_display_ioc_capabilities - Disply IOC's capabilities. - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) -{ - int i = 0; - char desc[16]; - u32 iounit_pg1_flags; - u32 bios_version; - - bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); - strncpy(desc, ioc->manu_pg0.ChipName, 16); - printk(MPT2SAS_INFO_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), " - "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n", - ioc->name, desc, - (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, - (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, - (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, - ioc->facts.FWVersion.Word & 0x000000FF, - ioc->pdev->revision, - (bios_version & 0xFF000000) >> 24, - (bios_version & 0x00FF0000) >> 16, - (bios_version & 0x0000FF00) >> 8, - bios_version & 0x000000FF); - - _base_display_dell_branding(ioc); - _base_display_intel_branding(ioc); - _base_display_hp_branding(ioc); - - printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name); - - if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) { - printk("Initiator"); - i++; - } - - if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) { - printk("%sTarget", i ? "," : ""); - i++; - } - - i = 0; - printk("), "); - printk("Capabilities=("); - - if (!ioc->hide_ir_msg) { - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { - printk("Raid"); - i++; - } - } - - if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) { - printk("%sTLR", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) { - printk("%sMulticast", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) { - printk("%sBIDI Target", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) { - printk("%sEEDP", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) { - printk("%sSnapshot Buffer", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) { - printk("%sDiag Trace Buffer", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) { - printk(KERN_INFO "%sDiag Extended Buffer", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) { - printk("%sTask Set Full", i ? "," : ""); - i++; - } - - iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); - if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) { - printk("%sNCQ", i ? "," : ""); - i++; - } - - printk(")\n"); -} - -/** - * mpt2sas_base_update_missing_delay - change the missing delay timers - * @ioc: per adapter object - * @device_missing_delay: amount of time till device is reported missing - * @io_missing_delay: interval IO is returned when there is a missing device - * - * Return nothing. - * - * Passed on the command line, this function will modify the device missing - * delay, as well as the io missing delay. This should be called at driver - * load time. - */ -void -mpt2sas_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc, - u16 device_missing_delay, u8 io_missing_delay) -{ - u16 dmd, dmd_new, dmd_orignal; - u8 io_missing_delay_original; - u16 sz; - Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; - Mpi2ConfigReply_t mpi_reply; - u8 num_phys = 0; - u16 ioc_status; - - mpt2sas_config_get_number_hba_phys(ioc, &num_phys); - if (!num_phys) - return; - - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); - sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); - if (!sas_iounit_pg1) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, - sas_iounit_pg1, sz))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - /* device missing delay */ - dmd = sas_iounit_pg1->ReportDeviceMissingDelay; - if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) - dmd = (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; - else - dmd = dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; - dmd_orignal = dmd; - if (device_missing_delay > 0x7F) { - dmd = (device_missing_delay > 0x7F0) ? 0x7F0 : - device_missing_delay; - dmd = dmd / 16; - dmd |= MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16; - } else - dmd = device_missing_delay; - sas_iounit_pg1->ReportDeviceMissingDelay = dmd; - - /* io missing delay */ - io_missing_delay_original = sas_iounit_pg1->IODeviceMissingDelay; - sas_iounit_pg1->IODeviceMissingDelay = io_missing_delay; - - if (!mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, - sz)) { - if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) - dmd_new = (dmd & - MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; - else - dmd_new = - dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; - printk(MPT2SAS_INFO_FMT "device_missing_delay: old(%d), " - "new(%d)\n", ioc->name, dmd_orignal, dmd_new); - printk(MPT2SAS_INFO_FMT "ioc_missing_delay: old(%d), " - "new(%d)\n", ioc->name, io_missing_delay_original, - io_missing_delay); - ioc->device_missing_delay = dmd_new; - ioc->io_missing_delay = io_missing_delay; - } - -out: - kfree(sas_iounit_pg1); -} - -/** - * _base_static_config_pages - static start of day config pages - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_static_config_pages(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2ConfigReply_t mpi_reply; - u32 iounit_pg1_flags; - - mpt2sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0); - if (ioc->ir_firmware) - mpt2sas_config_get_manufacturing_pg10(ioc, &mpi_reply, - &ioc->manu_pg10); - mpt2sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2); - mpt2sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3); - mpt2sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8); - mpt2sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0); - mpt2sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); - mpt2sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8); - _base_display_ioc_capabilities(ioc); - - /* - * Enable task_set_full handling in iounit_pg1 when the - * facts capabilities indicate that its supported. - */ - iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); - if ((ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING)) - iounit_pg1_flags &= - ~MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; - else - iounit_pg1_flags |= - MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; - ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags); - mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); - - if (ioc->iounit_pg8.NumSensors) - ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors; -} - -/** - * _base_release_memory_pools - release memory - * @ioc: per adapter object - * - * Free memory allocated from _base_allocate_memory_pools. - * - * Return nothing. - */ -static void -_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) -{ - int i = 0; - struct reply_post_struct *rps; - - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - if (ioc->request) { - pci_free_consistent(ioc->pdev, ioc->request_dma_sz, - ioc->request, ioc->request_dma); - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "request_pool(0x%p)" - ": free\n", ioc->name, ioc->request)); - ioc->request = NULL; - } - - if (ioc->sense) { - pci_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma); - if (ioc->sense_dma_pool) - pci_pool_destroy(ioc->sense_dma_pool); - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_pool(0x%p)" - ": free\n", ioc->name, ioc->sense)); - ioc->sense = NULL; - } - - if (ioc->reply) { - pci_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma); - if (ioc->reply_dma_pool) - pci_pool_destroy(ioc->reply_dma_pool); - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_pool(0x%p)" - ": free\n", ioc->name, ioc->reply)); - ioc->reply = NULL; - } - - if (ioc->reply_free) { - pci_pool_free(ioc->reply_free_dma_pool, ioc->reply_free, - ioc->reply_free_dma); - if (ioc->reply_free_dma_pool) - pci_pool_destroy(ioc->reply_free_dma_pool); - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_pool" - "(0x%p): free\n", ioc->name, ioc->reply_free)); - ioc->reply_free = NULL; - } - - if (ioc->reply_post) { - do { - rps = &ioc->reply_post[i]; - if (rps->reply_post_free) { - pci_pool_free( - ioc->reply_post_free_dma_pool, - rps->reply_post_free, - rps->reply_post_free_dma); - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT - "reply_post_free_pool(0x%p): free\n", - ioc->name, rps->reply_post_free)); - rps->reply_post_free = NULL; - } - } while (ioc->rdpq_array_enable && - (++i < ioc->reply_queue_count)); - - if (ioc->reply_post_free_dma_pool) - pci_pool_destroy(ioc->reply_post_free_dma_pool); - kfree(ioc->reply_post); - } - - if (ioc->config_page) { - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT - "config_page(0x%p): free\n", ioc->name, - ioc->config_page)); - pci_free_consistent(ioc->pdev, ioc->config_page_sz, - ioc->config_page, ioc->config_page_dma); - } - - if (ioc->scsi_lookup) { - free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages); - ioc->scsi_lookup = NULL; - } - kfree(ioc->hpr_lookup); - kfree(ioc->internal_lookup); - if (ioc->chain_lookup) { - for (i = 0; i < ioc->chain_depth; i++) { - if (ioc->chain_lookup[i].chain_buffer) - pci_pool_free(ioc->chain_dma_pool, - ioc->chain_lookup[i].chain_buffer, - ioc->chain_lookup[i].chain_buffer_dma); - } - if (ioc->chain_dma_pool) - pci_pool_destroy(ioc->chain_dma_pool); - free_pages((ulong)ioc->chain_lookup, ioc->chain_pages); - ioc->chain_lookup = NULL; - } -} - - -/** - * _base_allocate_memory_pools - allocate start of day memory pools - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 success, anything else error - */ -static int -_base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - struct mpt2sas_facts *facts; - u16 max_sge_elements; - u16 chains_needed_per_io; - u32 sz, total_sz, reply_post_free_sz; - u32 retry_sz; - u16 max_request_credit; - int i; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - retry_sz = 0; - facts = &ioc->facts; - - /* command line tunables for max sgl entries */ - if (max_sgl_entries != -1) { - ioc->shost->sg_tablesize = min_t(unsigned short, - max_sgl_entries, SCSI_MAX_SG_CHAIN_SEGMENTS); - if (ioc->shost->sg_tablesize > MPT2SAS_SG_DEPTH) - printk(MPT2SAS_WARN_FMT - "sg_tablesize(%u) is bigger than kernel defined" - " SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name, - ioc->shost->sg_tablesize, MPT2SAS_SG_DEPTH); - } else { - ioc->shost->sg_tablesize = MPT2SAS_SG_DEPTH; - } - - /* command line tunables for max controller queue depth */ - if (max_queue_depth != -1 && max_queue_depth != 0) { - max_request_credit = min_t(u16, max_queue_depth + - ioc->hi_priority_depth + ioc->internal_depth, - facts->RequestCredit); - if (max_request_credit > MAX_HBA_QUEUE_DEPTH) - max_request_credit = MAX_HBA_QUEUE_DEPTH; - } else - max_request_credit = min_t(u16, facts->RequestCredit, - MAX_HBA_QUEUE_DEPTH); - - ioc->hba_queue_depth = max_request_credit; - ioc->hi_priority_depth = facts->HighPriorityCredit; - ioc->internal_depth = ioc->hi_priority_depth + 5; - - /* request frame size */ - ioc->request_sz = facts->IOCRequestFrameSize * 4; - - /* reply frame size */ - ioc->reply_sz = facts->ReplyFrameSize * 4; - - retry_allocation: - total_sz = 0; - /* calculate number of sg elements left over in the 1st frame */ - max_sge_elements = ioc->request_sz - ((sizeof(Mpi2SCSIIORequest_t) - - sizeof(Mpi2SGEIOUnion_t)) + ioc->sge_size); - ioc->max_sges_in_main_message = max_sge_elements/ioc->sge_size; - - /* now do the same for a chain buffer */ - max_sge_elements = ioc->request_sz - ioc->sge_size; - ioc->max_sges_in_chain_message = max_sge_elements/ioc->sge_size; - - ioc->chain_offset_value_for_main_message = - ((sizeof(Mpi2SCSIIORequest_t) - sizeof(Mpi2SGEIOUnion_t)) + - (ioc->max_sges_in_chain_message * ioc->sge_size)) / 4; - - /* - * MPT2SAS_SG_DEPTH = CONFIG_FUSION_MAX_SGE - */ - chains_needed_per_io = ((ioc->shost->sg_tablesize - - ioc->max_sges_in_main_message)/ioc->max_sges_in_chain_message) - + 1; - if (chains_needed_per_io > facts->MaxChainDepth) { - chains_needed_per_io = facts->MaxChainDepth; - ioc->shost->sg_tablesize = min_t(u16, - ioc->max_sges_in_main_message + (ioc->max_sges_in_chain_message - * chains_needed_per_io), ioc->shost->sg_tablesize); - } - ioc->chains_needed_per_io = chains_needed_per_io; - - /* reply free queue sizing - taking into account for 64 FW events */ - ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; - - /* calculate reply descriptor post queue depth */ - ioc->reply_post_queue_depth = ioc->hba_queue_depth + - ioc->reply_free_queue_depth + 1; - /* align the reply post queue on the next 16 count boundary */ - if (ioc->reply_post_queue_depth % 16) - ioc->reply_post_queue_depth += 16 - - (ioc->reply_post_queue_depth % 16); - - - if (ioc->reply_post_queue_depth > - facts->MaxReplyDescriptorPostQueueDepth) { - ioc->reply_post_queue_depth = - facts->MaxReplyDescriptorPostQueueDepth - - (facts->MaxReplyDescriptorPostQueueDepth % 16); - ioc->hba_queue_depth = - ((ioc->reply_post_queue_depth - 64) / 2) - 1; - ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; - } - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: " - "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), " - "chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message, - ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize, - ioc->chains_needed_per_io)); - - /* reply post queue, 16 byte align */ - reply_post_free_sz = ioc->reply_post_queue_depth * - sizeof(Mpi2DefaultReplyDescriptor_t); - - sz = reply_post_free_sz; - if (_base_is_controller_msix_enabled(ioc) && !ioc->rdpq_array_enable) - sz *= ioc->reply_queue_count; - - ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ? - (ioc->reply_queue_count):1, - sizeof(struct reply_post_struct), GFP_KERNEL); - - if (!ioc->reply_post) { - printk(MPT2SAS_ERR_FMT "reply_post_free pool: kcalloc failed\n", - ioc->name); - goto out; - } - ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool", - ioc->pdev, sz, 16, 0); - if (!ioc->reply_post_free_dma_pool) { - printk(MPT2SAS_ERR_FMT - "reply_post_free pool: pci_pool_create failed\n", - ioc->name); - goto out; - } - i = 0; - do { - ioc->reply_post[i].reply_post_free = - pci_pool_alloc(ioc->reply_post_free_dma_pool, - GFP_KERNEL, - &ioc->reply_post[i].reply_post_free_dma); - if (!ioc->reply_post[i].reply_post_free) { - printk(MPT2SAS_ERR_FMT - "reply_post_free pool: pci_pool_alloc failed\n", - ioc->name); - goto out; - } - memset(ioc->reply_post[i].reply_post_free, 0, sz); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT - "reply post free pool (0x%p): depth(%d)," - "element_size(%d), pool_size(%d kB)\n", ioc->name, - ioc->reply_post[i].reply_post_free, - ioc->reply_post_queue_depth, 8, sz/1024)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT - "reply_post_free_dma = (0x%llx)\n", ioc->name, - (unsigned long long) - ioc->reply_post[i].reply_post_free_dma)); - total_sz += sz; - } while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count)); - - if (ioc->dma_mask == 64) { - if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) { - printk(MPT2SAS_WARN_FMT - "no suitable consistent DMA mask for %s\n", - ioc->name, pci_name(ioc->pdev)); - goto out; - } - } - - ioc->scsiio_depth = ioc->hba_queue_depth - - ioc->hi_priority_depth - ioc->internal_depth; - - /* set the scsi host can_queue depth - * with some internal commands that could be outstanding - */ - ioc->shost->can_queue = ioc->scsiio_depth; - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: " - "can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue)); - - /* contiguous pool for request and chains, 16 byte align, one extra " - * "frame for smid=0 - */ - ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth; - sz = ((ioc->scsiio_depth + 1) * ioc->request_sz); - - /* hi-priority queue */ - sz += (ioc->hi_priority_depth * ioc->request_sz); - - /* internal queue */ - sz += (ioc->internal_depth * ioc->request_sz); - - ioc->request_dma_sz = sz; - ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma); - if (!ioc->request) { - printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent " - "failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " - "total(%d kB)\n", ioc->name, ioc->hba_queue_depth, - ioc->chains_needed_per_io, ioc->request_sz, sz/1024); - if (ioc->scsiio_depth < MPT2SAS_SAS_QUEUE_DEPTH) - goto out; - retry_sz += 64; - ioc->hba_queue_depth = max_request_credit - retry_sz; - goto retry_allocation; - } - - if (retry_sz) - printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent " - "succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " - "total(%d kb)\n", ioc->name, ioc->hba_queue_depth, - ioc->chains_needed_per_io, ioc->request_sz, sz/1024); - - - /* hi-priority queue */ - ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) * - ioc->request_sz); - ioc->hi_priority_dma = ioc->request_dma + ((ioc->scsiio_depth + 1) * - ioc->request_sz); - - /* internal queue */ - ioc->internal = ioc->hi_priority + (ioc->hi_priority_depth * - ioc->request_sz); - ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth * - ioc->request_sz); - - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): " - "depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, - ioc->request, ioc->hba_queue_depth, ioc->request_sz, - (ioc->hba_queue_depth * ioc->request_sz)/1024)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n", - ioc->name, (unsigned long long) ioc->request_dma)); - total_sz += sz; - - sz = ioc->scsiio_depth * sizeof(struct scsiio_tracker); - ioc->scsi_lookup_pages = get_order(sz); - ioc->scsi_lookup = (struct scsiio_tracker *)__get_free_pages( - GFP_KERNEL, ioc->scsi_lookup_pages); - if (!ioc->scsi_lookup) { - printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, " - "sz(%d)\n", ioc->name, (int)sz); - goto out; - } - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsiio(0x%p): " - "depth(%d)\n", ioc->name, ioc->request, - ioc->scsiio_depth)); - - ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH); - sz = ioc->chain_depth * sizeof(struct chain_tracker); - ioc->chain_pages = get_order(sz); - - ioc->chain_lookup = (struct chain_tracker *)__get_free_pages( - GFP_KERNEL, ioc->chain_pages); - if (!ioc->chain_lookup) { - printk(MPT2SAS_ERR_FMT "chain_lookup: get_free_pages failed, " - "sz(%d)\n", ioc->name, (int)sz); - goto out; - } - ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev, - ioc->request_sz, 16, 0); - if (!ioc->chain_dma_pool) { - printk(MPT2SAS_ERR_FMT "chain_dma_pool: pci_pool_create " - "failed\n", ioc->name); - goto out; - } - for (i = 0; i < ioc->chain_depth; i++) { - ioc->chain_lookup[i].chain_buffer = pci_pool_alloc( - ioc->chain_dma_pool , GFP_KERNEL, - &ioc->chain_lookup[i].chain_buffer_dma); - if (!ioc->chain_lookup[i].chain_buffer) { - ioc->chain_depth = i; - goto chain_done; - } - total_sz += ioc->request_sz; - } -chain_done: - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool depth" - "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, - ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth * - ioc->request_sz))/1024)); - - /* initialize hi-priority queue smid's */ - ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth, - sizeof(struct request_tracker), GFP_KERNEL); - if (!ioc->hpr_lookup) { - printk(MPT2SAS_ERR_FMT "hpr_lookup: kcalloc failed\n", - ioc->name); - goto out; - } - ioc->hi_priority_smid = ioc->scsiio_depth + 1; - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hi_priority(0x%p): " - "depth(%d), start smid(%d)\n", ioc->name, ioc->hi_priority, - ioc->hi_priority_depth, ioc->hi_priority_smid)); - - /* initialize internal queue smid's */ - ioc->internal_lookup = kcalloc(ioc->internal_depth, - sizeof(struct request_tracker), GFP_KERNEL); - if (!ioc->internal_lookup) { - printk(MPT2SAS_ERR_FMT "internal_lookup: kcalloc failed\n", - ioc->name); - goto out; - } - ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth; - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "internal(0x%p): " - "depth(%d), start smid(%d)\n", ioc->name, ioc->internal, - ioc->internal_depth, ioc->internal_smid)); - - /* sense buffers, 4 byte align */ - sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE; - ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4, - 0); - if (!ioc->sense_dma_pool) { - printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_create failed\n", - ioc->name); - goto out; - } - ioc->sense = pci_pool_alloc(ioc->sense_dma_pool , GFP_KERNEL, - &ioc->sense_dma); - if (!ioc->sense) { - printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_alloc failed\n", - ioc->name); - goto out; - } - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT - "sense pool(0x%p): depth(%d), element_size(%d), pool_size" - "(%d kB)\n", ioc->name, ioc->sense, ioc->scsiio_depth, - SCSI_SENSE_BUFFERSIZE, sz/1024)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_dma(0x%llx)\n", - ioc->name, (unsigned long long)ioc->sense_dma)); - total_sz += sz; - - /* reply pool, 4 byte align */ - sz = ioc->reply_free_queue_depth * ioc->reply_sz; - ioc->reply_dma_pool = pci_pool_create("reply pool", ioc->pdev, sz, 4, - 0); - if (!ioc->reply_dma_pool) { - printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_create failed\n", - ioc->name); - goto out; - } - ioc->reply = pci_pool_alloc(ioc->reply_dma_pool , GFP_KERNEL, - &ioc->reply_dma); - if (!ioc->reply) { - printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_alloc failed\n", - ioc->name); - goto out; - } - ioc->reply_dma_min_address = (u32)(ioc->reply_dma); - ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz; - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply pool(0x%p): depth" - "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->reply, - ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_dma(0x%llx)\n", - ioc->name, (unsigned long long)ioc->reply_dma)); - total_sz += sz; - - /* reply free queue, 16 byte align */ - sz = ioc->reply_free_queue_depth * 4; - ioc->reply_free_dma_pool = pci_pool_create("reply_free pool", - ioc->pdev, sz, 16, 0); - if (!ioc->reply_free_dma_pool) { - printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_create " - "failed\n", ioc->name); - goto out; - } - ioc->reply_free = pci_pool_alloc(ioc->reply_free_dma_pool , GFP_KERNEL, - &ioc->reply_free_dma); - if (!ioc->reply_free) { - printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_alloc " - "failed\n", ioc->name); - goto out; - } - memset(ioc->reply_free, 0, sz); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free pool(0x%p): " - "depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->name, - ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_dma" - "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma)); - total_sz += sz; - - ioc->config_page_sz = 512; - ioc->config_page = pci_alloc_consistent(ioc->pdev, - ioc->config_page_sz, &ioc->config_page_dma); - if (!ioc->config_page) { - printk(MPT2SAS_ERR_FMT "config page: pci_pool_alloc " - "failed\n", ioc->name); - goto out; - } - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config page(0x%p): size" - "(%d)\n", ioc->name, ioc->config_page, ioc->config_page_sz)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma" - "(0x%llx)\n", ioc->name, (unsigned long long)ioc->config_page_dma)); - total_sz += ioc->config_page_sz; - - printk(MPT2SAS_INFO_FMT "Allocated physical memory: size(%d kB)\n", - ioc->name, total_sz/1024); - printk(MPT2SAS_INFO_FMT "Current Controller Queue Depth(%d), " - "Max Controller Queue Depth(%d)\n", - ioc->name, ioc->shost->can_queue, facts->RequestCredit); - printk(MPT2SAS_INFO_FMT "Scatter Gather Elements per IO(%d)\n", - ioc->name, ioc->shost->sg_tablesize); - return 0; - - out: - return -ENOMEM; -} - - -/** - * mpt2sas_base_get_iocstate - Get the current state of a MPT adapter. - * @ioc: Pointer to MPT_ADAPTER structure - * @cooked: Request raw or cooked IOC state - * - * Returns all IOC Doorbell register bits if cooked==0, else just the - * Doorbell bits in MPI_IOC_STATE_MASK. - */ -u32 -mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked) -{ - u32 s, sc; - - s = readl(&ioc->chip->Doorbell); - sc = s & MPI2_IOC_STATE_MASK; - return cooked ? sc : s; -} - -/** - * _base_wait_on_iocstate - waiting on a particular ioc state - * @ioc_state: controller state { READY, OPERATIONAL, or RESET } - * @timeout: timeout in second - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_wait_on_iocstate(struct MPT2SAS_ADAPTER *ioc, u32 ioc_state, int timeout, - int sleep_flag) -{ - u32 count, cntdn; - u32 current_state; - - count = 0; - cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; - do { - current_state = mpt2sas_base_get_iocstate(ioc, 1); - if (current_state == ioc_state) - return 0; - if (count && current_state == MPI2_IOC_STATE_FAULT) - break; - if (sleep_flag == CAN_SLEEP) - msleep(1); - else - udelay(500); - count++; - } while (--cntdn); - - return current_state; -} - -/** - * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by - * a write to the doorbell) - * @ioc: per adapter object - * @timeout: timeout in second - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - * - * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell. - */ -static int -_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout, - int sleep_flag) -{ - u32 cntdn, count; - u32 int_status; - - count = 0; - cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; - do { - int_status = readl(&ioc->chip->HostInterruptStatus); - if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "successful count(%d), timeout(%d)\n", ioc->name, - __func__, count, timeout)); - return 0; - } - if (sleep_flag == CAN_SLEEP) - msleep(1); - else - udelay(500); - count++; - } while (--cntdn); - - printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), " - "int_status(%x)!\n", ioc->name, __func__, count, int_status); - return -EFAULT; -} - -/** - * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell. - * @ioc: per adapter object - * @timeout: timeout in second - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - * - * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to - * doorbell. - */ -static int -_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout, - int sleep_flag) -{ - u32 cntdn, count; - u32 int_status; - u32 doorbell; - - count = 0; - cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; - do { - int_status = readl(&ioc->chip->HostInterruptStatus); - if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "successful count(%d), timeout(%d)\n", ioc->name, - __func__, count, timeout)); - return 0; - } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { - doorbell = readl(&ioc->chip->Doorbell); - if ((doorbell & MPI2_IOC_STATE_MASK) == - MPI2_IOC_STATE_FAULT) { - mpt2sas_base_fault_info(ioc , doorbell); - return -EFAULT; - } - } else if (int_status == 0xFFFFFFFF) - goto out; - - if (sleep_flag == CAN_SLEEP) - msleep(1); - else - udelay(500); - count++; - } while (--cntdn); - - out: - printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), " - "int_status(%x)!\n", ioc->name, __func__, count, int_status); - return -EFAULT; -} - -/** - * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use - * @ioc: per adapter object - * @timeout: timeout in second - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - * - */ -static int -_base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout, - int sleep_flag) -{ - u32 cntdn, count; - u32 doorbell_reg; - - count = 0; - cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; - do { - doorbell_reg = readl(&ioc->chip->Doorbell); - if (!(doorbell_reg & MPI2_DOORBELL_USED)) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "successful count(%d), timeout(%d)\n", ioc->name, - __func__, count, timeout)); - return 0; - } - if (sleep_flag == CAN_SLEEP) - msleep(1); - else - udelay(500); - count++; - } while (--cntdn); - - printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), " - "doorbell_reg(%x)!\n", ioc->name, __func__, count, doorbell_reg); - return -EFAULT; -} - -/** - * _base_send_ioc_reset - send doorbell reset - * @ioc: per adapter object - * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET - * @timeout: timeout in second - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_send_ioc_reset(struct MPT2SAS_ADAPTER *ioc, u8 reset_type, int timeout, - int sleep_flag) -{ - u32 ioc_state; - int r = 0; - - if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) { - printk(MPT2SAS_ERR_FMT "%s: unknown reset_type\n", - ioc->name, __func__); - return -EFAULT; - } - - if (!(ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY)) - return -EFAULT; - - printk(MPT2SAS_INFO_FMT "sending message unit reset !!\n", ioc->name); - - writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT, - &ioc->chip->Doorbell); - if ((_base_wait_for_doorbell_ack(ioc, 15, sleep_flag))) { - r = -EFAULT; - goto out; - } - ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, - timeout, sleep_flag); - if (ioc_state) { - printk(MPT2SAS_ERR_FMT "%s: failed going to ready state " - " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state); - r = -EFAULT; - goto out; - } - out: - printk(MPT2SAS_INFO_FMT "message unit reset: %s\n", - ioc->name, ((r == 0) ? "SUCCESS" : "FAILED")); - return r; -} - -/** - * _base_handshake_req_reply_wait - send request thru doorbell interface - * @ioc: per adapter object - * @request_bytes: request length - * @request: pointer having request payload - * @reply_bytes: reply length - * @reply: pointer to reply payload - * @timeout: timeout in second - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes, - u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag) -{ - MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply; - int i; - u8 failed; - u16 dummy; - __le32 *mfp; - - /* make sure doorbell is not in use */ - if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) { - printk(MPT2SAS_ERR_FMT "doorbell is in use " - " (line=%d)\n", ioc->name, __LINE__); - return -EFAULT; - } - - /* clear pending doorbell interrupts from previous state changes */ - if (readl(&ioc->chip->HostInterruptStatus) & - MPI2_HIS_IOC2SYS_DB_STATUS) - writel(0, &ioc->chip->HostInterruptStatus); - - /* send message to ioc */ - writel(((MPI2_FUNCTION_HANDSHAKE<chip->Doorbell); - - if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) { - printk(MPT2SAS_ERR_FMT "doorbell handshake " - "int failed (line=%d)\n", ioc->name, __LINE__); - return -EFAULT; - } - writel(0, &ioc->chip->HostInterruptStatus); - - if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) { - printk(MPT2SAS_ERR_FMT "doorbell handshake " - "ack failed (line=%d)\n", ioc->name, __LINE__); - return -EFAULT; - } - - /* 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); - if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) - failed = 1; - } - - if (failed) { - printk(MPT2SAS_ERR_FMT "doorbell handshake " - "sending request failed (line=%d)\n", ioc->name, __LINE__); - return -EFAULT; - } - - /* now wait for the reply */ - if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) { - printk(MPT2SAS_ERR_FMT "doorbell handshake " - "int failed (line=%d)\n", ioc->name, __LINE__); - return -EFAULT; - } - - /* read the first two 16-bits, it gives the total length of the reply */ - reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell) - & MPI2_DOORBELL_DATA_MASK); - writel(0, &ioc->chip->HostInterruptStatus); - if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) { - printk(MPT2SAS_ERR_FMT "doorbell handshake " - "int failed (line=%d)\n", ioc->name, __LINE__); - return -EFAULT; - } - reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell) - & MPI2_DOORBELL_DATA_MASK); - writel(0, &ioc->chip->HostInterruptStatus); - - for (i = 2; i < default_reply->MsgLength * 2; i++) { - if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) { - printk(MPT2SAS_ERR_FMT "doorbell " - "handshake int failed (line=%d)\n", ioc->name, - __LINE__); - return -EFAULT; - } - if (i >= reply_bytes/2) /* overflow case */ - dummy = readl(&ioc->chip->Doorbell); - else - reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell) - & MPI2_DOORBELL_DATA_MASK); - writel(0, &ioc->chip->HostInterruptStatus); - } - - _base_wait_for_doorbell_int(ioc, 5, sleep_flag); - if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "doorbell is in use " - " (line=%d)\n", ioc->name, __LINE__)); - } - writel(0, &ioc->chip->HostInterruptStatus); - - if (ioc->logging_level & MPT_DEBUG_INIT) { - mfp = (__le32 *)reply; - printk(KERN_INFO "\toffset:data\n"); - for (i = 0; i < reply_bytes/4; i++) - printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, - le32_to_cpu(mfp[i])); - } - return 0; -} - -/** - * mpt2sas_base_sas_iounit_control - send sas iounit control to FW - * @ioc: per adapter object - * @mpi_reply: the reply payload from FW - * @mpi_request: the request payload sent to FW - * - * The SAS IO Unit Control Request message allows the host to perform low-level - * operations, such as resets on the PHYs of the IO Unit, also allows the host - * to obtain the IOC assigned device handles for a device if it has other - * identifying information about the device, in addition allows the host to - * remove IOC resources associated with the device. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, - Mpi2SasIoUnitControlReply_t *mpi_reply, - Mpi2SasIoUnitControlRequest_t *mpi_request) -{ - u16 smid; - u32 ioc_state; - unsigned long timeleft; - bool issue_reset = false; - int rc; - void *request; - u16 wait_state_count; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - mutex_lock(&ioc->base_cmds.mutex); - - if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - - smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - rc = 0; - ioc->base_cmds.status = MPT2_CMD_PENDING; - request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->base_cmds.smid = smid; - memcpy(request, mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)); - if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || - mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) - ioc->ioc_link_reset_in_progress = 1; - init_completion(&ioc->base_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, - msecs_to_jiffies(10000)); - if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || - mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) && - ioc->ioc_link_reset_in_progress) - ioc->ioc_link_reset_in_progress = 0; - if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SasIoUnitControlRequest_t)/4); - if (!(ioc->base_cmds.status & MPT2_CMD_RESET)) - issue_reset = true; - goto issue_host_reset; - } - if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID) - memcpy(mpi_reply, ioc->base_cmds.reply, - sizeof(Mpi2SasIoUnitControlReply_t)); - else - memset(mpi_reply, 0, sizeof(Mpi2SasIoUnitControlReply_t)); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - goto out; - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - rc = -EFAULT; - out: - mutex_unlock(&ioc->base_cmds.mutex); - return rc; -} - - -/** - * mpt2sas_base_scsi_enclosure_processor - sending request to sep device - * @ioc: per adapter object - * @mpi_reply: the reply payload from FW - * @mpi_request: the request payload sent to FW - * - * The SCSI Enclosure Processor request message causes the IOC to - * communicate with SES devices to control LED status signals. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, - Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request) -{ - u16 smid; - u32 ioc_state; - unsigned long timeleft; - bool issue_reset = false; - int rc; - void *request; - u16 wait_state_count; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - mutex_lock(&ioc->base_cmds.mutex); - - if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - - smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - rc = 0; - ioc->base_cmds.status = MPT2_CMD_PENDING; - request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->base_cmds.smid = smid; - memcpy(request, mpi_request, sizeof(Mpi2SepReply_t)); - init_completion(&ioc->base_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, - msecs_to_jiffies(10000)); - if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SepRequest_t)/4); - if (!(ioc->base_cmds.status & MPT2_CMD_RESET)) - issue_reset = true; - goto issue_host_reset; - } - if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID) - memcpy(mpi_reply, ioc->base_cmds.reply, - sizeof(Mpi2SepReply_t)); - else - memset(mpi_reply, 0, sizeof(Mpi2SepReply_t)); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - goto out; - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - rc = -EFAULT; - out: - mutex_unlock(&ioc->base_cmds.mutex); - return rc; -} - -/** - * _base_get_port_facts - obtain port facts reply and save in ioc - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag) -{ - Mpi2PortFactsRequest_t mpi_request; - Mpi2PortFactsReply_t mpi_reply; - struct mpt2sas_port_facts *pfacts; - int mpi_reply_sz, mpi_request_sz, r; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - mpi_reply_sz = sizeof(Mpi2PortFactsReply_t); - mpi_request_sz = sizeof(Mpi2PortFactsRequest_t); - memset(&mpi_request, 0, mpi_request_sz); - mpi_request.Function = MPI2_FUNCTION_PORT_FACTS; - mpi_request.PortNumber = port; - r = _base_handshake_req_reply_wait(ioc, mpi_request_sz, - (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP); - - if (r != 0) { - printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n", - ioc->name, __func__, r); - return r; - } - - pfacts = &ioc->pfacts[port]; - memset(pfacts, 0, sizeof(struct mpt2sas_port_facts)); - pfacts->PortNumber = mpi_reply.PortNumber; - pfacts->VP_ID = mpi_reply.VP_ID; - pfacts->VF_ID = mpi_reply.VF_ID; - pfacts->MaxPostedCmdBuffers = - le16_to_cpu(mpi_reply.MaxPostedCmdBuffers); - - return 0; -} - -/** - * _base_wait_for_iocstate - Wait until the card is in READY or OPERATIONAL - * @ioc: per adapter object - * @timeout: - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_wait_for_iocstate(struct MPT2SAS_ADAPTER *ioc, int timeout, - int sleep_flag) -{ - u32 ioc_state, doorbell; - int rc; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - if (ioc->pci_error_recovery) - return 0; - - doorbell = mpt2sas_base_get_iocstate(ioc, 0); - ioc_state = doorbell & MPI2_IOC_STATE_MASK; - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n", - ioc->name, __func__, ioc_state)); - - switch (ioc_state) { - case MPI2_IOC_STATE_READY: - case MPI2_IOC_STATE_OPERATIONAL: - return 0; - } - - if (doorbell & MPI2_DOORBELL_USED) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT - "unexpected doorbell activ!e\n", ioc->name)); - goto issue_diag_reset; - } - - if (ioc_state == MPI2_IOC_STATE_FAULT) { - mpt2sas_base_fault_info(ioc, doorbell & - MPI2_DOORBELL_DATA_MASK); - goto issue_diag_reset; - } - - ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, - timeout, sleep_flag); - if (ioc_state) { - printk(MPT2SAS_ERR_FMT - "%s: failed going to ready state (ioc_state=0x%x)\n", - ioc->name, __func__, ioc_state); - return -EFAULT; - } - - issue_diag_reset: - rc = _base_diag_reset(ioc, sleep_flag); - return rc; -} - -/** - * _base_get_ioc_facts - obtain ioc facts reply and save in ioc - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - Mpi2IOCFactsRequest_t mpi_request; - Mpi2IOCFactsReply_t mpi_reply; - struct mpt2sas_facts *facts; - int mpi_reply_sz, mpi_request_sz, r; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - r = _base_wait_for_iocstate(ioc, 10, sleep_flag); - if (r) { - printk(MPT2SAS_ERR_FMT "%s: failed getting to correct state\n", - ioc->name, __func__); - return r; - } - - mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t); - mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t); - memset(&mpi_request, 0, mpi_request_sz); - mpi_request.Function = MPI2_FUNCTION_IOC_FACTS; - r = _base_handshake_req_reply_wait(ioc, mpi_request_sz, - (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP); - - if (r != 0) { - printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n", - ioc->name, __func__, r); - return r; - } - - facts = &ioc->facts; - memset(facts, 0, sizeof(struct mpt2sas_facts)); - facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion); - facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion); - facts->VP_ID = mpi_reply.VP_ID; - facts->VF_ID = mpi_reply.VF_ID; - facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions); - facts->MaxChainDepth = mpi_reply.MaxChainDepth; - facts->WhoInit = mpi_reply.WhoInit; - facts->NumberOfPorts = mpi_reply.NumberOfPorts; - facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors; - facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit); - facts->MaxReplyDescriptorPostQueueDepth = - le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth); - facts->ProductID = le16_to_cpu(mpi_reply.ProductID); - facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities); - if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)) - ioc->ir_firmware = 1; - if ((facts->IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE)) - ioc->rdpq_array_capable = 1; - facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word); - facts->IOCRequestFrameSize = - le16_to_cpu(mpi_reply.IOCRequestFrameSize); - facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators); - facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets); - ioc->shost->max_id = -1; - facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders); - facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures); - facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags); - facts->HighPriorityCredit = - le16_to_cpu(mpi_reply.HighPriorityCredit); - facts->ReplyFrameSize = mpi_reply.ReplyFrameSize; - facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle); - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hba queue depth(%d), " - "max chains per io(%d)\n", ioc->name, facts->RequestCredit, - facts->MaxChainDepth)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request frame size(%d), " - "reply frame size(%d)\n", ioc->name, - facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4)); - return 0; -} - -/** - * _base_send_ioc_init - send ioc_init to firmware - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - Mpi2IOCInitRequest_t mpi_request; - Mpi2IOCInitReply_t mpi_reply; - int i, r = 0; - struct timeval current_time; - u16 ioc_status; - u32 reply_post_free_array_sz = 0; - Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL; - dma_addr_t reply_post_free_array_dma; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t)); - mpi_request.Function = MPI2_FUNCTION_IOC_INIT; - mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER; - mpi_request.VF_ID = 0; /* TODO */ - mpi_request.VP_ID = 0; - mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION); - mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); - - if (_base_is_controller_msix_enabled(ioc)) - mpi_request.HostMSIxVectors = ioc->reply_queue_count; - mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4); - mpi_request.ReplyDescriptorPostQueueDepth = - cpu_to_le16(ioc->reply_post_queue_depth); - mpi_request.ReplyFreeQueueDepth = - cpu_to_le16(ioc->reply_free_queue_depth); - - mpi_request.SenseBufferAddressHigh = - cpu_to_le32((u64)ioc->sense_dma >> 32); - mpi_request.SystemReplyAddressHigh = - cpu_to_le32((u64)ioc->reply_dma >> 32); - mpi_request.SystemRequestFrameBaseAddress = - cpu_to_le64((u64)ioc->request_dma); - mpi_request.ReplyFreeQueueAddress = - cpu_to_le64((u64)ioc->reply_free_dma); - - if (ioc->rdpq_array_enable) { - reply_post_free_array_sz = ioc->reply_queue_count * - sizeof(Mpi2IOCInitRDPQArrayEntry); - reply_post_free_array = pci_alloc_consistent(ioc->pdev, - reply_post_free_array_sz, &reply_post_free_array_dma); - if (!reply_post_free_array) { - printk(MPT2SAS_ERR_FMT - "reply_post_free_array: pci_alloc_consistent failed\n", - ioc->name); - r = -ENOMEM; - goto out; - } - memset(reply_post_free_array, 0, reply_post_free_array_sz); - for (i = 0; i < ioc->reply_queue_count; i++) - reply_post_free_array[i].RDPQBaseAddress = - cpu_to_le64( - (u64)ioc->reply_post[i].reply_post_free_dma); - mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE; - mpi_request.ReplyDescriptorPostQueueAddress = - cpu_to_le64((u64)reply_post_free_array_dma); - } else { - mpi_request.ReplyDescriptorPostQueueAddress = - cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma); - } - - /* This time stamp specifies number of milliseconds - * since epoch ~ midnight January 1, 1970. - */ - do_gettimeofday(¤t_time); - mpi_request.TimeStamp = cpu_to_le64((u64)current_time.tv_sec * 1000 + - (current_time.tv_usec / 1000)); - - if (ioc->logging_level & MPT_DEBUG_INIT) { - __le32 *mfp; - int i; - - mfp = (__le32 *)&mpi_request; - printk(KERN_INFO "\toffset:data\n"); - for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++) - printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, - le32_to_cpu(mfp[i])); - } - - r = _base_handshake_req_reply_wait(ioc, - sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request, - sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10, - sleep_flag); - - if (r != 0) { - printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n", - ioc->name, __func__, r); - goto out; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS || - mpi_reply.IOCLogInfo) { - printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__); - r = -EIO; - } - -out: - if (reply_post_free_array) - pci_free_consistent(ioc->pdev, reply_post_free_array_sz, - reply_post_free_array, - reply_post_free_array_dma); - return r; -} - -/** - * mpt2sas_port_enable_done - command completion routine for port enable - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_port_enable_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - u16 ioc_status; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) - return 1; - - if (ioc->port_enable_cmds.status == MPT2_CMD_NOT_USED) - return 1; - - ioc->port_enable_cmds.status |= MPT2_CMD_COMPLETE; - if (mpi_reply) { - ioc->port_enable_cmds.status |= MPT2_CMD_REPLY_VALID; - memcpy(ioc->port_enable_cmds.reply, mpi_reply, - mpi_reply->MsgLength*4); - } - ioc->port_enable_cmds.status &= ~MPT2_CMD_PENDING; - - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - ioc->port_enable_failed = 1; - - if (ioc->is_driver_loading) { - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - mpt2sas_port_enable_complete(ioc); - return 1; - } else { - ioc->start_scan_failed = ioc_status; - ioc->start_scan = 0; - return 1; - } - } - complete(&ioc->port_enable_cmds.done); - return 1; -} - - -/** - * _base_send_port_enable - send port_enable(discovery stuff) to firmware - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - Mpi2PortEnableRequest_t *mpi_request; - Mpi2PortEnableReply_t *mpi_reply; - unsigned long timeleft; - int r = 0; - u16 smid; - u16 ioc_status; - - printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name); - - if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) { - printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n", - ioc->name, __func__); - return -EAGAIN; - } - - smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - return -EAGAIN; - } - - ioc->port_enable_cmds.status = MPT2_CMD_PENDING; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->port_enable_cmds.smid = smid; - memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); - mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; - - init_completion(&ioc->port_enable_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->port_enable_cmds.done, - 300*HZ); - if (!(ioc->port_enable_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2PortEnableRequest_t)/4); - if (ioc->port_enable_cmds.status & MPT2_CMD_RESET) - r = -EFAULT; - else - r = -ETIME; - goto out; - } - mpi_reply = ioc->port_enable_cmds.reply; - - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "%s: failed with (ioc_status=0x%08x)\n", - ioc->name, __func__, ioc_status); - r = -EFAULT; - goto out; - } - out: - ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED; - printk(MPT2SAS_INFO_FMT "port enable: %s\n", ioc->name, ((r == 0) ? - "SUCCESS" : "FAILED")); - return r; -} - -/** - * mpt2sas_port_enable - initiate firmware discovery (don't wait for reply) - * @ioc: per adapter object - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2PortEnableRequest_t *mpi_request; - u16 smid; - - printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name); - - if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) { - printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n", - ioc->name, __func__); - return -EAGAIN; - } - - smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - return -EAGAIN; - } - - ioc->port_enable_cmds.status = MPT2_CMD_PENDING; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->port_enable_cmds.smid = smid; - memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); - mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; - - mpt2sas_base_put_smid_default(ioc, smid); - return 0; -} - -/** - * _base_determine_wait_on_discovery - desposition - * @ioc: per adapter object - * - * Decide whether to wait on discovery to complete. Used to either - * locate boot device, or report volumes ahead of physical devices. - * - * Returns 1 for wait, 0 for don't wait - */ -static int -_base_determine_wait_on_discovery(struct MPT2SAS_ADAPTER *ioc) -{ - /* We wait for discovery to complete if IR firmware is loaded. - * The sas topology events arrive before PD events, so we need time to - * turn on the bit in ioc->pd_handles to indicate PD - * Also, it maybe required to report Volumes ahead of physical - * devices when MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING is set. - */ - if (ioc->ir_firmware) - return 1; - - /* if no Bios, then we don't need to wait */ - if (!ioc->bios_pg3.BiosVersion) - return 0; - - /* Bios is present, then we drop down here. - * - * If there any entries in the Bios Page 2, then we wait - * for discovery to complete. - */ - - /* Current Boot Device */ - if ((ioc->bios_pg2.CurrentBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK) == - MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && - /* Request Boot Device */ - (ioc->bios_pg2.ReqBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK) == - MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && - /* Alternate Request Boot Device */ - (ioc->bios_pg2.ReqAltBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK) == - MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED) - return 0; - - return 1; -} - - -/** - * _base_unmask_events - turn on notification for this event - * @ioc: per adapter object - * @event: firmware event - * - * The mask is stored in ioc->event_masks. - */ -static void -_base_unmask_events(struct MPT2SAS_ADAPTER *ioc, u16 event) -{ - u32 desired_event; - - if (event >= 128) - return; - - desired_event = (1 << (event % 32)); - - if (event < 32) - ioc->event_masks[0] &= ~desired_event; - else if (event < 64) - ioc->event_masks[1] &= ~desired_event; - else if (event < 96) - ioc->event_masks[2] &= ~desired_event; - else if (event < 128) - ioc->event_masks[3] &= ~desired_event; -} - -/** - * _base_event_notification - send event notification - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - Mpi2EventNotificationRequest_t *mpi_request; - unsigned long timeleft; - u16 smid; - int r = 0; - int i; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - if (ioc->base_cmds.status & MPT2_CMD_PENDING) { - printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n", - ioc->name, __func__); - return -EAGAIN; - } - - smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - return -EAGAIN; - } - ioc->base_cmds.status = MPT2_CMD_PENDING; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->base_cmds.smid = smid; - memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t)); - mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) - mpi_request->EventMasks[i] = - cpu_to_le32(ioc->event_masks[i]); - init_completion(&ioc->base_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); - if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2EventNotificationRequest_t)/4); - if (ioc->base_cmds.status & MPT2_CMD_RESET) - r = -EFAULT; - else - r = -ETIME; - } else - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n", - ioc->name, __func__)); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - return r; -} - -/** - * mpt2sas_base_validate_event_type - validating event types - * @ioc: per adapter object - * @event: firmware event - * - * This will turn on firmware event notification when application - * ask for that event. We don't mask events that are already enabled. - */ -void -mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type) -{ - int i, j; - u32 event_mask, desired_event; - u8 send_update_to_fw; - - for (i = 0, send_update_to_fw = 0; i < - MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) { - event_mask = ~event_type[i]; - desired_event = 1; - for (j = 0; j < 32; j++) { - if (!(event_mask & desired_event) && - (ioc->event_masks[i] & desired_event)) { - ioc->event_masks[i] &= ~desired_event; - send_update_to_fw = 1; - } - desired_event = (desired_event << 1); - } - } - - if (!send_update_to_fw) - return; - - mutex_lock(&ioc->base_cmds.mutex); - _base_event_notification(ioc, CAN_SLEEP); - mutex_unlock(&ioc->base_cmds.mutex); -} - -/** - * _base_diag_reset - the "big hammer" start of day reset - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - u32 host_diagnostic; - u32 ioc_state; - u32 count; - u32 hcb_size; - - printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name); - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n", - ioc->name)); - - count = 0; - do { - /* Write magic sequence to WriteSequence register - * Loop until in diagnostic mode - */ - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "write magic " - "sequence\n", ioc->name)); - writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence); - - /* wait 100 msec */ - if (sleep_flag == CAN_SLEEP) - msleep(100); - else - mdelay(100); - - if (count++ > 20) - goto out; - - host_diagnostic = readl(&ioc->chip->HostDiagnostic); - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "wrote magic " - "sequence: count(%d), host_diagnostic(0x%08x)\n", - ioc->name, count, host_diagnostic)); - - } while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0); - - hcb_size = readl(&ioc->chip->HCBSize); - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "diag reset: issued\n", - ioc->name)); - writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER, - &ioc->chip->HostDiagnostic); - - /* This delay allows the chip PCIe hardware time to finish reset tasks*/ - if (sleep_flag == CAN_SLEEP) - msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000); - else - mdelay(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000); - - /* Approximately 300 second max wait */ - for (count = 0; count < (300000000 / - MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) { - - host_diagnostic = readl(&ioc->chip->HostDiagnostic); - - if (host_diagnostic == 0xFFFFFFFF) - goto out; - if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER)) - break; - - /* Wait to pass the second read delay window */ - if (sleep_flag == CAN_SLEEP) - msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC - /1000); - else - mdelay(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC - /1000); - } - - if (host_diagnostic & MPI2_DIAG_HCB_MODE) { - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter " - "assuming the HCB Address points to good F/W\n", - ioc->name)); - host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK; - host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW; - writel(host_diagnostic, &ioc->chip->HostDiagnostic); - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT - "re-enable the HCDW\n", ioc->name)); - writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE, - &ioc->chip->HCBSize); - } - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter\n", - ioc->name)); - writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET, - &ioc->chip->HostDiagnostic); - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "disable writes to the " - "diagnostic register\n", ioc->name)); - writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "Wait for FW to go to the " - "READY state\n", ioc->name)); - ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20, - sleep_flag); - if (ioc_state) { - printk(MPT2SAS_ERR_FMT "%s: failed going to ready state " - " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state); - goto out; - } - - printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name); - return 0; - - out: - printk(MPT2SAS_ERR_FMT "diag reset: FAILED\n", ioc->name); - return -EFAULT; -} - -/** - * _base_make_ioc_ready - put controller in READY state - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * @type: FORCE_BIG_HAMMER or SOFT_RESET - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, - enum reset_type type) -{ - u32 ioc_state; - int rc; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - if (ioc->pci_error_recovery) - return 0; - - ioc_state = mpt2sas_base_get_iocstate(ioc, 0); - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n", - ioc->name, __func__, ioc_state)); - - if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) - return 0; - - if (ioc_state & MPI2_DOORBELL_USED) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell " - "active!\n", ioc->name)); - goto issue_diag_reset; - } - - if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { - mpt2sas_base_fault_info(ioc, ioc_state & - MPI2_DOORBELL_DATA_MASK); - goto issue_diag_reset; - } - - if (type == FORCE_BIG_HAMMER) - goto issue_diag_reset; - - if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL) - if (!(_base_send_ioc_reset(ioc, - MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) { - ioc->ioc_reset_count++; - return 0; - } - - issue_diag_reset: - rc = _base_diag_reset(ioc, CAN_SLEEP); - ioc->ioc_reset_count++; - return rc; -} - -/** - * _base_make_ioc_operational - put controller in OPERATIONAL state - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - int r, i; - unsigned long flags; - u32 reply_address; - u16 smid; - struct _tr_list *delayed_tr, *delayed_tr_next; - u8 hide_flag; - struct adapter_reply_queue *reply_q; - long reply_post_free; - u32 reply_post_free_sz, index = 0; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - /* clean the delayed target reset list */ - list_for_each_entry_safe(delayed_tr, delayed_tr_next, - &ioc->delayed_tr_list, list) { - list_del(&delayed_tr->list); - kfree(delayed_tr); - } - - list_for_each_entry_safe(delayed_tr, delayed_tr_next, - &ioc->delayed_tr_volume_list, list) { - list_del(&delayed_tr->list); - kfree(delayed_tr); - } - - /* initialize the scsi lookup free list */ - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - INIT_LIST_HEAD(&ioc->free_list); - smid = 1; - for (i = 0; i < ioc->scsiio_depth; i++, smid++) { - INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list); - ioc->scsi_lookup[i].cb_idx = 0xFF; - ioc->scsi_lookup[i].smid = smid; - ioc->scsi_lookup[i].scmd = NULL; - ioc->scsi_lookup[i].direct_io = 0; - list_add_tail(&ioc->scsi_lookup[i].tracker_list, - &ioc->free_list); - } - - /* hi-priority queue */ - INIT_LIST_HEAD(&ioc->hpr_free_list); - smid = ioc->hi_priority_smid; - for (i = 0; i < ioc->hi_priority_depth; i++, smid++) { - ioc->hpr_lookup[i].cb_idx = 0xFF; - ioc->hpr_lookup[i].smid = smid; - list_add_tail(&ioc->hpr_lookup[i].tracker_list, - &ioc->hpr_free_list); - } - - /* internal queue */ - INIT_LIST_HEAD(&ioc->internal_free_list); - smid = ioc->internal_smid; - for (i = 0; i < ioc->internal_depth; i++, smid++) { - ioc->internal_lookup[i].cb_idx = 0xFF; - ioc->internal_lookup[i].smid = smid; - list_add_tail(&ioc->internal_lookup[i].tracker_list, - &ioc->internal_free_list); - } - - /* chain pool */ - INIT_LIST_HEAD(&ioc->free_chain_list); - for (i = 0; i < ioc->chain_depth; i++) - list_add_tail(&ioc->chain_lookup[i].tracker_list, - &ioc->free_chain_list); - - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - - /* initialize Reply Free Queue */ - for (i = 0, reply_address = (u32)ioc->reply_dma ; - i < ioc->reply_free_queue_depth ; i++, reply_address += - ioc->reply_sz) - ioc->reply_free[i] = cpu_to_le32(reply_address); - - /* initialize reply queues */ - if (ioc->is_driver_loading) - _base_assign_reply_queues(ioc); - - /* initialize Reply Post Free Queue */ - reply_post_free_sz = ioc->reply_post_queue_depth * - sizeof(Mpi2DefaultReplyDescriptor_t); - reply_post_free = (long)ioc->reply_post[index].reply_post_free; - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - reply_q->reply_post_host_index = 0; - reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *) - reply_post_free; - for (i = 0; i < ioc->reply_post_queue_depth; i++) - reply_q->reply_post_free[i].Words = - cpu_to_le64(ULLONG_MAX); - if (!_base_is_controller_msix_enabled(ioc)) - goto skip_init_reply_post_free_queue; - /* - * If RDPQ is enabled, switch to the next allocation. - * Otherwise advance within the contiguous region. - */ - if (ioc->rdpq_array_enable) - reply_post_free = (long) - ioc->reply_post[++index].reply_post_free; - else - reply_post_free += reply_post_free_sz; - } - skip_init_reply_post_free_queue: - - r = _base_send_ioc_init(ioc, sleep_flag); - if (r) - return r; - - /* initialize reply free host index */ - ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1; - writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); - - /* initialize reply post host index */ - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - writel(reply_q->msix_index << MPI2_RPHI_MSIX_INDEX_SHIFT, - &ioc->chip->ReplyPostHostIndex); - if (!_base_is_controller_msix_enabled(ioc)) - goto skip_init_reply_post_host_index; - } - - skip_init_reply_post_host_index: - - _base_unmask_interrupts(ioc); - - r = _base_event_notification(ioc, sleep_flag); - if (r) - return r; - - if (sleep_flag == CAN_SLEEP) - _base_static_config_pages(ioc); - - - if (ioc->is_driver_loading) { - if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier - == 0x80) { - hide_flag = (u8) ( - le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) & - MFG_PAGE10_HIDE_SSDS_MASK); - if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK) - ioc->mfg_pg10_hide_flag = hide_flag; - } - ioc->wait_for_discovery_to_complete = - _base_determine_wait_on_discovery(ioc); - return r; /* scan_start and scan_finished support */ - } - r = _base_send_port_enable(ioc, sleep_flag); - if (r) - return r; - - return r; -} - -/** - * mpt2sas_base_free_resources - free resources controller resources (io/irq/memap) - * @ioc: per adapter object - * - * Return nothing. - */ -void -mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc) -{ - struct pci_dev *pdev = ioc->pdev; - - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - /* synchronizing freeing resource with pci_access_mutex lock */ - mutex_lock(&ioc->pci_access_mutex); - if (ioc->chip_phys && ioc->chip) { - _base_mask_interrupts(ioc); - ioc->shost_recovery = 1; - _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); - ioc->shost_recovery = 0; - } - - _base_free_irq(ioc); - _base_disable_msix(ioc); - - if (ioc->chip_phys && ioc->chip) - iounmap(ioc->chip); - ioc->chip_phys = 0; - - if (pci_is_enabled(pdev)) { - pci_release_selected_regions(ioc->pdev, ioc->bars); - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); - } - mutex_unlock(&ioc->pci_access_mutex); - return; -} - -/** - * mpt2sas_base_attach - attach controller instance - * @ioc: per adapter object - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) -{ - int r, i; - int cpu_id, last_cpu_id = 0; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - /* setup cpu_msix_table */ - ioc->cpu_count = num_online_cpus(); - for_each_online_cpu(cpu_id) - last_cpu_id = cpu_id; - ioc->cpu_msix_table_sz = last_cpu_id + 1; - ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL); - ioc->reply_queue_count = 1; - if (!ioc->cpu_msix_table) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for " - "cpu_msix_table failed!!!\n", ioc->name)); - r = -ENOMEM; - goto out_free_resources; - } - - if (ioc->is_warpdrive) { - ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz, - sizeof(resource_size_t *), GFP_KERNEL); - if (!ioc->reply_post_host_index) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation " - "for cpu_msix_table failed!!!\n", ioc->name)); - r = -ENOMEM; - goto out_free_resources; - } - } - - ioc->rdpq_array_enable_assigned = 0; - ioc->dma_mask = 0; - r = mpt2sas_base_map_resources(ioc); - if (r) - goto out_free_resources; - - if (ioc->is_warpdrive) { - ioc->reply_post_host_index[0] = (resource_size_t __iomem *) - &ioc->chip->ReplyPostHostIndex; - - for (i = 1; i < ioc->cpu_msix_table_sz; i++) - ioc->reply_post_host_index[i] = - (resource_size_t __iomem *) - ((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1) - * 4))); - } - - pci_set_drvdata(ioc->pdev, ioc->shost); - r = _base_get_ioc_facts(ioc, CAN_SLEEP); - if (r) - goto out_free_resources; - - r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); - if (r) - goto out_free_resources; - - ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, - sizeof(struct mpt2sas_port_facts), GFP_KERNEL); - if (!ioc->pfacts) { - r = -ENOMEM; - goto out_free_resources; - } - - for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { - r = _base_get_port_facts(ioc, i, CAN_SLEEP); - if (r) - goto out_free_resources; - } - - r = _base_allocate_memory_pools(ioc, CAN_SLEEP); - if (r) - goto out_free_resources; - - init_waitqueue_head(&ioc->reset_wq); - /* allocate memory pd handle bitmask list */ - ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8); - if (ioc->facts.MaxDevHandle % 8) - ioc->pd_handles_sz++; - ioc->pd_handles = kzalloc(ioc->pd_handles_sz, - GFP_KERNEL); - if (!ioc->pd_handles) { - r = -ENOMEM; - goto out_free_resources; - } - ioc->blocking_handles = kzalloc(ioc->pd_handles_sz, - GFP_KERNEL); - if (!ioc->blocking_handles) { - r = -ENOMEM; - goto out_free_resources; - } - ioc->fwfault_debug = mpt2sas_fwfault_debug; - - /* base internal command bits */ - mutex_init(&ioc->base_cmds.mutex); - ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - - /* port_enable command bits */ - ioc->port_enable_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED; - - /* transport internal command bits */ - ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->transport_cmds.status = MPT2_CMD_NOT_USED; - mutex_init(&ioc->transport_cmds.mutex); - - /* scsih internal command bits */ - ioc->scsih_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; - mutex_init(&ioc->scsih_cmds.mutex); - - /* task management internal command bits */ - ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - mutex_init(&ioc->tm_cmds.mutex); - - /* config page internal command bits */ - ioc->config_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->config_cmds.status = MPT2_CMD_NOT_USED; - mutex_init(&ioc->config_cmds.mutex); - - /* ctl module internal command bits */ - ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->ctl_cmds.sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); - ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - mutex_init(&ioc->ctl_cmds.mutex); - - if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || - !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || - !ioc->config_cmds.reply || !ioc->ctl_cmds.reply || - !ioc->ctl_cmds.sense) { - r = -ENOMEM; - goto out_free_resources; - } - - if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || - !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || - !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) { - r = -ENOMEM; - goto out_free_resources; - } - - for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) - ioc->event_masks[i] = -1; - - /* here we enable the events we care about */ - _base_unmask_events(ioc, MPI2_EVENT_SAS_DISCOVERY); - _base_unmask_events(ioc, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE); - _base_unmask_events(ioc, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); - _base_unmask_events(ioc, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); - _base_unmask_events(ioc, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); - _base_unmask_events(ioc, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); - _base_unmask_events(ioc, MPI2_EVENT_IR_VOLUME); - _base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK); - _base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS); - _base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED); - _base_unmask_events(ioc, MPI2_EVENT_TEMP_THRESHOLD); - r = _base_make_ioc_operational(ioc, CAN_SLEEP); - if (r) - goto out_free_resources; - - ioc->non_operational_loop = 0; - - return 0; - - out_free_resources: - - ioc->remove_host = 1; - mpt2sas_base_free_resources(ioc); - _base_release_memory_pools(ioc); - pci_set_drvdata(ioc->pdev, NULL); - kfree(ioc->cpu_msix_table); - if (ioc->is_warpdrive) - kfree(ioc->reply_post_host_index); - kfree(ioc->pd_handles); - kfree(ioc->blocking_handles); - kfree(ioc->tm_cmds.reply); - kfree(ioc->transport_cmds.reply); - kfree(ioc->scsih_cmds.reply); - kfree(ioc->config_cmds.reply); - kfree(ioc->base_cmds.reply); - kfree(ioc->port_enable_cmds.reply); - kfree(ioc->ctl_cmds.reply); - kfree(ioc->ctl_cmds.sense); - kfree(ioc->pfacts); - ioc->ctl_cmds.reply = NULL; - ioc->base_cmds.reply = NULL; - ioc->tm_cmds.reply = NULL; - ioc->scsih_cmds.reply = NULL; - ioc->transport_cmds.reply = NULL; - ioc->config_cmds.reply = NULL; - ioc->pfacts = NULL; - return r; -} - - -/** - * mpt2sas_base_detach - remove controller instance - * @ioc: per adapter object - * - * Return nothing. - */ -void -mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc) -{ - - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - mpt2sas_base_stop_watchdog(ioc); - mpt2sas_base_free_resources(ioc); - _base_release_memory_pools(ioc); - pci_set_drvdata(ioc->pdev, NULL); - kfree(ioc->cpu_msix_table); - if (ioc->is_warpdrive) - kfree(ioc->reply_post_host_index); - kfree(ioc->pd_handles); - kfree(ioc->blocking_handles); - kfree(ioc->pfacts); - kfree(ioc->ctl_cmds.reply); - kfree(ioc->ctl_cmds.sense); - kfree(ioc->base_cmds.reply); - kfree(ioc->port_enable_cmds.reply); - kfree(ioc->tm_cmds.reply); - kfree(ioc->transport_cmds.reply); - kfree(ioc->scsih_cmds.reply); - kfree(ioc->config_cmds.reply); -} - -/** - * _base_reset_handler - reset callback handler (for base) - * @ioc: per adapter object - * @reset_phase: phase - * - * The handler for doing any required cleanup or initialization. - * - * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, - * MPT2_IOC_DONE_RESET - * - * Return nothing. - */ -static void -_base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) -{ - mpt2sas_scsih_reset_handler(ioc, reset_phase); - mpt2sas_ctl_reset_handler(ioc, reset_phase); - switch (reset_phase) { - case MPT2_IOC_PRE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); - break; - case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); - if (ioc->transport_cmds.status & MPT2_CMD_PENDING) { - ioc->transport_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->transport_cmds.smid); - complete(&ioc->transport_cmds.done); - } - if (ioc->base_cmds.status & MPT2_CMD_PENDING) { - ioc->base_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->base_cmds.smid); - complete(&ioc->base_cmds.done); - } - if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) { - ioc->port_enable_failed = 1; - ioc->port_enable_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->port_enable_cmds.smid); - if (ioc->is_driver_loading) { - ioc->start_scan_failed = - MPI2_IOCSTATUS_INTERNAL_ERROR; - ioc->start_scan = 0; - ioc->port_enable_cmds.status = - MPT2_CMD_NOT_USED; - } else - complete(&ioc->port_enable_cmds.done); - - } - if (ioc->config_cmds.status & MPT2_CMD_PENDING) { - ioc->config_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid); - ioc->config_cmds.smid = USHRT_MAX; - complete(&ioc->config_cmds.done); - } - break; - case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); - break; - } -} - -/** - * _wait_for_commands_to_complete - reset controller - * @ioc: Pointer to MPT_ADAPTER structure - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * This function waiting(3s) for all pending commands to complete - * prior to putting controller in reset. - */ -static void -_wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - u32 ioc_state; - unsigned long flags; - u16 i; - - ioc->pending_io_count = 0; - if (sleep_flag != CAN_SLEEP) - return; - - ioc_state = mpt2sas_base_get_iocstate(ioc, 0); - if ((ioc_state & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) - return; - - /* pending command count */ - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - for (i = 0; i < ioc->scsiio_depth; i++) - if (ioc->scsi_lookup[i].cb_idx != 0xFF) - ioc->pending_io_count++; - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - - if (!ioc->pending_io_count) - return; - - /* wait for pending commands to complete */ - wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ); -} - -/** - * mpt2sas_base_hard_reset_handler - reset controller - * @ioc: Pointer to MPT_ADAPTER structure - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * @type: FORCE_BIG_HAMMER or SOFT_RESET - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, - enum reset_type type) -{ - int r; - unsigned long flags; - - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - if (ioc->pci_error_recovery) { - printk(MPT2SAS_ERR_FMT "%s: pci error recovery reset\n", - ioc->name, __func__); - r = 0; - goto out_unlocked; - } - - if (mpt2sas_fwfault_debug) - mpt2sas_halt_firmware(ioc); - - /* TODO - What we really should be doing is pulling - * out all the code associated with NO_SLEEP; its never used. - * That is legacy code from mpt fusion driver, ported over. - * I will leave this BUG_ON here for now till its been resolved. - */ - BUG_ON(sleep_flag == NO_SLEEP); - - /* wait for an active reset in progress to complete */ - if (!mutex_trylock(&ioc->reset_in_progress_mutex)) { - do { - ssleep(1); - } while (ioc->shost_recovery == 1); - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name, - __func__)); - return ioc->ioc_reset_in_progress_status; - } - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - ioc->shost_recovery = 1; - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); - - _base_reset_handler(ioc, MPT2_IOC_PRE_RESET); - _wait_for_commands_to_complete(ioc, sleep_flag); - _base_mask_interrupts(ioc); - r = _base_make_ioc_ready(ioc, sleep_flag, type); - if (r) - goto out; - _base_reset_handler(ioc, MPT2_IOC_AFTER_RESET); - - /* If this hard reset is called while port enable is active, then - * there is no reason to call make_ioc_operational - */ - if (ioc->is_driver_loading && ioc->port_enable_failed) { - ioc->remove_host = 1; - r = -EFAULT; - goto out; - } - - r = _base_get_ioc_facts(ioc, CAN_SLEEP); - if (r) - goto out; - - if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable) - panic("%s: Issue occurred with flashing controller firmware." - "Please reboot the system and ensure that the correct" - " firmware version is running\n", ioc->name); - - r = _base_make_ioc_operational(ioc, sleep_flag); - if (!r) - _base_reset_handler(ioc, MPT2_IOC_DONE_RESET); - out: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %s\n", - ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED"))); - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - ioc->ioc_reset_in_progress_status = r; - ioc->shost_recovery = 0; - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); - mutex_unlock(&ioc->reset_in_progress_mutex); - - out_unlocked: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name, - __func__)); - return r; -} diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h deleted file mode 100644 index 97ea360c6..000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ /dev/null @@ -1,1235 +0,0 @@ -/* - * This is the Fusion MPT base driver providing common API layer interface - * for access to MPT (Message Passing Technology) firmware. - * - * This code is based on drivers/scsi/mpt2sas/mpt2_base.h - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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. - * - * 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. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifndef MPT2SAS_BASE_H_INCLUDED -#define MPT2SAS_BASE_H_INCLUDED - -#include "mpi/mpi2_type.h" -#include "mpi/mpi2.h" -#include "mpi/mpi2_ioc.h" -#include "mpi/mpi2_cnfg.h" -#include "mpi/mpi2_init.h" -#include "mpi/mpi2_raid.h" -#include "mpi/mpi2_tool.h" -#include "mpi/mpi2_sas.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mpt2sas_debug.h" - -/* driver versioning info */ -#define MPT2SAS_DRIVER_NAME "mpt2sas" -#define MPT2SAS_AUTHOR "Avago Technologies " -#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "20.100.00.00" -#define MPT2SAS_MAJOR_VERSION 20 -#define MPT2SAS_MINOR_VERSION 100 -#define MPT2SAS_BUILD_VERSION 00 -#define MPT2SAS_RELEASE_VERSION 00 - -/* - * Set MPT2SAS_SG_DEPTH value based on user input. - */ -#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE -#if CONFIG_SCSI_MPT2SAS_MAX_SGE < 16 -#define MPT2SAS_SG_DEPTH 16 -#elif CONFIG_SCSI_MPT2SAS_MAX_SGE > 128 -#define MPT2SAS_SG_DEPTH 128 -#else -#define MPT2SAS_SG_DEPTH CONFIG_SCSI_MPT2SAS_MAX_SGE -#endif -#else -#define MPT2SAS_SG_DEPTH 128 /* MAX_HW_SEGMENTS */ -#endif - - -/* - * Generic Defines - */ -#define MPT2SAS_SATA_QUEUE_DEPTH 32 -#define MPT2SAS_SAS_QUEUE_DEPTH 254 -#define MPT2SAS_RAID_QUEUE_DEPTH 128 - -#define MPT_NAME_LENGTH 32 /* generic length of strings */ -#define MPT_STRING_LENGTH 64 - -#define MPT_MAX_CALLBACKS 16 - - -#define CAN_SLEEP 1 -#define NO_SLEEP 0 - -#define INTERNAL_CMDS_COUNT 10 /* reserved cmds */ - -#define MPI2_HIM_MASK 0xFFFFFFFF /* mask every bit*/ - -#define MPT2SAS_INVALID_DEVICE_HANDLE 0xFFFF - - -/* - * reset phases - */ -#define MPT2_IOC_PRE_RESET 1 /* prior to host reset */ -#define MPT2_IOC_AFTER_RESET 2 /* just after host reset */ -#define MPT2_IOC_DONE_RESET 3 /* links re-initialized */ - -/* - * logging format - */ -#define MPT2SAS_FMT "%s: " -#define MPT2SAS_INFO_FMT KERN_INFO MPT2SAS_FMT -#define MPT2SAS_NOTE_FMT KERN_NOTICE MPT2SAS_FMT -#define MPT2SAS_WARN_FMT KERN_WARNING MPT2SAS_FMT -#define MPT2SAS_ERR_FMT KERN_ERR MPT2SAS_FMT - -/* - * Dell HBA branding - */ -#define MPT2SAS_DELL_BRANDING_SIZE 32 - -#define MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING "Dell 6Gbps SAS HBA" -#define MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING "Dell PERC H200 Adapter" -#define MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING "Dell PERC H200 Integrated" -#define MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING "Dell PERC H200 Modular" -#define MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING "Dell PERC H200 Embedded" -#define MPT2SAS_DELL_PERC_H200_BRANDING "Dell PERC H200" -#define MPT2SAS_DELL_6GBPS_SAS_BRANDING "Dell 6Gbps SAS" - -/* - * Dell HBA SSDIDs - */ -#define MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID 0x1F1C -#define MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID 0x1F1D -#define MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID 0x1F1E -#define MPT2SAS_DELL_PERC_H200_MODULAR_SSDID 0x1F1F -#define MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID 0x1F20 -#define MPT2SAS_DELL_PERC_H200_SSDID 0x1F21 -#define MPT2SAS_DELL_6GBPS_SAS_SSDID 0x1F22 - -/* - * Intel HBA branding - */ -#define MPT2SAS_INTEL_RMS25JB080_BRANDING \ - "Intel(R) Integrated RAID Module RMS25JB080" -#define MPT2SAS_INTEL_RMS25JB040_BRANDING \ - "Intel(R) Integrated RAID Module RMS25JB040" -#define MPT2SAS_INTEL_RMS25KB080_BRANDING \ - "Intel(R) Integrated RAID Module RMS25KB080" -#define MPT2SAS_INTEL_RMS25KB040_BRANDING \ - "Intel(R) Integrated RAID Module RMS25KB040" -#define MPT2SAS_INTEL_RMS25LB040_BRANDING \ - "Intel(R) Integrated RAID Module RMS25LB040" -#define MPT2SAS_INTEL_RMS25LB080_BRANDING \ - "Intel(R) Integrated RAID Module RMS25LB080" -#define MPT2SAS_INTEL_RMS2LL080_BRANDING \ - "Intel Integrated RAID Module RMS2LL080" -#define MPT2SAS_INTEL_RMS2LL040_BRANDING \ - "Intel Integrated RAID Module RMS2LL040" -#define MPT2SAS_INTEL_RS25GB008_BRANDING \ - "Intel(R) RAID Controller RS25GB008" -#define MPT2SAS_INTEL_SSD910_BRANDING \ - "Intel(R) SSD 910 Series" -/* - * Intel HBA SSDIDs - */ -#define MPT2SAS_INTEL_RMS25JB080_SSDID 0x3516 -#define MPT2SAS_INTEL_RMS25JB040_SSDID 0x3517 -#define MPT2SAS_INTEL_RMS25KB080_SSDID 0x3518 -#define MPT2SAS_INTEL_RMS25KB040_SSDID 0x3519 -#define MPT2SAS_INTEL_RMS25LB040_SSDID 0x351A -#define MPT2SAS_INTEL_RMS25LB080_SSDID 0x351B -#define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E -#define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F -#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000 -#define MPT2SAS_INTEL_SSD910_SSDID 0x3700 - -/* - * HP HBA branding - */ -#define MPT2SAS_HP_3PAR_SSVID 0x1590 -#define MPT2SAS_HP_2_4_INTERNAL_BRANDING "HP H220 Host Bus Adapter" -#define MPT2SAS_HP_2_4_EXTERNAL_BRANDING "HP H221 Host Bus Adapter" -#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING "HP H222 Host Bus Adapter" -#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING "HP H220i Host Bus Adapter" -#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING "HP H210i Host Bus Adapter" - -/* - * HO HBA SSDIDs - */ -#define MPT2SAS_HP_2_4_INTERNAL_SSDID 0x0041 -#define MPT2SAS_HP_2_4_EXTERNAL_SSDID 0x0042 -#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID 0x0043 -#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044 -#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046 - -/* - * WarpDrive Specific Log codes - */ - -#define MPT2_WARPDRIVE_LOGENTRY (0x8002) -#define MPT2_WARPDRIVE_LC_SSDT (0x41) -#define MPT2_WARPDRIVE_LC_SSDLW (0x43) -#define MPT2_WARPDRIVE_LC_SSDLF (0x44) -#define MPT2_WARPDRIVE_LC_BRMF (0x4D) - -/* - * per target private data - */ -#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01 -#define MPT_TARGET_FLAGS_VOLUME 0x02 -#define MPT_TARGET_FLAGS_DELETED 0x04 - -/** - * struct MPT2SAS_TARGET - starget private hostdata - * @starget: starget object - * @sas_address: target sas address - * @raid_device: raid_device pointer to access volume data - * @handle: device handle - * @num_luns: number luns - * @flags: MPT_TARGET_FLAGS_XXX flags - * @deleted: target flaged for deletion - * @tm_busy: target is busy with TM request. - * @sdev: The sas_device associated with this target - */ -struct MPT2SAS_TARGET { - struct scsi_target *starget; - u64 sas_address; - struct _raid_device *raid_device; - u16 handle; - int num_luns; - u32 flags; - u8 deleted; - u8 tm_busy; - struct _sas_device *sdev; -}; - - -/* - * per device private data - */ -#define MPT_DEVICE_FLAGS_INIT 0x01 -#define MPT_DEVICE_TLR_ON 0x02 - -/** - * struct MPT2SAS_DEVICE - sdev private hostdata - * @sas_target: starget private hostdata - * @lun: lun number - * @flags: MPT_DEVICE_XXX flags - * @configured_lun: lun is configured - * @block: device is in SDEV_BLOCK state - * @tlr_snoop_check: flag used in determining whether to disable TLR - */ - -/* OEM Identifiers */ -#define MFG10_OEM_ID_INVALID (0x00000000) -#define MFG10_OEM_ID_DELL (0x00000001) -#define MFG10_OEM_ID_FSC (0x00000002) -#define MFG10_OEM_ID_SUN (0x00000003) -#define MFG10_OEM_ID_IBM (0x00000004) - -/* GENERIC Flags 0*/ -#define MFG10_GF0_OCE_DISABLED (0x00000001) -#define MFG10_GF0_R1E_DRIVE_COUNT (0x00000002) -#define MFG10_GF0_R10_DISPLAY (0x00000004) -#define MFG10_GF0_SSD_DATA_SCRUB_DISABLE (0x00000008) -#define MFG10_GF0_SINGLE_DRIVE_R0 (0x00000010) - -/* OEM Specific Flags will come from OEM specific header files */ -typedef struct _MPI2_CONFIG_PAGE_MAN_10 { - MPI2_CONFIG_PAGE_HEADER Header; /* 00h */ - U8 OEMIdentifier; /* 04h */ - U8 Reserved1; /* 05h */ - U16 Reserved2; /* 08h */ - U32 Reserved3; /* 0Ch */ - U32 GenericFlags0; /* 10h */ - U32 GenericFlags1; /* 14h */ - U32 Reserved4; /* 18h */ - U32 OEMSpecificFlags0; /* 1Ch */ - U32 OEMSpecificFlags1; /* 20h */ - U32 Reserved5[18]; /* 24h-60h*/ -} MPI2_CONFIG_PAGE_MAN_10, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_10, - Mpi2ManufacturingPage10_t, MPI2_POINTER pMpi2ManufacturingPage10_t; - -#define MFG_PAGE10_HIDE_SSDS_MASK (0x00000003) -#define MFG_PAGE10_HIDE_ALL_DISKS (0x00) -#define MFG_PAGE10_EXPOSE_ALL_DISKS (0x01) -#define MFG_PAGE10_HIDE_IF_VOL_PRESENT (0x02) - - -struct MPT2SAS_DEVICE { - struct MPT2SAS_TARGET *sas_target; - unsigned int lun; - u32 flags; - u8 configured_lun; - u8 block; - u8 tlr_snoop_check; -}; - -#define MPT2_CMD_NOT_USED 0x8000 /* free */ -#define MPT2_CMD_COMPLETE 0x0001 /* completed */ -#define MPT2_CMD_PENDING 0x0002 /* pending */ -#define MPT2_CMD_REPLY_VALID 0x0004 /* reply is valid */ -#define MPT2_CMD_RESET 0x0008 /* host reset dropped the command */ - -/** - * struct _internal_cmd - internal commands struct - * @mutex: mutex - * @done: completion - * @reply: reply message pointer - * @sense: sense data - * @status: MPT2_CMD_XXX status - * @smid: system message id - */ -struct _internal_cmd { - struct mutex mutex; - struct completion done; - void *reply; - void *sense; - u16 status; - u16 smid; -}; - - -/** - * struct _sas_device - attached device information - * @list: sas device list - * @starget: starget object - * @sas_address: device sas address - * @device_name: retrieved from the SAS IDENTIFY frame. - * @handle: device handle - * @sas_address_parent: sas address of parent expander or sas host - * @enclosure_handle: enclosure handle - * @enclosure_logical_id: enclosure logical identifier - * @volume_handle: volume handle (valid when hidden raid member) - * @volume_wwid: volume unique identifier - * @device_info: bitfield provides detailed info about the device - * @id: target id - * @channel: target channel - * @slot: number number - * @phy: phy identifier provided in sas device page 0 - * @responding: used in _scsih_sas_device_mark_responding - * @pfa_led_on: flag for PFA LED status - */ -struct _sas_device { - struct list_head list; - struct scsi_target *starget; - u64 sas_address; - u64 device_name; - u16 handle; - u64 sas_address_parent; - u16 enclosure_handle; - u64 enclosure_logical_id; - u16 volume_handle; - u64 volume_wwid; - u32 device_info; - int id; - int channel; - u16 slot; - u8 phy; - u8 responding; - u8 pfa_led_on; - struct kref refcount; -}; - -static inline void sas_device_get(struct _sas_device *s) -{ - kref_get(&s->refcount); -} - -static inline void sas_device_free(struct kref *r) -{ - kfree(container_of(r, struct _sas_device, refcount)); -} - -static inline void sas_device_put(struct _sas_device *s) -{ - kref_put(&s->refcount, sas_device_free); -} - -/** - * struct _raid_device - raid volume link list - * @list: sas device list - * @starget: starget object - * @sdev: scsi device struct (volumes are single lun) - * @wwid: unique identifier for the volume - * @handle: device handle - * @block_size: Block size of the volume - * @id: target id - * @channel: target channel - * @volume_type: the raid level - * @device_info: bitfield provides detailed info about the hidden components - * @num_pds: number of hidden raid components - * @responding: used in _scsih_raid_device_mark_responding - * @percent_complete: resync percent complete - * @direct_io_enabled: Whether direct io to PDs are allowed or not - * @stripe_exponent: X where 2powX is the stripe sz in blocks - * @block_exponent: X where 2powX is the block sz in bytes - * @max_lba: Maximum number of LBA in the volume - * @stripe_sz: Stripe Size of the volume - * @device_info: Device info of the volume member disk - * @pd_handle: Array of handles of the physical drives for direct I/O in le16 - */ -#define MPT_MAX_WARPDRIVE_PDS 8 -struct _raid_device { - struct list_head list; - struct scsi_target *starget; - struct scsi_device *sdev; - u64 wwid; - u16 handle; - u16 block_sz; - int id; - int channel; - u8 volume_type; - u8 num_pds; - u8 responding; - u8 percent_complete; - u8 direct_io_enabled; - u8 stripe_exponent; - u8 block_exponent; - u64 max_lba; - u32 stripe_sz; - u32 device_info; - u16 pd_handle[MPT_MAX_WARPDRIVE_PDS]; -}; - -/** - * struct _boot_device - boot device info - * @is_raid: flag to indicate whether this is volume - * @device: holds pointer for either struct _sas_device or - * struct _raid_device - */ -struct _boot_device { - u8 is_raid; - void *device; -}; - -/** - * struct _sas_port - wide/narrow sas port information - * @port_list: list of ports belonging to expander - * @num_phys: number of phys belonging to this port - * @remote_identify: attached device identification - * @rphy: sas transport rphy object - * @port: sas transport wide/narrow port object - * @phy_list: _sas_phy list objects belonging to this port - */ -struct _sas_port { - struct list_head port_list; - u8 num_phys; - struct sas_identify remote_identify; - struct sas_rphy *rphy; - struct sas_port *port; - struct list_head phy_list; -}; - -/** - * struct _sas_phy - phy information - * @port_siblings: list of phys belonging to a port - * @identify: phy identification - * @remote_identify: attached device identification - * @phy: sas transport phy object - * @phy_id: unique phy id - * @handle: device handle for this phy - * @attached_handle: device handle for attached device - * @phy_belongs_to_port: port has been created for this phy - */ -struct _sas_phy { - struct list_head port_siblings; - struct sas_identify identify; - struct sas_identify remote_identify; - struct sas_phy *phy; - u8 phy_id; - u16 handle; - u16 attached_handle; - u8 phy_belongs_to_port; -}; - -/** - * struct _sas_node - sas_host/expander information - * @list: list of expanders - * @parent_dev: parent device class - * @num_phys: number phys belonging to this sas_host/expander - * @sas_address: sas address of this sas_host/expander - * @handle: handle for this sas_host/expander - * @sas_address_parent: sas address of parent expander or sas host - * @enclosure_handle: handle for this a member of an enclosure - * @device_info: bitwise defining capabilities of this sas_host/expander - * @responding: used in _scsih_expander_device_mark_responding - * @phy: a list of phys that make up this sas_host/expander - * @sas_port_list: list of ports attached to this sas_host/expander - */ -struct _sas_node { - struct list_head list; - struct device *parent_dev; - u8 num_phys; - u64 sas_address; - u16 handle; - u64 sas_address_parent; - u16 enclosure_handle; - u64 enclosure_logical_id; - u8 responding; - struct _sas_phy *phy; - struct list_head sas_port_list; -}; - -/** - * enum reset_type - reset state - * @FORCE_BIG_HAMMER: issue diagnostic reset - * @SOFT_RESET: issue message_unit_reset, if fails to to big hammer - */ -enum reset_type { - FORCE_BIG_HAMMER, - SOFT_RESET, -}; - -/** - * struct chain_tracker - firmware chain tracker - * @chain_buffer: chain buffer - * @chain_buffer_dma: physical address - * @tracker_list: list of free request (ioc->free_chain_list) - */ -struct chain_tracker { - void *chain_buffer; - dma_addr_t chain_buffer_dma; - struct list_head tracker_list; -}; - -/** - * struct scsiio_tracker - scsi mf request tracker - * @smid: system message id - * @scmd: scsi request pointer - * @cb_idx: callback index - * @direct_io: To indicate whether I/O is direct (WARPDRIVE) - * @chain_list: list of chains associated to this IO - * @tracker_list: list of free request (ioc->free_list) - */ -struct scsiio_tracker { - u16 smid; - struct scsi_cmnd *scmd; - u8 cb_idx; - u8 direct_io; - struct list_head chain_list; - struct list_head tracker_list; -}; - -/** - * struct request_tracker - firmware request tracker - * @smid: system message id - * @cb_idx: callback index - * @tracker_list: list of free request (ioc->free_list) - */ -struct request_tracker { - u16 smid; - u8 cb_idx; - struct list_head tracker_list; -}; - -/** - * struct _tr_list - target reset list - * @handle: device handle - * @state: state machine - */ -struct _tr_list { - struct list_head list; - u16 handle; - u16 state; -}; - -typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); - -/** - * struct adapter_reply_queue - the reply queue struct - * @ioc: per adapter object - * @msix_index: msix index into vector table - * @vector: irq vector - * @reply_post_host_index: head index in the pool where FW completes IO - * @reply_post_free: reply post base virt address - * @name: the name registered to request_irq() - * @busy: isr is actively processing replies on another cpu - * @list: this list -*/ -struct adapter_reply_queue { - struct MPT2SAS_ADAPTER *ioc; - u8 msix_index; - unsigned int vector; - u32 reply_post_host_index; - Mpi2ReplyDescriptorsUnion_t *reply_post_free; - char name[MPT_NAME_LENGTH]; - atomic_t busy; - cpumask_var_t affinity_hint; - struct list_head list; -}; - -/* IOC Facts and Port Facts converted from little endian to cpu */ -union mpi2_version_union { - MPI2_VERSION_STRUCT Struct; - u32 Word; -}; - -struct mpt2sas_facts { - u16 MsgVersion; - u16 HeaderVersion; - u8 IOCNumber; - u8 VP_ID; - u8 VF_ID; - u16 IOCExceptions; - u16 IOCStatus; - u32 IOCLogInfo; - u8 MaxChainDepth; - u8 WhoInit; - u8 NumberOfPorts; - u8 MaxMSIxVectors; - u16 RequestCredit; - u16 ProductID; - u32 IOCCapabilities; - union mpi2_version_union FWVersion; - u16 IOCRequestFrameSize; - u16 Reserved3; - u16 MaxInitiators; - u16 MaxTargets; - u16 MaxSasExpanders; - u16 MaxEnclosures; - u16 ProtocolFlags; - u16 HighPriorityCredit; - u16 MaxReplyDescriptorPostQueueDepth; - u8 ReplyFrameSize; - u8 MaxVolumes; - u16 MaxDevHandle; - u16 MaxPersistentEntries; - u16 MinDevHandle; -}; - -struct mpt2sas_port_facts { - u8 PortNumber; - u8 VP_ID; - u8 VF_ID; - u8 PortType; - u16 MaxPostedCmdBuffers; -}; - -struct reply_post_struct { - Mpi2ReplyDescriptorsUnion_t *reply_post_free; - dma_addr_t reply_post_free_dma; -}; - -/** - * enum mutex_type - task management mutex type - * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it - * @TM_MUTEX_ON: mutex is required - */ -enum mutex_type { - TM_MUTEX_OFF = 0, - TM_MUTEX_ON = 1, -}; - -typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc); -/** - * struct MPT2SAS_ADAPTER - per adapter struct - * @list: ioc_list - * @shost: shost object - * @id: unique adapter id - * @cpu_count: number online cpus - * @name: generic ioc string - * @tmp_string: tmp string used for logging - * @pdev: pci pdev object - * @chip: memory mapped register space - * @chip_phys: physical addrss prior to mapping - * @logging_level: see mpt2sas_debug.h - * @fwfault_debug: debuging FW timeouts - * @ir_firmware: IR firmware present - * @bars: bitmask of BAR's that must be configured - * @mask_interrupts: ignore interrupt - * @dma_mask: used to set the consistent dma mask - * @fault_reset_work_q_name: fw fault work queue - * @fault_reset_work_q: "" - * @fault_reset_work: "" - * @firmware_event_name: fw event work queue - * @firmware_event_thread: "" - * @fw_events_off: flag to turn off fw event handling - * @fw_event_lock: - * @fw_event_list: list of fw events - * @aen_event_read_flag: event log was read - * @broadcast_aen_busy: broadcast aen waiting to be serviced - * @shost_recovery: host reset in progress - * @ioc_reset_in_progress_lock: - * @ioc_link_reset_in_progress: phy/hard reset in progress - * @ignore_loginfos: ignore loginfos during task management - * @remove_host: flag for when driver unloads, to avoid sending dev resets - * @pci_error_recovery: flag to prevent ioc access until slot reset completes - * @wait_for_discovery_to_complete: flag set at driver load time when - * waiting on reporting devices - * @is_driver_loading: flag set at driver load time - * @port_enable_failed: flag set when port enable has failed - * @start_scan: flag set from scan_start callback, cleared from _mpt2sas_fw_work - * @start_scan_failed: means port enable failed, return's the ioc_status - * @msix_enable: flag indicating msix is enabled - * @msix_vector_count: number msix vectors - * @cpu_msix_table: table for mapping cpus to msix index - * @cpu_msix_table_sz: table size - * @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands - * @scsi_io_cb_idx: shost generated commands - * @tm_cb_idx: task management commands - * @scsih_cb_idx: scsih internal commands - * @transport_cb_idx: transport internal commands - * @ctl_cb_idx: clt internal commands - * @base_cb_idx: base internal commands - * @config_cb_idx: base internal commands - * @tm_tr_cb_idx : device removal target reset handshake - * @tm_tr_volume_cb_idx : volume removal target reset - * @base_cmds: - * @transport_cmds: - * @scsih_cmds: - * @tm_cmds: - * @ctl_cmds: - * @config_cmds: - * @base_add_sg_single: handler for either 32/64 bit sgl's - * @event_type: bits indicating which events to log - * @event_context: unique id for each logged event - * @event_log: event log pointer - * @event_masks: events that are masked - * @facts: static facts data - * @pfacts: static port facts data - * @manu_pg0: static manufacturing page 0 - * @manu_pg10: static manufacturing page 10 - * @bios_pg2: static bios page 2 - * @bios_pg3: static bios page 3 - * @ioc_pg8: static ioc page 8 - * @iounit_pg0: static iounit page 0 - * @iounit_pg1: static iounit page 1 - * @iounit_pg8: static iounit page 8 - * @sas_hba: sas host object - * @sas_expander_list: expander object list - * @sas_node_lock: - * @sas_device_list: sas device object list - * @sas_device_init_list: sas device object list (used only at init time) - * @sas_device_lock: - * @io_missing_delay: time for IO completed by fw when PDR enabled - * @device_missing_delay: time for device missing by fw when PDR enabled - * @sas_id : used for setting volume target IDs - * @blocking_handles: bitmask used to identify which devices need blocking - * @pd_handles : bitmask for PD handles - * @pd_handles_sz : size of pd_handle bitmask - * @config_page_sz: config page size - * @config_page: reserve memory for config page payload - * @config_page_dma: - * @hba_queue_depth: hba request queue depth - * @sge_size: sg element size for either 32/64 bit - * @scsiio_depth: SCSI_IO queue depth - * @request_sz: per request frame size - * @request: pool of request frames - * @request_dma: - * @request_dma_sz: - * @scsi_lookup: firmware request tracker list - * @scsi_lookup_lock: - * @free_list: free list of request - * @chain: pool of chains - * @pending_io_count: - * @reset_wq: - * @chain_dma: - * @max_sges_in_main_message: number sg elements in main message - * @max_sges_in_chain_message: number sg elements per chain - * @chains_needed_per_io: max chains per io - * @chain_offset_value_for_main_message: location 1st sg in main - * @chain_depth: total chains allocated - * @hi_priority_smid: - * @hi_priority: - * @hi_priority_dma: - * @hi_priority_depth: - * @hpr_lookup: - * @hpr_free_list: - * @internal_smid: - * @internal: - * @internal_dma: - * @internal_depth: - * @internal_lookup: - * @internal_free_list: - * @sense: pool of sense - * @sense_dma: - * @sense_dma_pool: - * @reply_depth: hba reply queue depth: - * @reply_sz: per reply frame size: - * @reply: pool of replys: - * @reply_dma: - * @reply_dma_pool: - * @reply_free_queue_depth: reply free depth - * @reply_free: pool for reply free queue (32 bit addr) - * @reply_free_dma: - * @reply_free_dma_pool: - * @reply_free_host_index: tail index in pool to insert free replys - * @reply_post_queue_depth: reply post queue depth - * @reply_post_struct: struct for reply_post_free physical & virt address - * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init - * @rdpq_array_enable: rdpq_array support is enabled in the driver - * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag - * is assigned only ones - * @reply_queue_count: number of reply queue's - * @reply_queue_list: link list contaning the reply queue info - * @reply_post_host_index: head index in the pool where FW completes IO - * @delayed_tr_list: target reset link list - * @delayed_tr_volume_list: volume target reset link list - * @@temp_sensors_count: flag to carry the number of temperature sensors - * @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and - * pci resource handling. PCI resource freeing will lead to free - * vital hardware/memory resource, which might be in use by cli/sysfs - * path functions resulting in Null pointer reference followed by kernel - * crash. To avoid the above race condition we use mutex syncrhonization - * which ensures the syncrhonization between cli/sysfs_show path - */ -struct MPT2SAS_ADAPTER { - struct list_head list; - struct Scsi_Host *shost; - u8 id; - int cpu_count; - char name[MPT_NAME_LENGTH]; - char tmp_string[MPT_STRING_LENGTH]; - struct pci_dev *pdev; - Mpi2SystemInterfaceRegs_t __iomem *chip; - resource_size_t chip_phys; - int logging_level; - int fwfault_debug; - u8 ir_firmware; - int bars; - u8 mask_interrupts; - int dma_mask; - - /* fw fault handler */ - char fault_reset_work_q_name[20]; - struct workqueue_struct *fault_reset_work_q; - struct delayed_work fault_reset_work; - - /* fw event handler */ - char firmware_event_name[20]; - struct workqueue_struct *firmware_event_thread; - spinlock_t fw_event_lock; - struct list_head fw_event_list; - - /* misc flags */ - int aen_event_read_flag; - u8 broadcast_aen_busy; - u16 broadcast_aen_pending; - u8 shost_recovery; - - struct mutex reset_in_progress_mutex; - spinlock_t ioc_reset_in_progress_lock; - u8 ioc_link_reset_in_progress; - u8 ioc_reset_in_progress_status; - - u8 ignore_loginfos; - u8 remove_host; - u8 pci_error_recovery; - u8 wait_for_discovery_to_complete; - struct completion port_enable_done; - u8 is_driver_loading; - u8 port_enable_failed; - - u8 start_scan; - u16 start_scan_failed; - - u8 msix_enable; - u16 msix_vector_count; - u8 *cpu_msix_table; - resource_size_t __iomem **reply_post_host_index; - u16 cpu_msix_table_sz; - u32 ioc_reset_count; - MPT2SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; - u32 non_operational_loop; - - /* internal commands, callback index */ - u8 scsi_io_cb_idx; - u8 tm_cb_idx; - u8 transport_cb_idx; - u8 scsih_cb_idx; - u8 ctl_cb_idx; - u8 base_cb_idx; - u8 port_enable_cb_idx; - u8 config_cb_idx; - u8 tm_tr_cb_idx; - u8 tm_tr_volume_cb_idx; - u8 tm_sas_control_cb_idx; - struct _internal_cmd base_cmds; - struct _internal_cmd port_enable_cmds; - struct _internal_cmd transport_cmds; - struct _internal_cmd scsih_cmds; - struct _internal_cmd tm_cmds; - struct _internal_cmd ctl_cmds; - struct _internal_cmd config_cmds; - - MPT_ADD_SGE base_add_sg_single; - - /* event log */ - u32 event_type[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; - u32 event_context; - void *event_log; - u32 event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; - - /* static config pages */ - struct mpt2sas_facts facts; - struct mpt2sas_port_facts *pfacts; - Mpi2ManufacturingPage0_t manu_pg0; - Mpi2BiosPage2_t bios_pg2; - Mpi2BiosPage3_t bios_pg3; - Mpi2IOCPage8_t ioc_pg8; - Mpi2IOUnitPage0_t iounit_pg0; - Mpi2IOUnitPage1_t iounit_pg1; - Mpi2IOUnitPage8_t iounit_pg8; - - struct _boot_device req_boot_device; - struct _boot_device req_alt_boot_device; - struct _boot_device current_boot_device; - - /* sas hba, expander, and device list */ - struct _sas_node sas_hba; - struct list_head sas_expander_list; - spinlock_t sas_node_lock; - struct list_head sas_device_list; - struct list_head sas_device_init_list; - spinlock_t sas_device_lock; - struct list_head raid_device_list; - spinlock_t raid_device_lock; - u8 io_missing_delay; - u16 device_missing_delay; - int sas_id; - void *blocking_handles; - void *pd_handles; - u16 pd_handles_sz; - - /* config page */ - u16 config_page_sz; - void *config_page; - dma_addr_t config_page_dma; - - /* scsiio request */ - u16 hba_queue_depth; - u16 sge_size; - u16 scsiio_depth; - u16 request_sz; - u8 *request; - dma_addr_t request_dma; - u32 request_dma_sz; - struct scsiio_tracker *scsi_lookup; - ulong scsi_lookup_pages; - spinlock_t scsi_lookup_lock; - struct list_head free_list; - int pending_io_count; - wait_queue_head_t reset_wq; - - /* chain */ - struct chain_tracker *chain_lookup; - struct list_head free_chain_list; - struct dma_pool *chain_dma_pool; - ulong chain_pages; - u16 max_sges_in_main_message; - u16 max_sges_in_chain_message; - u16 chains_needed_per_io; - u16 chain_offset_value_for_main_message; - u32 chain_depth; - - /* hi-priority queue */ - u16 hi_priority_smid; - u8 *hi_priority; - dma_addr_t hi_priority_dma; - u16 hi_priority_depth; - struct request_tracker *hpr_lookup; - struct list_head hpr_free_list; - - /* internal queue */ - u16 internal_smid; - u8 *internal; - dma_addr_t internal_dma; - u16 internal_depth; - struct request_tracker *internal_lookup; - struct list_head internal_free_list; - - /* sense */ - u8 *sense; - dma_addr_t sense_dma; - struct dma_pool *sense_dma_pool; - - /* reply */ - u16 reply_sz; - u8 *reply; - dma_addr_t reply_dma; - u32 reply_dma_max_address; - u32 reply_dma_min_address; - struct dma_pool *reply_dma_pool; - - /* reply free queue */ - u16 reply_free_queue_depth; - __le32 *reply_free; - dma_addr_t reply_free_dma; - struct dma_pool *reply_free_dma_pool; - u32 reply_free_host_index; - - /* reply post queue */ - u16 reply_post_queue_depth; - struct reply_post_struct *reply_post; - u8 rdpq_array_capable; - u8 rdpq_array_enable; - u8 rdpq_array_enable_assigned; - struct dma_pool *reply_post_free_dma_pool; - u8 reply_queue_count; - struct list_head reply_queue_list; - - struct list_head delayed_tr_list; - struct list_head delayed_tr_volume_list; - u8 temp_sensors_count; - - /* diag buffer support */ - u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT]; - u32 diag_buffer_sz[MPI2_DIAG_BUF_TYPE_COUNT]; - dma_addr_t diag_buffer_dma[MPI2_DIAG_BUF_TYPE_COUNT]; - u8 diag_buffer_status[MPI2_DIAG_BUF_TYPE_COUNT]; - u32 unique_id[MPI2_DIAG_BUF_TYPE_COUNT]; - Mpi2ManufacturingPage10_t manu_pg10; - u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23]; - u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; - u32 ring_buffer_offset; - u32 ring_buffer_sz; - u8 is_warpdrive; - u8 hide_ir_msg; - u8 mfg_pg10_hide_flag; - u8 hide_drives; - - struct mutex pci_access_mutex; -}; - -typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); - - -/* base shared API */ -extern struct list_head mpt2sas_ioc_list; -/* spinlock on list operations over IOCs - * Case: when multiple warpdrive cards(IOCs) are in use - * Each IOC will added to the ioc list stucture on initialization. - * Watchdog threads run at regular intervals to check IOC for any - * fault conditions which will trigger the dead_ioc thread to - * deallocate pci resource, resulting deleting the IOC netry from list, - * this deletion need to protected by spinlock to enusre that - * ioc removal is syncrhonized, if not synchronized it might lead to - * list_del corruption as the ioc list is traversed in cli path - */ -extern spinlock_t gioc_lock; -void mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc); -void mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc); - -int mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc); -void mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc); -int mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc); -void mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc); -int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, - enum reset_type type); - -void *mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid); -void *mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid); -void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr); -__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, - u16 smid); -void mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc); - -/* hi-priority queue */ -u16 mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx); -u16 mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx, - struct scsi_cmnd *scmd); - -u16 mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx); -void mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid); -void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u16 handle); -void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid); -void mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u16 io_index); -void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid); -void mpt2sas_base_initialize_callback_handler(void); -u8 mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func); -void mpt2sas_base_release_callback_handler(u8 cb_idx); - -u8 mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); -u8 mpt2sas_port_enable_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u8 msix_index, u32 reply); -void *mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr); - -u32 mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked); - -void mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code); -int mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, - Mpi2SasIoUnitControlReply_t *mpi_reply, Mpi2SasIoUnitControlRequest_t - *mpi_request); -int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, - Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request); -void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type); - -void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc); - -void mpt2sas_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc, - u16 device_missing_delay, u8 io_missing_delay); - -int mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc); - -/* scsih shared API */ -void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, - u32 reply); -int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, - uint channel, uint id, uint lun, u8 type, u16 smid_task, - ulong timeout, enum mutex_type m_type); -void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); -void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); -void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address); -void mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address); -struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, - u16 handle); -struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER - *ioc, u64 sas_address); -struct _sas_device *mpt2sas_get_sdev_by_addr( - struct MPT2SAS_ADAPTER *ioc, u64 sas_address); -struct _sas_device *__mpt2sas_get_sdev_by_addr( - struct MPT2SAS_ADAPTER *ioc, u64 sas_address); - -void mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc); -void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase); - -/* config shared API */ -u8 mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); -int mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys); -int mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page); -int mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_t *config_page); -int mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2BiosPage2_t *config_page); -int mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2BiosPage3_t *config_page); -int mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2IOUnitPage0_t *config_page); -int mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle); -int mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle); -int mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz); -int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2IOUnitPage1_t *config_page); -int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2IOUnitPage1_t *config_page); -int mpt2sas_config_get_iounit_pg8(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page); -int mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz); -int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); -int mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); -int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2IOCPage8_t *config_page); -int mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle); -int mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number, u16 handle); -int mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle); -int mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number); -int mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number); -int mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u32 handle); -int mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 *num_pds); -int mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, u32 handle, u16 sz); -int mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form, - u32 form_specific); -int mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, - u16 *volume_handle); -int mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle, - u64 *wwid); -/* ctl shared API */ -extern struct device_attribute *mpt2sas_host_attrs[]; -extern struct device_attribute *mpt2sas_dev_attrs[]; -void mpt2sas_ctl_init(void); -void mpt2sas_ctl_exit(void); -u8 mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); -void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase); -void mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, - u32 reply); -void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventNotificationReply_t *mpi_reply); - -void mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, - u8 bits_to_regsiter); - -/* transport shared API */ -u8 mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); -struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, - u16 handle, u64 sas_address); -void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u64 sas_address_parent); -int mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy - *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev); -int mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy - *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev); -void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address, u16 handle, u8 phy_number, u8 link_rate); -extern struct sas_function_template mpt2sas_transport_functions; -extern struct scsi_transport_template *mpt2sas_transport_template; -extern int scsi_internal_device_block(struct scsi_device *sdev); -extern u8 mpt2sas_stm_zero_smid_handler(struct MPT2SAS_ADAPTER *ioc, - u8 msix_index, u32 reply); -extern int scsi_internal_device_unblock(struct scsi_device *sdev, - enum scsi_device_state new_state); - -#endif /* MPT2SAS_BASE_H_INCLUDED */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c deleted file mode 100644 index c43815b1a..000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_config.c +++ /dev/null @@ -1,1527 +0,0 @@ -/* - * This module provides common API for accessing firmware configuration pages - * - * This code is based on drivers/scsi/mpt2sas/mpt2_base.c - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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. - * - * 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. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mpt2sas_base.h" - -/* local definitions */ - -/* Timeout for config page request (in seconds) */ -#define MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT 15 - -/* Common sgl flags for READING a config page. */ -#define MPT2_CONFIG_COMMON_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \ - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \ - | MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT) - -/* Common sgl flags for WRITING a config page. */ -#define MPT2_CONFIG_COMMON_WRITE_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \ - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \ - | MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC) \ - << MPI2_SGE_FLAGS_SHIFT) - -/** - * struct config_request - obtain dma memory via routine - * @sz: size - * @page: virt pointer - * @page_dma: phys pointer - * - */ -struct config_request{ - u16 sz; - void *page; - dma_addr_t page_dma; -}; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _config_display_some_debug - debug routine - * @ioc: per adapter object - * @smid: system request message index - * @calling_function_name: string pass from calling function - * @mpi_reply: reply message frame - * Context: none. - * - * Function for displaying debug info helpful when debugging issues - * in this module. - */ -static void -_config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, - char *calling_function_name, MPI2DefaultReply_t *mpi_reply) -{ - Mpi2ConfigRequest_t *mpi_request; - char *desc = NULL; - - if (!(ioc->logging_level & MPT_DEBUG_CONFIG)) - return; - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - switch (mpi_request->Header.PageType & MPI2_CONFIG_PAGETYPE_MASK) { - case MPI2_CONFIG_PAGETYPE_IO_UNIT: - desc = "io_unit"; - break; - case MPI2_CONFIG_PAGETYPE_IOC: - desc = "ioc"; - break; - case MPI2_CONFIG_PAGETYPE_BIOS: - desc = "bios"; - break; - case MPI2_CONFIG_PAGETYPE_RAID_VOLUME: - desc = "raid_volume"; - break; - case MPI2_CONFIG_PAGETYPE_MANUFACTURING: - desc = "manufaucturing"; - break; - case MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK: - desc = "physdisk"; - break; - case MPI2_CONFIG_PAGETYPE_EXTENDED: - switch (mpi_request->ExtPageType) { - case MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT: - desc = "sas_io_unit"; - break; - case MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER: - desc = "sas_expander"; - break; - case MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE: - desc = "sas_device"; - break; - case MPI2_CONFIG_EXTPAGETYPE_SAS_PHY: - desc = "sas_phy"; - break; - case MPI2_CONFIG_EXTPAGETYPE_LOG: - desc = "log"; - break; - case MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE: - desc = "enclosure"; - break; - case MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG: - desc = "raid_config"; - break; - case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING: - desc = "driver_mapping"; - break; - } - break; - } - - if (!desc) - return; - - printk(MPT2SAS_INFO_FMT "%s: %s(%d), action(%d), form(0x%08x), " - "smid(%d)\n", ioc->name, calling_function_name, desc, - mpi_request->Header.PageNumber, mpi_request->Action, - le32_to_cpu(mpi_request->PageAddress), smid); - - if (!mpi_reply) - return; - - if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) - printk(MPT2SAS_INFO_FMT - "\tiocstatus(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); -} -#endif - -/** - * _config_alloc_config_dma_memory - obtain physical memory - * @ioc: per adapter object - * @mem: struct config_request - * - * A wrapper for obtaining dma-able memory for config page request. - * - * Returns 0 for success, non-zero for failure. - */ -static int -_config_alloc_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, - struct config_request *mem) -{ - int r = 0; - - if (mem->sz > ioc->config_page_sz) { - mem->page = dma_alloc_coherent(&ioc->pdev->dev, mem->sz, - &mem->page_dma, GFP_KERNEL); - if (!mem->page) { - printk(MPT2SAS_ERR_FMT "%s: dma_alloc_coherent" - " failed asking for (%d) bytes!!\n", - ioc->name, __func__, mem->sz); - r = -ENOMEM; - } - } else { /* use tmp buffer if less than 512 bytes */ - mem->page = ioc->config_page; - mem->page_dma = ioc->config_page_dma; - } - return r; -} - -/** - * _config_free_config_dma_memory - wrapper to free the memory - * @ioc: per adapter object - * @mem: struct config_request - * - * A wrapper to free dma-able memory when using _config_alloc_config_dma_memory. - * - * Returns 0 for success, non-zero for failure. - */ -static void -_config_free_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, - struct config_request *mem) -{ - if (mem->sz > ioc->config_page_sz) - dma_free_coherent(&ioc->pdev->dev, mem->sz, mem->page, - mem->page_dma); -} - -/** - * mpt2sas_config_done - config page completion routine - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: none. - * - * The callback handler when using _config_request. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - - if (ioc->config_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->config_cmds.smid != smid) - return 1; - ioc->config_cmds.status |= MPT2_CMD_COMPLETE; - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (mpi_reply) { - ioc->config_cmds.status |= MPT2_CMD_REPLY_VALID; - memcpy(ioc->config_cmds.reply, mpi_reply, - mpi_reply->MsgLength*4); - } - ioc->config_cmds.status &= ~MPT2_CMD_PENDING; -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - _config_display_some_debug(ioc, smid, "config_done", mpi_reply); -#endif - ioc->config_cmds.smid = USHRT_MAX; - complete(&ioc->config_cmds.done); - return 1; -} - -/** - * _config_request - main routine for sending config page requests - * @ioc: per adapter object - * @mpi_request: request message frame - * @mpi_reply: reply mf payload returned from firmware - * @timeout: timeout in seconds - * @config_page: contents of the config page - * @config_page_sz: size of config page - * Context: sleep - * - * A generic API for config page requests to firmware. - * - * The ioc->config_cmds.status flag should be MPT2_CMD_NOT_USED before calling - * this API. - * - * The callback index is set inside `ioc->config_cb_idx. - * - * Returns 0 for success, non-zero for failure. - */ -static int -_config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t - *mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout, - void *config_page, u16 config_page_sz) -{ - u16 smid; - u32 ioc_state; - unsigned long timeleft; - Mpi2ConfigRequest_t *config_request; - int r; - u8 retry_count, issue_host_reset = 0; - u16 wait_state_count; - struct config_request mem; - - mutex_lock(&ioc->config_cmds.mutex); - if (ioc->config_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: config_cmd in use\n", - ioc->name, __func__); - mutex_unlock(&ioc->config_cmds.mutex); - return -EAGAIN; - } - - retry_count = 0; - memset(&mem, 0, sizeof(struct config_request)); - - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - - if (config_page) { - mpi_request->Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request->Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request->Header.PageType = mpi_reply->Header.PageType; - mpi_request->Header.PageLength = mpi_reply->Header.PageLength; - mpi_request->ExtPageLength = mpi_reply->ExtPageLength; - mpi_request->ExtPageType = mpi_reply->ExtPageType; - if (mpi_request->Header.PageLength) - mem.sz = mpi_request->Header.PageLength * 4; - else - mem.sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r != 0) - goto out; - if (mpi_request->Action == - MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT || - mpi_request->Action == - MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) { - ioc->base_add_sg_single(&mpi_request->PageBufferSGE, - MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz, - mem.page_dma); - memcpy(mem.page, config_page, min_t(u16, mem.sz, - config_page_sz)); - } else { - memset(config_page, 0, config_page_sz); - ioc->base_add_sg_single(&mpi_request->PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.sz, mem.page_dma); - } - } - - retry_config: - if (retry_count) { - if (retry_count > 2) { /* attempt only 2 retries */ - r = -EFAULT; - goto free_mem; - } - printk(MPT2SAS_INFO_FMT "%s: attempting retry (%d)\n", - ioc->name, __func__, retry_count); - } - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - ioc->config_cmds.status = MPT2_CMD_NOT_USED; - r = -EFAULT; - goto free_mem; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - smid = mpt2sas_base_get_smid(ioc, ioc->config_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - ioc->config_cmds.status = MPT2_CMD_NOT_USED; - r = -EAGAIN; - goto free_mem; - } - - r = 0; - memset(mpi_reply, 0, sizeof(Mpi2ConfigReply_t)); - ioc->config_cmds.status = MPT2_CMD_PENDING; - config_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->config_cmds.smid = smid; - memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t)); -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - _config_display_some_debug(ioc, smid, "config_request", NULL); -#endif - init_completion(&ioc->config_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->config_cmds.done, - timeout*HZ); - if (!(ioc->config_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2ConfigRequest_t)/4); - retry_count++; - if (ioc->config_cmds.smid == smid) - mpt2sas_base_free_smid(ioc, smid); - if ((ioc->shost_recovery) || (ioc->config_cmds.status & - MPT2_CMD_RESET) || ioc->pci_error_recovery) - goto retry_config; - issue_host_reset = 1; - r = -EFAULT; - goto free_mem; - } - - if (ioc->config_cmds.status & MPT2_CMD_REPLY_VALID) - memcpy(mpi_reply, ioc->config_cmds.reply, - sizeof(Mpi2ConfigReply_t)); - if (retry_count) - printk(MPT2SAS_INFO_FMT "%s: retry (%d) completed!!\n", - ioc->name, __func__, retry_count); - if (config_page && mpi_request->Action == - MPI2_CONFIG_ACTION_PAGE_READ_CURRENT) - memcpy(config_page, mem.page, min_t(u16, mem.sz, - config_page_sz)); - free_mem: - if (config_page) - _config_free_config_dma_memory(ioc, &mem); - out: - ioc->config_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->config_cmds.mutex); - - if (issue_host_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - return r; -} - -/** - * mpt2sas_config_get_manufacturing_pg0 - obtain manufacturing page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_manufacturing_pg10 - obtain manufacturing page 10 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; - mpi_request.Header.PageNumber = 10; - mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_bios_pg2 - obtain bios page 2 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage2_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; - mpi_request.Header.PageNumber = 2; - mpi_request.Header.PageVersion = MPI2_BIOSPAGE2_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_bios_pg3 - obtain bios page 3 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2BiosPage3_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; - mpi_request.Header.PageNumber = 3; - mpi_request.Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_iounit_pg0 - obtain iounit page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage0_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_IOUNITPAGE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_iounit_pg1 - obtain iounit page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_set_iounit_pg1 - set iounit page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_iounit_pg3 - obtain iounit page 3 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @sz: size of buffer passed in config_page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; - mpi_request.Header.PageNumber = 3; - mpi_request.Header.PageVersion = MPI2_IOUNITPAGE3_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - return r; -} - -/** - * mpt2sas_config_get_iounit_pg8 - obtain iounit page 8 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_iounit_pg8(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; - mpi_request.Header.PageNumber = 8; - mpi_request.Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_ioc_pg8 - obtain ioc page 8 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC; - mpi_request.Header.PageNumber = 8; - mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_sas_device_pg0 - obtain sas device page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_HANDLE or HANDLE - * @handle: device handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; - mpi_request.Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION; - mpi_request.Header.PageNumber = 0; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_sas_device_pg1 - obtain sas device page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_HANDLE or HANDLE - * @handle: device handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; - mpi_request.Header.PageVersion = MPI2_SASDEVICE1_PAGEVERSION; - mpi_request.Header.PageNumber = 1; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_number_hba_phys - obtain number of phys on the host - * @ioc: per adapter object - * @num_phys: pointer returned with the number of phys - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - u16 ioc_status; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasIOUnitPage0_t config_page; - - *num_phys = 0; - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, - sizeof(Mpi2SasIOUnitPage0_t)); - if (!r) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) - *num_phys = config_page.NumPhys; - } - out: - return r; -} - -/** - * mpt2sas_config_get_sas_iounit_pg0 - obtain sas iounit page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @sz: size of buffer passed in config_page - * Context: sleep. - * - * Calling function should call config_get_number_hba_phys prior to - * this function, so enough memory is allocated for config_page. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - return r; -} - -/** - * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @sz: size of buffer passed in config_page - * Context: sleep. - * - * Calling function should call config_get_number_hba_phys prior to - * this function, so enough memory is allocated for config_page. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - return r; -} - -/** - * mpt2sas_config_set_sas_iounit_pg1 - send sas iounit page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @sz: size of buffer passed in config_page - * Context: sleep. - * - * Calling function should call config_get_number_hba_phys prior to - * this function, so enough memory is allocated for config_page. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; - _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - return r; -} - -/** - * mpt2sas_config_get_expander_pg0 - obtain expander page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_HANDLE or HANDLE - * @handle: expander handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_SASEXPANDER0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_expander_pg1 - obtain expander page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @phy_number: phy number - * @handle: expander handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number, - u16 handle) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_SASEXPANDER1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = - cpu_to_le32(MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM | - (phy_number << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_enclosure_pg0 - obtain enclosure page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_HANDLE or HANDLE - * @handle: expander handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_SASENCLOSURE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_phy_pg0 - obtain phy page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @phy_number: phy number - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_SASPHY0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = - cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_phy_pg1 - obtain phy page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @phy_number: phy number - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_SASPHY1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = - cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_raid_volume_pg1 - obtain raid volume page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_HANDLE or HANDLE - * @handle: volume handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, - u32 handle) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_number_pds - obtain number of phys disk assigned to volume - * @ioc: per adapter object - * @handle: volume handle - * @num_pds: returns pds count - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, - u8 *num_pds) -{ - Mpi2ConfigRequest_t mpi_request; - Mpi2RaidVolPage0_t config_page; - Mpi2ConfigReply_t mpi_reply; - int r; - u16 ioc_status; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - *num_pds = 0; - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = - cpu_to_le32(MPI2_RAID_VOLUME_PGAD_FORM_HANDLE | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, - sizeof(Mpi2RaidVolPage0_t)); - if (!r) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) - *num_pds = config_page.NumPhysDisks; - } - - out: - return r; -} - -/** - * mpt2sas_config_get_raid_volume_pg0 - obtain raid volume page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_HANDLE or HANDLE - * @handle: volume handle - * @sz: size of buffer passed in config_page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, - u32 handle, u16 sz) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - return r; -} - -/** - * mpt2sas_config_get_phys_disk_pg0 - obtain phys disk page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_PHYSDISKNUM, PHYSDISKNUM, DEVHANDLE - * @form_specific: specific to the form - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form, - u32 form_specific) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | form_specific); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_volume_handle - returns volume handle for give hidden raid components - * @ioc: per adapter object - * @pd_handle: phys disk handle - * @volume_handle: volume handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, - u16 *volume_handle) -{ - Mpi2RaidConfigurationPage0_t *config_page = NULL; - Mpi2ConfigRequest_t mpi_request; - Mpi2ConfigReply_t mpi_reply; - int r, i, config_page_sz; - u16 ioc_status; - int config_num; - u16 element_type; - u16 phys_disk_dev_handle; - - *volume_handle = 0; - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG; - mpi_request.Header.PageVersion = MPI2_RAIDCONFIG0_PAGEVERSION; - mpi_request.Header.PageNumber = 0; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4); - config_page = kmalloc(config_page_sz, GFP_KERNEL); - if (!config_page) { - r = -1; - goto out; - } - config_num = 0xff; - while (1) { - mpi_request.PageAddress = cpu_to_le32(config_num + - MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM); - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - config_page_sz); - if (r) - goto out; - r = -1; - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - goto out; - for (i = 0; i < config_page->NumElements; i++) { - element_type = le16_to_cpu(config_page-> - ConfigElement[i].ElementFlags) & - MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE; - if (element_type == - MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT || - element_type == - MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT) { - phys_disk_dev_handle = - le16_to_cpu(config_page->ConfigElement[i]. - PhysDiskDevHandle); - if (phys_disk_dev_handle == pd_handle) { - *volume_handle = - le16_to_cpu(config_page-> - ConfigElement[i].VolDevHandle); - r = 0; - goto out; - } - } else if (element_type == - MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT) { - *volume_handle = 0; - r = 0; - goto out; - } - } - config_num = config_page->ConfigNum; - } - out: - kfree(config_page); - return r; -} - -/** - * mpt2sas_config_get_volume_wwid - returns wwid given the volume handle - * @ioc: per adapter object - * @volume_handle: volume handle - * @wwid: volume wwid - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle, - u64 *wwid) -{ - Mpi2ConfigReply_t mpi_reply; - Mpi2RaidVolPage1_t raid_vol_pg1; - - *wwid = 0; - if (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - &raid_vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, - volume_handle))) { - *wwid = le64_to_cpu(raid_vol_pg1.WWID); - return 0; - } else - return -1; -} diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c deleted file mode 100644 index 3694b63bd..000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ /dev/null @@ -1,3101 +0,0 @@ -/* - * Management Module Support for MPT (Message Passing Technology) based - * controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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. - * - * 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. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "mpt2sas_base.h" -#include "mpt2sas_ctl.h" - -static DEFINE_MUTEX(_ctl_mutex); -static struct fasync_struct *async_queue; -static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait); - -static int _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, - u8 *issue_reset); - -/** - * enum block_state - blocking state - * @NON_BLOCKING: non blocking - * @BLOCKING: blocking - * - * These states are for ioctls that need to wait for a response - * from firmware, so they probably require sleep. - */ -enum block_state { - NON_BLOCKING, - BLOCKING, -}; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _ctl_sas_device_find_by_handle - sas device search - * @ioc: per adapter object - * @handle: sas device handle (assigned by firmware) - * Context: Calling function should acquire ioc->sas_device_lock - * - * This searches for sas_device based on sas_address, then return sas_device - * object. - */ -static struct _sas_device * -_ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_device *sas_device, *r; - - r = NULL; - list_for_each_entry(sas_device, &ioc->sas_device_list, list) { - if (sas_device->handle != handle) - continue; - r = sas_device; - goto out; - } - - out: - return r; -} - -/** - * _ctl_display_some_debug - debug routine - * @ioc: per adapter object - * @smid: system request message index - * @calling_function_name: string pass from calling function - * @mpi_reply: reply message frame - * Context: none. - * - * Function for displaying debug info helpful when debugging issues - * in this module. - */ -static void -_ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, - char *calling_function_name, MPI2DefaultReply_t *mpi_reply) -{ - Mpi2ConfigRequest_t *mpi_request; - char *desc = NULL; - - if (!(ioc->logging_level & MPT_DEBUG_IOCTL)) - return; - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - switch (mpi_request->Function) { - case MPI2_FUNCTION_SCSI_IO_REQUEST: - { - Mpi2SCSIIORequest_t *scsi_request = - (Mpi2SCSIIORequest_t *)mpi_request; - - snprintf(ioc->tmp_string, MPT_STRING_LENGTH, - "scsi_io, cmd(0x%02x), cdb_len(%d)", - scsi_request->CDB.CDB32[0], - le16_to_cpu(scsi_request->IoFlags) & 0xF); - desc = ioc->tmp_string; - break; - } - case MPI2_FUNCTION_SCSI_TASK_MGMT: - desc = "task_mgmt"; - break; - case MPI2_FUNCTION_IOC_INIT: - desc = "ioc_init"; - break; - case MPI2_FUNCTION_IOC_FACTS: - desc = "ioc_facts"; - break; - case MPI2_FUNCTION_CONFIG: - { - Mpi2ConfigRequest_t *config_request = - (Mpi2ConfigRequest_t *)mpi_request; - - snprintf(ioc->tmp_string, MPT_STRING_LENGTH, - "config, type(0x%02x), ext_type(0x%02x), number(%d)", - (config_request->Header.PageType & - MPI2_CONFIG_PAGETYPE_MASK), config_request->ExtPageType, - config_request->Header.PageNumber); - desc = ioc->tmp_string; - break; - } - case MPI2_FUNCTION_PORT_FACTS: - desc = "port_facts"; - break; - case MPI2_FUNCTION_PORT_ENABLE: - desc = "port_enable"; - break; - case MPI2_FUNCTION_EVENT_NOTIFICATION: - desc = "event_notification"; - break; - case MPI2_FUNCTION_FW_DOWNLOAD: - desc = "fw_download"; - break; - case MPI2_FUNCTION_FW_UPLOAD: - desc = "fw_upload"; - break; - case MPI2_FUNCTION_RAID_ACTION: - desc = "raid_action"; - break; - case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: - { - Mpi2SCSIIORequest_t *scsi_request = - (Mpi2SCSIIORequest_t *)mpi_request; - - snprintf(ioc->tmp_string, MPT_STRING_LENGTH, - "raid_pass, cmd(0x%02x), cdb_len(%d)", - scsi_request->CDB.CDB32[0], - le16_to_cpu(scsi_request->IoFlags) & 0xF); - desc = ioc->tmp_string; - break; - } - case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: - desc = "sas_iounit_cntl"; - break; - case MPI2_FUNCTION_SATA_PASSTHROUGH: - desc = "sata_pass"; - break; - case MPI2_FUNCTION_DIAG_BUFFER_POST: - desc = "diag_buffer_post"; - break; - case MPI2_FUNCTION_DIAG_RELEASE: - desc = "diag_release"; - break; - case MPI2_FUNCTION_SMP_PASSTHROUGH: - desc = "smp_passthrough"; - break; - } - - if (!desc) - return; - - printk(MPT2SAS_INFO_FMT "%s: %s, smid(%d)\n", - ioc->name, calling_function_name, desc, smid); - - if (!mpi_reply) - return; - - if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) - printk(MPT2SAS_INFO_FMT - "\tiocstatus(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); - - if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || - mpi_request->Function == - MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { - Mpi2SCSIIOReply_t *scsi_reply = - (Mpi2SCSIIOReply_t *)mpi_reply; - struct _sas_device *sas_device = NULL; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _ctl_sas_device_find_by_handle(ioc, - le16_to_cpu(scsi_reply->DevHandle)); - if (sas_device) { - printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), " - "phy(%d)\n", ioc->name, (unsigned long long) - sas_device->sas_address, sas_device->phy); - printk(MPT2SAS_WARN_FMT - "\tenclosure_logical_id(0x%016llx), slot(%d)\n", - ioc->name, sas_device->enclosure_logical_id, - sas_device->slot); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) - printk(MPT2SAS_INFO_FMT - "\tscsi_state(0x%02x), scsi_status" - "(0x%02x)\n", ioc->name, - scsi_reply->SCSIState, - scsi_reply->SCSIStatus); - } -} -#endif - -/** - * mpt2sas_ctl_done - ctl module completion routine - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: none. - * - * The callback handler when using ioc->ctl_cb_idx. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - Mpi2SCSIIOReply_t *scsiio_reply; - const void *sense_data; - u32 sz; - - if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->ctl_cmds.smid != smid) - return 1; - ioc->ctl_cmds.status |= MPT2_CMD_COMPLETE; - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (mpi_reply) { - memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); - ioc->ctl_cmds.status |= MPT2_CMD_REPLY_VALID; - /* get sense data */ - if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || - mpi_reply->Function == - MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { - scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply; - if (scsiio_reply->SCSIState & - MPI2_SCSI_STATE_AUTOSENSE_VALID) { - sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, - le32_to_cpu(scsiio_reply->SenseCount)); - sense_data = mpt2sas_base_get_sense_buffer(ioc, - smid); - memcpy(ioc->ctl_cmds.sense, sense_data, sz); - } - } - } -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); -#endif - ioc->ctl_cmds.status &= ~MPT2_CMD_PENDING; - complete(&ioc->ctl_cmds.done); - return 1; -} - -/** - * _ctl_check_event_type - determines when an event needs logging - * @ioc: per adapter object - * @event: firmware event - * - * The bitmask in ioc->event_type[] indicates which events should be - * be saved in the driver event_log. This bitmask is set by application. - * - * Returns 1 when event should be captured, or zero means no match. - */ -static int -_ctl_check_event_type(struct MPT2SAS_ADAPTER *ioc, u16 event) -{ - u16 i; - u32 desired_event; - - if (event >= 128 || !event || !ioc->event_log) - return 0; - - desired_event = (1 << (event % 32)); - if (!desired_event) - desired_event = 1; - i = event / 32; - return desired_event & ioc->event_type[i]; -} - -/** - * mpt2sas_ctl_add_to_event_log - add event - * @ioc: per adapter object - * @mpi_reply: reply message frame - * - * Return nothing. - */ -void -mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventNotificationReply_t *mpi_reply) -{ - struct MPT2_IOCTL_EVENTS *event_log; - u16 event; - int i; - u32 sz, event_data_sz; - u8 send_aen = 0; - - if (!ioc->event_log) - return; - - event = le16_to_cpu(mpi_reply->Event); - - if (_ctl_check_event_type(ioc, event)) { - - /* insert entry into circular event_log */ - i = ioc->event_context % MPT2SAS_CTL_EVENT_LOG_SIZE; - event_log = ioc->event_log; - event_log[i].event = event; - event_log[i].context = ioc->event_context++; - - event_data_sz = le16_to_cpu(mpi_reply->EventDataLength)*4; - sz = min_t(u32, event_data_sz, MPT2_EVENT_DATA_SIZE); - memset(event_log[i].data, 0, MPT2_EVENT_DATA_SIZE); - memcpy(event_log[i].data, mpi_reply->EventData, sz); - send_aen = 1; - } - - /* This aen_event_read_flag flag is set until the - * application has read the event log. - * For MPI2_EVENT_LOG_ENTRY_ADDED, we always notify. - */ - if (event == MPI2_EVENT_LOG_ENTRY_ADDED || - (send_aen && !ioc->aen_event_read_flag)) { - ioc->aen_event_read_flag = 1; - wake_up_interruptible(&ctl_poll_wait); - if (async_queue) - kill_fasync(&async_queue, SIGIO, POLL_IN); - } -} - -/** - * mpt2sas_ctl_event_callback - firmware event handler (called at ISR time) - * @ioc: per adapter object - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: interrupt. - * - * This function merely adds a new work task into ioc->firmware_event_thread. - * The tasks are worked from _firmware_event_work in user context. - * - * Returns void. - */ -void -mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, - u32 reply) -{ - Mpi2EventNotificationReply_t *mpi_reply; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (unlikely(!mpi_reply)) { - printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - mpt2sas_ctl_add_to_event_log(ioc, mpi_reply); - return; -} - -/** - * _ctl_verify_adapter - validates ioc_number passed from application - * @ioc: per adapter object - * @iocpp: The ioc pointer is returned in this. - * - * Return (-1) means error, else ioc_number. - */ -static int -_ctl_verify_adapter(int ioc_number, struct MPT2SAS_ADAPTER **iocpp) -{ - struct MPT2SAS_ADAPTER *ioc; - /* global ioc lock to protect controller on list operations */ - spin_lock(&gioc_lock); - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { - if (ioc->id != ioc_number) - continue; - spin_unlock(&gioc_lock); - *iocpp = ioc; - return ioc_number; - } - spin_unlock(&gioc_lock); - *iocpp = NULL; - return -1; -} - -/** - * mpt2sas_ctl_reset_handler - reset callback handler (for ctl) - * @ioc: per adapter object - * @reset_phase: phase - * - * The handler for doing any required cleanup or initialization. - * - * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, - * MPT2_IOC_DONE_RESET - */ -void -mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) -{ - int i; - u8 issue_reset; - - switch (reset_phase) { - case MPT2_IOC_PRE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); - for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { - if (!(ioc->diag_buffer_status[i] & - MPT2_DIAG_BUFFER_IS_REGISTERED)) - continue; - if ((ioc->diag_buffer_status[i] & - MPT2_DIAG_BUFFER_IS_RELEASED)) - continue; - _ctl_send_release(ioc, i, &issue_reset); - } - break; - case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); - if (ioc->ctl_cmds.status & MPT2_CMD_PENDING) { - ioc->ctl_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->ctl_cmds.smid); - complete(&ioc->ctl_cmds.done); - } - break; - case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); - - for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { - if (!(ioc->diag_buffer_status[i] & - MPT2_DIAG_BUFFER_IS_REGISTERED)) - continue; - if ((ioc->diag_buffer_status[i] & - MPT2_DIAG_BUFFER_IS_RELEASED)) - continue; - ioc->diag_buffer_status[i] |= - MPT2_DIAG_BUFFER_IS_DIAG_RESET; - } - break; - } -} - -/** - * _ctl_fasync - - * @fd - - * @filep - - * @mode - - * - * Called when application request fasyn callback handler. - */ -static int -_ctl_fasync(int fd, struct file *filep, int mode) -{ - return fasync_helper(fd, filep, mode, &async_queue); -} - -/** - * _ctl_poll - - * @file - - * @wait - - * - */ -static unsigned int -_ctl_poll(struct file *filep, poll_table *wait) -{ - struct MPT2SAS_ADAPTER *ioc; - - poll_wait(filep, &ctl_poll_wait, wait); - - /* global ioc lock to protect controller on list operations */ - spin_lock(&gioc_lock); - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { - if (ioc->aen_event_read_flag) { - spin_unlock(&gioc_lock); - return POLLIN | POLLRDNORM; - } - } - spin_unlock(&gioc_lock); - return 0; -} - -/** - * _ctl_set_task_mid - assign an active smid to tm request - * @ioc: per adapter object - * @karg - (struct mpt2_ioctl_command) - * @tm_request - pointer to mf from user space - * - * Returns 0 when an smid if found, else fail. - * during failure, the reply frame is filled. - */ -static int -_ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, - Mpi2SCSITaskManagementRequest_t *tm_request) -{ - u8 found = 0; - u16 i; - u16 handle; - struct scsi_cmnd *scmd; - struct MPT2SAS_DEVICE *priv_data; - unsigned long flags; - Mpi2SCSITaskManagementReply_t *tm_reply; - u32 sz; - u32 lun; - char *desc = NULL; - - if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) - desc = "abort_task"; - else if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) - desc = "query_task"; - else - return 0; - - lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN); - - handle = le16_to_cpu(tm_request->DevHandle); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - for (i = ioc->scsiio_depth; i && !found; i--) { - scmd = ioc->scsi_lookup[i - 1].scmd; - if (scmd == NULL || scmd->device == NULL || - scmd->device->hostdata == NULL) - continue; - if (lun != scmd->device->lun) - continue; - priv_data = scmd->device->hostdata; - if (priv_data->sas_target == NULL) - continue; - if (priv_data->sas_target->handle != handle) - continue; - tm_request->TaskMID = cpu_to_le16(ioc->scsi_lookup[i - 1].smid); - found = 1; - } - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - - if (!found) { - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name, - desc, le16_to_cpu(tm_request->DevHandle), lun)); - tm_reply = ioc->ctl_cmds.reply; - tm_reply->DevHandle = tm_request->DevHandle; - tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; - tm_reply->TaskType = tm_request->TaskType; - tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4; - tm_reply->VP_ID = tm_request->VP_ID; - tm_reply->VF_ID = tm_request->VF_ID; - sz = min_t(u32, karg->max_reply_bytes, ioc->reply_sz); - if (copy_to_user(karg->reply_frame_buf_ptr, ioc->ctl_cmds.reply, - sz)) - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - return 1; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name, - desc, le16_to_cpu(tm_request->DevHandle), lun, - le16_to_cpu(tm_request->TaskMID))); - return 0; -} - -/** - * _ctl_do_mpt_command - main handler for MPT2COMMAND opcode - * @ioc: per adapter object - * @karg - (struct mpt2_ioctl_command) - * @mf - pointer to mf in user space - */ -static long -_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command karg, - void __user *mf) -{ - MPI2RequestHeader_t *mpi_request = NULL, *request; - MPI2DefaultReply_t *mpi_reply; - u32 ioc_state; - u16 ioc_status; - u16 smid; - unsigned long timeout, timeleft; - u8 issue_reset; - u32 sz; - void *psge; - void *data_out = NULL; - dma_addr_t data_out_dma; - size_t data_out_sz = 0; - void *data_in = NULL; - dma_addr_t data_in_dma; - size_t data_in_sz = 0; - u32 sgl_flags; - long ret; - u16 wait_state_count; - - issue_reset = 0; - - if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", - ioc->name, __func__); - ret = -EAGAIN; - goto out; - } - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - ret = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL); - if (!mpi_request) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a memory for " - "mpi_request\n", ioc->name, __func__); - ret = -ENOMEM; - goto out; - } - - /* Check for overflow and wraparound */ - if (karg.data_sge_offset * 4 > ioc->request_sz || - karg.data_sge_offset > (UINT_MAX / 4)) { - ret = -EINVAL; - goto out; - } - - /* copy in request message frame from user */ - if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, - __func__); - ret = -EFAULT; - goto out; - } - - if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { - smid = mpt2sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - ret = -EAGAIN; - goto out; - } - } else { - - smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - ret = -EAGAIN; - goto out; - } - } - - ret = 0; - ioc->ctl_cmds.status = MPT2_CMD_PENDING; - memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); - request = mpt2sas_base_get_msg_frame(ioc, smid); - memcpy(request, mpi_request, karg.data_sge_offset*4); - ioc->ctl_cmds.smid = smid; - data_out_sz = karg.data_out_size; - data_in_sz = karg.data_in_size; - - if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || - mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { - if (!le16_to_cpu(mpi_request->FunctionDependent1) || - le16_to_cpu(mpi_request->FunctionDependent1) > - ioc->facts.MaxDevHandle) { - ret = -EINVAL; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - } - - /* obtain dma-able memory for data transfer */ - if (data_out_sz) /* WRITE */ { - data_out = pci_alloc_consistent(ioc->pdev, data_out_sz, - &data_out_dma); - if (!data_out) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - ret = -ENOMEM; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - if (copy_from_user(data_out, karg.data_out_buf_ptr, - data_out_sz)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - ret = -EFAULT; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - } - - if (data_in_sz) /* READ */ { - data_in = pci_alloc_consistent(ioc->pdev, data_in_sz, - &data_in_dma); - if (!data_in) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - ret = -ENOMEM; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - } - - /* add scatter gather elements */ - psge = (void *)request + (karg.data_sge_offset*4); - - if (!data_out_sz && !data_in_sz) { - mpt2sas_base_build_zero_len_sge(ioc, psge); - } else if (data_out_sz && data_in_sz) { - /* WRITE sgel first */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - data_out_sz, data_out_dma); - - /* incr sgel */ - psge += ioc->sge_size; - - /* READ sgel last */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - data_in_sz, data_in_dma); - } else if (data_out_sz) /* WRITE */ { - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - data_out_sz, data_out_dma); - } else if (data_in_sz) /* READ */ { - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - data_in_sz, data_in_dma); - } - - /* send command to firmware */ -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - _ctl_display_some_debug(ioc, smid, "ctl_request", NULL); -#endif - - init_completion(&ioc->ctl_cmds.done); - switch (mpi_request->Function) { - case MPI2_FUNCTION_SCSI_IO_REQUEST: - case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: - { - Mpi2SCSIIORequest_t *scsiio_request = - (Mpi2SCSIIORequest_t *)request; - scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; - scsiio_request->SenseBufferLowAddress = - mpt2sas_base_get_sense_buffer_dma(ioc, smid); - memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE); - if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) - mpt2sas_base_put_smid_scsi_io(ioc, smid, - le16_to_cpu(mpi_request->FunctionDependent1)); - else - mpt2sas_base_put_smid_default(ioc, smid); - break; - } - case MPI2_FUNCTION_SCSI_TASK_MGMT: - { - Mpi2SCSITaskManagementRequest_t *tm_request = - (Mpi2SCSITaskManagementRequest_t *)request; - - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "TASK_MGMT: " - "handle(0x%04x), task_type(0x%02x)\n", ioc->name, - le16_to_cpu(tm_request->DevHandle), tm_request->TaskType)); - - if (tm_request->TaskType == - MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK || - tm_request->TaskType == - MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) { - if (_ctl_set_task_mid(ioc, &karg, tm_request)) { - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - } - - mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu( - tm_request->DevHandle)); - mpt2sas_base_put_smid_hi_priority(ioc, smid); - break; - } - case MPI2_FUNCTION_SMP_PASSTHROUGH: - { - Mpi2SmpPassthroughRequest_t *smp_request = - (Mpi2SmpPassthroughRequest_t *)mpi_request; - u8 *data; - - /* ioc determines which port to use */ - smp_request->PhysicalPort = 0xFF; - if (smp_request->PassthroughFlags & - MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE) - data = (u8 *)&smp_request->SGL; - else { - if (unlikely(data_out == NULL)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - mpt2sas_base_free_smid(ioc, smid); - ret = -EINVAL; - goto out; - } - data = data_out; - } - - if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) { - ioc->ioc_link_reset_in_progress = 1; - ioc->ignore_loginfos = 1; - } - mpt2sas_base_put_smid_default(ioc, smid); - break; - } - case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: - { - Mpi2SasIoUnitControlRequest_t *sasiounit_request = - (Mpi2SasIoUnitControlRequest_t *)mpi_request; - - if (sasiounit_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET - || sasiounit_request->Operation == - MPI2_SAS_OP_PHY_LINK_RESET) { - ioc->ioc_link_reset_in_progress = 1; - ioc->ignore_loginfos = 1; - } - mpt2sas_base_put_smid_default(ioc, smid); - break; - } - default: - mpt2sas_base_put_smid_default(ioc, smid); - break; - } - - if (karg.timeout < MPT2_IOCTL_DEFAULT_TIMEOUT) - timeout = MPT2_IOCTL_DEFAULT_TIMEOUT; - else - timeout = karg.timeout; - timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, - timeout*HZ); - if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { - Mpi2SCSITaskManagementRequest_t *tm_request = - (Mpi2SCSITaskManagementRequest_t *)mpi_request; - mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu( - tm_request->DevHandle)); - } else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH || - mpi_request->Function == MPI2_FUNCTION_SAS_IO_UNIT_CONTROL) && - ioc->ioc_link_reset_in_progress) { - ioc->ioc_link_reset_in_progress = 0; - ioc->ignore_loginfos = 0; - } - if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, - __func__); - _debug_dump_mf(mpi_request, karg.data_sge_offset); - if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - mpi_reply = ioc->ctl_cmds.reply; - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT && - (ioc->logging_level & MPT_DEBUG_TM)) { - Mpi2SCSITaskManagementReply_t *tm_reply = - (Mpi2SCSITaskManagementReply_t *)mpi_reply; - - printk(MPT2SAS_INFO_FMT "TASK_MGMT: " - "IOCStatus(0x%04x), IOCLogInfo(0x%08x), " - "TerminationCount(0x%08x)\n", ioc->name, - le16_to_cpu(tm_reply->IOCStatus), - le32_to_cpu(tm_reply->IOCLogInfo), - le32_to_cpu(tm_reply->TerminationCount)); - } -#endif - /* copy out xdata to user */ - if (data_in_sz) { - if (copy_to_user(karg.data_in_buf_ptr, data_in, - data_in_sz)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - ret = -ENODATA; - goto out; - } - } - - /* copy out reply message frame to user */ - if (karg.max_reply_bytes) { - sz = min_t(u32, karg.max_reply_bytes, ioc->reply_sz); - if (copy_to_user(karg.reply_frame_buf_ptr, ioc->ctl_cmds.reply, - sz)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - ret = -ENODATA; - goto out; - } - } - - /* copy out sense to user */ - if (karg.max_sense_bytes && (mpi_request->Function == - MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == - MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { - sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE); - if (copy_to_user(karg.sense_data_ptr, - ioc->ctl_cmds.sense, sz)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - ret = -ENODATA; - goto out; - } - } - - issue_host_reset: - if (issue_reset) { - ret = -ENODATA; - if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || - mpi_request->Function == - MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || - mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) { - printk(MPT2SAS_INFO_FMT "issue target reset: handle " - "= (0x%04x)\n", ioc->name, - le16_to_cpu(mpi_request->FunctionDependent1)); - mpt2sas_halt_firmware(ioc); - mpt2sas_scsih_issue_tm(ioc, - le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, - 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10, - TM_MUTEX_ON); - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - } else - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - } - - out: - - /* free memory associated with sg buffers */ - if (data_in) - pci_free_consistent(ioc->pdev, data_in_sz, data_in, - data_in_dma); - - if (data_out) - pci_free_consistent(ioc->pdev, data_out_sz, data_out, - data_out_dma); - - kfree(mpi_request); - ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - return ret; -} - -/** - * _ctl_getiocinfo - main handler for MPT2IOCINFO opcode - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_getiocinfo(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_ioctl_iocinfo karg; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - memset(&karg, 0 , sizeof(karg)); - if (ioc->is_warpdrive) - karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200; - else - karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; - if (ioc->pfacts) - karg.port_number = ioc->pfacts[0].PortNumber; - karg.hw_rev = ioc->pdev->revision; - karg.pci_id = ioc->pdev->device; - karg.subsystem_device = ioc->pdev->subsystem_device; - karg.subsystem_vendor = ioc->pdev->subsystem_vendor; - karg.pci_information.u.bits.bus = ioc->pdev->bus->number; - karg.pci_information.u.bits.device = PCI_SLOT(ioc->pdev->devfn); - karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn); - karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus); - karg.firmware_version = ioc->facts.FWVersion.Word; - strcpy(karg.driver_version, MPT2SAS_DRIVER_NAME); - strcat(karg.driver_version, "-"); - strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION); - karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); - - if (copy_to_user(arg, &karg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - return 0; -} - -/** - * _ctl_eventquery - main handler for MPT2EVENTQUERY opcode - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_eventquery(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_ioctl_eventquery karg; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - karg.event_entries = MPT2SAS_CTL_EVENT_LOG_SIZE; - memcpy(karg.event_types, ioc->event_type, - MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); - - if (copy_to_user(arg, &karg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - return 0; -} - -/** - * _ctl_eventenable - main handler for MPT2EVENTENABLE opcode - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_eventenable(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_ioctl_eventenable karg; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - if (ioc->event_log) - return 0; - memcpy(ioc->event_type, karg.event_types, - MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); - mpt2sas_base_validate_event_type(ioc, ioc->event_type); - - /* initialize event_log */ - ioc->event_context = 0; - ioc->aen_event_read_flag = 0; - ioc->event_log = kcalloc(MPT2SAS_CTL_EVENT_LOG_SIZE, - sizeof(struct MPT2_IOCTL_EVENTS), GFP_KERNEL); - if (!ioc->event_log) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -ENOMEM; - } - return 0; -} - -/** - * _ctl_eventreport - main handler for MPT2EVENTREPORT opcode - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_eventreport(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_ioctl_eventreport karg; - u32 number_bytes, max_events, max; - struct mpt2_ioctl_eventreport __user *uarg = arg; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - number_bytes = karg.hdr.max_data_size - - sizeof(struct mpt2_ioctl_header); - max_events = number_bytes/sizeof(struct MPT2_IOCTL_EVENTS); - max = min_t(u32, MPT2SAS_CTL_EVENT_LOG_SIZE, max_events); - - /* If fewer than 1 event is requested, there must have - * been some type of error. - */ - if (!max || !ioc->event_log) - return -ENODATA; - - number_bytes = max * sizeof(struct MPT2_IOCTL_EVENTS); - if (copy_to_user(uarg->event_data, ioc->event_log, number_bytes)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - /* reset flag so SIGIO can restart */ - ioc->aen_event_read_flag = 0; - return 0; -} - -/** - * _ctl_do_reset - main handler for MPT2HARDRESET opcode - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_do_reset(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_ioctl_diag_reset karg; - int retval; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - if (ioc->shost_recovery || ioc->pci_error_recovery || - ioc->is_driver_loading) - return -EAGAIN; - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - printk(MPT2SAS_INFO_FMT "host reset: %s\n", - ioc->name, ((!retval) ? "SUCCESS" : "FAILED")); - return 0; -} - -/** - * _ctl_btdh_search_sas_device - searching for sas device - * @ioc: per adapter object - * @btdh: btdh ioctl payload - */ -static int -_ctl_btdh_search_sas_device(struct MPT2SAS_ADAPTER *ioc, - struct mpt2_ioctl_btdh_mapping *btdh) -{ - struct _sas_device *sas_device; - unsigned long flags; - int rc = 0; - - if (list_empty(&ioc->sas_device_list)) - return rc; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_for_each_entry(sas_device, &ioc->sas_device_list, list) { - if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && - btdh->handle == sas_device->handle) { - btdh->bus = sas_device->channel; - btdh->id = sas_device->id; - rc = 1; - goto out; - } else if (btdh->bus == sas_device->channel && btdh->id == - sas_device->id && btdh->handle == 0xFFFF) { - btdh->handle = sas_device->handle; - rc = 1; - goto out; - } - } - out: - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return rc; -} - -/** - * _ctl_btdh_search_raid_device - searching for raid device - * @ioc: per adapter object - * @btdh: btdh ioctl payload - */ -static int -_ctl_btdh_search_raid_device(struct MPT2SAS_ADAPTER *ioc, - struct mpt2_ioctl_btdh_mapping *btdh) -{ - struct _raid_device *raid_device; - unsigned long flags; - int rc = 0; - - if (list_empty(&ioc->raid_device_list)) - return rc; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - list_for_each_entry(raid_device, &ioc->raid_device_list, list) { - if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && - btdh->handle == raid_device->handle) { - btdh->bus = raid_device->channel; - btdh->id = raid_device->id; - rc = 1; - goto out; - } else if (btdh->bus == raid_device->channel && btdh->id == - raid_device->id && btdh->handle == 0xFFFF) { - btdh->handle = raid_device->handle; - rc = 1; - goto out; - } - } - out: - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - return rc; -} - -/** - * _ctl_btdh_mapping - main handler for MPT2BTDHMAPPING opcode - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_btdh_mapping(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_ioctl_btdh_mapping karg; - int rc; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - rc = _ctl_btdh_search_sas_device(ioc, &karg); - if (!rc) - _ctl_btdh_search_raid_device(ioc, &karg); - - if (copy_to_user(arg, &karg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - return 0; -} - -/** - * _ctl_diag_capability - return diag buffer capability - * @ioc: per adapter object - * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED - * - * returns 1 when diag buffer support is enabled in firmware - */ -static u8 -_ctl_diag_capability(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type) -{ - u8 rc = 0; - - switch (buffer_type) { - case MPI2_DIAG_BUF_TYPE_TRACE: - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) - rc = 1; - break; - case MPI2_DIAG_BUF_TYPE_SNAPSHOT: - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) - rc = 1; - break; - case MPI2_DIAG_BUF_TYPE_EXTENDED: - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) - rc = 1; - } - - return rc; -} - -/** - * _ctl_diag_register_2 - wrapper for registering diag buffer support - * @ioc: per adapter object - * @diag_register: the diag_register struct passed in from user space - * - */ -static long -_ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc, - struct mpt2_diag_register *diag_register) -{ - int rc, i; - void *request_data = NULL; - dma_addr_t request_data_dma; - u32 request_data_sz = 0; - Mpi2DiagBufferPostRequest_t *mpi_request; - Mpi2DiagBufferPostReply_t *mpi_reply; - u8 buffer_type; - unsigned long timeleft; - u16 smid; - u16 ioc_status; - u8 issue_reset = 0; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - buffer_type = diag_register->buffer_type; - if (!_ctl_diag_capability(ioc, buffer_type)) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -EPERM; - } - - if (ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_REGISTERED) { - printk(MPT2SAS_ERR_FMT "%s: already has a registered " - "buffer for buffer_type(0x%02x)\n", ioc->name, __func__, - buffer_type); - return -EINVAL; - } - - if (diag_register->requested_buffer_size % 4) { - printk(MPT2SAS_ERR_FMT "%s: the requested_buffer_size " - "is not 4 byte aligned\n", ioc->name, __func__); - return -EINVAL; - } - - smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - rc = 0; - ioc->ctl_cmds.status = MPT2_CMD_PENDING; - memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->ctl_cmds.smid = smid; - - request_data = ioc->diag_buffer[buffer_type]; - request_data_sz = diag_register->requested_buffer_size; - ioc->unique_id[buffer_type] = diag_register->unique_id; - ioc->diag_buffer_status[buffer_type] = 0; - memcpy(ioc->product_specific[buffer_type], - diag_register->product_specific, MPT2_PRODUCT_SPECIFIC_DWORDS); - ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags; - - if (request_data) { - request_data_dma = ioc->diag_buffer_dma[buffer_type]; - if (request_data_sz != ioc->diag_buffer_sz[buffer_type]) { - pci_free_consistent(ioc->pdev, - ioc->diag_buffer_sz[buffer_type], - request_data, request_data_dma); - request_data = NULL; - } - } - - if (request_data == NULL) { - ioc->diag_buffer_sz[buffer_type] = 0; - ioc->diag_buffer_dma[buffer_type] = 0; - request_data = pci_alloc_consistent( - ioc->pdev, request_data_sz, &request_data_dma); - if (request_data == NULL) { - printk(MPT2SAS_ERR_FMT "%s: failed allocating memory" - " for diag buffers, requested size(%d)\n", - ioc->name, __func__, request_data_sz); - mpt2sas_base_free_smid(ioc, smid); - return -ENOMEM; - } - ioc->diag_buffer[buffer_type] = request_data; - ioc->diag_buffer_sz[buffer_type] = request_data_sz; - ioc->diag_buffer_dma[buffer_type] = request_data_dma; - } - - mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; - mpi_request->BufferType = diag_register->buffer_type; - mpi_request->Flags = cpu_to_le32(diag_register->diagnostic_flags); - mpi_request->BufferAddress = cpu_to_le64(request_data_dma); - mpi_request->BufferLength = cpu_to_le32(request_data_sz); - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(0x%p), " - "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data, - (unsigned long long)request_data_dma, - le32_to_cpu(mpi_request->BufferLength))); - - for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) - mpi_request->ProductSpecific[i] = - cpu_to_le32(ioc->product_specific[buffer_type][i]); - - init_completion(&ioc->ctl_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, - MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); - - if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, - __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2DiagBufferPostRequest_t)/4); - if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - /* process the completed Reply Message Frame */ - if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) { - printk(MPT2SAS_ERR_FMT "%s: no reply message\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - - mpi_reply = ioc->ctl_cmds.reply; - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - ioc->diag_buffer_status[buffer_type] |= - MPT2_DIAG_BUFFER_IS_REGISTERED; - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n", - ioc->name, __func__)); - } else { - printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " - "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); - rc = -EFAULT; - } - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - - out: - - if (rc && request_data) - pci_free_consistent(ioc->pdev, request_data_sz, - request_data, request_data_dma); - - ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - return rc; -} - -/** - * mpt2sas_enable_diag_buffer - enabling diag_buffers support driver load time - * @ioc: per adapter object - * @bits_to_register: bitwise field where trace is bit 0, and snapshot is bit 1 - * - * This is called when command line option diag_buffer_enable is enabled - * at driver load time. - */ -void -mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, u8 bits_to_register) -{ - struct mpt2_diag_register diag_register; - - memset(&diag_register, 0, sizeof(struct mpt2_diag_register)); - - if (bits_to_register & 1) { - printk(MPT2SAS_INFO_FMT "registering trace buffer support\n", - ioc->name); - diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; - /* register for 1MB buffers */ - diag_register.requested_buffer_size = (1024 * 1024); - diag_register.unique_id = 0x7075900; - _ctl_diag_register_2(ioc, &diag_register); - } - - if (bits_to_register & 2) { - printk(MPT2SAS_INFO_FMT "registering snapshot buffer support\n", - ioc->name); - diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT; - /* register for 2MB buffers */ - diag_register.requested_buffer_size = 2 * (1024 * 1024); - diag_register.unique_id = 0x7075901; - _ctl_diag_register_2(ioc, &diag_register); - } - - if (bits_to_register & 4) { - printk(MPT2SAS_INFO_FMT "registering extended buffer support\n", - ioc->name); - diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED; - /* register for 2MB buffers */ - diag_register.requested_buffer_size = 2 * (1024 * 1024); - diag_register.unique_id = 0x7075901; - _ctl_diag_register_2(ioc, &diag_register); - } -} - -/** - * _ctl_diag_register - application register with driver - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - * - * This will allow the driver to setup any required buffers that will be - * needed by firmware to communicate with the driver. - */ -static long -_ctl_diag_register(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_diag_register karg; - long rc; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - rc = _ctl_diag_register_2(ioc, &karg); - return rc; -} - -/** - * _ctl_diag_unregister - application unregister with driver - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - * - * This will allow the driver to cleanup any memory allocated for diag - * messages and to free up any resources. - */ -static long -_ctl_diag_unregister(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_diag_unregister karg; - void *request_data; - dma_addr_t request_data_dma; - u32 request_data_sz; - u8 buffer_type; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - buffer_type = karg.unique_id & 0x000000ff; - if (!_ctl_diag_capability(ioc, buffer_type)) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -EPERM; - } - - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " - "registered\n", ioc->name, __func__, buffer_type); - return -EINVAL; - } - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_RELEASED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) has not been " - "released\n", ioc->name, __func__, buffer_type); - return -EINVAL; - } - - if (karg.unique_id != ioc->unique_id[buffer_type]) { - printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " - "registered\n", ioc->name, __func__, karg.unique_id); - return -EINVAL; - } - - request_data = ioc->diag_buffer[buffer_type]; - if (!request_data) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -ENOMEM; - } - - request_data_sz = ioc->diag_buffer_sz[buffer_type]; - request_data_dma = ioc->diag_buffer_dma[buffer_type]; - pci_free_consistent(ioc->pdev, request_data_sz, - request_data, request_data_dma); - ioc->diag_buffer[buffer_type] = NULL; - ioc->diag_buffer_status[buffer_type] = 0; - return 0; -} - -/** - * _ctl_diag_query - query relevant info associated with diag buffers - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - * - * The application will send only buffer_type and unique_id. Driver will - * inspect unique_id first, if valid, fill in all the info. If unique_id is - * 0x00, the driver will return info specified by Buffer Type. - */ -static long -_ctl_diag_query(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_diag_query karg; - void *request_data; - int i; - u8 buffer_type; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - karg.application_flags = 0; - buffer_type = karg.buffer_type; - - if (!_ctl_diag_capability(ioc, buffer_type)) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -EPERM; - } - - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " - "registered\n", ioc->name, __func__, buffer_type); - return -EINVAL; - } - - if (karg.unique_id & 0xffffff00) { - if (karg.unique_id != ioc->unique_id[buffer_type]) { - printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " - "registered\n", ioc->name, __func__, - karg.unique_id); - return -EINVAL; - } - } - - request_data = ioc->diag_buffer[buffer_type]; - if (!request_data) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -ENOMEM; - } - - if (ioc->diag_buffer_status[buffer_type] & MPT2_DIAG_BUFFER_IS_RELEASED) - karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED | - MPT2_APP_FLAGS_BUFFER_VALID); - else - karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED | - MPT2_APP_FLAGS_BUFFER_VALID | - MPT2_APP_FLAGS_FW_BUFFER_ACCESS); - - for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) - karg.product_specific[i] = - ioc->product_specific[buffer_type][i]; - - karg.total_buffer_size = ioc->diag_buffer_sz[buffer_type]; - karg.driver_added_buffer_size = 0; - karg.unique_id = ioc->unique_id[buffer_type]; - karg.diagnostic_flags = ioc->diagnostic_flags[buffer_type]; - - if (copy_to_user(arg, &karg, sizeof(struct mpt2_diag_query))) { - printk(MPT2SAS_ERR_FMT "%s: unable to write mpt2_diag_query " - "data @ %p\n", ioc->name, __func__, arg); - return -EFAULT; - } - return 0; -} - -/** - * _ctl_send_release - Diag Release Message - * @ioc: per adapter object - * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED - * @issue_reset - specifies whether host reset is required. - * - */ -static int -_ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) -{ - Mpi2DiagReleaseRequest_t *mpi_request; - Mpi2DiagReleaseReply_t *mpi_reply; - u16 smid; - u16 ioc_status; - u32 ioc_state; - int rc; - unsigned long timeleft; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - rc = 0; - *issue_reset = 0; - - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "skipping due to FAULT state\n", ioc->name, - __func__)); - rc = -EAGAIN; - goto out; - } - - if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - ioc->ctl_cmds.status = MPT2_CMD_PENDING; - memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->ctl_cmds.smid = smid; - - mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE; - mpi_request->BufferType = buffer_type; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - - init_completion(&ioc->ctl_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, - MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); - - if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, - __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2DiagReleaseRequest_t)/4); - if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) - *issue_reset = 1; - rc = -EFAULT; - goto out; - } - - /* process the completed Reply Message Frame */ - if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) { - printk(MPT2SAS_ERR_FMT "%s: no reply message\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - - mpi_reply = ioc->ctl_cmds.reply; - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - ioc->diag_buffer_status[buffer_type] |= - MPT2_DIAG_BUFFER_IS_RELEASED; - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n", - ioc->name, __func__)); - } else { - printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " - "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); - rc = -EFAULT; - } - - out: - ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - return rc; -} - -/** - * _ctl_diag_release - request to send Diag Release Message to firmware - * @arg - user space buffer containing ioctl content - * - * This allows ownership of the specified buffer to returned to the driver, - * allowing an application to read the buffer without fear that firmware is - * overwritting information in the buffer. - */ -static long -_ctl_diag_release(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_diag_release karg; - void *request_data; - int rc; - u8 buffer_type; - u8 issue_reset = 0; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - buffer_type = karg.unique_id & 0x000000ff; - if (!_ctl_diag_capability(ioc, buffer_type)) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -EPERM; - } - - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " - "registered\n", ioc->name, __func__, buffer_type); - return -EINVAL; - } - - if (karg.unique_id != ioc->unique_id[buffer_type]) { - printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " - "registered\n", ioc->name, __func__, karg.unique_id); - return -EINVAL; - } - - if (ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_RELEASED) { - printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) " - "is already released\n", ioc->name, __func__, - buffer_type); - return 0; - } - - request_data = ioc->diag_buffer[buffer_type]; - - if (!request_data) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -ENOMEM; - } - - /* buffers were released by due to host reset */ - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_DIAG_RESET)) { - ioc->diag_buffer_status[buffer_type] |= - MPT2_DIAG_BUFFER_IS_RELEASED; - ioc->diag_buffer_status[buffer_type] &= - ~MPT2_DIAG_BUFFER_IS_DIAG_RESET; - printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) " - "was released due to host reset\n", ioc->name, __func__, - buffer_type); - return 0; - } - - rc = _ctl_send_release(ioc, buffer_type, &issue_reset); - - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - - return rc; -} - -/** - * _ctl_diag_read_buffer - request for copy of the diag buffer - * @ioc: per adapter object - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_diag_read_buffer(struct MPT2SAS_ADAPTER *ioc, void __user *arg) -{ - struct mpt2_diag_read_buffer karg; - struct mpt2_diag_read_buffer __user *uarg = arg; - void *request_data, *diag_data; - Mpi2DiagBufferPostRequest_t *mpi_request; - Mpi2DiagBufferPostReply_t *mpi_reply; - int rc, i; - u8 buffer_type; - unsigned long timeleft, request_size, copy_size; - u16 smid; - u16 ioc_status; - u8 issue_reset = 0; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - buffer_type = karg.unique_id & 0x000000ff; - if (!_ctl_diag_capability(ioc, buffer_type)) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -EPERM; - } - - if (karg.unique_id != ioc->unique_id[buffer_type]) { - printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " - "registered\n", ioc->name, __func__, karg.unique_id); - return -EINVAL; - } - - request_data = ioc->diag_buffer[buffer_type]; - if (!request_data) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -ENOMEM; - } - - request_size = ioc->diag_buffer_sz[buffer_type]; - - if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) { - printk(MPT2SAS_ERR_FMT "%s: either the starting_offset " - "or bytes_to_read are not 4 byte aligned\n", ioc->name, - __func__); - return -EINVAL; - } - - if (karg.starting_offset > request_size) - return -EINVAL; - - diag_data = (void *)(request_data + karg.starting_offset); - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), " - "offset(%d), sz(%d)\n", ioc->name, __func__, - diag_data, karg.starting_offset, karg.bytes_to_read)); - - /* Truncate data on requests that are too large */ - if ((diag_data + karg.bytes_to_read < diag_data) || - (diag_data + karg.bytes_to_read > request_data + request_size)) - copy_size = request_size - karg.starting_offset; - else - copy_size = karg.bytes_to_read; - - if (copy_to_user((void __user *)uarg->diagnostic_data, - diag_data, copy_size)) { - printk(MPT2SAS_ERR_FMT "%s: Unable to write " - "mpt_diag_read_buffer_t data @ %p\n", ioc->name, - __func__, diag_data); - return -EFAULT; - } - - if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0) - return 0; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: Reregister " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type)); - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_RELEASED) == 0) { - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "buffer_type(0x%02x) is still registered\n", ioc->name, - __func__, buffer_type)); - return 0; - } - /* Get a free request frame and save the message context. - */ - - if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - rc = 0; - ioc->ctl_cmds.status = MPT2_CMD_PENDING; - memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->ctl_cmds.smid = smid; - - mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; - mpi_request->BufferType = buffer_type; - mpi_request->BufferLength = - cpu_to_le32(ioc->diag_buffer_sz[buffer_type]); - mpi_request->BufferAddress = - cpu_to_le64(ioc->diag_buffer_dma[buffer_type]); - for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) - mpi_request->ProductSpecific[i] = - cpu_to_le32(ioc->product_specific[buffer_type][i]); - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - - init_completion(&ioc->ctl_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, - MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); - - if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, - __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2DiagBufferPostRequest_t)/4); - if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - /* process the completed Reply Message Frame */ - if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) { - printk(MPT2SAS_ERR_FMT "%s: no reply message\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - - mpi_reply = ioc->ctl_cmds.reply; - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - ioc->diag_buffer_status[buffer_type] |= - MPT2_DIAG_BUFFER_IS_REGISTERED; - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n", - ioc->name, __func__)); - } else { - printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " - "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); - rc = -EFAULT; - } - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - - out: - - ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - return rc; -} - - -#ifdef CONFIG_COMPAT -/** - * _ctl_compat_mpt_command - convert 32bit pointers to 64bit. - * @ioc: per adapter object - * @cmd - ioctl opcode - * @arg - (struct mpt2_ioctl_command32) - * - * MPT2COMMAND32 - Handle 32bit applications running on 64bit os. - */ -static long -_ctl_compat_mpt_command(struct MPT2SAS_ADAPTER *ioc, unsigned cmd, - void __user *arg) -{ - struct mpt2_ioctl_command32 karg32; - struct mpt2_ioctl_command32 __user *uarg; - struct mpt2_ioctl_command karg; - - if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32)) - return -EINVAL; - - uarg = (struct mpt2_ioctl_command32 __user *) arg; - - if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - memset(&karg, 0, sizeof(struct mpt2_ioctl_command)); - karg.hdr.ioc_number = karg32.hdr.ioc_number; - karg.hdr.port_number = karg32.hdr.port_number; - karg.hdr.max_data_size = karg32.hdr.max_data_size; - karg.timeout = karg32.timeout; - karg.max_reply_bytes = karg32.max_reply_bytes; - karg.data_in_size = karg32.data_in_size; - karg.data_out_size = karg32.data_out_size; - karg.max_sense_bytes = karg32.max_sense_bytes; - karg.data_sge_offset = karg32.data_sge_offset; - karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr); - karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr); - karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr); - karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr); - return _ctl_do_mpt_command(ioc, karg, &uarg->mf); -} -#endif - -/** - * _ctl_ioctl_main - main ioctl entry point - * @file - (struct file) - * @cmd - ioctl opcode - * @arg - - * compat - handles 32 bit applications in 64bit os - */ -static long -_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, - u8 compat) -{ - struct MPT2SAS_ADAPTER *ioc; - struct mpt2_ioctl_header ioctl_header; - enum block_state state; - long ret = -EINVAL; - - /* get IOCTL header */ - if (copy_from_user(&ioctl_header, (char __user *)arg, - sizeof(struct mpt2_ioctl_header))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - /* pci_access_mutex lock acquired by ioctl path */ - mutex_lock(&ioc->pci_access_mutex); - if (ioc->shost_recovery || ioc->pci_error_recovery || - ioc->is_driver_loading || ioc->remove_host) { - ret = -EAGAIN; - goto out_unlock_pciaccess; - } - - state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; - if (state == NON_BLOCKING) { - if (!mutex_trylock(&ioc->ctl_cmds.mutex)) { - ret = -EAGAIN; - goto out_unlock_pciaccess; - } - } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) { - ret = -ERESTARTSYS; - goto out_unlock_pciaccess; - } - - switch (cmd) { - case MPT2IOCINFO: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_iocinfo)) - ret = _ctl_getiocinfo(ioc, arg); - break; -#ifdef CONFIG_COMPAT - case MPT2COMMAND32: -#endif - case MPT2COMMAND: - { - struct mpt2_ioctl_command __user *uarg; - struct mpt2_ioctl_command karg; -#ifdef CONFIG_COMPAT - if (compat) { - ret = _ctl_compat_mpt_command(ioc, cmd, arg); - break; - } -#endif - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - ret = -EFAULT; - break; - } - - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) { - uarg = arg; - ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf); - } - break; - } - case MPT2EVENTQUERY: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventquery)) - ret = _ctl_eventquery(ioc, arg); - break; - case MPT2EVENTENABLE: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventenable)) - ret = _ctl_eventenable(ioc, arg); - break; - case MPT2EVENTREPORT: - ret = _ctl_eventreport(ioc, arg); - break; - case MPT2HARDRESET: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_diag_reset)) - ret = _ctl_do_reset(ioc, arg); - break; - case MPT2BTDHMAPPING: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_btdh_mapping)) - ret = _ctl_btdh_mapping(ioc, arg); - break; - case MPT2DIAGREGISTER: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_register)) - ret = _ctl_diag_register(ioc, arg); - break; - case MPT2DIAGUNREGISTER: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_unregister)) - ret = _ctl_diag_unregister(ioc, arg); - break; - case MPT2DIAGQUERY: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_query)) - ret = _ctl_diag_query(ioc, arg); - break; - case MPT2DIAGRELEASE: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_release)) - ret = _ctl_diag_release(ioc, arg); - break; - case MPT2DIAGREADBUFFER: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_read_buffer)) - ret = _ctl_diag_read_buffer(ioc, arg); - break; - default: - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT - "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd)); - break; - } - - mutex_unlock(&ioc->ctl_cmds.mutex); -out_unlock_pciaccess: - mutex_unlock(&ioc->pci_access_mutex); - return ret; -} - -/** - * _ctl_ioctl - main ioctl entry point (unlocked) - * @file - (struct file) - * @cmd - ioctl opcode - * @arg - - */ -static long -_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - long ret; - - ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0); - return ret; -} -#ifdef CONFIG_COMPAT -/** - * _ctl_ioctl_compat - main ioctl entry point (compat) - * @file - - * @cmd - - * @arg - - * - * This routine handles 32 bit applications in 64bit os. - */ -static long -_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) -{ - long ret; - - ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1); - return ret; -} -#endif - -/* scsi host attributes */ - -/** - * _ctl_version_fw_show - firmware version - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_version_fw_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", - (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, - (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, - (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, - ioc->facts.FWVersion.Word & 0x000000FF); -} -static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL); - -/** - * _ctl_version_bios_show - bios version - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_version_bios_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - u32 version = le32_to_cpu(ioc->bios_pg3.BiosVersion); - - return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", - (version & 0xFF000000) >> 24, - (version & 0x00FF0000) >> 16, - (version & 0x0000FF00) >> 8, - version & 0x000000FF); -} -static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL); - -/** - * _ctl_version_mpi_show - MPI (message passing interface) version - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%03x.%02x\n", - ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8); -} -static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL); - -/** - * _ctl_version_product_show - product name - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_version_product_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName); -} -static DEVICE_ATTR(version_product, S_IRUGO, - _ctl_version_product_show, NULL); - -/** - * _ctl_version_nvdata_persistent_show - ndvata persistent version - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_version_nvdata_persistent_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%08xh\n", - le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); -} -static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, - _ctl_version_nvdata_persistent_show, NULL); - -/** - * _ctl_version_nvdata_default_show - nvdata default version - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_version_nvdata_default_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%08xh\n", - le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); -} -static DEVICE_ATTR(version_nvdata_default, S_IRUGO, - _ctl_version_nvdata_default_show, NULL); - -/** - * _ctl_board_name_show - board name - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_board_name_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName); -} -static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL); - -/** - * _ctl_board_assembly_show - board assembly name - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly); -} -static DEVICE_ATTR(board_assembly, S_IRUGO, - _ctl_board_assembly_show, NULL); - -/** - * _ctl_board_tracer_show - board tracer number - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber); -} -static DEVICE_ATTR(board_tracer, S_IRUGO, - _ctl_board_tracer_show, NULL); - -/** - * _ctl_io_delay_show - io missing delay - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is for firmware implemention for deboucing device - * removal events. - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_io_delay_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay); -} -static DEVICE_ATTR(io_delay, S_IRUGO, - _ctl_io_delay_show, NULL); - -/** - * _ctl_device_delay_show - device missing delay - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is for firmware implemention for deboucing device - * removal events. - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_device_delay_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay); -} -static DEVICE_ATTR(device_delay, S_IRUGO, - _ctl_device_delay_show, NULL); - -/** - * _ctl_fw_queue_depth_show - global credits - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is firmware queue depth limit - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit); -} -static DEVICE_ATTR(fw_queue_depth, S_IRUGO, - _ctl_fw_queue_depth_show, NULL); - -/** - * _ctl_sas_address_show - sas address - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is the controller sas address - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "0x%016llx\n", - (unsigned long long)ioc->sas_hba.sas_address); -} -static DEVICE_ATTR(host_sas_address, S_IRUGO, - _ctl_host_sas_address_show, NULL); - -/** - * _ctl_logging_level_show - logging level - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read/write' shost attribute. - */ -static ssize_t -_ctl_logging_level_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level); -} -static ssize_t -_ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int val = 0; - - if (sscanf(buf, "%x", &val) != 1) - return -EINVAL; - - ioc->logging_level = val; - printk(MPT2SAS_INFO_FMT "logging_level=%08xh\n", ioc->name, - ioc->logging_level); - return strlen(buf); -} -static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, - _ctl_logging_level_show, _ctl_logging_level_store); - -/* device attributes */ -/* - * _ctl_fwfault_debug_show - show/store fwfault_debug - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * mpt2sas_fwfault_debug is command line option - * A sysfs 'read/write' shost attribute. - */ -static ssize_t -_ctl_fwfault_debug_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug); -} -static ssize_t -_ctl_fwfault_debug_store(struct device *cdev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int val = 0; - - if (sscanf(buf, "%d", &val) != 1) - return -EINVAL; - - ioc->fwfault_debug = val; - printk(MPT2SAS_INFO_FMT "fwfault_debug=%d\n", ioc->name, - ioc->fwfault_debug); - return strlen(buf); -} -static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, - _ctl_fwfault_debug_show, _ctl_fwfault_debug_store); - - -/** - * _ctl_ioc_reset_count_show - ioc reset count - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is firmware queue depth limit - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%08d\n", ioc->ioc_reset_count); -} -static DEVICE_ATTR(ioc_reset_count, S_IRUGO, - _ctl_ioc_reset_count_show, NULL); - -/** - * _ctl_ioc_reply_queue_count_show - number of reply queues - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is number of reply queues - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_ioc_reply_queue_count_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - u8 reply_queue_count; - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - if ((ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable) - reply_queue_count = ioc->reply_queue_count; - else - reply_queue_count = 1; - return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count); -} -static DEVICE_ATTR(reply_queue_count, S_IRUGO, - _ctl_ioc_reply_queue_count_show, NULL); - -/** - * _ctl_BRM_status_show - Backup Rail Monitor Status - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is number of reply queues - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - Mpi2IOUnitPage3_t *io_unit_pg3 = NULL; - Mpi2ConfigReply_t mpi_reply; - u16 backup_rail_monitor_status = 0; - u16 ioc_status; - int sz; - ssize_t rc = 0; - - if (!ioc->is_warpdrive) { - printk(MPT2SAS_ERR_FMT "%s: BRM attribute is only for"\ - "warpdrive\n", ioc->name, __func__); - goto out; - } - /* pci_access_mutex lock acquired by sysfs show path */ - mutex_lock(&ioc->pci_access_mutex); - if (ioc->pci_error_recovery || ioc->remove_host) { - mutex_unlock(&ioc->pci_access_mutex); - return 0; - } - - /* allocate upto GPIOVal 36 entries */ - sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36); - io_unit_pg3 = kzalloc(sz, GFP_KERNEL); - if (!io_unit_pg3) { - printk(MPT2SAS_ERR_FMT "%s: failed allocating memory"\ - "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz); - goto out; - } - - if (mpt2sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) != - 0) { - printk(MPT2SAS_ERR_FMT - "%s: failed reading iounit_pg3\n", ioc->name, - __func__); - goto out; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "%s: iounit_pg3 failed with"\ - "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status); - goto out; - } - - if (io_unit_pg3->GPIOCount < 25) { - printk(MPT2SAS_ERR_FMT "%s: iounit_pg3->GPIOCount less than"\ - "25 entries, detected (%d) entries\n", ioc->name, __func__, - io_unit_pg3->GPIOCount); - goto out; - } - - /* BRM status is in bit zero of GPIOVal[24] */ - backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]); - rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1)); - - out: - kfree(io_unit_pg3); - mutex_unlock(&ioc->pci_access_mutex); - return rc; -} -static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL); - -struct DIAG_BUFFER_START { - __le32 Size; - __le32 DiagVersion; - u8 BufferType; - u8 Reserved[3]; - __le32 Reserved1; - __le32 Reserved2; - __le32 Reserved3; -}; -/** - * _ctl_host_trace_buffer_size_show - host buffer size (trace only) - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_host_trace_buffer_size_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - u32 size = 0; - struct DIAG_BUFFER_START *request_data; - - if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { - printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " - "registered\n", ioc->name, __func__); - return 0; - } - - if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " - "registered\n", ioc->name, __func__); - return 0; - } - - request_data = (struct DIAG_BUFFER_START *) - ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]; - if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 || - le32_to_cpu(request_data->DiagVersion) == 0x01000000) && - le32_to_cpu(request_data->Reserved3) == 0x4742444c) - size = le32_to_cpu(request_data->Size); - - ioc->ring_buffer_sz = size; - return snprintf(buf, PAGE_SIZE, "%d\n", size); -} -static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO, - _ctl_host_trace_buffer_size_show, NULL); - -/** - * _ctl_host_trace_buffer_show - firmware ring buffer (trace only) - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read/write' shost attribute. - * - * You will only be able to read 4k bytes of ring buffer at a time. - * In order to read beyond 4k bytes, you will have to write out the - * offset to the same attribute, it will move the pointer. - */ -static ssize_t -_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - void *request_data; - u32 size; - - if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { - printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " - "registered\n", ioc->name, __func__); - return 0; - } - - if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " - "registered\n", ioc->name, __func__); - return 0; - } - - if (ioc->ring_buffer_offset > ioc->ring_buffer_sz) - return 0; - - size = ioc->ring_buffer_sz - ioc->ring_buffer_offset; - size = (size > PAGE_SIZE) ? PAGE_SIZE : size; - request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset; - memcpy(buf, request_data, size); - return size; -} - -static ssize_t -_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int val = 0; - - if (sscanf(buf, "%d", &val) != 1) - return -EINVAL; - - ioc->ring_buffer_offset = val; - return strlen(buf); -} -static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR, - _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store); - -/*****************************************/ - -/** - * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only) - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read/write' shost attribute. - * - * This is a mechnism to post/release host_trace_buffers - */ -static ssize_t -_ctl_host_trace_buffer_enable_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) || - ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0)) - return snprintf(buf, PAGE_SIZE, "off\n"); - else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_RELEASED)) - return snprintf(buf, PAGE_SIZE, "release\n"); - else - return snprintf(buf, PAGE_SIZE, "post\n"); -} - -static ssize_t -_ctl_host_trace_buffer_enable_store(struct device *cdev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - char str[10] = ""; - struct mpt2_diag_register diag_register; - u8 issue_reset = 0; - - if (sscanf(buf, "%9s", str) != 1) - return -EINVAL; - - if (!strcmp(str, "post")) { - /* exit out if host buffers are already posted */ - if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) && - (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) && - ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_RELEASED) == 0)) - goto out; - memset(&diag_register, 0, sizeof(struct mpt2_diag_register)); - printk(MPT2SAS_INFO_FMT "posting host trace buffers\n", - ioc->name); - diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; - diag_register.requested_buffer_size = (1024 * 1024); - diag_register.unique_id = 0x7075900; - ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0; - _ctl_diag_register_2(ioc, &diag_register); - } else if (!strcmp(str, "release")) { - /* exit out if host buffers are already released */ - if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) - goto out; - if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) - goto out; - if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_RELEASED)) - goto out; - printk(MPT2SAS_INFO_FMT "releasing host trace buffer\n", - ioc->name); - _ctl_send_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset); - } - - out: - return strlen(buf); -} -static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR, - _ctl_host_trace_buffer_enable_show, _ctl_host_trace_buffer_enable_store); - -struct device_attribute *mpt2sas_host_attrs[] = { - &dev_attr_version_fw, - &dev_attr_version_bios, - &dev_attr_version_mpi, - &dev_attr_version_product, - &dev_attr_version_nvdata_persistent, - &dev_attr_version_nvdata_default, - &dev_attr_board_name, - &dev_attr_board_assembly, - &dev_attr_board_tracer, - &dev_attr_io_delay, - &dev_attr_device_delay, - &dev_attr_logging_level, - &dev_attr_fwfault_debug, - &dev_attr_fw_queue_depth, - &dev_attr_host_sas_address, - &dev_attr_ioc_reset_count, - &dev_attr_host_trace_buffer_size, - &dev_attr_host_trace_buffer, - &dev_attr_host_trace_buffer_enable, - &dev_attr_reply_queue_count, - &dev_attr_BRM_status, - NULL, -}; - -/** - * _ctl_device_sas_address_show - sas address - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is the sas address for the target - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata; - - return snprintf(buf, PAGE_SIZE, "0x%016llx\n", - (unsigned long long)sas_device_priv_data->sas_target->sas_address); -} -static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL); - -/** - * _ctl_device_handle_show - device handle - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is the firmware assigned device handle - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_device_handle_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata; - - return snprintf(buf, PAGE_SIZE, "0x%04x\n", - sas_device_priv_data->sas_target->handle); -} -static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL); - -struct device_attribute *mpt2sas_dev_attrs[] = { - &dev_attr_sas_address, - &dev_attr_sas_device_handle, - NULL, -}; - -static const struct file_operations ctl_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = _ctl_ioctl, - .poll = _ctl_poll, - .fasync = _ctl_fasync, -#ifdef CONFIG_COMPAT - .compat_ioctl = _ctl_ioctl_compat, -#endif - .llseek = noop_llseek, -}; - -static struct miscdevice ctl_dev = { - .minor = MPT2SAS_MINOR, - .name = MPT2SAS_DEV_NAME, - .fops = &ctl_fops, -}; - -/** - * mpt2sas_ctl_init - main entry point for ctl. - * - */ -void -mpt2sas_ctl_init(void) -{ - async_queue = NULL; - if (misc_register(&ctl_dev) < 0) - printk(KERN_ERR "%s can't register misc device [minor=%d]\n", - MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR); - - init_waitqueue_head(&ctl_poll_wait); -} - -/** - * mpt2sas_ctl_exit - exit point for ctl - * - */ -void -mpt2sas_ctl_exit(void) -{ - struct MPT2SAS_ADAPTER *ioc; - int i; - - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { - - /* free memory associated to diag buffers */ - for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { - if (!ioc->diag_buffer[i]) - continue; - pci_free_consistent(ioc->pdev, ioc->diag_buffer_sz[i], - ioc->diag_buffer[i], ioc->diag_buffer_dma[i]); - ioc->diag_buffer[i] = NULL; - ioc->diag_buffer_status[i] = 0; - } - - kfree(ioc->event_log); - } - misc_deregister(&ctl_dev); -} - diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h deleted file mode 100644 index 46b2fc5b7..000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h +++ /dev/null @@ -1,419 +0,0 @@ -/* - * Management Module Support for MPT (Message Passing Technology) based - * controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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. - * - * 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. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifndef MPT2SAS_CTL_H_INCLUDED -#define MPT2SAS_CTL_H_INCLUDED - -#ifdef __KERNEL__ -#include -#endif - -#define MPT2SAS_DEV_NAME "mpt2ctl" -#define MPT2_MAGIC_NUMBER 'L' -#define MPT2_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */ - -/** - * IOCTL opcodes - */ -#define MPT2IOCINFO _IOWR(MPT2_MAGIC_NUMBER, 17, \ - struct mpt2_ioctl_iocinfo) -#define MPT2COMMAND _IOWR(MPT2_MAGIC_NUMBER, 20, \ - struct mpt2_ioctl_command) -#ifdef CONFIG_COMPAT -#define MPT2COMMAND32 _IOWR(MPT2_MAGIC_NUMBER, 20, \ - struct mpt2_ioctl_command32) -#endif -#define MPT2EVENTQUERY _IOWR(MPT2_MAGIC_NUMBER, 21, \ - struct mpt2_ioctl_eventquery) -#define MPT2EVENTENABLE _IOWR(MPT2_MAGIC_NUMBER, 22, \ - struct mpt2_ioctl_eventenable) -#define MPT2EVENTREPORT _IOWR(MPT2_MAGIC_NUMBER, 23, \ - struct mpt2_ioctl_eventreport) -#define MPT2HARDRESET _IOWR(MPT2_MAGIC_NUMBER, 24, \ - struct mpt2_ioctl_diag_reset) -#define MPT2BTDHMAPPING _IOWR(MPT2_MAGIC_NUMBER, 31, \ - struct mpt2_ioctl_btdh_mapping) - -/* diag buffer support */ -#define MPT2DIAGREGISTER _IOWR(MPT2_MAGIC_NUMBER, 26, \ - struct mpt2_diag_register) -#define MPT2DIAGRELEASE _IOWR(MPT2_MAGIC_NUMBER, 27, \ - struct mpt2_diag_release) -#define MPT2DIAGUNREGISTER _IOWR(MPT2_MAGIC_NUMBER, 28, \ - struct mpt2_diag_unregister) -#define MPT2DIAGQUERY _IOWR(MPT2_MAGIC_NUMBER, 29, \ - struct mpt2_diag_query) -#define MPT2DIAGREADBUFFER _IOWR(MPT2_MAGIC_NUMBER, 30, \ - struct mpt2_diag_read_buffer) - -/** - * struct mpt2_ioctl_header - main header structure - * @ioc_number - IOC unit number - * @port_number - IOC port number - * @max_data_size - maximum number bytes to transfer on read - */ -struct mpt2_ioctl_header { - uint32_t ioc_number; - uint32_t port_number; - uint32_t max_data_size; -}; - -/** - * struct mpt2_ioctl_diag_reset - diagnostic reset - * @hdr - generic header - */ -struct mpt2_ioctl_diag_reset { - struct mpt2_ioctl_header hdr; -}; - - -/** - * struct mpt2_ioctl_pci_info - pci device info - * @device - pci device id - * @function - pci function id - * @bus - pci bus id - * @segment_id - pci segment id - */ -struct mpt2_ioctl_pci_info { - union { - struct { - uint32_t device:5; - uint32_t function:3; - uint32_t bus:24; - } bits; - uint32_t word; - } u; - uint32_t segment_id; -}; - - -#define MPT2_IOCTL_INTERFACE_SCSI (0x00) -#define MPT2_IOCTL_INTERFACE_FC (0x01) -#define MPT2_IOCTL_INTERFACE_FC_IP (0x02) -#define MPT2_IOCTL_INTERFACE_SAS (0x03) -#define MPT2_IOCTL_INTERFACE_SAS2 (0x04) -#define MPT2_IOCTL_INTERFACE_SAS2_SSS6200 (0x05) -#define MPT2_IOCTL_VERSION_LENGTH (32) - -/** - * struct mpt2_ioctl_iocinfo - generic controller info - * @hdr - generic header - * @adapter_type - type of adapter (spi, fc, sas) - * @port_number - port number - * @pci_id - PCI Id - * @hw_rev - hardware revision - * @sub_system_device - PCI subsystem Device ID - * @sub_system_vendor - PCI subsystem Vendor ID - * @rsvd0 - reserved - * @firmware_version - firmware version - * @bios_version - BIOS version - * @driver_version - driver version - 32 ASCII characters - * @rsvd1 - reserved - * @scsi_id - scsi id of adapter 0 - * @rsvd2 - reserved - * @pci_information - pci info (2nd revision) - */ -struct mpt2_ioctl_iocinfo { - struct mpt2_ioctl_header hdr; - uint32_t adapter_type; - uint32_t port_number; - uint32_t pci_id; - uint32_t hw_rev; - uint32_t subsystem_device; - uint32_t subsystem_vendor; - uint32_t rsvd0; - uint32_t firmware_version; - uint32_t bios_version; - uint8_t driver_version[MPT2_IOCTL_VERSION_LENGTH]; - uint8_t rsvd1; - uint8_t scsi_id; - uint16_t rsvd2; - struct mpt2_ioctl_pci_info pci_information; -}; - - -/* number of event log entries */ -#define MPT2SAS_CTL_EVENT_LOG_SIZE (50) - -/** - * struct mpt2_ioctl_eventquery - query event count and type - * @hdr - generic header - * @event_entries - number of events returned by get_event_report - * @rsvd - reserved - * @event_types - type of events currently being captured - */ -struct mpt2_ioctl_eventquery { - struct mpt2_ioctl_header hdr; - uint16_t event_entries; - uint16_t rsvd; - uint32_t event_types[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; -}; - -/** - * struct mpt2_ioctl_eventenable - enable/disable event capturing - * @hdr - generic header - * @event_types - toggle off/on type of events to be captured - */ -struct mpt2_ioctl_eventenable { - struct mpt2_ioctl_header hdr; - uint32_t event_types[4]; -}; - -#define MPT2_EVENT_DATA_SIZE (192) -/** - * struct MPT2_IOCTL_EVENTS - - * @event - the event that was reported - * @context - unique value for each event assigned by driver - * @data - event data returned in fw reply message - */ -struct MPT2_IOCTL_EVENTS { - uint32_t event; - uint32_t context; - uint8_t data[MPT2_EVENT_DATA_SIZE]; -}; - -/** - * struct mpt2_ioctl_eventreport - returing event log - * @hdr - generic header - * @event_data - (see struct MPT2_IOCTL_EVENTS) - */ -struct mpt2_ioctl_eventreport { - struct mpt2_ioctl_header hdr; - struct MPT2_IOCTL_EVENTS event_data[1]; -}; - -/** - * struct mpt2_ioctl_command - generic mpt firmware passthru ioctl - * @hdr - generic header - * @timeout - command timeout in seconds. (if zero then use driver default - * value). - * @reply_frame_buf_ptr - reply location - * @data_in_buf_ptr - destination for read - * @data_out_buf_ptr - data source for write - * @sense_data_ptr - sense data location - * @max_reply_bytes - maximum number of reply bytes to be sent to app. - * @data_in_size - number bytes for data transfer in (read) - * @data_out_size - number bytes for data transfer out (write) - * @max_sense_bytes - maximum number of bytes for auto sense buffers - * @data_sge_offset - offset in words from the start of the request message to - * the first SGL - * @mf[1]; - */ -struct mpt2_ioctl_command { - struct mpt2_ioctl_header hdr; - uint32_t timeout; - void __user *reply_frame_buf_ptr; - void __user *data_in_buf_ptr; - void __user *data_out_buf_ptr; - void __user *sense_data_ptr; - uint32_t max_reply_bytes; - uint32_t data_in_size; - uint32_t data_out_size; - uint32_t max_sense_bytes; - uint32_t data_sge_offset; - uint8_t mf[1]; -}; - -#ifdef CONFIG_COMPAT -struct mpt2_ioctl_command32 { - struct mpt2_ioctl_header hdr; - uint32_t timeout; - uint32_t reply_frame_buf_ptr; - uint32_t data_in_buf_ptr; - uint32_t data_out_buf_ptr; - uint32_t sense_data_ptr; - uint32_t max_reply_bytes; - uint32_t data_in_size; - uint32_t data_out_size; - uint32_t max_sense_bytes; - uint32_t data_sge_offset; - uint8_t mf[1]; -}; -#endif - -/** - * struct mpt2_ioctl_btdh_mapping - mapping info - * @hdr - generic header - * @id - target device identification number - * @bus - SCSI bus number that the target device exists on - * @handle - device handle for the target device - * @rsvd - reserved - * - * To obtain a bus/id the application sets - * handle to valid handle, and bus/id to 0xFFFF. - * - * To obtain the device handle the application sets - * bus/id valid value, and the handle to 0xFFFF. - */ -struct mpt2_ioctl_btdh_mapping { - struct mpt2_ioctl_header hdr; - uint32_t id; - uint32_t bus; - uint16_t handle; - uint16_t rsvd; -}; - - -/* status bits for ioc->diag_buffer_status */ -#define MPT2_DIAG_BUFFER_IS_REGISTERED (0x01) -#define MPT2_DIAG_BUFFER_IS_RELEASED (0x02) -#define MPT2_DIAG_BUFFER_IS_DIAG_RESET (0x04) - -/* application flags for mpt2_diag_register, mpt2_diag_query */ -#define MPT2_APP_FLAGS_APP_OWNED (0x0001) -#define MPT2_APP_FLAGS_BUFFER_VALID (0x0002) -#define MPT2_APP_FLAGS_FW_BUFFER_ACCESS (0x0004) - -/* flags for mpt2_diag_read_buffer */ -#define MPT2_FLAGS_REREGISTER (0x0001) - -#define MPT2_PRODUCT_SPECIFIC_DWORDS 23 - -/** - * struct mpt2_diag_register - application register with driver - * @hdr - generic header - * @reserved - - * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED - * @application_flags - misc flags - * @diagnostic_flags - specifies flags affecting command processing - * @product_specific - product specific information - * @requested_buffer_size - buffers size in bytes - * @unique_id - tag specified by application that is used to signal ownership - * of the buffer. - * - * This will allow the driver to setup any required buffers that will be - * needed by firmware to communicate with the driver. - */ -struct mpt2_diag_register { - struct mpt2_ioctl_header hdr; - uint8_t reserved; - uint8_t buffer_type; - uint16_t application_flags; - uint32_t diagnostic_flags; - uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS]; - uint32_t requested_buffer_size; - uint32_t unique_id; -}; - -/** - * struct mpt2_diag_unregister - application unregister with driver - * @hdr - generic header - * @unique_id - tag uniquely identifies the buffer to be unregistered - * - * This will allow the driver to cleanup any memory allocated for diag - * messages and to free up any resources. - */ -struct mpt2_diag_unregister { - struct mpt2_ioctl_header hdr; - uint32_t unique_id; -}; - -/** - * struct mpt2_diag_query - query relevant info associated with diag buffers - * @hdr - generic header - * @reserved - - * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED - * @application_flags - misc flags - * @diagnostic_flags - specifies flags affecting command processing - * @product_specific - product specific information - * @total_buffer_size - diag buffer size in bytes - * @driver_added_buffer_size - size of extra space appended to end of buffer - * @unique_id - unique id associated with this buffer. - * - * The application will send only buffer_type and unique_id. Driver will - * inspect unique_id first, if valid, fill in all the info. If unique_id is - * 0x00, the driver will return info specified by Buffer Type. - */ -struct mpt2_diag_query { - struct mpt2_ioctl_header hdr; - uint8_t reserved; - uint8_t buffer_type; - uint16_t application_flags; - uint32_t diagnostic_flags; - uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS]; - uint32_t total_buffer_size; - uint32_t driver_added_buffer_size; - uint32_t unique_id; -}; - -/** - * struct mpt2_diag_release - request to send Diag Release Message to firmware - * @hdr - generic header - * @unique_id - tag uniquely identifies the buffer to be released - * - * This allows ownership of the specified buffer to returned to the driver, - * allowing an application to read the buffer without fear that firmware is - * overwritting information in the buffer. - */ -struct mpt2_diag_release { - struct mpt2_ioctl_header hdr; - uint32_t unique_id; -}; - -/** - * struct mpt2_diag_read_buffer - request for copy of the diag buffer - * @hdr - generic header - * @status - - * @reserved - - * @flags - misc flags - * @starting_offset - starting offset within drivers buffer where to start - * reading data at into the specified application buffer - * @bytes_to_read - number of bytes to copy from the drivers buffer into the - * application buffer starting at starting_offset. - * @unique_id - unique id associated with this buffer. - * @diagnostic_data - data payload - */ -struct mpt2_diag_read_buffer { - struct mpt2_ioctl_header hdr; - uint8_t status; - uint8_t reserved; - uint16_t flags; - uint32_t starting_offset; - uint32_t bytes_to_read; - uint32_t unique_id; - uint32_t diagnostic_data[1]; -}; - -#endif /* MPT2SAS_CTL_H_INCLUDED */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h deleted file mode 100644 index 277120d45..000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_debug.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Logging Support for MPT (Message Passing Technology) based controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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. - * - * 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. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifndef MPT2SAS_DEBUG_H_INCLUDED -#define MPT2SAS_DEBUG_H_INCLUDED - -#define MPT_DEBUG 0x00000001 -#define MPT_DEBUG_MSG_FRAME 0x00000002 -#define MPT_DEBUG_SG 0x00000004 -#define MPT_DEBUG_EVENTS 0x00000008 -#define MPT_DEBUG_EVENT_WORK_TASK 0x00000010 -#define MPT_DEBUG_INIT 0x00000020 -#define MPT_DEBUG_EXIT 0x00000040 -#define MPT_DEBUG_FAIL 0x00000080 -#define MPT_DEBUG_TM 0x00000100 -#define MPT_DEBUG_REPLY 0x00000200 -#define MPT_DEBUG_HANDSHAKE 0x00000400 -#define MPT_DEBUG_CONFIG 0x00000800 -#define MPT_DEBUG_DL 0x00001000 -#define MPT_DEBUG_RESET 0x00002000 -#define MPT_DEBUG_SCSI 0x00004000 -#define MPT_DEBUG_IOCTL 0x00008000 -#define MPT_DEBUG_CSMISAS 0x00010000 -#define MPT_DEBUG_SAS 0x00020000 -#define MPT_DEBUG_TRANSPORT 0x00040000 -#define MPT_DEBUG_TASK_SET_FULL 0x00080000 - -#define MPT_DEBUG_TARGET_MODE 0x00100000 - - -/* - * CONFIG_SCSI_MPT2SAS_LOGGING - enabled in Kconfig - */ - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -#define MPT_CHECK_LOGGING(IOC, CMD, BITS) \ -{ \ - if (IOC->logging_level & BITS) \ - CMD; \ -} -#else -#define MPT_CHECK_LOGGING(IOC, CMD, BITS) -#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */ - - -/* - * debug macros - */ - -#define dprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG) - -#define dsgprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SG) - -#define devtprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENTS) - -#define dewtprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENT_WORK_TASK) - -#define dinitprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_INIT) - -#define dexitprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EXIT) - -#define dfailprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FAIL) - -#define dtmprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TM) - -#define dreplyprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_REPLY) - -#define dhsprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_HANDSHAKE) - -#define dcprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CONFIG) - -#define ddlprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DL) - -#define drsprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_RESET) - -#define dsprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SCSI) - -#define dctlprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL) - -#define dcsmisasprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CSMISAS) - -#define dsasprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS) - -#define dsastransport(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE) - -#define dmfprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_MSG_FRAME) - -#define dtsfprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TASK_SET_FULL) - -#define dtransportprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TRANSPORT) - -#define dTMprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TARGET_MODE) - -/* inline functions for dumping debug data*/ -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _debug_dump_mf - print message frame contents - * @mpi_request: pointer to message frame - * @sz: number of dwords - */ -static inline void -_debug_dump_mf(void *mpi_request, int sz) -{ - int i; - __le32 *mfp = (__le32 *)mpi_request; - - printk(KERN_INFO "mf:\n\t"); - for (i = 0; i < sz; i++) { - if (i && ((i % 8) == 0)) - printk("\n\t"); - printk("%08x ", le32_to_cpu(mfp[i])); - } - printk("\n"); -} -#else -#define _debug_dump_mf(mpi_request, sz) -#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */ - -#endif /* MPT2SAS_DEBUG_H_INCLUDED */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c deleted file mode 100644 index 0ad09b2bf..000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ /dev/null @@ -1,8855 +0,0 @@ -/* - * Scsi Host Layer for MPT (Message Passing Technology) based controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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. - * - * 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. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "mpt2sas_base.h" - -MODULE_AUTHOR(MPT2SAS_AUTHOR); -MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION); -MODULE_LICENSE("GPL"); -MODULE_VERSION(MPT2SAS_DRIVER_VERSION); - -#define RAID_CHANNEL 1 - -/* forward proto's */ -static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_expander); -static void _firmware_event_work(struct work_struct *work); - -static u8 _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid); - -static void _scsih_scan_start(struct Scsi_Host *shost); -static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time); - -/* global parameters */ -LIST_HEAD(mpt2sas_ioc_list); -/* global ioc lock for list operations */ -DEFINE_SPINLOCK(gioc_lock); -/* local parameters */ -static u8 scsi_io_cb_idx = -1; -static u8 tm_cb_idx = -1; -static u8 ctl_cb_idx = -1; -static u8 base_cb_idx = -1; -static u8 port_enable_cb_idx = -1; -static u8 transport_cb_idx = -1; -static u8 scsih_cb_idx = -1; -static u8 config_cb_idx = -1; -static int mpt_ids; - -static u8 tm_tr_cb_idx = -1 ; -static u8 tm_tr_volume_cb_idx = -1 ; -static u8 tm_sas_control_cb_idx = -1; - -/* command line options */ -static u32 logging_level; -MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info " - "(default=0)"); - -static ushort max_sectors = 0xFFFF; -module_param(max_sectors, ushort, 0); -MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767 default=32767"); - -static int missing_delay[2] = {-1, -1}; -module_param_array(missing_delay, int, NULL, 0); -MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay"); - -/* scsi-mid layer global parmeter is max_report_luns, which is 511 */ -#define MPT2SAS_MAX_LUN (16895) -static int max_lun = MPT2SAS_MAX_LUN; -module_param(max_lun, int, 0); -MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); - -/* diag_buffer_enable is bitwise - * bit 0 set = TRACE - * bit 1 set = SNAPSHOT - * bit 2 set = EXTENDED - * - * Either bit can be set, or both - */ -static int diag_buffer_enable = -1; -module_param(diag_buffer_enable, int, 0); -MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers " - "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); - -static int disable_discovery = -1; -module_param(disable_discovery, int, 0); -MODULE_PARM_DESC(disable_discovery, " disable discovery "); - -/* permit overriding the host protection capabilities mask (EEDP/T10 PI) */ -static int prot_mask = 0; -module_param(prot_mask, int, 0); -MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 "); - -/** - * struct sense_info - common structure for obtaining sense keys - * @skey: sense key - * @asc: additional sense code - * @ascq: additional sense code qualifier - */ -struct sense_info { - u8 skey; - u8 asc; - u8 ascq; -}; - - -#define MPT2SAS_TURN_ON_PFA_LED (0xFFFC) -#define MPT2SAS_PORT_ENABLE_COMPLETE (0xFFFD) -#define MPT2SAS_REMOVE_UNRESPONDING_DEVICES (0xFFFF) -/** - * struct fw_event_work - firmware event struct - * @list: link list framework - * @work: work object (ioc->fault_reset_work_q) - * @cancel_pending_work: flag set during reset handling - * @ioc: per adapter object - * @device_handle: device handle - * @VF_ID: virtual function id - * @VP_ID: virtual port id - * @ignore: flag meaning this event has been marked to ignore - * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h - * @event_data: reply event data payload follows - * - * This object stored on ioc->fw_event_list. - */ -struct fw_event_work { - struct list_head list; - u8 cancel_pending_work; - struct delayed_work delayed_work; - struct MPT2SAS_ADAPTER *ioc; - u16 device_handle; - u8 VF_ID; - u8 VP_ID; - u8 ignore; - u16 event; - struct kref refcount; - char event_data[0] __aligned(4); -}; - -static void fw_event_work_free(struct kref *r) -{ - kfree(container_of(r, struct fw_event_work, refcount)); -} - -static void fw_event_work_get(struct fw_event_work *fw_work) -{ - kref_get(&fw_work->refcount); -} - -static void fw_event_work_put(struct fw_event_work *fw_work) -{ - kref_put(&fw_work->refcount, fw_event_work_free); -} - -static struct fw_event_work *alloc_fw_event_work(int len) -{ - struct fw_event_work *fw_event; - - fw_event = kzalloc(sizeof(*fw_event) + len, GFP_ATOMIC); - if (!fw_event) - return NULL; - - kref_init(&fw_event->refcount); - return fw_event; -} - -/* raid transport support */ -static struct raid_template *mpt2sas_raid_template; - -/** - * struct _scsi_io_transfer - scsi io transfer - * @handle: sas device handle (assigned by firmware) - * @is_raid: flag set for hidden raid components - * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE, - * @data_length: data transfer length - * @data_dma: dma pointer to data - * @sense: sense data - * @lun: lun number - * @cdb_length: cdb length - * @cdb: cdb contents - * @timeout: timeout for this command - * @VF_ID: virtual function id - * @VP_ID: virtual port id - * @valid_reply: flag set for reply message - * @sense_length: sense length - * @ioc_status: ioc status - * @scsi_state: scsi state - * @scsi_status: scsi staus - * @log_info: log information - * @transfer_length: data length transfer when there is a reply message - * - * Used for sending internal scsi commands to devices within this module. - * Refer to _scsi_send_scsi_io(). - */ -struct _scsi_io_transfer { - u16 handle; - u8 is_raid; - enum dma_data_direction dir; - u32 data_length; - dma_addr_t data_dma; - u8 sense[SCSI_SENSE_BUFFERSIZE]; - u32 lun; - u8 cdb_length; - u8 cdb[32]; - u8 timeout; - u8 VF_ID; - u8 VP_ID; - u8 valid_reply; - /* the following bits are only valid when 'valid_reply = 1' */ - u32 sense_length; - u16 ioc_status; - u8 scsi_state; - u8 scsi_status; - u32 log_info; - u32 transfer_length; -}; - -/* - * The pci device ids are defined in mpi/mpi2_cnfg.h. - */ -static struct pci_device_id scsih_pci_table[] = { - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004, - PCI_ANY_ID, PCI_ANY_ID }, - /* Falcon ~ 2008*/ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008, - PCI_ANY_ID, PCI_ANY_ID }, - /* Liberator ~ 2108 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3, - PCI_ANY_ID, PCI_ANY_ID }, - /* Meteor ~ 2116 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2, - PCI_ANY_ID, PCI_ANY_ID }, - /* Thunderbolt ~ 2208 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, - PCI_ANY_ID, PCI_ANY_ID }, - /* Mustang ~ 2308 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, - PCI_ANY_ID, PCI_ANY_ID }, - /* SSS6200 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200, - PCI_ANY_ID, PCI_ANY_ID }, - {0} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, scsih_pci_table); - -/** - * _scsih_set_debug_level - global setting of ioc->logging_level. - * - * Note: The logging levels are defined in mpt2sas_debug.h. - */ -static int -_scsih_set_debug_level(const char *val, struct kernel_param *kp) -{ - int ret = param_set_int(val, kp); - struct MPT2SAS_ADAPTER *ioc; - - if (ret) - return ret; - - printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level); - spin_lock(&gioc_lock); - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) - ioc->logging_level = logging_level; - spin_unlock(&gioc_lock); - return 0; -} -module_param_call(logging_level, _scsih_set_debug_level, param_get_int, - &logging_level, 0644); - -/** - * _scsih_srch_boot_sas_address - search based on sas_address - * @sas_address: sas address - * @boot_device: boot device object from bios page 2 - * - * Returns 1 when there's a match, 0 means no match. - */ -static inline int -_scsih_srch_boot_sas_address(u64 sas_address, - Mpi2BootDeviceSasWwid_t *boot_device) -{ - return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0; -} - -/** - * _scsih_srch_boot_device_name - search based on device name - * @device_name: device name specified in INDENTIFY fram - * @boot_device: boot device object from bios page 2 - * - * Returns 1 when there's a match, 0 means no match. - */ -static inline int -_scsih_srch_boot_device_name(u64 device_name, - Mpi2BootDeviceDeviceName_t *boot_device) -{ - return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0; -} - -/** - * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot - * @enclosure_logical_id: enclosure logical id - * @slot_number: slot number - * @boot_device: boot device object from bios page 2 - * - * Returns 1 when there's a match, 0 means no match. - */ -static inline int -_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number, - Mpi2BootDeviceEnclosureSlot_t *boot_device) -{ - return (enclosure_logical_id == le64_to_cpu(boot_device-> - EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device-> - SlotNumber)) ? 1 : 0; -} - -/** - * _scsih_is_boot_device - search for matching boot device. - * @sas_address: sas address - * @device_name: device name specified in INDENTIFY fram - * @enclosure_logical_id: enclosure logical id - * @slot_number: slot number - * @form: specifies boot device form - * @boot_device: boot device object from bios page 2 - * - * Returns 1 when there's a match, 0 means no match. - */ -static int -_scsih_is_boot_device(u64 sas_address, u64 device_name, - u64 enclosure_logical_id, u16 slot, u8 form, - Mpi2BiosPage2BootDevice_t *boot_device) -{ - int rc = 0; - - switch (form) { - case MPI2_BIOSPAGE2_FORM_SAS_WWID: - if (!sas_address) - break; - rc = _scsih_srch_boot_sas_address( - sas_address, &boot_device->SasWwid); - break; - case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT: - if (!enclosure_logical_id) - break; - rc = _scsih_srch_boot_encl_slot( - enclosure_logical_id, - slot, &boot_device->EnclosureSlot); - break; - case MPI2_BIOSPAGE2_FORM_DEVICE_NAME: - if (!device_name) - break; - rc = _scsih_srch_boot_device_name( - device_name, &boot_device->DeviceName); - break; - case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED: - break; - } - - return rc; -} - -/** - * _scsih_get_sas_address - set the sas_address for given device handle - * @handle: device handle - * @sas_address: sas address - * - * Returns 0 success, non-zero when failure - */ -static int -_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle, - u64 *sas_address) -{ - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2ConfigReply_t mpi_reply; - u32 ioc_status; - *sas_address = 0; - - if (handle <= ioc->sas_hba.num_phys) { - *sas_address = ioc->sas_hba.sas_address; - return 0; - } - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); - return -ENXIO; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - *sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - return 0; - } - - /* we hit this becuase the given parent handle doesn't exist */ - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - return -ENXIO; - /* else error case */ - printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x), " - "failure at %s:%d/%s()!\n", ioc->name, handle, ioc_status, - __FILE__, __LINE__, __func__); - return -EIO; -} - -/** - * _scsih_determine_boot_device - determine boot device. - * @ioc: per adapter object - * @device: either sas_device or raid_device object - * @is_raid: [flag] 1 = raid object, 0 = sas object - * - * Determines whether this device should be first reported device to - * to scsi-ml or sas transport, this purpose is for persistent boot device. - * There are primary, alternate, and current entries in bios page 2. The order - * priority is primary, alternate, then current. This routine saves - * the corresponding device object and is_raid flag in the ioc object. - * The saved data to be used later in _scsih_probe_boot_devices(). - */ -static void -_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc, - void *device, u8 is_raid) -{ - struct _sas_device *sas_device; - struct _raid_device *raid_device; - u64 sas_address; - u64 device_name; - u64 enclosure_logical_id; - u16 slot; - - /* only process this function when driver loads */ - if (!ioc->is_driver_loading) - return; - - /* no Bios, return immediately */ - if (!ioc->bios_pg3.BiosVersion) - return; - - if (!is_raid) { - sas_device = device; - sas_address = sas_device->sas_address; - device_name = sas_device->device_name; - enclosure_logical_id = sas_device->enclosure_logical_id; - slot = sas_device->slot; - } else { - raid_device = device; - sas_address = raid_device->wwid; - device_name = 0; - enclosure_logical_id = 0; - slot = 0; - } - - if (!ioc->req_boot_device.device) { - if (_scsih_is_boot_device(sas_address, device_name, - enclosure_logical_id, slot, - (ioc->bios_pg2.ReqBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK), - &ioc->bios_pg2.RequestedBootDevice)) { - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s: req_boot_device(0x%016llx)\n", - ioc->name, __func__, - (unsigned long long)sas_address)); - ioc->req_boot_device.device = device; - ioc->req_boot_device.is_raid = is_raid; - } - } - - if (!ioc->req_alt_boot_device.device) { - if (_scsih_is_boot_device(sas_address, device_name, - enclosure_logical_id, slot, - (ioc->bios_pg2.ReqAltBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK), - &ioc->bios_pg2.RequestedAltBootDevice)) { - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s: req_alt_boot_device(0x%016llx)\n", - ioc->name, __func__, - (unsigned long long)sas_address)); - ioc->req_alt_boot_device.device = device; - ioc->req_alt_boot_device.is_raid = is_raid; - } - } - - if (!ioc->current_boot_device.device) { - if (_scsih_is_boot_device(sas_address, device_name, - enclosure_logical_id, slot, - (ioc->bios_pg2.CurrentBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK), - &ioc->bios_pg2.CurrentBootDevice)) { - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s: current_boot_device(0x%016llx)\n", - ioc->name, __func__, - (unsigned long long)sas_address)); - ioc->current_boot_device.device = device; - ioc->current_boot_device.is_raid = is_raid; - } - } -} - -static struct _sas_device * -__mpt2sas_get_sdev_from_target(struct MPT2SAS_ADAPTER *ioc, - struct MPT2SAS_TARGET *tgt_priv) -{ - struct _sas_device *ret; - - assert_spin_locked(&ioc->sas_device_lock); - - ret = tgt_priv->sdev; - if (ret) - sas_device_get(ret); - - return ret; -} - -static struct _sas_device * -mpt2sas_get_sdev_from_target(struct MPT2SAS_ADAPTER *ioc, - struct MPT2SAS_TARGET *tgt_priv) -{ - struct _sas_device *ret; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - ret = __mpt2sas_get_sdev_from_target(ioc, tgt_priv); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - return ret; -} - - -struct _sas_device * -__mpt2sas_get_sdev_by_addr(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address) -{ - struct _sas_device *sas_device; - - assert_spin_locked(&ioc->sas_device_lock); - - list_for_each_entry(sas_device, &ioc->sas_device_list, list) - if (sas_device->sas_address == sas_address) - goto found_device; - - list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) - if (sas_device->sas_address == sas_address) - goto found_device; - - return NULL; - -found_device: - sas_device_get(sas_device); - return sas_device; -} - -/** - * mpt2sas_get_sdev_by_addr - sas device search - * @ioc: per adapter object - * @sas_address: sas address - * Context: Calling function should acquire ioc->sas_device_lock - * - * This searches for sas_device based on sas_address, then return sas_device - * object. - */ -struct _sas_device * -mpt2sas_get_sdev_by_addr(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address) -{ - struct _sas_device *sas_device; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - return sas_device; -} - -static struct _sas_device * -__mpt2sas_get_sdev_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_device *sas_device; - - assert_spin_locked(&ioc->sas_device_lock); - - list_for_each_entry(sas_device, &ioc->sas_device_list, list) - if (sas_device->handle == handle) - goto found_device; - - list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) - if (sas_device->handle == handle) - goto found_device; - - return NULL; - -found_device: - sas_device_get(sas_device); - return sas_device; -} - -/** - * mpt2sas_get_sdev_by_handle - sas device search - * @ioc: per adapter object - * @handle: sas device handle (assigned by firmware) - * Context: Calling function should acquire ioc->sas_device_lock - * - * This searches for sas_device based on sas_address, then return sas_device - * object. - */ -static struct _sas_device * -mpt2sas_get_sdev_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_device *sas_device; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - return sas_device; -} - -/** - * _scsih_sas_device_remove - remove sas_device from list. - * @ioc: per adapter object - * @sas_device: the sas_device object - * Context: This function will acquire ioc->sas_device_lock. - * - * If sas_device is on the list, remove it and decrement its reference count. - */ -static void -_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - unsigned long flags; - - if (!sas_device) - return; - - /* - * The lock serializes access to the list, but we still need to verify - * that nobody removed the entry while we were waiting on the lock. - */ - spin_lock_irqsave(&ioc->sas_device_lock, flags); - if (!list_empty(&sas_device->list)) { - list_del_init(&sas_device->list); - sas_device_put(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -} - - -/** - * _scsih_sas_device_add - insert sas_device to the list. - * @ioc: per adapter object - * @sas_device: the sas_device object - * Context: This function will acquire ioc->sas_device_lock. - * - * Adding new object to the ioc->sas_device_list. - */ -static void -_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - unsigned long flags; - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle" - "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device->handle, (unsigned long long)sas_device->sas_address)); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device_get(sas_device); - list_add_tail(&sas_device->list, &ioc->sas_device_list); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (!mpt2sas_transport_port_add(ioc, sas_device->handle, - sas_device->sas_address_parent)) { - _scsih_sas_device_remove(ioc, sas_device); - } else if (!sas_device->starget) { - /* When asyn scanning is enabled, its not possible to remove - * devices while scanning is turned on due to an oops in - * scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start() - */ - if (!ioc->is_driver_loading) { - mpt2sas_transport_port_remove(ioc, - sas_device->sas_address, - sas_device->sas_address_parent); - _scsih_sas_device_remove(ioc, sas_device); - } - } -} - -/** - * _scsih_sas_device_init_add - insert sas_device to the list. - * @ioc: per adapter object - * @sas_device: the sas_device object - * Context: This function will acquire ioc->sas_device_lock. - * - * Adding new object at driver load time to the ioc->sas_device_init_list. - */ -static void -_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - unsigned long flags; - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle" - "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device->handle, (unsigned long long)sas_device->sas_address)); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device_get(sas_device); - list_add_tail(&sas_device->list, &ioc->sas_device_init_list); - _scsih_determine_boot_device(ioc, sas_device, 0); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -} - -/** - * _scsih_raid_device_find_by_id - raid device search - * @ioc: per adapter object - * @id: sas device target id - * @channel: sas device channel - * Context: Calling function should acquire ioc->raid_device_lock - * - * This searches for raid_device based on target id, then return raid_device - * object. - */ -static struct _raid_device * -_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel) -{ - struct _raid_device *raid_device, *r; - - r = NULL; - list_for_each_entry(raid_device, &ioc->raid_device_list, list) { - if (raid_device->id == id && raid_device->channel == channel) { - r = raid_device; - goto out; - } - } - - out: - return r; -} - -/** - * _scsih_raid_device_find_by_handle - raid device search - * @ioc: per adapter object - * @handle: sas device handle (assigned by firmware) - * Context: Calling function should acquire ioc->raid_device_lock - * - * This searches for raid_device based on handle, then return raid_device - * object. - */ -static struct _raid_device * -_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _raid_device *raid_device, *r; - - r = NULL; - list_for_each_entry(raid_device, &ioc->raid_device_list, list) { - if (raid_device->handle != handle) - continue; - r = raid_device; - goto out; - } - - out: - return r; -} - -/** - * _scsih_raid_device_find_by_wwid - raid device search - * @ioc: per adapter object - * @handle: sas device handle (assigned by firmware) - * Context: Calling function should acquire ioc->raid_device_lock - * - * This searches for raid_device based on wwid, then return raid_device - * object. - */ -static struct _raid_device * -_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid) -{ - struct _raid_device *raid_device, *r; - - r = NULL; - list_for_each_entry(raid_device, &ioc->raid_device_list, list) { - if (raid_device->wwid != wwid) - continue; - r = raid_device; - goto out; - } - - out: - return r; -} - -/** - * _scsih_raid_device_add - add raid_device object - * @ioc: per adapter object - * @raid_device: raid_device object - * - * This is added to the raid_device_list link list. - */ -static void -_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc, - struct _raid_device *raid_device) -{ - unsigned long flags; - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle" - "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, - raid_device->handle, (unsigned long long)raid_device->wwid)); - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - list_add_tail(&raid_device->list, &ioc->raid_device_list); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -} - -/** - * _scsih_raid_device_remove - delete raid_device object - * @ioc: per adapter object - * @raid_device: raid_device object - * - */ -static void -_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc, - struct _raid_device *raid_device) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - list_del(&raid_device->list); - kfree(raid_device); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -} - -/** - * mpt2sas_scsih_expander_find_by_handle - expander device search - * @ioc: per adapter object - * @handle: expander handle (assigned by firmware) - * Context: Calling function should acquire ioc->sas_device_lock - * - * This searches for expander device based on handle, then returns the - * sas_node object. - */ -struct _sas_node * -mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_node *sas_expander, *r; - - r = NULL; - list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { - if (sas_expander->handle != handle) - continue; - r = sas_expander; - goto out; - } - out: - return r; -} - -/** - * mpt2sas_scsih_expander_find_by_sas_address - expander device search - * @ioc: per adapter object - * @sas_address: sas address - * Context: Calling function should acquire ioc->sas_node_lock. - * - * This searches for expander device based on sas_address, then returns the - * sas_node object. - */ -struct _sas_node * -mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address) -{ - struct _sas_node *sas_expander, *r; - - r = NULL; - list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { - if (sas_expander->sas_address != sas_address) - continue; - r = sas_expander; - goto out; - } - out: - return r; -} - -/** - * _scsih_expander_node_add - insert expander device to the list. - * @ioc: per adapter object - * @sas_expander: the sas_device object - * Context: This function will acquire ioc->sas_node_lock. - * - * Adding new object to the ioc->sas_expander_list. - * - * Return nothing. - */ -static void -_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_expander) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - list_add_tail(&sas_expander->list, &ioc->sas_expander_list); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -} - -/** - * _scsih_is_end_device - determines if device is an end device - * @device_info: bitfield providing information about the device. - * Context: none - * - * Returns 1 if end device. - */ -static int -_scsih_is_end_device(u32 device_info) -{ - if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE && - ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) | - (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) | - (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE))) - return 1; - else - return 0; -} - -/** - * _scsih_scsi_lookup_get - returns scmd entry - * @ioc: per adapter object - * @smid: system request message index - * - * Returns the smid stored scmd pointer. - */ -static struct scsi_cmnd * -_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return ioc->scsi_lookup[smid - 1].scmd; -} - -/** - * _scsih_scsi_lookup_get_clear - returns scmd entry - * @ioc: per adapter object - * @smid: system request message index - * - * Returns the smid stored scmd pointer. - * Then will derefrence the stored scmd pointer. - */ -static inline struct scsi_cmnd * -_scsih_scsi_lookup_get_clear(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - unsigned long flags; - struct scsi_cmnd *scmd; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - scmd = ioc->scsi_lookup[smid - 1].scmd; - ioc->scsi_lookup[smid - 1].scmd = NULL; - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - - return scmd; -} - -/** - * _scsih_scsi_lookup_find_by_scmd - scmd lookup - * @ioc: per adapter object - * @smid: system request message index - * @scmd: pointer to scsi command object - * Context: This function will acquire ioc->scsi_lookup_lock. - * - * This will search for a scmd pointer in the scsi_lookup array, - * returning the revelent smid. A returned value of zero means invalid. - */ -static u16 -_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd - *scmd) -{ - u16 smid; - unsigned long flags; - int i; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - smid = 0; - for (i = 0; i < ioc->scsiio_depth; i++) { - if (ioc->scsi_lookup[i].scmd == scmd) { - smid = ioc->scsi_lookup[i].smid; - goto out; - } - } - out: - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return smid; -} - -/** - * _scsih_scsi_lookup_find_by_target - search for matching channel:id - * @ioc: per adapter object - * @id: target id - * @channel: channel - * Context: This function will acquire ioc->scsi_lookup_lock. - * - * This will search for a matching channel:id in the scsi_lookup array, - * returning 1 if found. - */ -static u8 -_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id, - int channel) -{ - u8 found; - unsigned long flags; - int i; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - found = 0; - for (i = 0 ; i < ioc->scsiio_depth; i++) { - if (ioc->scsi_lookup[i].scmd && - (ioc->scsi_lookup[i].scmd->device->id == id && - ioc->scsi_lookup[i].scmd->device->channel == channel)) { - found = 1; - goto out; - } - } - out: - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return found; -} - -/** - * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun - * @ioc: per adapter object - * @id: target id - * @lun: lun number - * @channel: channel - * Context: This function will acquire ioc->scsi_lookup_lock. - * - * This will search for a matching channel:id:lun in the scsi_lookup array, - * returning 1 if found. - */ -static u8 -_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id, - unsigned int lun, int channel) -{ - u8 found; - unsigned long flags; - int i; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - found = 0; - for (i = 0 ; i < ioc->scsiio_depth; i++) { - if (ioc->scsi_lookup[i].scmd && - (ioc->scsi_lookup[i].scmd->device->id == id && - ioc->scsi_lookup[i].scmd->device->channel == channel && - ioc->scsi_lookup[i].scmd->device->lun == lun)) { - found = 1; - goto out; - } - } - out: - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return found; -} - -/** - * _scsih_get_chain_buffer_tracker - obtain chain tracker - * @ioc: per adapter object - * @smid: smid associated to an IO request - * - * Returns chain tracker(from ioc->free_chain_list) - */ -static struct chain_tracker * -_scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - struct chain_tracker *chain_req; - unsigned long flags; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - if (list_empty(&ioc->free_chain_list)) { - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT "chain buffers not " - "available\n", ioc->name)); - return NULL; - } - chain_req = list_entry(ioc->free_chain_list.next, - struct chain_tracker, tracker_list); - list_del_init(&chain_req->tracker_list); - list_add_tail(&chain_req->tracker_list, - &ioc->scsi_lookup[smid - 1].chain_list); - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return chain_req; -} - -/** - * _scsih_build_scatter_gather - main sg creation routine - * @ioc: per adapter object - * @scmd: scsi command - * @smid: system request message index - * Context: none. - * - * The main routine that builds scatter gather table from a given - * scsi request sent via the .queuecommand main handler. - * - * Returns 0 success, anything else error - */ -static int -_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, - struct scsi_cmnd *scmd, u16 smid) -{ - Mpi2SCSIIORequest_t *mpi_request; - dma_addr_t chain_dma; - struct scatterlist *sg_scmd; - void *sg_local, *chain; - u32 chain_offset; - u32 chain_length; - u32 chain_flags; - int sges_left; - u32 sges_in_segment; - u32 sgl_flags; - u32 sgl_flags_last_element; - u32 sgl_flags_end_buffer; - struct chain_tracker *chain_req; - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - - /* init scatter gather flags */ - sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT; - if (scmd->sc_data_direction == DMA_TO_DEVICE) - sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC; - sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT) - << MPI2_SGE_FLAGS_SHIFT; - sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST) - << MPI2_SGE_FLAGS_SHIFT; - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - - sg_scmd = scsi_sglist(scmd); - sges_left = scsi_dma_map(scmd); - if (sges_left < 0) { - sdev_printk(KERN_ERR, scmd->device, "pci_map_sg" - " failed: request for %d bytes!\n", scsi_bufflen(scmd)); - return -ENOMEM; - } - - sg_local = &mpi_request->SGL; - sges_in_segment = ioc->max_sges_in_main_message; - if (sges_left <= sges_in_segment) - goto fill_in_last_segment; - - mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) + - (sges_in_segment * ioc->sge_size))/4; - - /* fill in main message segment when there is a chain following */ - while (sges_in_segment) { - if (sges_in_segment == 1) - ioc->base_add_sg_single(sg_local, - sgl_flags_last_element | sg_dma_len(sg_scmd), - sg_dma_address(sg_scmd)); - else - ioc->base_add_sg_single(sg_local, sgl_flags | - sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); - sg_scmd = sg_next(sg_scmd); - sg_local += ioc->sge_size; - sges_left--; - sges_in_segment--; - } - - /* initializing the chain flags and pointers */ - chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT; - chain_req = _scsih_get_chain_buffer_tracker(ioc, smid); - if (!chain_req) - return -1; - chain = chain_req->chain_buffer; - chain_dma = chain_req->chain_buffer_dma; - do { - sges_in_segment = (sges_left <= - ioc->max_sges_in_chain_message) ? sges_left : - ioc->max_sges_in_chain_message; - chain_offset = (sges_left == sges_in_segment) ? - 0 : (sges_in_segment * ioc->sge_size)/4; - chain_length = sges_in_segment * ioc->sge_size; - if (chain_offset) { - chain_offset = chain_offset << - MPI2_SGE_CHAIN_OFFSET_SHIFT; - chain_length += ioc->sge_size; - } - ioc->base_add_sg_single(sg_local, chain_flags | chain_offset | - chain_length, chain_dma); - sg_local = chain; - if (!chain_offset) - goto fill_in_last_segment; - - /* fill in chain segments */ - while (sges_in_segment) { - if (sges_in_segment == 1) - ioc->base_add_sg_single(sg_local, - sgl_flags_last_element | - sg_dma_len(sg_scmd), - sg_dma_address(sg_scmd)); - else - ioc->base_add_sg_single(sg_local, sgl_flags | - sg_dma_len(sg_scmd), - sg_dma_address(sg_scmd)); - sg_scmd = sg_next(sg_scmd); - sg_local += ioc->sge_size; - sges_left--; - sges_in_segment--; - } - - chain_req = _scsih_get_chain_buffer_tracker(ioc, smid); - if (!chain_req) - return -1; - chain = chain_req->chain_buffer; - chain_dma = chain_req->chain_buffer_dma; - } while (1); - - - fill_in_last_segment: - - /* fill the last segment */ - while (sges_left) { - if (sges_left == 1) - ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer | - sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); - else - ioc->base_add_sg_single(sg_local, sgl_flags | - sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); - sg_scmd = sg_next(sg_scmd); - sg_local += ioc->sge_size; - sges_left--; - } - - return 0; -} - -/** - * _scsih_change_queue_depth - setting device queue depth - * @sdev: scsi device struct - * @qdepth: requested queue depth - * - * Returns queue depth. - */ -static int -_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) -{ - struct Scsi_Host *shost = sdev->host; - int max_depth; - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct _sas_device *sas_device; - unsigned long flags; - - max_depth = shost->can_queue; - - /* limit max device queue for SATA to 32 */ - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - goto not_sata; - sas_target_priv_data = sas_device_priv_data->sas_target; - if (!sas_target_priv_data) - goto not_sata; - if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) - goto not_sata; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_from_target(ioc, sas_target_priv_data); - if (sas_device) { - if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) - max_depth = MPT2SAS_SATA_QUEUE_DEPTH; - - sas_device_put(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - not_sata: - if (!sdev->tagged_supported) - max_depth = 1; - if (qdepth > max_depth) - qdepth = max_depth; - return scsi_change_queue_depth(sdev, qdepth); -} - -/** - * _scsih_target_alloc - target add routine - * @starget: scsi target struct - * - * Returns 0 if ok. Any other return is assumed to be an error and - * the device is ignored. - */ -static int -_scsih_target_alloc(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct MPT2SAS_TARGET *sas_target_priv_data; - struct _sas_device *sas_device; - struct _raid_device *raid_device; - unsigned long flags; - struct sas_rphy *rphy; - - sas_target_priv_data = kzalloc(sizeof(*sas_target_priv_data), - GFP_KERNEL); - if (!sas_target_priv_data) - return -ENOMEM; - - starget->hostdata = sas_target_priv_data; - sas_target_priv_data->starget = starget; - sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE; - - /* RAID volumes */ - if (starget->channel == RAID_CHANNEL) { - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_id(ioc, starget->id, - starget->channel); - if (raid_device) { - sas_target_priv_data->handle = raid_device->handle; - sas_target_priv_data->sas_address = raid_device->wwid; - sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME; - if (ioc->is_warpdrive) - sas_target_priv_data->raid_device = raid_device; - raid_device->starget = starget; - } - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - return 0; - } - - /* sas/sata devices */ - spin_lock_irqsave(&ioc->sas_device_lock, flags); - rphy = dev_to_rphy(starget->dev.parent); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - rphy->identify.sas_address); - - if (sas_device) { - sas_target_priv_data->handle = sas_device->handle; - sas_target_priv_data->sas_address = sas_device->sas_address; - sas_target_priv_data->sdev = sas_device; - sas_device->starget = starget; - sas_device->id = starget->id; - sas_device->channel = starget->channel; - if (test_bit(sas_device->handle, ioc->pd_handles)) - sas_target_priv_data->flags |= - MPT_TARGET_FLAGS_RAID_COMPONENT; - - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - return 0; -} - -/** - * _scsih_target_destroy - target destroy routine - * @starget: scsi target struct - * - * Returns nothing. - */ -static void -_scsih_target_destroy(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct MPT2SAS_TARGET *sas_target_priv_data; - struct _sas_device *sas_device; - struct _raid_device *raid_device; - unsigned long flags; - struct sas_rphy *rphy; - - sas_target_priv_data = starget->hostdata; - if (!sas_target_priv_data) - return; - - if (starget->channel == RAID_CHANNEL) { - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_id(ioc, starget->id, - starget->channel); - if (raid_device) { - raid_device->starget = NULL; - raid_device->sdev = NULL; - } - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - goto out; - } - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - rphy = dev_to_rphy(starget->dev.parent); - sas_device = __mpt2sas_get_sdev_from_target(ioc, sas_target_priv_data); - if (sas_device && (sas_device->starget == starget) && - (sas_device->id == starget->id) && - (sas_device->channel == starget->channel)) - sas_device->starget = NULL; - - if (sas_device) { - /* - * Corresponding get() is in _scsih_target_alloc() - */ - sas_target_priv_data->sdev = NULL; - sas_device_put(sas_device); - - sas_device_put(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - out: - kfree(sas_target_priv_data); - starget->hostdata = NULL; -} - -/** - * _scsih_slave_alloc - device add routine - * @sdev: scsi device struct - * - * Returns 0 if ok. Any other return is assumed to be an error and - * the device is ignored. - */ -static int -_scsih_slave_alloc(struct scsi_device *sdev) -{ - struct Scsi_Host *shost; - struct MPT2SAS_ADAPTER *ioc; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_target *starget; - struct _raid_device *raid_device; - struct _sas_device *sas_device; - unsigned long flags; - - sas_device_priv_data = kzalloc(sizeof(*sas_device_priv_data), - GFP_KERNEL); - if (!sas_device_priv_data) - return -ENOMEM; - - sas_device_priv_data->lun = sdev->lun; - sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT; - - starget = scsi_target(sdev); - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->num_luns++; - sas_device_priv_data->sas_target = sas_target_priv_data; - sdev->hostdata = sas_device_priv_data; - if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT)) - sdev->no_uld_attach = 1; - - shost = dev_to_shost(&starget->dev); - ioc = shost_priv(shost); - if (starget->channel == RAID_CHANNEL) { - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_id(ioc, - starget->id, starget->channel); - if (raid_device) - raid_device->sdev = sdev; /* raid is single lun */ - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - } - - if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - sas_target_priv_data->sas_address); - if (sas_device && (sas_device->starget == NULL)) { - sdev_printk(KERN_INFO, sdev, - "%s : sas_device->starget set to starget @ %d\n", - __func__, __LINE__); - sas_device->starget = starget; - } - - if (sas_device) - sas_device_put(sas_device); - - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } - - return 0; -} - -/** - * _scsih_slave_destroy - device destroy routine - * @sdev: scsi device struct - * - * Returns nothing. - */ -static void -_scsih_slave_destroy(struct scsi_device *sdev) -{ - struct MPT2SAS_TARGET *sas_target_priv_data; - struct scsi_target *starget; - struct Scsi_Host *shost; - struct MPT2SAS_ADAPTER *ioc; - struct _sas_device *sas_device; - unsigned long flags; - - if (!sdev->hostdata) - return; - - starget = scsi_target(sdev); - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->num_luns--; - - shost = dev_to_shost(&starget->dev); - ioc = shost_priv(shost); - - if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_from_target(ioc, - sas_target_priv_data); - if (sas_device && !sas_target_priv_data->num_luns) - sas_device->starget = NULL; - - if (sas_device) - sas_device_put(sas_device); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } - - kfree(sdev->hostdata); - sdev->hostdata = NULL; -} - -/** - * _scsih_display_sata_capabilities - sata capabilities - * @ioc: per adapter object - * @handle: device handle - * @sdev: scsi device struct - */ -static void -_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, - u16 handle, struct scsi_device *sdev) -{ - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - u32 ioc_status; - u16 flags; - u32 device_info; - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - flags = le16_to_cpu(sas_device_pg0.Flags); - device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); - - sdev_printk(KERN_INFO, sdev, - "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), " - "sw_preserve(%s)\n", - (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n", - (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n", - (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" : - "n", - (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n", - (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n", - (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n"); -} - -/** - * _scsih_is_raid - return boolean indicating device is raid volume - * @dev the device struct object - */ -static int -_scsih_is_raid(struct device *dev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); - - if (ioc->is_warpdrive) - return 0; - return (sdev->channel == RAID_CHANNEL) ? 1 : 0; -} - -/** - * _scsih_get_resync - get raid volume resync percent complete - * @dev the device struct object - */ -static void -_scsih_get_resync(struct device *dev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); - static struct _raid_device *raid_device; - unsigned long flags; - Mpi2RaidVolPage0_t vol_pg0; - Mpi2ConfigReply_t mpi_reply; - u32 volume_status_flags; - u8 percent_complete; - u16 handle; - - percent_complete = 0; - handle = 0; - if (ioc->is_warpdrive) - goto out; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, - sdev->channel); - if (raid_device) { - handle = raid_device->handle; - percent_complete = raid_device->percent_complete; - } - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - - if (!handle) - goto out; - - if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, - MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, - sizeof(Mpi2RaidVolPage0_t))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - percent_complete = 0; - goto out; - } - - volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags); - if (!(volume_status_flags & - MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS)) - percent_complete = 0; - - out: - raid_set_resync(mpt2sas_raid_template, dev, percent_complete); -} - -/** - * _scsih_get_state - get raid volume level - * @dev the device struct object - */ -static void -_scsih_get_state(struct device *dev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); - static struct _raid_device *raid_device; - unsigned long flags; - Mpi2RaidVolPage0_t vol_pg0; - Mpi2ConfigReply_t mpi_reply; - u32 volstate; - enum raid_state state = RAID_STATE_UNKNOWN; - u16 handle = 0; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, - sdev->channel); - if (raid_device) - handle = raid_device->handle; - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - - if (!raid_device) - goto out; - - if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, - MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, - sizeof(Mpi2RaidVolPage0_t))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags); - if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) { - state = RAID_STATE_RESYNCING; - goto out; - } - - switch (vol_pg0.VolumeState) { - case MPI2_RAID_VOL_STATE_OPTIMAL: - case MPI2_RAID_VOL_STATE_ONLINE: - state = RAID_STATE_ACTIVE; - break; - case MPI2_RAID_VOL_STATE_DEGRADED: - state = RAID_STATE_DEGRADED; - break; - case MPI2_RAID_VOL_STATE_FAILED: - case MPI2_RAID_VOL_STATE_MISSING: - state = RAID_STATE_OFFLINE; - break; - } - out: - raid_set_state(mpt2sas_raid_template, dev, state); -} - -/** - * _scsih_set_level - set raid level - * @sdev: scsi device struct - * @volume_type: volume type - */ -static void -_scsih_set_level(struct scsi_device *sdev, u8 volume_type) -{ - enum raid_level level = RAID_LEVEL_UNKNOWN; - - switch (volume_type) { - case MPI2_RAID_VOL_TYPE_RAID0: - level = RAID_LEVEL_0; - break; - case MPI2_RAID_VOL_TYPE_RAID10: - level = RAID_LEVEL_10; - break; - case MPI2_RAID_VOL_TYPE_RAID1E: - level = RAID_LEVEL_1E; - break; - case MPI2_RAID_VOL_TYPE_RAID1: - level = RAID_LEVEL_1; - break; - } - - raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level); -} - -/** - * _scsih_get_volume_capabilities - volume capabilities - * @ioc: per adapter object - * @sas_device: the raid_device object - * - * Returns 0 for success, else 1 - */ -static int -_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc, - struct _raid_device *raid_device) -{ - Mpi2RaidVolPage0_t *vol_pg0; - Mpi2RaidPhysDiskPage0_t pd_pg0; - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 sz; - u8 num_pds; - - if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, - &num_pds)) || !num_pds) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); - return 1; - } - - raid_device->num_pds = num_pds; - sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * - sizeof(Mpi2RaidVol0PhysDisk_t)); - vol_pg0 = kzalloc(sz, GFP_KERNEL); - if (!vol_pg0) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); - return 1; - } - - if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, - MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); - kfree(vol_pg0); - return 1; - } - - raid_device->volume_type = vol_pg0->VolumeType; - - /* figure out what the underlying devices are by - * obtaining the device_info bits for the 1st device - */ - if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, - &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, - vol_pg0->PhysDisk[0].PhysDiskNum))) { - if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, - &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, - le16_to_cpu(pd_pg0.DevHandle)))) { - raid_device->device_info = - le32_to_cpu(sas_device_pg0.DeviceInfo); - } - } - - kfree(vol_pg0); - return 0; -} -/** - * _scsih_disable_ddio - Disable direct I/O for all the volumes - * @ioc: per adapter object - */ -static void -_scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2RaidVolPage1_t vol_pg1; - Mpi2ConfigReply_t mpi_reply; - struct _raid_device *raid_device; - u16 handle; - u16 ioc_status; - unsigned long flags; - - handle = 0xFFFF; - while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - handle = le16_to_cpu(vol_pg1.DevHandle); - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - if (raid_device) - raid_device->direct_io_enabled = 0; - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - } - return; -} - - -/** - * _scsih_get_num_volumes - Get number of volumes in the ioc - * @ioc: per adapter object - */ -static u8 -_scsih_get_num_volumes(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2RaidVolPage1_t vol_pg1; - Mpi2ConfigReply_t mpi_reply; - u16 handle; - u8 vol_cnt = 0; - u16 ioc_status; - - handle = 0xFFFF; - while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - vol_cnt++; - handle = le16_to_cpu(vol_pg1.DevHandle); - } - return vol_cnt; -} - - -/** - * _scsih_init_warpdrive_properties - Set properties for warpdrive direct I/O. - * @ioc: per adapter object - * @raid_device: the raid_device object - */ -static void -_scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc, - struct _raid_device *raid_device) -{ - Mpi2RaidVolPage0_t *vol_pg0; - Mpi2RaidPhysDiskPage0_t pd_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 sz; - u8 num_pds, count; - unsigned long stripe_sz, block_sz; - u8 stripe_exp, block_exp; - u64 dev_max_lba; - - if (!ioc->is_warpdrive) - return; - - if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "globally as drives are exposed\n", ioc->name); - return; - } - if (_scsih_get_num_volumes(ioc) > 1) { - _scsih_disable_ddio(ioc); - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "globally as number of drives > 1\n", ioc->name); - return; - } - if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, - &num_pds)) || !num_pds) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "Failure in computing number of drives\n", ioc->name); - return; - } - - sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * - sizeof(Mpi2RaidVol0PhysDisk_t)); - vol_pg0 = kzalloc(sz, GFP_KERNEL); - if (!vol_pg0) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "Memory allocation failure for RVPG0\n", ioc->name); - return; - } - - if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, - MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "Failure in retrieving RVPG0\n", ioc->name); - kfree(vol_pg0); - return; - } - - /* - * WARPDRIVE:If number of physical disks in a volume exceeds the max pds - * assumed for WARPDRIVE, disable direct I/O - */ - if (num_pds > MPT_MAX_WARPDRIVE_PDS) { - printk(MPT2SAS_WARN_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x): num_mem=%d, " - "max_mem_allowed=%d\n", ioc->name, raid_device->handle, - num_pds, MPT_MAX_WARPDRIVE_PDS); - kfree(vol_pg0); - return; - } - for (count = 0; count < num_pds; count++) { - if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, - &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, - vol_pg0->PhysDisk[count].PhysDiskNum) || - le16_to_cpu(pd_pg0.DevHandle) == - MPT2SAS_INVALID_DEVICE_HANDLE) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is " - "disabled for the drive with handle(0x%04x) member" - "handle retrieval failed for member number=%d\n", - ioc->name, raid_device->handle, - vol_pg0->PhysDisk[count].PhysDiskNum); - goto out_error; - } - /* Disable direct I/O if member drive lba exceeds 4 bytes */ - dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA); - if (dev_max_lba >> 32) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is " - "disabled for the drive with handle(0x%04x) member" - "handle (0x%04x) unsupported max lba 0x%016llx\n", - ioc->name, raid_device->handle, - le16_to_cpu(pd_pg0.DevHandle), - (unsigned long long)dev_max_lba); - goto out_error; - } - - raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle); - } - - /* - * Assumption for WD: Direct I/O is not supported if the volume is - * not RAID0 - */ - if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x): type=%d, " - "s_sz=%uK, blk_size=%u\n", ioc->name, - raid_device->handle, raid_device->volume_type, - (le32_to_cpu(vol_pg0->StripeSize) * - le16_to_cpu(vol_pg0->BlockSize)) / 1024, - le16_to_cpu(vol_pg0->BlockSize)); - goto out_error; - } - - stripe_sz = le32_to_cpu(vol_pg0->StripeSize); - stripe_exp = find_first_bit(&stripe_sz, 32); - if (stripe_exp == 32) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x) invalid stripe sz %uK\n", - ioc->name, raid_device->handle, - (le32_to_cpu(vol_pg0->StripeSize) * - le16_to_cpu(vol_pg0->BlockSize)) / 1024); - goto out_error; - } - raid_device->stripe_exponent = stripe_exp; - block_sz = le16_to_cpu(vol_pg0->BlockSize); - block_exp = find_first_bit(&block_sz, 16); - if (block_exp == 16) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x) invalid block sz %u\n", - ioc->name, raid_device->handle, - le16_to_cpu(vol_pg0->BlockSize)); - goto out_error; - } - raid_device->block_exponent = block_exp; - raid_device->direct_io_enabled = 1; - - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is Enabled for the drive" - " with handle(0x%04x)\n", ioc->name, raid_device->handle); - /* - * WARPDRIVE: Though the following fields are not used for direct IO, - * stored for future purpose: - */ - raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA); - raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize); - raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize); - - - kfree(vol_pg0); - return; - -out_error: - raid_device->direct_io_enabled = 0; - for (count = 0; count < num_pds; count++) - raid_device->pd_handle[count] = 0; - kfree(vol_pg0); - return; -} - -/** - * _scsih_enable_tlr - setting TLR flags - * @ioc: per adapter object - * @sdev: scsi device struct - * - * Enabling Transaction Layer Retries for tape devices when - * vpd page 0x90 is present - * - */ -static void -_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev) -{ - /* only for TAPE */ - if (sdev->type != TYPE_TAPE) - return; - - if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)) - return; - - sas_enable_tlr(sdev); - sdev_printk(KERN_INFO, sdev, "TLR %s\n", - sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled"); - return; - -} - -/** - * _scsih_slave_configure - device configure routine. - * @sdev: scsi device struct - * - * Returns 0 if ok. Any other return is assumed to be an error and - * the device is ignored. - */ -static int -_scsih_slave_configure(struct scsi_device *sdev) -{ - struct Scsi_Host *shost = sdev->host; - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct _sas_device *sas_device; - struct _raid_device *raid_device; - unsigned long flags; - int qdepth; - u8 ssp_target = 0; - char *ds = ""; - char *r_level = ""; - u16 handle, volume_handle = 0; - u64 volume_wwid = 0; - - qdepth = 1; - sas_device_priv_data = sdev->hostdata; - sas_device_priv_data->configured_lun = 1; - sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT; - sas_target_priv_data = sas_device_priv_data->sas_target; - handle = sas_target_priv_data->handle; - - /* raid volume handling */ - if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) { - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - if (!raid_device) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, - __LINE__, __func__)); - return 1; - } - - if (_scsih_get_volume_capabilities(ioc, raid_device)) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, - __LINE__, __func__)); - return 1; - } - /* - * WARPDRIVE: Initialize the required data for Direct IO - */ - _scsih_init_warpdrive_properties(ioc, raid_device); - - /* RAID Queue Depth Support - * IS volume = underlying qdepth of drive type, either - * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH - * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH) - */ - if (raid_device->device_info & - MPI2_SAS_DEVICE_INFO_SSP_TARGET) { - qdepth = MPT2SAS_SAS_QUEUE_DEPTH; - ds = "SSP"; - } else { - qdepth = MPT2SAS_SATA_QUEUE_DEPTH; - if (raid_device->device_info & - MPI2_SAS_DEVICE_INFO_SATA_DEVICE) - ds = "SATA"; - else - ds = "STP"; - } - - switch (raid_device->volume_type) { - case MPI2_RAID_VOL_TYPE_RAID0: - r_level = "RAID0"; - break; - case MPI2_RAID_VOL_TYPE_RAID1E: - qdepth = MPT2SAS_RAID_QUEUE_DEPTH; - if (ioc->manu_pg10.OEMIdentifier && - (le32_to_cpu(ioc->manu_pg10.GenericFlags0) & - MFG10_GF0_R10_DISPLAY) && - !(raid_device->num_pds % 2)) - r_level = "RAID10"; - else - r_level = "RAID1E"; - break; - case MPI2_RAID_VOL_TYPE_RAID1: - qdepth = MPT2SAS_RAID_QUEUE_DEPTH; - r_level = "RAID1"; - break; - case MPI2_RAID_VOL_TYPE_RAID10: - qdepth = MPT2SAS_RAID_QUEUE_DEPTH; - r_level = "RAID10"; - break; - case MPI2_RAID_VOL_TYPE_UNKNOWN: - default: - qdepth = MPT2SAS_RAID_QUEUE_DEPTH; - r_level = "RAIDX"; - break; - } - - if (!ioc->hide_ir_msg) - sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " - "wwid(0x%016llx), pd_count(%d), type(%s)\n", - r_level, raid_device->handle, - (unsigned long long)raid_device->wwid, - raid_device->num_pds, ds); - _scsih_change_queue_depth(sdev, qdepth); - /* raid transport support */ - if (!ioc->is_warpdrive) - _scsih_set_level(sdev, raid_device->volume_type); - return 0; - } - - /* non-raid handling */ - if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { - if (mpt2sas_config_get_volume_handle(ioc, handle, - &volume_handle)) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__)); - return 1; - } - if (volume_handle && mpt2sas_config_get_volume_wwid(ioc, - volume_handle, &volume_wwid)) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__)); - return 1; - } - } - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - sas_device_priv_data->sas_target->sas_address); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, - __LINE__, __func__)); - return 1; - } - sas_device->volume_handle = volume_handle; - sas_device->volume_wwid = volume_wwid; - if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) { - qdepth = MPT2SAS_SAS_QUEUE_DEPTH; - ssp_target = 1; - ds = "SSP"; - } else { - qdepth = MPT2SAS_SATA_QUEUE_DEPTH; - if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) - ds = "STP"; - else if (sas_device->device_info & - MPI2_SAS_DEVICE_INFO_SATA_DEVICE) - ds = "SATA"; - } - sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " - "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n", - ds, sas_device->handle, - (unsigned long long)sas_device->sas_address, - sas_device->phy, - (unsigned long long)sas_device->device_name); - sdev_printk(KERN_INFO, sdev, "%s: " - "enclosure_logical_id(0x%016llx), slot(%d)\n", ds, - (unsigned long long) sas_device->enclosure_logical_id, - sas_device->slot); - - sas_device_put(sas_device); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!ssp_target) - _scsih_display_sata_capabilities(ioc, handle, sdev); - - _scsih_change_queue_depth(sdev, qdepth); - - if (ssp_target) { - sas_read_port_mode_page(sdev); - _scsih_enable_tlr(ioc, sdev); - } - - return 0; -} - -/** - * _scsih_bios_param - fetch head, sector, cylinder info for a disk - * @sdev: scsi device struct - * @bdev: pointer to block device context - * @capacity: device size (in 512 byte sectors) - * @params: three element array to place output: - * params[0] number of heads (max 255) - * params[1] number of sectors (max 63) - * params[2] number of cylinders - * - * Return nothing. - */ -static int -_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int params[]) -{ - int heads; - int sectors; - sector_t cylinders; - ulong dummy; - - heads = 64; - sectors = 32; - - dummy = heads * sectors; - cylinders = capacity; - sector_div(cylinders, dummy); - - /* - * Handle extended translation size for logical drives - * > 1Gb - */ - if ((ulong)capacity >= 0x200000) { - heads = 255; - sectors = 63; - dummy = heads * sectors; - cylinders = capacity; - sector_div(cylinders, dummy); - } - - /* return result */ - params[0] = heads; - params[1] = sectors; - params[2] = cylinders; - - return 0; -} - -/** - * _scsih_response_code - translation of device response code - * @ioc: per adapter object - * @response_code: response code returned by the device - * - * Return nothing. - */ -static void -_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code) -{ - char *desc; - - switch (response_code) { - case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: - desc = "task management request completed"; - break; - case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: - desc = "invalid frame"; - break; - case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: - desc = "task management request not supported"; - break; - case MPI2_SCSITASKMGMT_RSP_TM_FAILED: - desc = "task management request failed"; - break; - case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: - desc = "task management request succeeded"; - break; - case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: - desc = "invalid lun"; - break; - case 0xA: - desc = "overlapped tag attempted"; - break; - case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: - desc = "task queued, however not sent to target"; - break; - default: - desc = "unknown"; - break; - } - printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n", - ioc->name, response_code, desc); -} - -/** - * _scsih_tm_done - tm completion routine - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: none. - * - * The callback handler when using scsih_issue_tm. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - - if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->tm_cmds.smid != smid) - return 1; - mpt2sas_base_flush_reply_queues(ioc); - ioc->tm_cmds.status |= MPT2_CMD_COMPLETE; - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (mpi_reply) { - memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); - ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID; - } - ioc->tm_cmds.status &= ~MPT2_CMD_PENDING; - complete(&ioc->tm_cmds.done); - return 1; -} - -/** - * mpt2sas_scsih_set_tm_flag - set per target tm_busy - * @ioc: per adapter object - * @handle: device handle - * - * During taskmangement request, we need to freeze the device queue. - */ -void -mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - u8 skip = 0; - - shost_for_each_device(sdev, ioc->shost) { - if (skip) - continue; - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (sas_device_priv_data->sas_target->handle == handle) { - sas_device_priv_data->sas_target->tm_busy = 1; - skip = 1; - ioc->ignore_loginfos = 1; - } - } -} - -/** - * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy - * @ioc: per adapter object - * @handle: device handle - * - * During taskmangement request, we need to freeze the device queue. - */ -void -mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - u8 skip = 0; - - shost_for_each_device(sdev, ioc->shost) { - if (skip) - continue; - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (sas_device_priv_data->sas_target->handle == handle) { - sas_device_priv_data->sas_target->tm_busy = 0; - skip = 1; - ioc->ignore_loginfos = 0; - } - } -} - - -/** - * mpt2sas_scsih_issue_tm - main routine for sending tm requests - * @ioc: per adapter struct - * @device_handle: device handle - * @channel: the channel assigned by the OS - * @id: the id assigned by the OS - * @lun: lun number - * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h) - * @smid_task: smid assigned to the task - * @timeout: timeout in seconds - * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF - * Context: user - * - * A generic API for sending task management requests to firmware. - * - * The callback index is set inside `ioc->tm_cb_idx`. - * - * Return SUCCESS or FAILED. - */ -int -mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, - uint id, uint lun, u8 type, u16 smid_task, ulong timeout, - enum mutex_type m_type) -{ - Mpi2SCSITaskManagementRequest_t *mpi_request; - Mpi2SCSITaskManagementReply_t *mpi_reply; - u16 smid = 0; - u32 ioc_state; - unsigned long timeleft; - struct scsiio_tracker *scsi_lookup = NULL; - int rc; - - if (m_type == TM_MUTEX_ON) - mutex_lock(&ioc->tm_cmds.mutex); - if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n", - __func__, ioc->name); - rc = FAILED; - goto err_out; - } - - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - rc = FAILED; - goto err_out; - } - - ioc_state = mpt2sas_base_get_iocstate(ioc, 0); - if (ioc_state & MPI2_DOORBELL_USED) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell " - "active!\n", ioc->name)); - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; - goto err_out; - } - - if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { - mpt2sas_base_fault_info(ioc, ioc_state & - MPI2_DOORBELL_DATA_MASK); - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; - goto err_out; - } - - smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = FAILED; - goto err_out; - } - - if (type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) - scsi_lookup = &ioc->scsi_lookup[smid_task - 1]; - - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x)," - " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, - smid_task)); - ioc->tm_cmds.status = MPT2_CMD_PENDING; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->tm_cmds.smid = smid; - memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); - memset(ioc->tm_cmds.reply, 0, sizeof(Mpi2SCSITaskManagementReply_t)); - mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; - mpi_request->DevHandle = cpu_to_le16(handle); - mpi_request->TaskType = type; - mpi_request->TaskMID = cpu_to_le16(smid_task); - int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN); - mpt2sas_scsih_set_tm_flag(ioc, handle); - init_completion(&ioc->tm_cmds.done); - mpt2sas_base_put_smid_hi_priority(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); - if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SCSITaskManagementRequest_t)/4); - if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) { - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - mpt2sas_scsih_clear_tm_flag(ioc, handle); - goto err_out; - } - } - - if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) { - mpi_reply = ioc->tm_cmds.reply; - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: " - "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo), - le32_to_cpu(mpi_reply->TerminationCount))); - if (ioc->logging_level & MPT_DEBUG_TM) { - _scsih_response_code(ioc, mpi_reply->ResponseCode); - if (mpi_reply->IOCStatus) - _debug_dump_mf(mpi_request, - sizeof(Mpi2SCSITaskManagementRequest_t)/4); - } - } - - switch (type) { - case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: - rc = SUCCESS; - if (scsi_lookup->scmd == NULL) - break; - rc = FAILED; - break; - - case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: - if (_scsih_scsi_lookup_find_by_target(ioc, id, channel)) - rc = FAILED; - else - rc = SUCCESS; - break; - - case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: - case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: - if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel)) - rc = FAILED; - else - rc = SUCCESS; - break; - case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK: - rc = SUCCESS; - break; - default: - rc = FAILED; - break; - } - - mpt2sas_scsih_clear_tm_flag(ioc, handle); - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - if (m_type == TM_MUTEX_ON) - mutex_unlock(&ioc->tm_cmds.mutex); - - return rc; - - err_out: - if (m_type == TM_MUTEX_ON) - mutex_unlock(&ioc->tm_cmds.mutex); - return rc; -} - -/** - * _scsih_tm_display_info - displays info about the device - * @ioc: per adapter struct - * @scmd: pointer to scsi command object - * - * Called by task management callback handlers. - */ -static void -_scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) -{ - struct scsi_target *starget = scmd->device->sdev_target; - struct MPT2SAS_TARGET *priv_target = starget->hostdata; - struct _sas_device *sas_device = NULL; - unsigned long flags; - char *device_str = NULL; - - if (!priv_target) - return; - if (ioc->hide_ir_msg) - device_str = "WarpDrive"; - else - device_str = "volume"; - - scsi_print_command(scmd); - if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { - starget_printk(KERN_INFO, starget, "%s handle(0x%04x), " - "%s wwid(0x%016llx)\n", device_str, priv_target->handle, - device_str, (unsigned long long)priv_target->sas_address); - } else { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_from_target(ioc, priv_target); - if (sas_device) { - if (priv_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) { - starget_printk(KERN_INFO, starget, - "volume handle(0x%04x), " - "volume wwid(0x%016llx)\n", - sas_device->volume_handle, - (unsigned long long)sas_device->volume_wwid); - } - starget_printk(KERN_INFO, starget, - "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n", - sas_device->handle, - (unsigned long long)sas_device->sas_address, - sas_device->phy); - starget_printk(KERN_INFO, starget, - "enclosure_logical_id(0x%016llx), slot(%d)\n", - (unsigned long long)sas_device->enclosure_logical_id, - sas_device->slot); - - sas_device_put(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } -} - -/** - * _scsih_abort - eh threads main abort routine - * @scmd: pointer to scsi command object - * - * Returns SUCCESS if command aborted else FAILED - */ -static int -_scsih_abort(struct scsi_cmnd *scmd) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); - struct MPT2SAS_DEVICE *sas_device_priv_data; - u16 smid; - u16 handle; - int r; - - sdev_printk(KERN_INFO, scmd->device, "attempting task abort! " - "scmd(%p)\n", scmd); - _scsih_tm_display_info(ioc, scmd); - - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - sdev_printk(KERN_INFO, scmd->device, "device been deleted! " - "scmd(%p)\n", scmd); - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - r = SUCCESS; - goto out; - } - - /* search for the command */ - smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd); - if (!smid) { - scmd->result = DID_RESET << 16; - r = SUCCESS; - goto out; - } - - /* for hidden raid components and volumes this is not supported */ - if (sas_device_priv_data->sas_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT || - sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) { - scmd->result = DID_RESET << 16; - r = FAILED; - goto out; - } - - mpt2sas_halt_firmware(ioc); - - handle = sas_device_priv_data->sas_target->handle; - r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, - scmd->device->id, scmd->device->lun, - MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, TM_MUTEX_ON); - - out: - sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", - ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); - return r; -} - -/** - * _scsih_dev_reset - eh threads main device reset routine - * @scmd: pointer to scsi command object - * - * Returns SUCCESS if command aborted else FAILED - */ -static int -_scsih_dev_reset(struct scsi_cmnd *scmd) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct _sas_device *sas_device = NULL; - u16 handle; - int r; - - struct scsi_target *starget = scmd->device->sdev_target; - struct MPT2SAS_TARGET *target_priv_data = starget->hostdata; - - starget_printk(KERN_INFO, starget, "attempting device reset! " - "scmd(%p)\n", scmd); - _scsih_tm_display_info(ioc, scmd); - - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - starget_printk(KERN_INFO, starget, "device been deleted! " - "scmd(%p)\n", scmd); - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - r = SUCCESS; - goto out; - } - - /* for hidden raid components obtain the volume_handle */ - handle = 0; - if (sas_device_priv_data->sas_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) { - sas_device = mpt2sas_get_sdev_from_target(ioc, - target_priv_data); - if (sas_device) - handle = sas_device->volume_handle; - } else - handle = sas_device_priv_data->sas_target->handle; - - if (!handle) { - scmd->result = DID_RESET << 16; - r = FAILED; - goto out; - } - - r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, - scmd->device->id, scmd->device->lun, - MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, TM_MUTEX_ON); - - out: - sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", - ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); - - if (sas_device) - sas_device_put(sas_device); - - return r; -} - -/** - * _scsih_target_reset - eh threads main target reset routine - * @scmd: pointer to scsi command object - * - * Returns SUCCESS if command aborted else FAILED - */ -static int -_scsih_target_reset(struct scsi_cmnd *scmd) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct _sas_device *sas_device = NULL; - u16 handle; - int r; - struct scsi_target *starget = scmd->device->sdev_target; - struct MPT2SAS_TARGET *target_priv_data = starget->hostdata; - - starget_printk(KERN_INFO, starget, "attempting target reset! " - "scmd(%p)\n", scmd); - _scsih_tm_display_info(ioc, scmd); - - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - starget_printk(KERN_INFO, starget, "target been deleted! " - "scmd(%p)\n", scmd); - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - r = SUCCESS; - goto out; - } - - /* for hidden raid components obtain the volume_handle */ - handle = 0; - if (sas_device_priv_data->sas_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) { - sas_device = mpt2sas_get_sdev_from_target(ioc, - target_priv_data); - if (sas_device) - handle = sas_device->volume_handle; - } else - handle = sas_device_priv_data->sas_target->handle; - - if (!handle) { - scmd->result = DID_RESET << 16; - r = FAILED; - goto out; - } - - r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, - scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, - 30, TM_MUTEX_ON); - - out: - starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", - ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); - - if (sas_device) - sas_device_put(sas_device); - - return r; -} - -/** - * _scsih_host_reset - eh threads main host reset routine - * @scmd: pointer to scsi command object - * - * Returns SUCCESS if command aborted else FAILED - */ -static int -_scsih_host_reset(struct scsi_cmnd *scmd) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); - int r, retval; - - printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n", - ioc->name, scmd); - scsi_print_command(scmd); - - if (ioc->is_driver_loading) { - printk(MPT2SAS_INFO_FMT "Blocking the host reset\n", - ioc->name); - r = FAILED; - goto out; - } - - retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - r = (retval < 0) ? FAILED : SUCCESS; - - out: - printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n", - ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); - - return r; -} - -/** - * _scsih_fw_event_add - insert and queue up fw_event - * @ioc: per adapter object - * @fw_event: object describing the event - * Context: This function will acquire ioc->fw_event_lock. - * - * This adds the firmware event object into link list, then queues it up to - * be processed from user context. - * - * Return nothing. - */ -static void -_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event) -{ - unsigned long flags; - - if (ioc->firmware_event_thread == NULL) - return; - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - fw_event_work_get(fw_event); - list_add_tail(&fw_event->list, &ioc->fw_event_list); - INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work); - fw_event_work_get(fw_event); - queue_delayed_work(ioc->firmware_event_thread, - &fw_event->delayed_work, 0); - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -} - -/** - * _scsih_fw_event_del_from_list - delete fw_event from the list - * @ioc: per adapter object - * @fw_event: object describing the event - * Context: This function will acquire ioc->fw_event_lock. - * - * If the fw_event is on the fw_event_list, remove it and do a put. - * - * Return nothing. - */ -static void -_scsih_fw_event_del_from_list(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work - *fw_event) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - if (!list_empty(&fw_event->list)) { - list_del_init(&fw_event->list); - fw_event_work_put(fw_event); - } - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -} - -/** - * _scsih_error_recovery_delete_devices - remove devices not responding - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_scsih_error_recovery_delete_devices(struct MPT2SAS_ADAPTER *ioc) -{ - struct fw_event_work *fw_event; - - if (ioc->is_driver_loading) - return; - - fw_event = alloc_fw_event_work(0); - if (!fw_event) - return; - - fw_event->event = MPT2SAS_REMOVE_UNRESPONDING_DEVICES; - fw_event->ioc = ioc; - _scsih_fw_event_add(ioc, fw_event); - fw_event_work_put(fw_event); -} - -/** - * mpt2sas_port_enable_complete - port enable completed (fake event) - * @ioc: per adapter object - * - * Return nothing. - */ -void -mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc) -{ - struct fw_event_work *fw_event; - - fw_event = alloc_fw_event_work(0); - if (!fw_event) - return; - fw_event->event = MPT2SAS_PORT_ENABLE_COMPLETE; - fw_event->ioc = ioc; - _scsih_fw_event_add(ioc, fw_event); - fw_event_work_put(fw_event); -} - -static struct fw_event_work *dequeue_next_fw_event(struct MPT2SAS_ADAPTER *ioc) -{ - unsigned long flags; - struct fw_event_work *fw_event = NULL; - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - if (!list_empty(&ioc->fw_event_list)) { - fw_event = list_first_entry(&ioc->fw_event_list, - struct fw_event_work, list); - list_del_init(&fw_event->list); - } - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); - - return fw_event; -} - -/** - * _scsih_fw_event_cleanup_queue - cleanup event queue - * @ioc: per adapter object - * - * Walk the firmware event queue, either killing timers, or waiting - * for outstanding events to complete - * - * Return nothing. - */ -static void -_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc) -{ - struct fw_event_work *fw_event; - - if (list_empty(&ioc->fw_event_list) || - !ioc->firmware_event_thread || in_interrupt()) - return; - - while ((fw_event = dequeue_next_fw_event(ioc))) { - /* - * Wait on the fw_event to complete. If this returns 1, then - * the event was never executed, and we need a put for the - * reference the delayed_work had on the fw_event. - * - * If it did execute, we wait for it to finish, and the put will - * happen from _firmware_event_work() - */ - if (cancel_delayed_work_sync(&fw_event->delayed_work)) - fw_event_work_put(fw_event); - - fw_event_work_put(fw_event); - } -} - -/** - * _scsih_ublock_io_all_device - unblock every device - * @ioc: per adapter object - * - * change the device state from block to running - */ -static void -_scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (!sas_device_priv_data->block) - continue; - sas_device_priv_data->block = 0; - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, " - "handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle)); - scsi_internal_device_unblock(sdev, SDEV_RUNNING); - } -} -/** - * _scsih_ublock_io_device - set the device state to SDEV_RUNNING - * @ioc: per adapter object - * @handle: device handle - * - * During device pull we need to appropiately set the sdev state. - */ -static void -_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (!sas_device_priv_data->block) - continue; - if (sas_device_priv_data->sas_target->sas_address == - sas_address) { - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, - MPT2SAS_INFO_FMT "SDEV_RUNNING: " - "sas address(0x%016llx)\n", ioc->name, - (unsigned long long)sas_address)); - sas_device_priv_data->block = 0; - scsi_internal_device_unblock(sdev, SDEV_RUNNING); - } - } -} - -/** - * _scsih_block_io_all_device - set the device state to SDEV_BLOCK - * @ioc: per adapter object - * @handle: device handle - * - * During device pull we need to appropiately set the sdev state. - */ -static void -_scsih_block_io_all_device(struct MPT2SAS_ADAPTER *ioc) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (sas_device_priv_data->block) - continue; - sas_device_priv_data->block = 1; - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_blocked, " - "handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle)); - scsi_internal_device_block(sdev); - } -} - - -/** - * _scsih_block_io_device - set the device state to SDEV_BLOCK - * @ioc: per adapter object - * @handle: device handle - * - * During device pull we need to appropiately set the sdev state. - */ -static void -_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (sas_device_priv_data->block) - continue; - if (sas_device_priv_data->sas_target->handle == handle) { - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, - MPT2SAS_INFO_FMT "SDEV_BLOCK: " - "handle(0x%04x)\n", ioc->name, handle)); - sas_device_priv_data->block = 1; - scsi_internal_device_block(sdev); - } - } -} - -/** - * _scsih_block_io_to_children_attached_to_ex - * @ioc: per adapter object - * @sas_expander: the sas_device object - * - * This routine set sdev state to SDEV_BLOCK for all devices - * attached to this expander. This function called when expander is - * pulled. - */ -static void -_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_expander) -{ - struct _sas_port *mpt2sas_port; - struct _sas_device *sas_device; - struct _sas_node *expander_sibling; - unsigned long flags; - - if (!sas_expander) - return; - - list_for_each_entry(mpt2sas_port, - &sas_expander->sas_port_list, port_list) { - if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - mpt2sas_port->remote_identify.sas_address); - if (sas_device) { - set_bit(sas_device->handle, - ioc->blocking_handles); - sas_device_put(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } - } - - list_for_each_entry(mpt2sas_port, - &sas_expander->sas_port_list, port_list) { - - if (mpt2sas_port->remote_identify.device_type == - SAS_EDGE_EXPANDER_DEVICE || - mpt2sas_port->remote_identify.device_type == - SAS_FANOUT_EXPANDER_DEVICE) { - expander_sibling = - mpt2sas_scsih_expander_find_by_sas_address( - ioc, mpt2sas_port->remote_identify.sas_address); - _scsih_block_io_to_children_attached_to_ex(ioc, - expander_sibling); - } - } -} - -/** - * _scsih_block_io_to_children_attached_directly - * @ioc: per adapter object - * @event_data: topology change event data - * - * This routine set sdev state to SDEV_BLOCK for all devices - * direct attached during device pull. - */ -static void -_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataSasTopologyChangeList_t *event_data) -{ - int i; - u16 handle; - u16 reason_code; - u8 phy_number; - - for (i = 0; i < event_data->NumEntries; i++) { - handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); - if (!handle) - continue; - phy_number = event_data->StartPhyNum + i; - reason_code = event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_RC_MASK; - if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING) - _scsih_block_io_device(ioc, handle); - } -} - -/** - * _scsih_tm_tr_send - send task management request - * @ioc: per adapter object - * @handle: device handle - * Context: interrupt time. - * - * This code is to initiate the device removal handshake protocol - * with controller firmware. This function will issue target reset - * using high priority request queue. It will send a sas iounit - * control request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion. - * - * This is designed to send muliple task management request at the same - * time to the fifo. If the fifo is full, we will append the request, - * and process it in a future completion. - */ -static void -_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - Mpi2SCSITaskManagementRequest_t *mpi_request; - u16 smid; - struct _sas_device *sas_device = NULL; - struct MPT2SAS_TARGET *sas_target_priv_data = NULL; - u64 sas_address = 0; - unsigned long flags; - struct _tr_list *delayed_tr; - u32 ioc_state; - - if (ioc->remove_host) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been " - "removed: handle(0x%04x)\n", __func__, ioc->name, handle)); - return; - } else if (ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci " - "error recovery: handle(0x%04x)\n", __func__, ioc->name, - handle)); - return; - } - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not " - "operational: handle(0x%04x)\n", __func__, ioc->name, - handle)); - return; - } - - /* if PD, then return */ - if (test_bit(handle, ioc->pd_handles)) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device && sas_device->starget && - sas_device->starget->hostdata) { - sas_target_priv_data = sas_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - sas_address = sas_device->sas_address; - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (sas_target_priv_data) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "setting delete flag: " - "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, handle, - (unsigned long long)sas_address)); - _scsih_ublock_io_device(ioc, sas_address); - sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE; - } - - smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx); - if (!smid) { - delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); - if (!delayed_tr) - goto out; - INIT_LIST_HEAD(&delayed_tr->list); - delayed_tr->handle = handle; - list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "DELAYED:tr:handle(0x%04x), (open)\n", - ioc->name, handle)); - goto out; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), " - "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid, - ioc->tm_tr_cb_idx)); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; - mpi_request->DevHandle = cpu_to_le16(handle); - mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; - mpt2sas_base_put_smid_hi_priority(ioc, smid); -out: - if (sas_device) - sas_device_put(sas_device); -} - - - -/** - * _scsih_sas_control_complete - completion routine - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: interrupt time. - * - * This is the sas iounit control completion routine. - * This code is part of the code to initiate the device removal - * handshake protocol with controller firmware. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u8 msix_index, u32 reply) -{ - Mpi2SasIoUnitControlReply_t *mpi_reply = - mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (likely(mpi_reply)) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "sc_complete:handle(0x%04x), (open) " - "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid, - le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo))); - } else { - printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - } - return 1; -} - -/** - * _scsih_tm_tr_volume_send - send target reset request for volumes - * @ioc: per adapter object - * @handle: device handle - * Context: interrupt time. - * - * This is designed to send muliple task management request at the same - * time to the fifo. If the fifo is full, we will append the request, - * and process it in a future completion. - */ -static void -_scsih_tm_tr_volume_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - Mpi2SCSITaskManagementRequest_t *mpi_request; - u16 smid; - struct _tr_list *delayed_tr; - - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " - "progress!\n", __func__, ioc->name)); - return; - } - - smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx); - if (!smid) { - delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); - if (!delayed_tr) - return; - INIT_LIST_HEAD(&delayed_tr->list); - delayed_tr->handle = handle; - list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "DELAYED:tr:handle(0x%04x), (open)\n", - ioc->name, handle)); - return; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), " - "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid, - ioc->tm_tr_volume_cb_idx)); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; - mpi_request->DevHandle = cpu_to_le16(handle); - mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; - mpt2sas_base_put_smid_hi_priority(ioc, smid); -} - -/** - * _scsih_tm_volume_tr_complete - target reset completion - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: interrupt time. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u8 msix_index, u32 reply) -{ - u16 handle; - Mpi2SCSITaskManagementRequest_t *mpi_request_tm; - Mpi2SCSITaskManagementReply_t *mpi_reply = - mpt2sas_base_get_reply_virt_addr(ioc, reply); - - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " - "progress!\n", __func__, ioc->name)); - return 1; - } - if (unlikely(!mpi_reply)) { - printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return 1; - } - mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); - handle = le16_to_cpu(mpi_request_tm->DevHandle); - if (handle != le16_to_cpu(mpi_reply->DevHandle)) { - dewtprintk(ioc, printk("spurious interrupt: " - "handle(0x%04x:0x%04x), smid(%d)!!!\n", handle, - le16_to_cpu(mpi_reply->DevHandle), smid)); - return 0; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " - "loginfo(0x%08x), completed(%d)\n", ioc->name, - handle, smid, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo), - le32_to_cpu(mpi_reply->TerminationCount))); - - return _scsih_check_for_pending_tm(ioc, smid); -} - -/** - * _scsih_tm_tr_complete - - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: interrupt time. - * - * This is the target reset completion routine. - * This code is part of the code to initiate the device removal - * handshake protocol with controller firmware. - * It will send a sas iounit control request (MPI2_SAS_OP_REMOVE_DEVICE) - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - u16 handle; - Mpi2SCSITaskManagementRequest_t *mpi_request_tm; - Mpi2SCSITaskManagementReply_t *mpi_reply = - mpt2sas_base_get_reply_virt_addr(ioc, reply); - Mpi2SasIoUnitControlRequest_t *mpi_request; - u16 smid_sas_ctrl; - u32 ioc_state; - - if (ioc->remove_host) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been " - "removed\n", __func__, ioc->name)); - return 1; - } else if (ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci " - "error recovery\n", __func__, ioc->name)); - return 1; - } - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not " - "operational\n", __func__, ioc->name)); - return 1; - } - if (unlikely(!mpi_reply)) { - printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return 1; - } - mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); - handle = le16_to_cpu(mpi_request_tm->DevHandle); - if (handle != le16_to_cpu(mpi_reply->DevHandle)) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: " - "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle, - le16_to_cpu(mpi_reply->DevHandle), smid)); - return 0; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " - "loginfo(0x%08x), completed(%d)\n", ioc->name, - handle, smid, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo), - le32_to_cpu(mpi_reply->TerminationCount))); - - smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx); - if (!smid_sas_ctrl) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - return 1; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), " - "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl, - ioc->tm_sas_control_cb_idx)); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl); - memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; - mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; - mpi_request->DevHandle = mpi_request_tm->DevHandle; - mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl); - - return _scsih_check_for_pending_tm(ioc, smid); -} - -/** - * _scsih_check_for_pending_tm - check for pending task management - * @ioc: per adapter object - * @smid: system request message index - * - * This will check delayed target reset list, and feed the - * next reqeust. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - struct _tr_list *delayed_tr; - - if (!list_empty(&ioc->delayed_tr_volume_list)) { - delayed_tr = list_entry(ioc->delayed_tr_volume_list.next, - struct _tr_list, list); - mpt2sas_base_free_smid(ioc, smid); - _scsih_tm_tr_volume_send(ioc, delayed_tr->handle); - list_del(&delayed_tr->list); - kfree(delayed_tr); - return 0; - } - - if (!list_empty(&ioc->delayed_tr_list)) { - delayed_tr = list_entry(ioc->delayed_tr_list.next, - struct _tr_list, list); - mpt2sas_base_free_smid(ioc, smid); - _scsih_tm_tr_send(ioc, delayed_tr->handle); - list_del(&delayed_tr->list); - kfree(delayed_tr); - return 0; - } - - return 1; -} - -/** - * _scsih_check_topo_delete_events - sanity check on topo events - * @ioc: per adapter object - * @event_data: the event data payload - * - * This routine added to better handle cable breaker. - * - * This handles the case where driver receives multiple expander - * add and delete events in a single shot. When there is a delete event - * the routine will void any pending add events waiting in the event queue. - * - * Return nothing. - */ -static void -_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataSasTopologyChangeList_t *event_data) -{ - struct fw_event_work *fw_event; - Mpi2EventDataSasTopologyChangeList_t *local_event_data; - u16 expander_handle; - struct _sas_node *sas_expander; - unsigned long flags; - int i, reason_code; - u16 handle; - - for (i = 0 ; i < event_data->NumEntries; i++) { - handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); - if (!handle) - continue; - reason_code = event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_RC_MASK; - if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING) - _scsih_tm_tr_send(ioc, handle); - } - - expander_handle = le16_to_cpu(event_data->ExpanderDevHandle); - if (expander_handle < ioc->sas_hba.num_phys) { - _scsih_block_io_to_children_attached_directly(ioc, event_data); - return; - } - if (event_data->ExpStatus == - MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING) { - /* put expander attached devices into blocking state */ - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, - expander_handle); - _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - do { - handle = find_first_bit(ioc->blocking_handles, - ioc->facts.MaxDevHandle); - if (handle < ioc->facts.MaxDevHandle) - _scsih_block_io_device(ioc, handle); - } while (test_and_clear_bit(handle, ioc->blocking_handles)); - } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING) - _scsih_block_io_to_children_attached_directly(ioc, event_data); - - if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) - return; - - /* mark ignore flag for pending events */ - spin_lock_irqsave(&ioc->fw_event_lock, flags); - list_for_each_entry(fw_event, &ioc->fw_event_list, list) { - if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST || - fw_event->ignore) - continue; - local_event_data = (Mpi2EventDataSasTopologyChangeList_t *) - fw_event->event_data; - if (local_event_data->ExpStatus == - MPI2_EVENT_SAS_TOPO_ES_ADDED || - local_event_data->ExpStatus == - MPI2_EVENT_SAS_TOPO_ES_RESPONDING) { - if (le16_to_cpu(local_event_data->ExpanderDevHandle) == - expander_handle) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "setting ignoring flag\n", ioc->name)); - fw_event->ignore = 1; - } - } - } - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -} - -/** - * _scsih_set_volume_delete_flag - setting volume delete flag - * @ioc: per adapter object - * @handle: device handle - * - * This - * Return nothing. - */ -static void -_scsih_set_volume_delete_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _raid_device *raid_device; - struct MPT2SAS_TARGET *sas_target_priv_data; - unsigned long flags; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - if (raid_device && raid_device->starget && - raid_device->starget->hostdata) { - sas_target_priv_data = - raid_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "setting delete flag: handle(0x%04x), " - "wwid(0x%016llx)\n", ioc->name, handle, - (unsigned long long) raid_device->wwid)); - } - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -} - -/** - * _scsih_set_volume_handle_for_tr - set handle for target reset to volume - * @handle: input handle - * @a: handle for volume a - * @b: handle for volume b - * - * IR firmware only supports two raid volumes. The purpose of this - * routine is to set the volume handle in either a or b. When the given - * input handle is non-zero, or when a and b have not been set before. - */ -static void -_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b) -{ - if (!handle || handle == *a || handle == *b) - return; - if (!*a) - *a = handle; - else if (!*b) - *b = handle; -} - -/** - * _scsih_check_ir_config_unhide_events - check for UNHIDE events - * @ioc: per adapter object - * @event_data: the event data payload - * Context: interrupt time. - * - * This routine will send target reset to volume, followed by target - * resets to the PDs. This is called when a PD has been removed, or - * volume has been deleted or removed. When the target reset is sent - * to volume, the PD target resets need to be queued to start upon - * completion of the volume target reset. - * - * Return nothing. - */ -static void -_scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataIrConfigChangeList_t *event_data) -{ - Mpi2EventIrConfigElement_t *element; - int i; - u16 handle, volume_handle, a, b; - struct _tr_list *delayed_tr; - - a = 0; - b = 0; - - if (ioc->is_warpdrive) - return; - - /* Volume Resets for Deleted or Removed */ - element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - for (i = 0; i < event_data->NumElements; i++, element++) { - if (element->ReasonCode == - MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED || - element->ReasonCode == - MPI2_EVENT_IR_CHANGE_RC_REMOVED) { - volume_handle = le16_to_cpu(element->VolDevHandle); - _scsih_set_volume_delete_flag(ioc, volume_handle); - _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); - } - } - - /* Volume Resets for UNHIDE events */ - element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - for (i = 0; i < event_data->NumElements; i++, element++) { - if (le32_to_cpu(event_data->Flags) & - MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) - continue; - if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) { - volume_handle = le16_to_cpu(element->VolDevHandle); - _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); - } - } - - if (a) - _scsih_tm_tr_volume_send(ioc, a); - if (b) - _scsih_tm_tr_volume_send(ioc, b); - - /* PD target resets */ - element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - for (i = 0; i < event_data->NumElements; i++, element++) { - if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE) - continue; - handle = le16_to_cpu(element->PhysDiskDevHandle); - volume_handle = le16_to_cpu(element->VolDevHandle); - clear_bit(handle, ioc->pd_handles); - if (!volume_handle) - _scsih_tm_tr_send(ioc, handle); - else if (volume_handle == a || volume_handle == b) { - delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); - BUG_ON(!delayed_tr); - INIT_LIST_HEAD(&delayed_tr->list); - delayed_tr->handle = handle; - list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name, - handle)); - } else - _scsih_tm_tr_send(ioc, handle); - } -} - - -/** - * _scsih_check_volume_delete_events - set delete flag for volumes - * @ioc: per adapter object - * @event_data: the event data payload - * Context: interrupt time. - * - * This will handle the case when the cable connected to entire volume is - * pulled. We will take care of setting the deleted flag so normal IO will - * not be sent. - * - * Return nothing. - */ -static void -_scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataIrVolume_t *event_data) -{ - u32 state; - - if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) - return; - state = le32_to_cpu(event_data->NewValue); - if (state == MPI2_RAID_VOL_STATE_MISSING || state == - MPI2_RAID_VOL_STATE_FAILED) - _scsih_set_volume_delete_flag(ioc, - le16_to_cpu(event_data->VolDevHandle)); -} - -/** - * _scsih_temp_threshold_events - display temperature threshold exceeded events - * @ioc: per adapter object - * @event_data: the temp threshold event data - * Context: interrupt time. - * - * Return nothing. - */ -static void -_scsih_temp_threshold_events(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataTemperature_t *event_data) -{ - if (ioc->temp_sensors_count >= event_data->SensorNum) { - printk(MPT2SAS_ERR_FMT "Temperature Threshold flags %s%s%s%s" - " exceeded for Sensor: %d !!!\n", ioc->name, - ((le16_to_cpu(event_data->Status) & 0x1) == 1) ? "0 " : " ", - ((le16_to_cpu(event_data->Status) & 0x2) == 2) ? "1 " : " ", - ((le16_to_cpu(event_data->Status) & 0x4) == 4) ? "2 " : " ", - ((le16_to_cpu(event_data->Status) & 0x8) == 8) ? "3 " : " ", - event_data->SensorNum); - printk(MPT2SAS_ERR_FMT "Current Temp In Celsius: %d\n", - ioc->name, event_data->CurrentTemperature); - } -} - -/** - * _scsih_flush_running_cmds - completing outstanding commands. - * @ioc: per adapter object - * - * The flushing out of all pending scmd commands following host reset, - * where all IO is dropped to the floor. - * - * Return nothing. - */ -static void -_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc) -{ - struct scsi_cmnd *scmd; - u16 smid; - u16 count = 0; - - for (smid = 1; smid <= ioc->scsiio_depth; smid++) { - scmd = _scsih_scsi_lookup_get_clear(ioc, smid); - if (!scmd) - continue; - count++; - mpt2sas_base_free_smid(ioc, smid); - scsi_dma_unmap(scmd); - if (ioc->pci_error_recovery) - scmd->result = DID_NO_CONNECT << 16; - else - scmd->result = DID_RESET << 16; - scmd->scsi_done(scmd); - } - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n", - ioc->name, count)); -} - -/** - * _scsih_setup_eedp - setup MPI request for EEDP transfer - * @scmd: pointer to scsi command object - * @mpi_request: pointer to the SCSI_IO reqest message frame - * - * Supporting protection 1 and 3. - * - * Returns nothing - */ -static void -_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request) -{ - u16 eedp_flags; - unsigned char prot_op = scsi_get_prot_op(scmd); - unsigned char prot_type = scsi_get_prot_type(scmd); - - if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL) - return; - - if (prot_op == SCSI_PROT_READ_STRIP) - eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP; - else if (prot_op == SCSI_PROT_WRITE_INSERT) - eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP; - else - return; - - switch (prot_type) { - case SCSI_PROT_DIF_TYPE1: - case SCSI_PROT_DIF_TYPE2: - - /* - * enable ref/guard checking - * auto increment ref tag - */ - eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | - MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | - MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; - mpi_request->CDB.EEDP32.PrimaryReferenceTag = - cpu_to_be32(scsi_get_lba(scmd)); - break; - - case SCSI_PROT_DIF_TYPE3: - - /* - * enable guard checking - */ - eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; - break; - } - mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size); - mpi_request->EEDPFlags = cpu_to_le16(eedp_flags); -} - -/** - * _scsih_eedp_error_handling - return sense code for EEDP errors - * @scmd: pointer to scsi command object - * @ioc_status: ioc status - * - * Returns nothing - */ -static void -_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) -{ - u8 ascq; - - switch (ioc_status) { - case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: - ascq = 0x01; - break; - case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: - ascq = 0x02; - break; - case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: - ascq = 0x03; - break; - default: - ascq = 0x00; - break; - } - - scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 0x10, ascq); - scmd->result = DRIVER_SENSE << 24 | (DID_ABORT << 16) | - SAM_STAT_CHECK_CONDITION; -} - -/** - * _scsih_scsi_direct_io_get - returns direct io flag - * @ioc: per adapter object - * @smid: system request message index - * - * Returns the smid stored scmd pointer. - */ -static inline u8 -_scsih_scsi_direct_io_get(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return ioc->scsi_lookup[smid - 1].direct_io; -} - -/** - * _scsih_scsi_direct_io_set - sets direct io flag - * @ioc: per adapter object - * @smid: system request message index - * @direct_io: Zero or non-zero value to set in the direct_io flag - * - * Returns Nothing. - */ -static inline void -_scsih_scsi_direct_io_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 direct_io) -{ - ioc->scsi_lookup[smid - 1].direct_io = direct_io; -} - - -/** - * _scsih_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O - * @ioc: per adapter object - * @scmd: pointer to scsi command object - * @raid_device: pointer to raid device data structure - * @mpi_request: pointer to the SCSI_IO reqest message frame - * @smid: system request message index - * - * Returns nothing - */ -static void -_scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, - struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, - u16 smid) -{ - sector_t v_lba, p_lba, stripe_off, column, io_size; - u32 stripe_sz, stripe_exp; - u8 num_pds, cmd = scmd->cmnd[0]; - - if (cmd != READ_10 && cmd != WRITE_10 && - cmd != READ_16 && cmd != WRITE_16) - return; - - if (cmd == READ_10 || cmd == WRITE_10) - v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]); - else - v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]); - - io_size = scsi_bufflen(scmd) >> raid_device->block_exponent; - - if (v_lba + io_size - 1 > raid_device->max_lba) - return; - - stripe_sz = raid_device->stripe_sz; - stripe_exp = raid_device->stripe_exponent; - stripe_off = v_lba & (stripe_sz - 1); - - /* Return unless IO falls within a stripe */ - if (stripe_off + io_size > stripe_sz) - return; - - num_pds = raid_device->num_pds; - p_lba = v_lba >> stripe_exp; - column = sector_div(p_lba, num_pds); - p_lba = (p_lba << stripe_exp) + stripe_off; - - mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]); - - if (cmd == READ_10 || cmd == WRITE_10) - put_unaligned_be32(lower_32_bits(p_lba), - &mpi_request->CDB.CDB32[2]); - else - put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]); - - _scsih_scsi_direct_io_set(ioc, smid, 1); -} - -/** - * _scsih_qcmd - main scsi request entry point - * @scmd: pointer to scsi command object - * @done: function pointer to be invoked on completion - * - * The callback index is set inside `ioc->scsi_io_cb_idx`. - * - * Returns 0 on success. If there's a failure, return either: - * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or - * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full - */ -static int -_scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct _raid_device *raid_device; - Mpi2SCSIIORequest_t *mpi_request; - u32 mpi_control; - u16 smid; - - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - return 0; - } - - if (ioc->pci_error_recovery || ioc->remove_host) { - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - return 0; - } - - sas_target_priv_data = sas_device_priv_data->sas_target; - /* invalid device handle */ - if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) { - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - return 0; - } - - /* host recovery or link resets sent via IOCTLs */ - if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress) - return SCSI_MLQUEUE_HOST_BUSY; - /* device busy with task management */ - else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy) - return SCSI_MLQUEUE_DEVICE_BUSY; - /* device has been deleted */ - else if (sas_target_priv_data->deleted) { - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - return 0; - } - - if (scmd->sc_data_direction == DMA_FROM_DEVICE) - mpi_control = MPI2_SCSIIO_CONTROL_READ; - else if (scmd->sc_data_direction == DMA_TO_DEVICE) - mpi_control = MPI2_SCSIIO_CONTROL_WRITE; - else - mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; - - /* set tags */ - mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; - - /* Make sure Device is not raid volume. - * We do not expose raid functionality to upper layer for warpdrive. - */ - if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) && - sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32) - mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; - - smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - goto out; - } - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t)); - _scsih_setup_eedp(scmd, mpi_request); - if (scmd->cmd_len == 32) - mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT; - mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; - if (sas_device_priv_data->sas_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) - mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; - else - mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; - mpi_request->DevHandle = - cpu_to_le16(sas_device_priv_data->sas_target->handle); - mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); - mpi_request->Control = cpu_to_le32(mpi_control); - mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len); - mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR; - mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; - mpi_request->SenseBufferLowAddress = - mpt2sas_base_get_sense_buffer_dma(ioc, smid); - mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4; - mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI + - MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR); - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *) - mpi_request->LUN); - memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); - - if (!mpi_request->DataLength) { - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL); - } else { - if (_scsih_build_scatter_gather(ioc, scmd, smid)) { - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - } - - raid_device = sas_target_priv_data->raid_device; - if (raid_device && raid_device->direct_io_enabled) - _scsih_setup_direct_io(ioc, scmd, raid_device, mpi_request, - smid); - - if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) - mpt2sas_base_put_smid_scsi_io(ioc, smid, - le16_to_cpu(mpi_request->DevHandle)); - else - mpt2sas_base_put_smid_default(ioc, smid); - return 0; - - out: - return SCSI_MLQUEUE_HOST_BUSY; -} - -/** - * _scsih_normalize_sense - normalize descriptor and fixed format sense data - * @sense_buffer: sense data returned by target - * @data: normalized skey/asc/ascq - * - * Return nothing. - */ -static void -_scsih_normalize_sense(char *sense_buffer, struct sense_info *data) -{ - if ((sense_buffer[0] & 0x7F) >= 0x72) { - /* descriptor format */ - data->skey = sense_buffer[1] & 0x0F; - data->asc = sense_buffer[2]; - data->ascq = sense_buffer[3]; - } else { - /* fixed format */ - data->skey = sense_buffer[2] & 0x0F; - data->asc = sense_buffer[12]; - data->ascq = sense_buffer[13]; - } -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _scsih_scsi_ioc_info - translated non-successful SCSI_IO request - * @ioc: per adapter object - * @scmd: pointer to scsi command object - * @mpi_reply: reply mf payload returned from firmware - * - * scsi_status - SCSI Status code returned from target device - * scsi_state - state info associated with SCSI_IO determined by ioc - * ioc_status - ioc supplied status info - * - * Return nothing. - */ -static void -_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, - Mpi2SCSIIOReply_t *mpi_reply, u16 smid) -{ - u32 response_info; - u8 *response_bytes; - u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & - MPI2_IOCSTATUS_MASK; - u8 scsi_state = mpi_reply->SCSIState; - u8 scsi_status = mpi_reply->SCSIStatus; - char *desc_ioc_state = NULL; - char *desc_scsi_status = NULL; - char *desc_scsi_state = ioc->tmp_string; - u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo); - struct _sas_device *sas_device = NULL; - struct scsi_target *starget = scmd->device->sdev_target; - struct MPT2SAS_TARGET *priv_target = starget->hostdata; - char *device_str = NULL; - - if (!priv_target) - return; - - if (ioc->hide_ir_msg) - device_str = "WarpDrive"; - else - device_str = "volume"; - - if (log_info == 0x31170000) - return; - - switch (ioc_status) { - case MPI2_IOCSTATUS_SUCCESS: - desc_ioc_state = "success"; - break; - case MPI2_IOCSTATUS_INVALID_FUNCTION: - desc_ioc_state = "invalid function"; - break; - case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: - desc_ioc_state = "scsi recovered error"; - break; - case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: - desc_ioc_state = "scsi invalid dev handle"; - break; - case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: - desc_ioc_state = "scsi device not there"; - break; - case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: - desc_ioc_state = "scsi data overrun"; - break; - case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: - desc_ioc_state = "scsi data underrun"; - break; - case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: - desc_ioc_state = "scsi io data error"; - break; - case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: - desc_ioc_state = "scsi protocol error"; - break; - case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: - desc_ioc_state = "scsi task terminated"; - break; - case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: - desc_ioc_state = "scsi residual mismatch"; - break; - case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: - desc_ioc_state = "scsi task mgmt failed"; - break; - case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: - desc_ioc_state = "scsi ioc terminated"; - break; - case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: - desc_ioc_state = "scsi ext terminated"; - break; - case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: - desc_ioc_state = "eedp guard error"; - break; - case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: - desc_ioc_state = "eedp ref tag error"; - break; - case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: - desc_ioc_state = "eedp app tag error"; - break; - default: - desc_ioc_state = "unknown"; - break; - } - - switch (scsi_status) { - case MPI2_SCSI_STATUS_GOOD: - desc_scsi_status = "good"; - break; - case MPI2_SCSI_STATUS_CHECK_CONDITION: - desc_scsi_status = "check condition"; - break; - case MPI2_SCSI_STATUS_CONDITION_MET: - desc_scsi_status = "condition met"; - break; - case MPI2_SCSI_STATUS_BUSY: - desc_scsi_status = "busy"; - break; - case MPI2_SCSI_STATUS_INTERMEDIATE: - desc_scsi_status = "intermediate"; - break; - case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET: - desc_scsi_status = "intermediate condmet"; - break; - case MPI2_SCSI_STATUS_RESERVATION_CONFLICT: - desc_scsi_status = "reservation conflict"; - break; - case MPI2_SCSI_STATUS_COMMAND_TERMINATED: - desc_scsi_status = "command terminated"; - break; - case MPI2_SCSI_STATUS_TASK_SET_FULL: - desc_scsi_status = "task set full"; - break; - case MPI2_SCSI_STATUS_ACA_ACTIVE: - desc_scsi_status = "aca active"; - break; - case MPI2_SCSI_STATUS_TASK_ABORTED: - desc_scsi_status = "task aborted"; - break; - default: - desc_scsi_status = "unknown"; - break; - } - - desc_scsi_state[0] = '\0'; - if (!scsi_state) - desc_scsi_state = " "; - if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) - strcat(desc_scsi_state, "response info "); - if (scsi_state & MPI2_SCSI_STATE_TERMINATED) - strcat(desc_scsi_state, "state terminated "); - if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS) - strcat(desc_scsi_state, "no status "); - if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED) - strcat(desc_scsi_state, "autosense failed "); - if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) - strcat(desc_scsi_state, "autosense valid "); - - scsi_print_command(scmd); - - if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { - printk(MPT2SAS_WARN_FMT "\t%s wwid(0x%016llx)\n", ioc->name, - device_str, (unsigned long long)priv_target->sas_address); - } else { - sas_device = mpt2sas_get_sdev_from_target(ioc, priv_target); - if (sas_device) { - printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), " - "phy(%d)\n", ioc->name, sas_device->sas_address, - sas_device->phy); - printk(MPT2SAS_WARN_FMT - "\tenclosure_logical_id(0x%016llx), slot(%d)\n", - ioc->name, sas_device->enclosure_logical_id, - sas_device->slot); - - sas_device_put(sas_device); - } - } - - printk(MPT2SAS_WARN_FMT "\thandle(0x%04x), ioc_status(%s)(0x%04x), " - "smid(%d)\n", ioc->name, le16_to_cpu(mpi_reply->DevHandle), - desc_ioc_state, ioc_status, smid); - printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), " - "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow, - scsi_get_resid(scmd)); - printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), " - "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag), - le32_to_cpu(mpi_reply->TransferCount), scmd->result); - printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), " - "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status, - scsi_status, desc_scsi_state, scsi_state); - - if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { - struct sense_info data; - _scsih_normalize_sense(scmd->sense_buffer, &data); - printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: " - "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey, - data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount)); - } - - if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { - response_info = le32_to_cpu(mpi_reply->ResponseInfo); - response_bytes = (u8 *)&response_info; - _scsih_response_code(ioc, response_bytes[0]); - } -} -#endif - -/** - * _scsih_turn_on_pfa_led - illuminate PFA LED - * @ioc: per adapter object - * @handle: device handle - * Context: process - * - * Return nothing. - */ -static void -_scsih_turn_on_pfa_led(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - Mpi2SepReply_t mpi_reply; - Mpi2SepRequest_t mpi_request; - struct _sas_device *sas_device; - - sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); - if (!sas_device) - return; - - memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t)); - mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; - mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; - mpi_request.SlotStatus = - cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); - mpi_request.DevHandle = cpu_to_le16(handle); - mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS; - if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, - &mpi_request)) != 0) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); - goto out; - } - sas_device->pfa_led_on = 1; - - - if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo))); - goto out; - } -out: - sas_device_put(sas_device); -} - -/** - * _scsih_turn_off_pfa_led - turn off PFA LED - * @ioc: per adapter object - * @sas_device: sas device whose PFA LED has to turned off - * Context: process - * - * Return nothing. - */ -static void -_scsih_turn_off_pfa_led(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - Mpi2SepReply_t mpi_reply; - Mpi2SepRequest_t mpi_request; - - memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t)); - mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; - mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; - mpi_request.SlotStatus = 0; - mpi_request.Slot = cpu_to_le16(sas_device->slot); - mpi_request.DevHandle = 0; - mpi_request.EnclosureHandle = cpu_to_le16(sas_device->enclosure_handle); - mpi_request.Flags = MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS; - if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, - &mpi_request)) != 0) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); - return; - } - - if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "enclosure_processor: " - "ioc_status (0x%04x), loginfo(0x%08x)\n", ioc->name, - le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo))); - return; - } -} - -/** - * _scsih_send_event_to_turn_on_pfa_led - fire delayed event - * @ioc: per adapter object - * @handle: device handle - * Context: interrupt. - * - * Return nothing. - */ -static void -_scsih_send_event_to_turn_on_pfa_led(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct fw_event_work *fw_event; - - fw_event = alloc_fw_event_work(0); - if (!fw_event) - return; - fw_event->event = MPT2SAS_TURN_ON_PFA_LED; - fw_event->device_handle = handle; - fw_event->ioc = ioc; - _scsih_fw_event_add(ioc, fw_event); - fw_event_work_put(fw_event); -} - -/** - * _scsih_smart_predicted_fault - process smart errors - * @ioc: per adapter object - * @handle: device handle - * Context: interrupt. - * - * Return nothing. - */ -static void -_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct scsi_target *starget; - struct MPT2SAS_TARGET *sas_target_priv_data; - Mpi2EventNotificationReply_t *event_reply; - Mpi2EventDataSasDeviceStatusChange_t *event_data; - struct _sas_device *sas_device; - ssize_t sz; - unsigned long flags; - - /* only handle non-raid devices */ - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); - if (!sas_device) { - goto out_unlock; - } - starget = sas_device->starget; - sas_target_priv_data = starget->hostdata; - - if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) || - ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) - goto out_unlock; - - starget_printk(KERN_WARNING, starget, "predicted fault\n"); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) - _scsih_send_event_to_turn_on_pfa_led(ioc, handle); - - /* insert into event log */ - sz = offsetof(Mpi2EventNotificationReply_t, EventData) + - sizeof(Mpi2EventDataSasDeviceStatusChange_t); - event_reply = kzalloc(sz, GFP_ATOMIC); - if (!event_reply) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; - event_reply->Event = - cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); - event_reply->MsgLength = sz/4; - event_reply->EventDataLength = - cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4); - event_data = (Mpi2EventDataSasDeviceStatusChange_t *) - event_reply->EventData; - event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA; - event_data->ASC = 0x5D; - event_data->DevHandle = cpu_to_le16(handle); - event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address); - mpt2sas_ctl_add_to_event_log(ioc, event_reply); - kfree(event_reply); -out: - if (sas_device) - sas_device_put(sas_device); - return; - -out_unlock: - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - goto out; -} - -/** - * _scsih_io_done - scsi request callback - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Callback handler when using _scsih_qcmd. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -{ - Mpi2SCSIIORequest_t *mpi_request; - Mpi2SCSIIOReply_t *mpi_reply; - struct scsi_cmnd *scmd; - u16 ioc_status; - u32 xfer_cnt; - u8 scsi_state; - u8 scsi_status; - u32 log_info; - struct MPT2SAS_DEVICE *sas_device_priv_data; - u32 response_code = 0; - unsigned long flags; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - scmd = _scsih_scsi_lookup_get_clear(ioc, smid); - if (scmd == NULL) - return 1; - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - - if (mpi_reply == NULL) { - scmd->result = DID_OK << 16; - goto out; - } - - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target || - sas_device_priv_data->sas_target->deleted) { - scmd->result = DID_NO_CONNECT << 16; - goto out; - } - ioc_status = le16_to_cpu(mpi_reply->IOCStatus); - /* - * WARPDRIVE: If direct_io is set then it is directIO, - * the failed direct I/O should be redirected to volume - */ - if (_scsih_scsi_direct_io_get(ioc, smid) && - ((ioc_status & MPI2_IOCSTATUS_MASK) - != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) { - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - ioc->scsi_lookup[smid - 1].scmd = scmd; - _scsih_scsi_direct_io_set(ioc, smid, 0); - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); - mpi_request->DevHandle = - cpu_to_le16(sas_device_priv_data->sas_target->handle); - mpt2sas_base_put_smid_scsi_io(ioc, smid, - sas_device_priv_data->sas_target->handle); - return 0; - } - - - /* turning off TLR */ - scsi_state = mpi_reply->SCSIState; - if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) - response_code = - le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; - if (!sas_device_priv_data->tlr_snoop_check) { - sas_device_priv_data->tlr_snoop_check++; - /* Make sure Device is not raid volume. - * We do not expose raid functionality to upper layer for warpdrive. - */ - if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) && - sas_is_tlr_enabled(scmd->device) && - response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) { - sas_disable_tlr(scmd->device); - sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n"); - } - } - - xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); - scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt); - if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) - log_info = le32_to_cpu(mpi_reply->IOCLogInfo); - else - log_info = 0; - ioc_status &= MPI2_IOCSTATUS_MASK; - scsi_status = mpi_reply->SCSIStatus; - - if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 && - (scsi_status == MPI2_SCSI_STATUS_BUSY || - scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT || - scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) { - ioc_status = MPI2_IOCSTATUS_SUCCESS; - } - - if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { - struct sense_info data; - const void *sense_data = mpt2sas_base_get_sense_buffer(ioc, - smid); - u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, - le32_to_cpu(mpi_reply->SenseCount)); - memcpy(scmd->sense_buffer, sense_data, sz); - _scsih_normalize_sense(scmd->sense_buffer, &data); - /* failure prediction threshold exceeded */ - if (data.asc == 0x5D) - _scsih_smart_predicted_fault(ioc, - le16_to_cpu(mpi_reply->DevHandle)); - } - - switch (ioc_status) { - case MPI2_IOCSTATUS_BUSY: - case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: - scmd->result = SAM_STAT_BUSY; - break; - - case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: - scmd->result = DID_NO_CONNECT << 16; - break; - - case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: - if (sas_device_priv_data->block) { - scmd->result = DID_TRANSPORT_DISRUPTED << 16; - goto out; - } - if (log_info == 0x32010081) { - scmd->result = DID_RESET << 16; - break; - } - scmd->result = DID_SOFT_ERROR << 16; - break; - case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: - case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: - scmd->result = DID_RESET << 16; - break; - - case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: - if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt)) - scmd->result = DID_SOFT_ERROR << 16; - else - scmd->result = (DID_OK << 16) | scsi_status; - break; - - case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: - scmd->result = (DID_OK << 16) | scsi_status; - - if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)) - break; - - if (xfer_cnt < scmd->underflow) { - if (scsi_status == SAM_STAT_BUSY) - scmd->result = SAM_STAT_BUSY; - else - scmd->result = DID_SOFT_ERROR << 16; - } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | - MPI2_SCSI_STATE_NO_SCSI_STATUS)) - scmd->result = DID_SOFT_ERROR << 16; - else if (scsi_state & MPI2_SCSI_STATE_TERMINATED) - scmd->result = DID_RESET << 16; - else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) { - mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID; - mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION; - scmd->result = (DRIVER_SENSE << 24) | - SAM_STAT_CHECK_CONDITION; - scmd->sense_buffer[0] = 0x70; - scmd->sense_buffer[2] = ILLEGAL_REQUEST; - scmd->sense_buffer[12] = 0x20; - scmd->sense_buffer[13] = 0; - } - break; - - case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: - scsi_set_resid(scmd, 0); - case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: - case MPI2_IOCSTATUS_SUCCESS: - scmd->result = (DID_OK << 16) | scsi_status; - if (response_code == - MPI2_SCSITASKMGMT_RSP_INVALID_FRAME || - (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | - MPI2_SCSI_STATE_NO_SCSI_STATUS))) - scmd->result = DID_SOFT_ERROR << 16; - else if (scsi_state & MPI2_SCSI_STATE_TERMINATED) - scmd->result = DID_RESET << 16; - break; - - case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: - case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: - case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: - _scsih_eedp_error_handling(scmd, ioc_status); - break; - case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: - case MPI2_IOCSTATUS_INVALID_FUNCTION: - case MPI2_IOCSTATUS_INVALID_SGL: - case MPI2_IOCSTATUS_INTERNAL_ERROR: - case MPI2_IOCSTATUS_INVALID_FIELD: - case MPI2_IOCSTATUS_INVALID_STATE: - case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: - case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: - default: - scmd->result = DID_SOFT_ERROR << 16; - break; - - } - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY)) - _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid); -#endif - - out: - scsi_dma_unmap(scmd); - scmd->scsi_done(scmd); - return 1; -} - -/** - * _scsih_sas_host_refresh - refreshing sas host object contents - * @ioc: per adapter object - * Context: user - * - * During port enable, fw will send topology events for every device. Its - * possible that the handles may change from the previous setting, so this - * code keeping handles updating if changed. - * - * Return nothing. - */ -static void -_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc) -{ - u16 sz; - u16 ioc_status; - int i; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; - u16 attached_handle; - u8 link_rate; - - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT - "updating handles for sas_host(0x%016llx)\n", - ioc->name, (unsigned long long)ioc->sas_hba.sas_address)); - - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys - * sizeof(Mpi2SasIOUnit0PhyData_t)); - sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); - if (!sas_iounit_pg0) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, - sas_iounit_pg0, sz)) != 0) - goto out; - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - goto out; - for (i = 0; i < ioc->sas_hba.num_phys ; i++) { - link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4; - if (i == 0) - ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> - PhyData[0].ControllerDevHandle); - ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; - attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i]. - AttachedDevHandle); - if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) - link_rate = MPI2_SAS_NEG_LINK_RATE_1_5; - mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address, - attached_handle, i, link_rate); - } - out: - kfree(sas_iounit_pg0); -} - -/** - * _scsih_sas_host_add - create sas host object - * @ioc: per adapter object - * - * Creating host side data object, stored in ioc->sas_hba - * - * Return nothing. - */ -static void -_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc) -{ - int i; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; - Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; - Mpi2SasPhyPage0_t phy_pg0; - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2SasEnclosurePage0_t enclosure_pg0; - u16 ioc_status; - u16 sz; - u16 device_missing_delay; - - mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys); - if (!ioc->sas_hba.num_phys) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - /* sas_iounit page 0 */ - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit0PhyData_t)); - sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); - if (!sas_iounit_pg0) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, - sas_iounit_pg0, sz))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - /* sas_iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); - sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); - if (!sas_iounit_pg1) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, - sas_iounit_pg1, sz))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - ioc->io_missing_delay = - le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay); - device_missing_delay = - le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay); - if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) - ioc->device_missing_delay = (device_missing_delay & - MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; - else - ioc->device_missing_delay = device_missing_delay & - MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; - - ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev; - ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys, - sizeof(struct _sas_phy), GFP_KERNEL); - if (!ioc->sas_hba.phy) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - for (i = 0; i < ioc->sas_hba.num_phys ; i++) { - if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, - i))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - if (i == 0) - ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> - PhyData[0].ControllerDevHandle); - ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; - ioc->sas_hba.phy[i].phy_id = i; - mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i], - phy_pg0, ioc->sas_hba.parent_dev); - } - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - ioc->sas_hba.enclosure_handle = - le16_to_cpu(sas_device_pg0.EnclosureHandle); - ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), " - "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle, - (unsigned long long) ioc->sas_hba.sas_address, - ioc->sas_hba.num_phys) ; - - if (ioc->sas_hba.enclosure_handle) { - if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply, - &enclosure_pg0, - MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, - ioc->sas_hba.enclosure_handle))) { - ioc->sas_hba.enclosure_logical_id = - le64_to_cpu(enclosure_pg0.EnclosureLogicalID); - } - } - - out: - kfree(sas_iounit_pg1); - kfree(sas_iounit_pg0); -} - -/** - * _scsih_expander_add - creating expander object - * @ioc: per adapter object - * @handle: expander handle - * - * Creating expander object, stored in ioc->sas_expander_list. - * - * Return 0 for success, else error. - */ -static int -_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_node *sas_expander; - Mpi2ConfigReply_t mpi_reply; - Mpi2ExpanderPage0_t expander_pg0; - Mpi2ExpanderPage1_t expander_pg1; - Mpi2SasEnclosurePage0_t enclosure_pg0; - u32 ioc_status; - u16 parent_handle; - u64 sas_address, sas_address_parent = 0; - int i; - unsigned long flags; - struct _sas_port *mpt2sas_port = NULL; - int rc = 0; - - if (!handle) - return -1; - - if (ioc->shost_recovery || ioc->pci_error_recovery) - return -1; - - if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, - MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - /* handle out of order topology events */ - parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle); - if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent) - != 0) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - if (sas_address_parent != ioc->sas_hba.sas_address) { - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, - sas_address_parent); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (!sas_expander) { - rc = _scsih_expander_add(ioc, parent_handle); - if (rc != 0) - return rc; - } - } - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_address = le64_to_cpu(expander_pg0.SASAddress); - sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, - sas_address); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - if (sas_expander) - return 0; - - sas_expander = kzalloc(sizeof(struct _sas_node), - GFP_KERNEL); - if (!sas_expander) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - sas_expander->handle = handle; - sas_expander->num_phys = expander_pg0.NumPhys; - sas_expander->sas_address_parent = sas_address_parent; - sas_expander->sas_address = sas_address; - - printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x)," - " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name, - handle, parent_handle, (unsigned long long) - sas_expander->sas_address, sas_expander->num_phys); - - if (!sas_expander->num_phys) - goto out_fail; - sas_expander->phy = kcalloc(sas_expander->num_phys, - sizeof(struct _sas_phy), GFP_KERNEL); - if (!sas_expander->phy) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -1; - goto out_fail; - } - - INIT_LIST_HEAD(&sas_expander->sas_port_list); - mpt2sas_port = mpt2sas_transport_port_add(ioc, handle, - sas_address_parent); - if (!mpt2sas_port) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -1; - goto out_fail; - } - sas_expander->parent_dev = &mpt2sas_port->rphy->dev; - - for (i = 0 ; i < sas_expander->num_phys ; i++) { - if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply, - &expander_pg1, i, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -1; - goto out_fail; - } - sas_expander->phy[i].handle = handle; - sas_expander->phy[i].phy_id = i; - - if ((mpt2sas_transport_add_expander_phy(ioc, - &sas_expander->phy[i], expander_pg1, - sas_expander->parent_dev))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -1; - goto out_fail; - } - } - - if (sas_expander->enclosure_handle) { - if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply, - &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, - sas_expander->enclosure_handle))) { - sas_expander->enclosure_logical_id = - le64_to_cpu(enclosure_pg0.EnclosureLogicalID); - } - } - - _scsih_expander_node_add(ioc, sas_expander); - return 0; - - out_fail: - - if (mpt2sas_port) - mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, - sas_address_parent); - kfree(sas_expander); - return rc; -} - -/** - * _scsih_done - scsih callback handler. - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Callback handler when sending internal generated message frames. - * The callback index passed is `ioc->scsih_cb_idx` - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->scsih_cmds.smid != smid) - return 1; - ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE; - if (mpi_reply) { - memcpy(ioc->scsih_cmds.reply, mpi_reply, - mpi_reply->MsgLength*4); - ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID; - } - ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING; - complete(&ioc->scsih_cmds.done); - return 1; -} - -/** - * mpt2sas_expander_remove - removing expander object - * @ioc: per adapter object - * @sas_address: expander sas_address - * - * Return nothing. - */ -void -mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) -{ - struct _sas_node *sas_expander; - unsigned long flags; - - if (ioc->shost_recovery) - return; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, - sas_address); - if (sas_expander) - list_del(&sas_expander->list); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (sas_expander) - _scsih_expander_node_remove(ioc, sas_expander); -} - -/** - * _scsih_check_access_status - check access flags - * @ioc: per adapter object - * @sas_address: sas address - * @handle: sas device handle - * @access_flags: errors returned during discovery of the device - * - * Return 0 for success, else failure - */ -static u8 -_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u16 handle, u8 access_status) -{ - u8 rc = 1; - char *desc = NULL; - - switch (access_status) { - case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS: - case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION: - rc = 0; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED: - desc = "sata capability failed"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT: - desc = "sata affiliation conflict"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE: - desc = "route not addressable"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE: - desc = "smp error not addressable"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED: - desc = "device blocked"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX: - desc = "sata initialization failed"; - break; - default: - desc = "unknown"; - break; - } - - if (!rc) - return 0; - - printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), " - "handle(0x%04x)\n", ioc->name, desc, - (unsigned long long)sas_address, handle); - return rc; -} - -static void -_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - struct _sas_device *sas_device; - u32 ioc_status; - unsigned long flags; - u64 sas_address; - struct scsi_target *starget; - struct MPT2SAS_TARGET *sas_target_priv_data; - u32 device_info; - - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) - return; - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - return; - - /* check if this is end device */ - device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); - if (!(_scsih_is_end_device(device_info))) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - sas_address); - - if (!sas_device) { - printk(MPT2SAS_ERR_FMT "device is not present " - "handle(0x%04x), no sas_device!!!\n", ioc->name, handle); - goto out_unlock; - } - - if (unlikely(sas_device->handle != handle)) { - starget = sas_device->starget; - sas_target_priv_data = starget->hostdata; - starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)" - " to (0x%04x)!!!\n", sas_device->handle, handle); - sas_target_priv_data->handle = handle; - sas_device->handle = handle; - } - - /* check if device is present */ - if (!(le16_to_cpu(sas_device_pg0.Flags) & - MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { - printk(MPT2SAS_ERR_FMT "device is not present " - "handle(0x%04x), flags!!!\n", ioc->name, handle); - goto out_unlock; - } - - /* check if there were any issues with discovery */ - if (_scsih_check_access_status(ioc, sas_address, handle, - sas_device_pg0.AccessStatus)) - goto out_unlock; - - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - _scsih_ublock_io_device(ioc, sas_address); - if (sas_device) - sas_device_put(sas_device); - return; - -out_unlock: - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) - sas_device_put(sas_device); -} - -/** - * _scsih_add_device - creating sas device object - * @ioc: per adapter object - * @handle: sas device handle - * @phy_num: phy number end device attached to - * @is_pd: is this hidden raid component - * - * Creating end device object, stored in ioc->sas_device_list. - * - * Returns 0 for success, non-zero for failure. - */ -static int -_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) -{ - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2SasEnclosurePage0_t enclosure_pg0; - struct _sas_device *sas_device; - u32 ioc_status; - __le64 sas_address; - u32 device_info; - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - - /* check if device is present */ - if (!(le16_to_cpu(sas_device_pg0.Flags) & - MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n", - ioc->name, le16_to_cpu(sas_device_pg0.Flags)); - return -1; - } - - /* check if there were any issues with discovery */ - if (_scsih_check_access_status(ioc, sas_address, handle, - sas_device_pg0.AccessStatus)) - return -1; - - /* check if this is end device */ - device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); - if (!(_scsih_is_end_device(device_info))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - sas_device = mpt2sas_get_sdev_by_addr(ioc, - sas_address); - - if (sas_device) { - sas_device_put(sas_device); - return 0; - } - - sas_device = kzalloc(sizeof(struct _sas_device), - GFP_KERNEL); - if (!sas_device) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - kref_init(&sas_device->refcount); - sas_device->handle = handle; - if (_scsih_get_sas_address(ioc, le16_to_cpu - (sas_device_pg0.ParentDevHandle), - &sas_device->sas_address_parent) != 0) - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - sas_device->enclosure_handle = - le16_to_cpu(sas_device_pg0.EnclosureHandle); - sas_device->slot = - le16_to_cpu(sas_device_pg0.Slot); - sas_device->device_info = device_info; - sas_device->sas_address = sas_address; - sas_device->phy = sas_device_pg0.PhyNum; - - /* get enclosure_logical_id */ - if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0( - ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, - sas_device->enclosure_handle))) - sas_device->enclosure_logical_id = - le64_to_cpu(enclosure_pg0.EnclosureLogicalID); - - /* get device name */ - sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName); - - if (ioc->wait_for_discovery_to_complete) - _scsih_sas_device_init_add(ioc, sas_device); - else - _scsih_sas_device_add(ioc, sas_device); - - sas_device_put(sas_device); - return 0; -} - -/** - * _scsih_remove_device - removing sas device object - * @ioc: per adapter object - * @sas_device_delete: the sas_device object - * - * Return nothing. - */ -static void -_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - struct MPT2SAS_TARGET *sas_target_priv_data; - - if ((ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) && - (sas_device->pfa_led_on)) { - _scsih_turn_off_pfa_led(ioc, sas_device); - sas_device->pfa_led_on = 0; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: " - "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device->handle, (unsigned long long) - sas_device->sas_address)); - - if (sas_device->starget && sas_device->starget->hostdata) { - sas_target_priv_data = sas_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - _scsih_ublock_io_device(ioc, sas_device->sas_address); - sas_target_priv_data->handle = - MPT2SAS_INVALID_DEVICE_HANDLE; - } - - if (!ioc->hide_drives) - mpt2sas_transport_port_remove(ioc, - sas_device->sas_address, - sas_device->sas_address_parent); - - printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" - "(0x%016llx)\n", ioc->name, sas_device->handle, - (unsigned long long) sas_device->sas_address); - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: " - "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device->handle, (unsigned long long) - sas_device->sas_address)); -} -/** - * _scsih_device_remove_by_handle - removing device object by handle - * @ioc: per adapter object - * @handle: device handle - * - * Return nothing. - */ -static void -_scsih_device_remove_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_device *sas_device; - unsigned long flags; - - if (ioc->shost_recovery) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device) { - list_del_init(&sas_device->list); - sas_device_put(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (sas_device) { - _scsih_remove_device(ioc, sas_device); - sas_device_put(sas_device); - } -} - -/** - * mpt2sas_device_remove_by_sas_address - removing device object by sas address - * @ioc: per adapter object - * @sas_address: device sas_address - * - * Return nothing. - */ -void -mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address) -{ - struct _sas_device *sas_device; - unsigned long flags; - - if (ioc->shost_recovery) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, sas_address); - if (sas_device) { - list_del_init(&sas_device->list); - sas_device_put(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (sas_device) { - _scsih_remove_device(ioc, sas_device); - sas_device_put(sas_device); - } -} -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _scsih_sas_topology_change_event_debug - debug for topology event - * @ioc: per adapter object - * @event_data: event data payload - * Context: user. - */ -static void -_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataSasTopologyChangeList_t *event_data) -{ - int i; - u16 handle; - u16 reason_code; - u8 phy_number; - char *status_str = NULL; - u8 link_rate, prev_link_rate; - - switch (event_data->ExpStatus) { - case MPI2_EVENT_SAS_TOPO_ES_ADDED: - status_str = "add"; - break; - case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING: - status_str = "remove"; - break; - case MPI2_EVENT_SAS_TOPO_ES_RESPONDING: - case 0: - status_str = "responding"; - break; - case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING: - status_str = "remove delay"; - break; - default: - status_str = "unknown status"; - break; - } - printk(MPT2SAS_INFO_FMT "sas topology change: (%s)\n", - ioc->name, status_str); - printk(KERN_INFO "\thandle(0x%04x), enclosure_handle(0x%04x) " - "start_phy(%02d), count(%d)\n", - le16_to_cpu(event_data->ExpanderDevHandle), - le16_to_cpu(event_data->EnclosureHandle), - event_data->StartPhyNum, event_data->NumEntries); - for (i = 0; i < event_data->NumEntries; i++) { - handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); - if (!handle) - continue; - phy_number = event_data->StartPhyNum + i; - reason_code = event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_RC_MASK; - switch (reason_code) { - case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: - status_str = "target add"; - break; - case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: - status_str = "target remove"; - break; - case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: - status_str = "delay target remove"; - break; - case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: - status_str = "link rate change"; - break; - case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: - status_str = "target responding"; - break; - default: - status_str = "unknown"; - break; - } - link_rate = event_data->PHY[i].LinkRate >> 4; - prev_link_rate = event_data->PHY[i].LinkRate & 0xF; - printk(KERN_INFO "\tphy(%02d), attached_handle(0x%04x): %s:" - " link rate: new(0x%02x), old(0x%02x)\n", phy_number, - handle, status_str, link_rate, prev_link_rate); - - } -} -#endif - -/** - * _scsih_sas_topology_change_event - handle topology changes - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - */ -static void -_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - int i; - u16 parent_handle, handle; - u16 reason_code; - u8 phy_number, max_phys; - struct _sas_node *sas_expander; - u64 sas_address; - unsigned long flags; - u8 link_rate, prev_link_rate; - Mpi2EventDataSasTopologyChangeList_t *event_data = - (Mpi2EventDataSasTopologyChangeList_t *) - fw_event->event_data; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - _scsih_sas_topology_change_event_debug(ioc, event_data); -#endif - - if (ioc->remove_host || ioc->pci_error_recovery) - return; - - if (!ioc->sas_hba.num_phys) - _scsih_sas_host_add(ioc); - else - _scsih_sas_host_refresh(ioc); - - if (fw_event->ignore) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring expander " - "event\n", ioc->name)); - return; - } - - parent_handle = le16_to_cpu(event_data->ExpanderDevHandle); - - /* handle expander add */ - if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED) - if (_scsih_expander_add(ioc, parent_handle) != 0) - return; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, - parent_handle); - if (sas_expander) { - sas_address = sas_expander->sas_address; - max_phys = sas_expander->num_phys; - } else if (parent_handle < ioc->sas_hba.num_phys) { - sas_address = ioc->sas_hba.sas_address; - max_phys = ioc->sas_hba.num_phys; - } else { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - /* handle siblings events */ - for (i = 0; i < event_data->NumEntries; i++) { - if (fw_event->ignore) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring " - "expander event\n", ioc->name)); - return; - } - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) - return; - phy_number = event_data->StartPhyNum + i; - if (phy_number >= max_phys) - continue; - reason_code = event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_RC_MASK; - if ((event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code != - MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) - continue; - handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); - if (!handle) - continue; - link_rate = event_data->PHY[i].LinkRate >> 4; - prev_link_rate = event_data->PHY[i].LinkRate & 0xF; - switch (reason_code) { - case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: - - if (ioc->shost_recovery) - break; - - if (link_rate == prev_link_rate) - break; - - mpt2sas_transport_update_links(ioc, sas_address, - handle, phy_number, link_rate); - - if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) - break; - - _scsih_check_device(ioc, handle); - break; - case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: - - if (ioc->shost_recovery) - break; - - mpt2sas_transport_update_links(ioc, sas_address, - handle, phy_number, link_rate); - - _scsih_add_device(ioc, handle, phy_number, 0); - break; - case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: - - _scsih_device_remove_by_handle(ioc, handle); - break; - } - } - - /* handle expander removal */ - if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING && - sas_expander) - mpt2sas_expander_remove(ioc, sas_address); - -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _scsih_sas_device_status_change_event_debug - debug for device event - * @event_data: event data payload - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataSasDeviceStatusChange_t *event_data) -{ - char *reason_str = NULL; - - switch (event_data->ReasonCode) { - case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA: - reason_str = "smart data"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: - reason_str = "unsupported device discovered"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: - reason_str = "internal device reset"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: - reason_str = "internal task abort"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: - reason_str = "internal task abort set"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: - reason_str = "internal clear task set"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: - reason_str = "internal query task"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE: - reason_str = "sata init failure"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET: - reason_str = "internal device reset complete"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL: - reason_str = "internal task abort complete"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION: - reason_str = "internal async notification"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY: - reason_str = "expander reduced functionality"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY: - reason_str = "expander reduced functionality complete"; - break; - default: - reason_str = "unknown reason"; - break; - } - printk(MPT2SAS_INFO_FMT "device status change: (%s)\n" - "\thandle(0x%04x), sas address(0x%016llx), tag(%d)", - ioc->name, reason_str, le16_to_cpu(event_data->DevHandle), - (unsigned long long)le64_to_cpu(event_data->SASAddress), - le16_to_cpu(event_data->TaskTag)); - if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA) - printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, - event_data->ASC, event_data->ASCQ); - printk(KERN_INFO "\n"); -} -#endif - -/** - * _scsih_sas_device_status_change_event - handle device status change - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - struct MPT2SAS_TARGET *target_priv_data; - struct _sas_device *sas_device; - u64 sas_address; - unsigned long flags; - Mpi2EventDataSasDeviceStatusChange_t *event_data = - (Mpi2EventDataSasDeviceStatusChange_t *) - fw_event->event_data; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - _scsih_sas_device_status_change_event_debug(ioc, - event_data); -#endif - - /* In MPI Revision K (0xC), the internal device reset complete was - * implemented, so avoid setting tm_busy flag for older firmware. - */ - if ((ioc->facts.HeaderVersion >> 8) < 0xC) - return; - - if (event_data->ReasonCode != - MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && - event_data->ReasonCode != - MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_address = le64_to_cpu(event_data->SASAddress); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - sas_address); - - if (!sas_device || !sas_device->starget) - goto out; - - target_priv_data = sas_device->starget->hostdata; - if (!target_priv_data) - goto out; - - if (event_data->ReasonCode == - MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET) - target_priv_data->tm_busy = 1; - else - target_priv_data->tm_busy = 0; - -out: - if (sas_device) - sas_device_put(sas_device); - - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event - * @ioc: per adapter object - * @event_data: event data payload - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataSasEnclDevStatusChange_t *event_data) -{ - char *reason_str = NULL; - - switch (event_data->ReasonCode) { - case MPI2_EVENT_SAS_ENCL_RC_ADDED: - reason_str = "enclosure add"; - break; - case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING: - reason_str = "enclosure remove"; - break; - default: - reason_str = "unknown reason"; - break; - } - - printk(MPT2SAS_INFO_FMT "enclosure status change: (%s)\n" - "\thandle(0x%04x), enclosure logical id(0x%016llx)" - " number slots(%d)\n", ioc->name, reason_str, - le16_to_cpu(event_data->EnclosureHandle), - (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID), - le16_to_cpu(event_data->StartSlot)); -} -#endif - -/** - * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - _scsih_sas_enclosure_dev_status_change_event_debug(ioc, - (Mpi2EventDataSasEnclDevStatusChange_t *) - fw_event->event_data); -#endif -} - -/** - * _scsih_sas_broadcast_primitive_event - handle broadcast events - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_broadcast_primitive_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - struct scsi_cmnd *scmd; - struct scsi_device *sdev; - u16 smid, handle; - u32 lun; - struct MPT2SAS_DEVICE *sas_device_priv_data; - u32 termination_count; - u32 query_count; - Mpi2SCSITaskManagementReply_t *mpi_reply; - Mpi2EventDataSasBroadcastPrimitive_t *event_data = - (Mpi2EventDataSasBroadcastPrimitive_t *) - fw_event->event_data; - u16 ioc_status; - unsigned long flags; - int r; - u8 max_retries = 0; - u8 task_abort_retries; - - mutex_lock(&ioc->tm_cmds.mutex); - pr_info(MPT2SAS_FMT - "%s: enter: phy number(%d), width(%d)\n", - ioc->name, __func__, event_data->PhyNum, - event_data->PortWidth); - - _scsih_block_io_all_device(ioc); - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - mpi_reply = ioc->tm_cmds.reply; -broadcast_aen_retry: - - /* sanity checks for retrying this loop */ - if (max_retries++ == 5) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: giving up\n", - ioc->name, __func__)); - goto out; - } else if (max_retries > 1) - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %d retry\n", - ioc->name, __func__, max_retries - 1)); - - termination_count = 0; - query_count = 0; - for (smid = 1; smid <= ioc->scsiio_depth; smid++) { - if (ioc->shost_recovery) - goto out; - scmd = _scsih_scsi_lookup_get(ioc, smid); - if (!scmd) - continue; - sdev = scmd->device; - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) - continue; - /* skip hidden raid components */ - if (sas_device_priv_data->sas_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) - continue; - /* skip volumes */ - if (sas_device_priv_data->sas_target->flags & - MPT_TARGET_FLAGS_VOLUME) - continue; - - handle = sas_device_priv_data->sas_target->handle; - lun = sas_device_priv_data->lun; - query_count++; - - if (ioc->shost_recovery) - goto out; - - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - r = mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, - MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, - TM_MUTEX_OFF); - if (r == FAILED) { - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: FAILED when sending " - "QUERY_TASK: scmd(%p)\n", scmd); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) - & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - sdev_printk(KERN_WARNING, sdev, "query task: FAILED " - "with IOCSTATUS(0x%04x), scmd(%p)\n", ioc_status, - scmd); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } - - /* see if IO is still owned by IOC and target */ - if (mpi_reply->ResponseCode == - MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED || - mpi_reply->ResponseCode == - MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC) { - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - continue; - } - task_abort_retries = 0; - tm_retry: - if (task_abort_retries++ == 60) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s: ABORT_TASK: giving up\n", ioc->name, - __func__)); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } - - if (ioc->shost_recovery) - goto out_no_lock; - - r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id, - sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, - TM_MUTEX_OFF); - if (r == FAILED) { - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: ABORT_TASK: FAILED : " - "scmd(%p)\n", scmd); - goto tm_retry; - } - - if (task_abort_retries > 1) - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: ABORT_TASK: RETRIES (%d):" - " scmd(%p)\n", - task_abort_retries - 1, scmd); - - termination_count += le32_to_cpu(mpi_reply->TerminationCount); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - } - - if (ioc->broadcast_aen_pending) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: loop back due to" - " pending AEN\n", ioc->name, __func__)); - ioc->broadcast_aen_pending = 0; - goto broadcast_aen_retry; - } - - out: - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - out_no_lock: - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s - exit, query_count = %d termination_count = %d\n", - ioc->name, __func__, query_count, termination_count)); - - ioc->broadcast_aen_busy = 0; - if (!ioc->shost_recovery) - _scsih_ublock_io_all_device(ioc); - mutex_unlock(&ioc->tm_cmds.mutex); -} - -/** - * _scsih_sas_discovery_event - handle discovery events - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - Mpi2EventDataSasDiscovery_t *event_data = - (Mpi2EventDataSasDiscovery_t *) - fw_event->event_data; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { - printk(MPT2SAS_INFO_FMT "discovery event: (%s)", ioc->name, - (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? - "start" : "stop"); - if (event_data->DiscoveryStatus) - printk("discovery_status(0x%08x)", - le32_to_cpu(event_data->DiscoveryStatus)); - printk("\n"); - } -#endif - - if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED && - !ioc->sas_hba.num_phys) { - if (disable_discovery > 0 && ioc->shost_recovery) { - /* Wait for the reset to complete */ - while (ioc->shost_recovery) - ssleep(1); - } - _scsih_sas_host_add(ioc); - } -} - -/** - * _scsih_reprobe_lun - reprobing lun - * @sdev: scsi device struct - * @no_uld_attach: sdev->no_uld_attach flag setting - * - **/ -static void -_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach) -{ - int rc; - - sdev->no_uld_attach = no_uld_attach ? 1 : 0; - sdev_printk(KERN_INFO, sdev, "%s raid component\n", - sdev->no_uld_attach ? "hidding" : "exposing"); - rc = scsi_device_reprobe(sdev); -} - -/** - * _scsih_sas_volume_add - add new volume - * @ioc: per adapter object - * @element: IR config element data - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventIrConfigElement_t *element) -{ - struct _raid_device *raid_device; - unsigned long flags; - u64 wwid; - u16 handle = le16_to_cpu(element->VolDevHandle); - int rc; - - mpt2sas_config_get_volume_wwid(ioc, handle, &wwid); - if (!wwid) { - printk(MPT2SAS_ERR_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); - return; - } - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - - if (raid_device) - return; - - raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); - if (!raid_device) { - printk(MPT2SAS_ERR_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); - return; - } - - raid_device->id = ioc->sas_id++; - raid_device->channel = RAID_CHANNEL; - raid_device->handle = handle; - raid_device->wwid = wwid; - _scsih_raid_device_add(ioc, raid_device); - if (!ioc->wait_for_discovery_to_complete) { - rc = scsi_add_device(ioc->shost, RAID_CHANNEL, - raid_device->id, 0); - if (rc) - _scsih_raid_device_remove(ioc, raid_device); - } else { - spin_lock_irqsave(&ioc->raid_device_lock, flags); - _scsih_determine_boot_device(ioc, raid_device, 1); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - } -} - -/** - * _scsih_sas_volume_delete - delete volume - * @ioc: per adapter object - * @handle: volume device handle - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _raid_device *raid_device; - unsigned long flags; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct scsi_target *starget = NULL; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - if (raid_device) { - if (raid_device->starget) { - starget = raid_device->starget; - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->deleted = 1; - } - printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" - "(0x%016llx)\n", ioc->name, raid_device->handle, - (unsigned long long) raid_device->wwid); - list_del(&raid_device->list); - kfree(raid_device); - } - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - if (starget) - scsi_remove_target(&starget->dev); -} - -/** - * _scsih_sas_pd_expose - expose pd component to /dev/sdX - * @ioc: per adapter object - * @element: IR config element data - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventIrConfigElement_t *element) -{ - struct _sas_device *sas_device; - struct scsi_target *starget = NULL; - struct MPT2SAS_TARGET *sas_target_priv_data; - unsigned long flags; - u16 handle = le16_to_cpu(element->PhysDiskDevHandle); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device) { - sas_device->volume_handle = 0; - sas_device->volume_wwid = 0; - clear_bit(handle, ioc->pd_handles); - if (sas_device->starget && sas_device->starget->hostdata) { - starget = sas_device->starget; - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->flags &= - ~MPT_TARGET_FLAGS_RAID_COMPONENT; - } - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_device) - return; - - /* exposing raid component */ - if (starget) - starget_for_each_device(starget, NULL, _scsih_reprobe_lun); - - sas_device_put(sas_device); -} - -/** - * _scsih_sas_pd_hide - hide pd component from /dev/sdX - * @ioc: per adapter object - * @element: IR config element data - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventIrConfigElement_t *element) -{ - struct _sas_device *sas_device; - struct scsi_target *starget = NULL; - struct MPT2SAS_TARGET *sas_target_priv_data; - unsigned long flags; - u16 handle = le16_to_cpu(element->PhysDiskDevHandle); - u16 volume_handle = 0; - u64 volume_wwid = 0; - - mpt2sas_config_get_volume_handle(ioc, handle, &volume_handle); - if (volume_handle) - mpt2sas_config_get_volume_wwid(ioc, volume_handle, - &volume_wwid); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device) { - set_bit(handle, ioc->pd_handles); - if (sas_device->starget && sas_device->starget->hostdata) { - starget = sas_device->starget; - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->flags |= - MPT_TARGET_FLAGS_RAID_COMPONENT; - sas_device->volume_handle = volume_handle; - sas_device->volume_wwid = volume_wwid; - } - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_device) - return; - - /* hiding raid component */ - if (starget) - starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun); - - sas_device_put(sas_device); -} - -/** - * _scsih_sas_pd_delete - delete pd component - * @ioc: per adapter object - * @element: IR config element data - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventIrConfigElement_t *element) -{ - u16 handle = le16_to_cpu(element->PhysDiskDevHandle); - - _scsih_device_remove_by_handle(ioc, handle); -} - -/** - * _scsih_sas_pd_add - remove pd component - * @ioc: per adapter object - * @element: IR config element data - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventIrConfigElement_t *element) -{ - struct _sas_device *sas_device; - u16 handle = le16_to_cpu(element->PhysDiskDevHandle); - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - u32 ioc_status; - u64 sas_address; - u16 parent_handle; - - set_bit(handle, ioc->pd_handles); - - sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device) { - sas_device_put(sas_device); - return; - } - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); - if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) - mpt2sas_transport_update_links(ioc, sas_address, handle, - sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); - - _scsih_add_device(ioc, handle, 0, 1); -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events - * @ioc: per adapter object - * @event_data: event data payload - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataIrConfigChangeList_t *event_data) -{ - Mpi2EventIrConfigElement_t *element; - u8 element_type; - int i; - char *reason_str = NULL, *element_str = NULL; - - element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - - printk(MPT2SAS_INFO_FMT "raid config change: (%s), elements(%d)\n", - ioc->name, (le32_to_cpu(event_data->Flags) & - MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? - "foreign" : "native", event_data->NumElements); - for (i = 0; i < event_data->NumElements; i++, element++) { - switch (element->ReasonCode) { - case MPI2_EVENT_IR_CHANGE_RC_ADDED: - reason_str = "add"; - break; - case MPI2_EVENT_IR_CHANGE_RC_REMOVED: - reason_str = "remove"; - break; - case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE: - reason_str = "no change"; - break; - case MPI2_EVENT_IR_CHANGE_RC_HIDE: - reason_str = "hide"; - break; - case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: - reason_str = "unhide"; - break; - case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: - reason_str = "volume_created"; - break; - case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: - reason_str = "volume_deleted"; - break; - case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: - reason_str = "pd_created"; - break; - case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: - reason_str = "pd_deleted"; - break; - default: - reason_str = "unknown reason"; - break; - } - element_type = le16_to_cpu(element->ElementFlags) & - MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK; - switch (element_type) { - case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT: - element_str = "volume"; - break; - case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT: - element_str = "phys disk"; - break; - case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT: - element_str = "hot spare"; - break; - default: - element_str = "unknown element"; - break; - } - printk(KERN_INFO "\t(%s:%s), vol handle(0x%04x), " - "pd handle(0x%04x), pd num(0x%02x)\n", element_str, - reason_str, le16_to_cpu(element->VolDevHandle), - le16_to_cpu(element->PhysDiskDevHandle), - element->PhysDiskNum); - } -} -#endif - -/** - * _scsih_sas_ir_config_change_event - handle ir configuration change events - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - Mpi2EventIrConfigElement_t *element; - int i; - u8 foreign_config; - Mpi2EventDataIrConfigChangeList_t *event_data = - (Mpi2EventDataIrConfigChangeList_t *) - fw_event->event_data; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - && !ioc->hide_ir_msg) - _scsih_sas_ir_config_change_event_debug(ioc, event_data); - -#endif - - if (ioc->shost_recovery) - return; - - foreign_config = (le32_to_cpu(event_data->Flags) & - MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; - - element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - for (i = 0; i < event_data->NumElements; i++, element++) { - - switch (element->ReasonCode) { - case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: - case MPI2_EVENT_IR_CHANGE_RC_ADDED: - if (!foreign_config) - _scsih_sas_volume_add(ioc, element); - break; - case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: - case MPI2_EVENT_IR_CHANGE_RC_REMOVED: - if (!foreign_config) - _scsih_sas_volume_delete(ioc, - le16_to_cpu(element->VolDevHandle)); - break; - case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: - if (!ioc->is_warpdrive) - _scsih_sas_pd_hide(ioc, element); - break; - case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: - if (!ioc->is_warpdrive) - _scsih_sas_pd_expose(ioc, element); - break; - case MPI2_EVENT_IR_CHANGE_RC_HIDE: - if (!ioc->is_warpdrive) - _scsih_sas_pd_add(ioc, element); - break; - case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: - if (!ioc->is_warpdrive) - _scsih_sas_pd_delete(ioc, element); - break; - } - } -} - -/** - * _scsih_sas_ir_volume_event - IR volume event - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - u64 wwid; - unsigned long flags; - struct _raid_device *raid_device; - u16 handle; - u32 state; - int rc; - Mpi2EventDataIrVolume_t *event_data = - (Mpi2EventDataIrVolume_t *) - fw_event->event_data; - - if (ioc->shost_recovery) - return; - - if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) - return; - - handle = le16_to_cpu(event_data->VolDevHandle); - state = le32_to_cpu(event_data->NewValue); - if (!ioc->hide_ir_msg) - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " - "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); - - switch (state) { - case MPI2_RAID_VOL_STATE_MISSING: - case MPI2_RAID_VOL_STATE_FAILED: - _scsih_sas_volume_delete(ioc, handle); - break; - - case MPI2_RAID_VOL_STATE_ONLINE: - case MPI2_RAID_VOL_STATE_DEGRADED: - case MPI2_RAID_VOL_STATE_OPTIMAL: - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - - if (raid_device) - break; - - mpt2sas_config_get_volume_wwid(ioc, handle, &wwid); - if (!wwid) { - printk(MPT2SAS_ERR_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); - break; - } - - raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); - if (!raid_device) { - printk(MPT2SAS_ERR_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); - break; - } - - raid_device->id = ioc->sas_id++; - raid_device->channel = RAID_CHANNEL; - raid_device->handle = handle; - raid_device->wwid = wwid; - _scsih_raid_device_add(ioc, raid_device); - rc = scsi_add_device(ioc->shost, RAID_CHANNEL, - raid_device->id, 0); - if (rc) - _scsih_raid_device_remove(ioc, raid_device); - break; - - case MPI2_RAID_VOL_STATE_INITIALIZING: - default: - break; - } -} - -/** - * _scsih_sas_ir_physical_disk_event - PD event - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - u16 handle, parent_handle; - u32 state; - struct _sas_device *sas_device; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - u32 ioc_status; - Mpi2EventDataIrPhysicalDisk_t *event_data = - (Mpi2EventDataIrPhysicalDisk_t *) - fw_event->event_data; - u64 sas_address; - - if (ioc->shost_recovery) - return; - - if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED) - return; - - handle = le16_to_cpu(event_data->PhysDiskDevHandle); - state = le32_to_cpu(event_data->NewValue); - - if (!ioc->hide_ir_msg) - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " - "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); - - switch (state) { - case MPI2_RAID_PD_STATE_ONLINE: - case MPI2_RAID_PD_STATE_DEGRADED: - case MPI2_RAID_PD_STATE_REBUILDING: - case MPI2_RAID_PD_STATE_OPTIMAL: - case MPI2_RAID_PD_STATE_HOT_SPARE: - - if (!ioc->is_warpdrive) - set_bit(handle, ioc->pd_handles); - - sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device) { - sas_device_put(sas_device); - return; - } - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, - &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, - handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); - if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) - mpt2sas_transport_update_links(ioc, sas_address, handle, - sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); - - _scsih_add_device(ioc, handle, 0, 1); - - break; - - case MPI2_RAID_PD_STATE_OFFLINE: - case MPI2_RAID_PD_STATE_NOT_CONFIGURED: - case MPI2_RAID_PD_STATE_NOT_COMPATIBLE: - default: - break; - } -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _scsih_sas_ir_operation_status_event_debug - debug for IR op event - * @ioc: per adapter object - * @event_data: event data payload - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataIrOperationStatus_t *event_data) -{ - char *reason_str = NULL; - - switch (event_data->RAIDOperation) { - case MPI2_EVENT_IR_RAIDOP_RESYNC: - reason_str = "resync"; - break; - case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION: - reason_str = "online capacity expansion"; - break; - case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK: - reason_str = "consistency check"; - break; - case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT: - reason_str = "background init"; - break; - case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT: - reason_str = "make data consistent"; - break; - } - - if (!reason_str) - return; - - printk(MPT2SAS_INFO_FMT "raid operational status: (%s)" - "\thandle(0x%04x), percent complete(%d)\n", - ioc->name, reason_str, - le16_to_cpu(event_data->VolDevHandle), - event_data->PercentComplete); -} -#endif - -/** - * _scsih_sas_ir_operation_status_event - handle RAID operation events - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - Mpi2EventDataIrOperationStatus_t *event_data = - (Mpi2EventDataIrOperationStatus_t *) - fw_event->event_data; - static struct _raid_device *raid_device; - unsigned long flags; - u16 handle; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - && !ioc->hide_ir_msg) - _scsih_sas_ir_operation_status_event_debug(ioc, - event_data); -#endif - - /* code added for raid transport support */ - if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) { - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - handle = le16_to_cpu(event_data->VolDevHandle); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - if (raid_device) - raid_device->percent_complete = - event_data->PercentComplete; - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - } -} - -/** - * _scsih_prep_device_scan - initialize parameters prior to device scan - * @ioc: per adapter object - * - * Set the deleted flag prior to device scan. If the device is found during - * the scan, then we clear the deleted flag. - */ -static void -_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (sas_device_priv_data && sas_device_priv_data->sas_target) - sas_device_priv_data->sas_target->deleted = 1; - } -} - -/** - * _scsih_mark_responding_sas_device - mark a sas_devices as responding - * @ioc: per adapter object - * @sas_address: sas address - * @slot: enclosure slot id - * @handle: device handle - * - * After host reset, find out whether devices are still responding. - * Used in _scsi_remove_unresponsive_sas_devices. - * - * Return nothing. - */ -static void -_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u16 slot, u16 handle) -{ - struct MPT2SAS_TARGET *sas_target_priv_data = NULL; - struct scsi_target *starget; - struct _sas_device *sas_device; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_for_each_entry(sas_device, &ioc->sas_device_list, list) { - if (sas_device->sas_address == sas_address && - sas_device->slot == slot) { - sas_device->responding = 1; - starget = sas_device->starget; - if (starget && starget->hostdata) { - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->tm_busy = 0; - sas_target_priv_data->deleted = 0; - } else - sas_target_priv_data = NULL; - if (starget) - starget_printk(KERN_INFO, starget, - "handle(0x%04x), sas_addr(0x%016llx), " - "enclosure logical id(0x%016llx), " - "slot(%d)\n", handle, - (unsigned long long)sas_device->sas_address, - (unsigned long long) - sas_device->enclosure_logical_id, - sas_device->slot); - if (sas_device->handle == handle) - goto out; - printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", - sas_device->handle); - sas_device->handle = handle; - if (sas_target_priv_data) - sas_target_priv_data->handle = handle; - goto out; - } - } - out: - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -} - -/** - * _scsih_search_responding_sas_devices - - * @ioc: per adapter object - * - * After host reset, find out whether devices are still responding. - * If not remove. - * - * Return nothing. - */ -static void -_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 ioc_status; - __le64 sas_address; - u16 handle; - u32 device_info; - u16 slot; - - printk(MPT2SAS_INFO_FMT "search for end-devices: start\n", ioc->name); - - if (list_empty(&ioc->sas_device_list)) - goto out; - - handle = 0xFFFF; - while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, - &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, - handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - break; - handle = le16_to_cpu(sas_device_pg0.DevHandle); - device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); - if (!(_scsih_is_end_device(device_info))) - continue; - sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - slot = le16_to_cpu(sas_device_pg0.Slot); - _scsih_mark_responding_sas_device(ioc, sas_address, slot, - handle); - } -out: - printk(MPT2SAS_INFO_FMT "search for end-devices: complete\n", - ioc->name); -} - -/** - * _scsih_mark_responding_raid_device - mark a raid_device as responding - * @ioc: per adapter object - * @wwid: world wide identifier for raid volume - * @handle: device handle - * - * After host reset, find out whether devices are still responding. - * Used in _scsi_remove_unresponsive_raid_devices. - * - * Return nothing. - */ -static void -_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, - u16 handle) -{ - struct MPT2SAS_TARGET *sas_target_priv_data; - struct scsi_target *starget; - struct _raid_device *raid_device; - unsigned long flags; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - list_for_each_entry(raid_device, &ioc->raid_device_list, list) { - if (raid_device->wwid == wwid && raid_device->starget) { - starget = raid_device->starget; - if (starget && starget->hostdata) { - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->deleted = 0; - } else - sas_target_priv_data = NULL; - raid_device->responding = 1; - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - starget_printk(KERN_INFO, raid_device->starget, - "handle(0x%04x), wwid(0x%016llx)\n", handle, - (unsigned long long)raid_device->wwid); - /* - * WARPDRIVE: The handles of the PDs might have changed - * across the host reset so re-initialize the - * required data for Direct IO - */ - _scsih_init_warpdrive_properties(ioc, raid_device); - spin_lock_irqsave(&ioc->raid_device_lock, flags); - if (raid_device->handle == handle) { - spin_unlock_irqrestore(&ioc->raid_device_lock, - flags); - return; - } - printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", - raid_device->handle); - raid_device->handle = handle; - if (sas_target_priv_data) - sas_target_priv_data->handle = handle; - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - return; - } - } - - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -} - -/** - * _scsih_search_responding_raid_devices - - * @ioc: per adapter object - * - * After host reset, find out whether devices are still responding. - * If not remove. - * - * Return nothing. - */ -static void -_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2RaidVolPage1_t volume_pg1; - Mpi2RaidVolPage0_t volume_pg0; - Mpi2RaidPhysDiskPage0_t pd_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 ioc_status; - u16 handle; - u8 phys_disk_num; - - if (!ioc->ir_firmware) - return; - - printk(MPT2SAS_INFO_FMT "search for raid volumes: start\n", - ioc->name); - - if (list_empty(&ioc->raid_device_list)) - goto out; - - handle = 0xFFFF; - while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - break; - handle = le16_to_cpu(volume_pg1.DevHandle); - - if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, - &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, - sizeof(Mpi2RaidVolPage0_t))) - continue; - - if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || - volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || - volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) - _scsih_mark_responding_raid_device(ioc, - le64_to_cpu(volume_pg1.WWID), handle); - } - - /* refresh the pd_handles */ - if (!ioc->is_warpdrive) { - phys_disk_num = 0xFF; - memset(ioc->pd_handles, 0, ioc->pd_handles_sz); - while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, - &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, - phys_disk_num))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - break; - phys_disk_num = pd_pg0.PhysDiskNum; - handle = le16_to_cpu(pd_pg0.DevHandle); - set_bit(handle, ioc->pd_handles); - } - } -out: - printk(MPT2SAS_INFO_FMT "search for responding raid volumes: " - "complete\n", ioc->name); -} - -/** - * _scsih_mark_responding_expander - mark a expander as responding - * @ioc: per adapter object - * @sas_address: sas address - * @handle: - * - * After host reset, find out whether devices are still responding. - * Used in _scsi_remove_unresponsive_expanders. - * - * Return nothing. - */ -static void -_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u16 handle) -{ - struct _sas_node *sas_expander; - unsigned long flags; - int i; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { - if (sas_expander->sas_address != sas_address) - continue; - sas_expander->responding = 1; - if (sas_expander->handle == handle) - goto out; - printk(KERN_INFO "\texpander(0x%016llx): handle changed" - " from(0x%04x) to (0x%04x)!!!\n", - (unsigned long long)sas_expander->sas_address, - sas_expander->handle, handle); - sas_expander->handle = handle; - for (i = 0 ; i < sas_expander->num_phys ; i++) - sas_expander->phy[i].handle = handle; - goto out; - } - out: - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -} - -/** - * _scsih_search_responding_expanders - - * @ioc: per adapter object - * - * After host reset, find out whether devices are still responding. - * If not remove. - * - * Return nothing. - */ -static void -_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2ExpanderPage0_t expander_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 ioc_status; - u64 sas_address; - u16 handle; - - printk(MPT2SAS_INFO_FMT "search for expanders: start\n", ioc->name); - - if (list_empty(&ioc->sas_expander_list)) - goto out; - - handle = 0xFFFF; - while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, - MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) { - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - break; - - handle = le16_to_cpu(expander_pg0.DevHandle); - sas_address = le64_to_cpu(expander_pg0.SASAddress); - printk(KERN_INFO "\texpander present: handle(0x%04x), " - "sas_addr(0x%016llx)\n", handle, - (unsigned long long)sas_address); - _scsih_mark_responding_expander(ioc, sas_address, handle); - } - - out: - printk(MPT2SAS_INFO_FMT "search for expanders: complete\n", ioc->name); -} - -/** - * _scsih_remove_unresponding_sas_devices - removing unresponding devices - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc) -{ - struct _sas_device *sas_device, *sas_device_next; - struct _sas_node *sas_expander, *sas_expander_next; - struct _raid_device *raid_device, *raid_device_next; - struct list_head tmp_list; - unsigned long flags; - LIST_HEAD(head); - - printk(MPT2SAS_INFO_FMT "removing unresponding devices: start\n", - ioc->name); - - /* removing unresponding end devices */ - printk(MPT2SAS_INFO_FMT "removing unresponding devices: end-devices\n", - ioc->name); - - /* - * Iterate, pulling off devices marked as non-responding. We become the - * owner for the reference the list had on any object we prune. - */ - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_for_each_entry_safe(sas_device, sas_device_next, - &ioc->sas_device_list, list) { - if (!sas_device->responding) - list_move_tail(&sas_device->list, &head); - else - sas_device->responding = 0; - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - /* - * Now, uninitialize and remove the unresponding devices we pruned. - */ - list_for_each_entry_safe(sas_device, sas_device_next, &head, list) { - _scsih_remove_device(ioc, sas_device); - list_del_init(&sas_device->list); - sas_device_put(sas_device); - } - - /* removing unresponding volumes */ - if (ioc->ir_firmware) { - printk(MPT2SAS_INFO_FMT "removing unresponding devices: " - "volumes\n", ioc->name); - list_for_each_entry_safe(raid_device, raid_device_next, - &ioc->raid_device_list, list) { - if (!raid_device->responding) - _scsih_sas_volume_delete(ioc, - raid_device->handle); - else - raid_device->responding = 0; - } - } - /* removing unresponding expanders */ - printk(MPT2SAS_INFO_FMT "removing unresponding devices: expanders\n", - ioc->name); - spin_lock_irqsave(&ioc->sas_node_lock, flags); - INIT_LIST_HEAD(&tmp_list); - list_for_each_entry_safe(sas_expander, sas_expander_next, - &ioc->sas_expander_list, list) { - if (!sas_expander->responding) - list_move_tail(&sas_expander->list, &tmp_list); - else - sas_expander->responding = 0; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - list_for_each_entry_safe(sas_expander, sas_expander_next, &tmp_list, - list) { - list_del(&sas_expander->list); - _scsih_expander_node_remove(ioc, sas_expander); - } - printk(MPT2SAS_INFO_FMT "removing unresponding devices: complete\n", - ioc->name); - /* unblock devices */ - _scsih_ublock_io_all_device(ioc); -} - -static void -_scsih_refresh_expander_links(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_expander, u16 handle) -{ - Mpi2ExpanderPage1_t expander_pg1; - Mpi2ConfigReply_t mpi_reply; - int i; - - for (i = 0 ; i < sas_expander->num_phys ; i++) { - if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply, - &expander_pg1, i, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - mpt2sas_transport_update_links(ioc, sas_expander->sas_address, - le16_to_cpu(expander_pg1.AttachedDevHandle), i, - expander_pg1.NegotiatedLinkRate >> 4); - } -} - -/** - * _scsih_scan_for_devices_after_reset - scan for devices after host reset - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2ExpanderPage0_t expander_pg0; - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2RaidVolPage1_t volume_pg1; - Mpi2RaidVolPage0_t volume_pg0; - Mpi2RaidPhysDiskPage0_t pd_pg0; - Mpi2EventIrConfigElement_t element; - Mpi2ConfigReply_t mpi_reply; - u8 phys_disk_num; - u16 ioc_status; - u16 handle, parent_handle; - u64 sas_address; - struct _sas_device *sas_device; - struct _sas_node *expander_device; - static struct _raid_device *raid_device; - u8 retry_count; - unsigned long flags; - - printk(MPT2SAS_INFO_FMT "scan devices: start\n", ioc->name); - - _scsih_sas_host_refresh(ioc); - - printk(MPT2SAS_INFO_FMT "\tscan devices: expanders start\n", - ioc->name); - /* expanders */ - handle = 0xFFFF; - while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, - MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_INFO_FMT "\tbreak from expander scan: " - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); - break; - } - handle = le16_to_cpu(expander_pg0.DevHandle); - spin_lock_irqsave(&ioc->sas_node_lock, flags); - expander_device = mpt2sas_scsih_expander_find_by_sas_address( - ioc, le64_to_cpu(expander_pg0.SASAddress)); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (expander_device) - _scsih_refresh_expander_links(ioc, expander_device, - handle); - else { - printk(MPT2SAS_INFO_FMT "\tBEFORE adding expander: " - "handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(expander_pg0.SASAddress)); - _scsih_expander_add(ioc, handle); - printk(MPT2SAS_INFO_FMT "\tAFTER adding expander: " - "handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(expander_pg0.SASAddress)); - } - } - - printk(MPT2SAS_INFO_FMT "\tscan devices: expanders complete\n", - ioc->name); - - if (!ioc->ir_firmware) - goto skip_to_sas; - - printk(MPT2SAS_INFO_FMT "\tscan devices phys disk start\n", ioc->name); - /* phys disk */ - phys_disk_num = 0xFF; - while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, - &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, - phys_disk_num))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan:" - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); - break; - } - phys_disk_num = pd_pg0.PhysDiskNum; - handle = le16_to_cpu(pd_pg0.DevHandle); - sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); - if (sas_device) { - sas_device_put(sas_device); - continue; - } - if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, - &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, - handle) != 0) - continue; - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan " - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); - break; - } - parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); - if (!_scsih_get_sas_address(ioc, parent_handle, - &sas_address)) { - printk(MPT2SAS_INFO_FMT "\tBEFORE adding phys disk: " - " handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(sas_device_pg0.SASAddress)); - mpt2sas_transport_update_links(ioc, sas_address, - handle, sas_device_pg0.PhyNum, - MPI2_SAS_NEG_LINK_RATE_1_5); - set_bit(handle, ioc->pd_handles); - retry_count = 0; - /* This will retry adding the end device. - * _scsih_add_device() will decide on retries and - * return "1" when it should be retried - */ - while (_scsih_add_device(ioc, handle, retry_count++, - 1)) { - ssleep(1); - } - printk(MPT2SAS_INFO_FMT "\tAFTER adding phys disk: " - " handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(sas_device_pg0.SASAddress)); - } - } - - printk(MPT2SAS_INFO_FMT "\tscan devices: phys disk complete\n", - ioc->name); - - printk(MPT2SAS_INFO_FMT "\tscan devices: volumes start\n", ioc->name); - /* volumes */ - handle = 0xFFFF; - while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: " - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); - break; - } - handle = le16_to_cpu(volume_pg1.DevHandle); - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_wwid(ioc, - le64_to_cpu(volume_pg1.WWID)); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - if (raid_device) - continue; - if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, - &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, - sizeof(Mpi2RaidVolPage0_t))) - continue; - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: " - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); - break; - } - if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || - volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || - volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) { - memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t)); - element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED; - element.VolDevHandle = volume_pg1.DevHandle; - printk(MPT2SAS_INFO_FMT "\tBEFORE adding volume: " - " handle (0x%04x)\n", ioc->name, - volume_pg1.DevHandle); - _scsih_sas_volume_add(ioc, &element); - printk(MPT2SAS_INFO_FMT "\tAFTER adding volume: " - " handle (0x%04x)\n", ioc->name, - volume_pg1.DevHandle); - } - } - - printk(MPT2SAS_INFO_FMT "\tscan devices: volumes complete\n", - ioc->name); - - skip_to_sas: - - printk(MPT2SAS_INFO_FMT "\tscan devices: end devices start\n", - ioc->name); - /* sas devices */ - handle = 0xFFFF; - while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, - &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, - handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_INFO_FMT "\tbreak from end device scan:" - " ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, ioc_status, - le32_to_cpu(mpi_reply.IOCLogInfo)); - break; - } - handle = le16_to_cpu(sas_device_pg0.DevHandle); - if (!(_scsih_is_end_device( - le32_to_cpu(sas_device_pg0.DeviceInfo)))) - continue; - sas_device = mpt2sas_get_sdev_by_addr(ioc, - le64_to_cpu(sas_device_pg0.SASAddress)); - if (sas_device) { - sas_device_put(sas_device); - continue; - } - parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); - if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) { - printk(MPT2SAS_INFO_FMT "\tBEFORE adding end device: " - "handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(sas_device_pg0.SASAddress)); - mpt2sas_transport_update_links(ioc, sas_address, handle, - sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); - retry_count = 0; - /* This will retry adding the end device. - * _scsih_add_device() will decide on retries and - * return "1" when it should be retried - */ - while (_scsih_add_device(ioc, handle, retry_count++, - 0)) { - ssleep(1); - } - printk(MPT2SAS_INFO_FMT "\tAFTER adding end device: " - "handle (0x%04x), sas_addr(0x%016llx)\n", - ioc->name, handle, (unsigned long long) - le64_to_cpu(sas_device_pg0.SASAddress)); - } - } - - printk(MPT2SAS_INFO_FMT "\tscan devices: end devices complete\n", - ioc->name); - - printk(MPT2SAS_INFO_FMT "scan devices: complete\n", ioc->name); -} - - -/** - * mpt2sas_scsih_reset_handler - reset callback handler (for scsih) - * @ioc: per adapter object - * @reset_phase: phase - * - * The handler for doing any required cleanup or initialization. - * - * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, - * MPT2_IOC_DONE_RESET - * - * Return nothing. - */ -void -mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) -{ - switch (reset_phase) { - case MPT2_IOC_PRE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); - break; - case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); - if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) { - ioc->scsih_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid); - complete(&ioc->scsih_cmds.done); - } - if (ioc->tm_cmds.status & MPT2_CMD_PENDING) { - ioc->tm_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid); - complete(&ioc->tm_cmds.done); - } - _scsih_fw_event_cleanup_queue(ioc); - _scsih_flush_running_cmds(ioc); - break; - case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); - _scsih_sas_host_refresh(ioc); - _scsih_prep_device_scan(ioc); - _scsih_search_responding_sas_devices(ioc); - _scsih_search_responding_raid_devices(ioc); - _scsih_search_responding_expanders(ioc); - if ((!ioc->is_driver_loading) && !(disable_discovery > 0 && - !ioc->sas_hba.num_phys)) { - _scsih_prep_device_scan(ioc); - _scsih_search_responding_sas_devices(ioc); - _scsih_search_responding_raid_devices(ioc); - _scsih_search_responding_expanders(ioc); - _scsih_error_recovery_delete_devices(ioc); - } - break; - } -} - -/** - * _firmware_event_work - delayed task for processing firmware events - * @ioc: per adapter object - * @work: equal to the fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_firmware_event_work(struct work_struct *work) -{ - struct fw_event_work *fw_event = container_of(work, - struct fw_event_work, delayed_work.work); - struct MPT2SAS_ADAPTER *ioc = fw_event->ioc; - - _scsih_fw_event_del_from_list(ioc, fw_event); - - /* the queue is being flushed so ignore this event */ - if (ioc->remove_host || ioc->pci_error_recovery) { - fw_event_work_put(fw_event); - return; - } - - switch (fw_event->event) { - case MPT2SAS_REMOVE_UNRESPONDING_DEVICES: - while (scsi_host_in_recovery(ioc->shost) || - ioc->shost_recovery) { - /* - * If we're unloading, bail. Otherwise, this can become - * an infinite loop. - */ - if (ioc->remove_host) - goto out; - - ssleep(1); - } - _scsih_remove_unresponding_sas_devices(ioc); - _scsih_scan_for_devices_after_reset(ioc); - break; - case MPT2SAS_PORT_ENABLE_COMPLETE: - ioc->start_scan = 0; - - if (missing_delay[0] != -1 && missing_delay[1] != -1) - mpt2sas_base_update_missing_delay(ioc, missing_delay[0], - missing_delay[1]); - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "port enable: complete " - "from worker thread\n", ioc->name)); - break; - case MPT2SAS_TURN_ON_PFA_LED: - _scsih_turn_on_pfa_led(ioc, fw_event->device_handle); - break; - case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: - _scsih_sas_topology_change_event(ioc, fw_event); - break; - case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: - _scsih_sas_device_status_change_event(ioc, - fw_event); - break; - case MPI2_EVENT_SAS_DISCOVERY: - _scsih_sas_discovery_event(ioc, - fw_event); - break; - case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: - _scsih_sas_broadcast_primitive_event(ioc, - fw_event); - break; - case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: - _scsih_sas_enclosure_dev_status_change_event(ioc, - fw_event); - break; - case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - _scsih_sas_ir_config_change_event(ioc, fw_event); - break; - case MPI2_EVENT_IR_VOLUME: - _scsih_sas_ir_volume_event(ioc, fw_event); - break; - case MPI2_EVENT_IR_PHYSICAL_DISK: - _scsih_sas_ir_physical_disk_event(ioc, fw_event); - break; - case MPI2_EVENT_IR_OPERATION_STATUS: - _scsih_sas_ir_operation_status_event(ioc, fw_event); - break; - } -out: - fw_event_work_put(fw_event); -} - -/** - * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time) - * @ioc: per adapter object - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: interrupt. - * - * This function merely adds a new work task into ioc->firmware_event_thread. - * The tasks are worked from _firmware_event_work in user context. - * - * Returns void. - */ -void -mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, - u32 reply) -{ - struct fw_event_work *fw_event; - Mpi2EventNotificationReply_t *mpi_reply; - u16 event; - u16 sz; - - /* events turned off due to host reset or driver unloading */ - if (ioc->remove_host || ioc->pci_error_recovery) - return; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - - if (unlikely(!mpi_reply)) { - printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - event = le16_to_cpu(mpi_reply->Event); - - switch (event) { - /* handle these */ - case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: - { - Mpi2EventDataSasBroadcastPrimitive_t *baen_data = - (Mpi2EventDataSasBroadcastPrimitive_t *) - mpi_reply->EventData; - - if (baen_data->Primitive != - MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) - return; - - if (ioc->broadcast_aen_busy) { - ioc->broadcast_aen_pending++; - return; - } else - ioc->broadcast_aen_busy = 1; - break; - } - - case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: - _scsih_check_topo_delete_events(ioc, - (Mpi2EventDataSasTopologyChangeList_t *) - mpi_reply->EventData); - break; - case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - _scsih_check_ir_config_unhide_events(ioc, - (Mpi2EventDataIrConfigChangeList_t *) - mpi_reply->EventData); - break; - case MPI2_EVENT_IR_VOLUME: - _scsih_check_volume_delete_events(ioc, - (Mpi2EventDataIrVolume_t *) - mpi_reply->EventData); - break; - case MPI2_EVENT_LOG_ENTRY_ADDED: - { - Mpi2EventDataLogEntryAdded_t *log_entry; - __le32 *log_code; - - if (!ioc->is_warpdrive) - break; - - log_entry = (Mpi2EventDataLogEntryAdded_t *) - mpi_reply->EventData; - log_code = (__le32 *)log_entry->LogData; - - if (le16_to_cpu(log_entry->LogEntryQualifier) - != MPT2_WARPDRIVE_LOGENTRY) - break; - - switch (le32_to_cpu(*log_code)) { - case MPT2_WARPDRIVE_LC_SSDT: - printk(MPT2SAS_WARN_FMT "WarpDrive Warning: " - "IO Throttling has occurred in the WarpDrive " - "subsystem. Check WarpDrive documentation for " - "additional details.\n", ioc->name); - break; - case MPT2_WARPDRIVE_LC_SSDLW: - printk(MPT2SAS_WARN_FMT "WarpDrive Warning: " - "Program/Erase Cycles for the WarpDrive subsystem " - "in degraded range. Check WarpDrive documentation " - "for additional details.\n", ioc->name); - break; - case MPT2_WARPDRIVE_LC_SSDLF: - printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: " - "There are no Program/Erase Cycles for the " - "WarpDrive subsystem. The storage device will be " - "in read-only mode. Check WarpDrive documentation " - "for additional details.\n", ioc->name); - break; - case MPT2_WARPDRIVE_LC_BRMF: - printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: " - "The Backup Rail Monitor has failed on the " - "WarpDrive subsystem. Check WarpDrive " - "documentation for additional details.\n", - ioc->name); - break; - } - - break; - } - case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: - case MPI2_EVENT_IR_OPERATION_STATUS: - case MPI2_EVENT_SAS_DISCOVERY: - case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: - case MPI2_EVENT_IR_PHYSICAL_DISK: - break; - - case MPI2_EVENT_TEMP_THRESHOLD: - _scsih_temp_threshold_events(ioc, - (Mpi2EventDataTemperature_t *) - mpi_reply->EventData); - break; - - default: /* ignore the rest */ - return; - } - - sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; - fw_event = alloc_fw_event_work(sz); - if (!fw_event) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - memcpy(fw_event->event_data, mpi_reply->EventData, sz); - fw_event->ioc = ioc; - fw_event->VF_ID = mpi_reply->VF_ID; - fw_event->VP_ID = mpi_reply->VP_ID; - fw_event->event = event; - _scsih_fw_event_add(ioc, fw_event); - fw_event_work_put(fw_event); - return; -} - -/* shost template */ -static struct scsi_host_template scsih_driver_template = { - .module = THIS_MODULE, - .name = "Fusion MPT SAS Host", - .proc_name = MPT2SAS_DRIVER_NAME, - .queuecommand = _scsih_qcmd, - .target_alloc = _scsih_target_alloc, - .slave_alloc = _scsih_slave_alloc, - .slave_configure = _scsih_slave_configure, - .target_destroy = _scsih_target_destroy, - .slave_destroy = _scsih_slave_destroy, - .scan_finished = _scsih_scan_finished, - .scan_start = _scsih_scan_start, - .change_queue_depth = _scsih_change_queue_depth, - .eh_abort_handler = _scsih_abort, - .eh_device_reset_handler = _scsih_dev_reset, - .eh_target_reset_handler = _scsih_target_reset, - .eh_host_reset_handler = _scsih_host_reset, - .bios_param = _scsih_bios_param, - .can_queue = 1, - .this_id = -1, - .sg_tablesize = MPT2SAS_SG_DEPTH, - .max_sectors = 32767, - .cmd_per_lun = 7, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = mpt2sas_host_attrs, - .sdev_attrs = mpt2sas_dev_attrs, - .track_queue_depth = 1, -}; - -/** - * _scsih_expander_node_remove - removing expander device from list. - * @ioc: per adapter object - * @sas_expander: the sas_device object - * Context: Calling function should acquire ioc->sas_node_lock. - * - * Removing object and freeing associated memory from the - * ioc->sas_expander_list. - * - * Return nothing. - */ -static void -_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_expander) -{ - struct _sas_port *mpt2sas_port, *next; - - /* remove sibling ports attached to this expander */ - list_for_each_entry_safe(mpt2sas_port, next, - &sas_expander->sas_port_list, port_list) { - if (ioc->shost_recovery) - return; - if (mpt2sas_port->remote_identify.device_type == - SAS_END_DEVICE) - mpt2sas_device_remove_by_sas_address(ioc, - mpt2sas_port->remote_identify.sas_address); - else if (mpt2sas_port->remote_identify.device_type == - SAS_EDGE_EXPANDER_DEVICE || - mpt2sas_port->remote_identify.device_type == - SAS_FANOUT_EXPANDER_DEVICE) - mpt2sas_expander_remove(ioc, - mpt2sas_port->remote_identify.sas_address); - } - - mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, - sas_expander->sas_address_parent); - - printk(MPT2SAS_INFO_FMT "expander_remove: handle" - "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, - sas_expander->handle, (unsigned long long) - sas_expander->sas_address); - - kfree(sas_expander->phy); - kfree(sas_expander); -} - -/** - * _scsih_ir_shutdown - IR shutdown notification - * @ioc: per adapter object - * - * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that - * the host system is shutting down. - * - * Return nothing. - */ -static void -_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2RaidActionRequest_t *mpi_request; - Mpi2RaidActionReply_t *mpi_reply; - u16 smid; - - /* is IR firmware build loaded ? */ - if (!ioc->ir_firmware) - return; - - mutex_lock(&ioc->scsih_cmds.mutex); - - if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n", - ioc->name, __func__); - goto out; - } - ioc->scsih_cmds.status = MPT2_CMD_PENDING; - - smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; - goto out; - } - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->scsih_cmds.smid = smid; - memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t)); - - mpi_request->Function = MPI2_FUNCTION_RAID_ACTION; - mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; - - if (!ioc->hide_ir_msg) - printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name); - init_completion(&ioc->scsih_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); - - if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - goto out; - } - - if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) { - mpi_reply = ioc->scsih_cmds.reply; - - if (!ioc->hide_ir_msg) - printk(MPT2SAS_INFO_FMT "IR shutdown (complete): " - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); - } - - out: - ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->scsih_cmds.mutex); -} - -/** - * _scsih_shutdown - routine call during system shutdown - * @pdev: PCI device struct - * - * Return nothing. - */ -static void -_scsih_shutdown(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct workqueue_struct *wq; - unsigned long flags; - - ioc->remove_host = 1; - _scsih_fw_event_cleanup_queue(ioc); - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - wq = ioc->firmware_event_thread; - ioc->firmware_event_thread = NULL; - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); - if (wq) - destroy_workqueue(wq); - - _scsih_ir_shutdown(ioc); - mpt2sas_base_detach(ioc); -} - -/** - * _scsih_remove - detach and remove add host - * @pdev: PCI device struct - * - * Routine called when unloading the driver. - * Return nothing. - */ -static void -_scsih_remove(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct _sas_port *mpt2sas_port, *next_port; - struct _raid_device *raid_device, *next; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct workqueue_struct *wq; - unsigned long flags; - - ioc->remove_host = 1; - _scsih_fw_event_cleanup_queue(ioc); - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - wq = ioc->firmware_event_thread; - ioc->firmware_event_thread = NULL; - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); - if (wq) - destroy_workqueue(wq); - - /* release all the volumes */ - _scsih_ir_shutdown(ioc); - list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list, - list) { - if (raid_device->starget) { - sas_target_priv_data = - raid_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - scsi_remove_target(&raid_device->starget->dev); - } - printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" - "(0x%016llx)\n", ioc->name, raid_device->handle, - (unsigned long long) raid_device->wwid); - _scsih_raid_device_remove(ioc, raid_device); - } - - /* free ports attached to the sas_host */ - list_for_each_entry_safe(mpt2sas_port, next_port, - &ioc->sas_hba.sas_port_list, port_list) { - if (mpt2sas_port->remote_identify.device_type == - SAS_END_DEVICE) - mpt2sas_device_remove_by_sas_address(ioc, - mpt2sas_port->remote_identify.sas_address); - else if (mpt2sas_port->remote_identify.device_type == - SAS_EDGE_EXPANDER_DEVICE || - mpt2sas_port->remote_identify.device_type == - SAS_FANOUT_EXPANDER_DEVICE) - mpt2sas_expander_remove(ioc, - mpt2sas_port->remote_identify.sas_address); - } - - /* free phys attached to the sas_host */ - if (ioc->sas_hba.num_phys) { - kfree(ioc->sas_hba.phy); - ioc->sas_hba.phy = NULL; - ioc->sas_hba.num_phys = 0; - } - - sas_remove_host(shost); - scsi_remove_host(shost); - mpt2sas_base_detach(ioc); - spin_lock(&gioc_lock); - list_del(&ioc->list); - spin_unlock(&gioc_lock); - scsi_host_put(shost); -} - -/** - * _scsih_probe_boot_devices - reports 1st device - * @ioc: per adapter object - * - * If specified in bios page 2, this routine reports the 1st - * device scsi-ml or sas transport for persistent boot device - * purposes. Please refer to function _scsih_determine_boot_device() - */ -static void -_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc) -{ - u8 is_raid; - void *device; - struct _sas_device *sas_device; - struct _raid_device *raid_device; - u16 handle; - u64 sas_address_parent; - u64 sas_address; - unsigned long flags; - int rc; - - /* no Bios, return immediately */ - if (!ioc->bios_pg3.BiosVersion) - return; - - device = NULL; - is_raid = 0; - if (ioc->req_boot_device.device) { - device = ioc->req_boot_device.device; - is_raid = ioc->req_boot_device.is_raid; - } else if (ioc->req_alt_boot_device.device) { - device = ioc->req_alt_boot_device.device; - is_raid = ioc->req_alt_boot_device.is_raid; - } else if (ioc->current_boot_device.device) { - device = ioc->current_boot_device.device; - is_raid = ioc->current_boot_device.is_raid; - } - - if (!device) - return; - - if (is_raid) { - raid_device = device; - rc = scsi_add_device(ioc->shost, RAID_CHANNEL, - raid_device->id, 0); - if (rc) - _scsih_raid_device_remove(ioc, raid_device); - } else { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = device; - handle = sas_device->handle; - sas_address_parent = sas_device->sas_address_parent; - sas_address = sas_device->sas_address; - list_move_tail(&sas_device->list, &ioc->sas_device_list); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (ioc->hide_drives) - return; - if (!mpt2sas_transport_port_add(ioc, sas_device->handle, - sas_device->sas_address_parent)) { - _scsih_sas_device_remove(ioc, sas_device); - } else if (!sas_device->starget) { - if (!ioc->is_driver_loading) { - mpt2sas_transport_port_remove(ioc, - sas_address, - sas_address_parent); - _scsih_sas_device_remove(ioc, sas_device); - } - } - } -} - -/** - * _scsih_probe_raid - reporting raid volumes to scsi-ml - * @ioc: per adapter object - * - * Called during initial loading of the driver. - */ -static void -_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc) -{ - struct _raid_device *raid_device, *raid_next; - int rc; - - list_for_each_entry_safe(raid_device, raid_next, - &ioc->raid_device_list, list) { - if (raid_device->starget) - continue; - rc = scsi_add_device(ioc->shost, RAID_CHANNEL, - raid_device->id, 0); - if (rc) - _scsih_raid_device_remove(ioc, raid_device); - } -} - -static struct _sas_device *get_next_sas_device(struct MPT2SAS_ADAPTER *ioc) -{ - struct _sas_device *sas_device = NULL; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - if (!list_empty(&ioc->sas_device_init_list)) { - sas_device = list_first_entry(&ioc->sas_device_init_list, - struct _sas_device, list); - sas_device_get(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - return sas_device; -} - -static void sas_device_make_active(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - - /* - * Since we dropped the lock during the call to port_add(), we need to - * be careful here that somebody else didn't move or delete this item - * while we were busy with other things. - * - * If it was on the list, we need a put() for the reference the list - * had. Either way, we need a get() for the destination list. - */ - if (!list_empty(&sas_device->list)) { - list_del_init(&sas_device->list); - sas_device_put(sas_device); - } - - sas_device_get(sas_device); - list_add_tail(&sas_device->list, &ioc->sas_device_list); - - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -} - -/** - * _scsih_probe_sas - reporting sas devices to sas transport - * @ioc: per adapter object - * - * Called during initial loading of the driver. - */ -static void -_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) -{ - struct _sas_device *sas_device; - - if (ioc->hide_drives) - return; - - while ((sas_device = get_next_sas_device(ioc))) { - if (!mpt2sas_transport_port_add(ioc, sas_device->handle, - sas_device->sas_address_parent)) { - _scsih_sas_device_remove(ioc, sas_device); - sas_device_put(sas_device); - continue; - } else if (!sas_device->starget) { - if (!ioc->is_driver_loading) { - mpt2sas_transport_port_remove(ioc, - sas_device->sas_address, - sas_device->sas_address_parent); - _scsih_sas_device_remove(ioc, sas_device); - sas_device_put(sas_device); - continue; - } - } - - sas_device_make_active(ioc, sas_device); - sas_device_put(sas_device); - } -} - -/** - * _scsih_probe_devices - probing for devices - * @ioc: per adapter object - * - * Called during initial loading of the driver. - */ -static void -_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc) -{ - u16 volume_mapping_flags; - - if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR)) - return; /* return when IOC doesn't support initiator mode */ - - _scsih_probe_boot_devices(ioc); - - if (ioc->ir_firmware) { - volume_mapping_flags = - le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) & - MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; - if (volume_mapping_flags == - MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) { - _scsih_probe_raid(ioc); - _scsih_probe_sas(ioc); - } else { - _scsih_probe_sas(ioc); - _scsih_probe_raid(ioc); - } - } else - _scsih_probe_sas(ioc); -} - - -/** - * _scsih_scan_start - scsi lld callback for .scan_start - * @shost: SCSI host pointer - * - * The shost has the ability to discover targets on its own instead - * of scanning the entire bus. In our implemention, we will kick off - * firmware discovery. - */ -static void -_scsih_scan_start(struct Scsi_Host *shost) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int rc; - - if (diag_buffer_enable != -1 && diag_buffer_enable != 0) - mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); - - if (disable_discovery > 0) - return; - - ioc->start_scan = 1; - rc = mpt2sas_port_enable(ioc); - - if (rc != 0) - printk(MPT2SAS_INFO_FMT "port enable: FAILED\n", ioc->name); -} - -/** - * _scsih_scan_finished - scsi lld callback for .scan_finished - * @shost: SCSI host pointer - * @time: elapsed time of the scan in jiffies - * - * This function will be called periodically until it returns 1 with the - * scsi_host and the elapsed time of the scan in jiffies. In our implemention, - * we wait for firmware discovery to complete, then return 1. - */ -static int -_scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - if (disable_discovery > 0) { - ioc->is_driver_loading = 0; - ioc->wait_for_discovery_to_complete = 0; - return 1; - } - - if (time >= (300 * HZ)) { - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - printk(MPT2SAS_INFO_FMT "port enable: FAILED with timeout " - "(timeout=300s)\n", ioc->name); - ioc->is_driver_loading = 0; - return 1; - } - - if (ioc->start_scan) - return 0; - - if (ioc->start_scan_failed) { - printk(MPT2SAS_INFO_FMT "port enable: FAILED with " - "(ioc_status=0x%08x)\n", ioc->name, ioc->start_scan_failed); - ioc->is_driver_loading = 0; - ioc->wait_for_discovery_to_complete = 0; - ioc->remove_host = 1; - return 1; - } - - printk(MPT2SAS_INFO_FMT "port enable: SUCCESS\n", ioc->name); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - - if (ioc->wait_for_discovery_to_complete) { - ioc->wait_for_discovery_to_complete = 0; - _scsih_probe_devices(ioc); - } - mpt2sas_base_start_watchdog(ioc); - ioc->is_driver_loading = 0; - return 1; -} - - -/** - * _scsih_probe - attach and add scsi host - * @pdev: PCI device struct - * @id: pci device id - * - * Returns 0 success, anything else error. - */ -static int -_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct MPT2SAS_ADAPTER *ioc; - struct Scsi_Host *shost; - int rv; - - shost = scsi_host_alloc(&scsih_driver_template, - sizeof(struct MPT2SAS_ADAPTER)); - if (!shost) - return -ENODEV; - - /* init local params */ - ioc = shost_priv(shost); - memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER)); - INIT_LIST_HEAD(&ioc->list); - spin_lock(&gioc_lock); - list_add_tail(&ioc->list, &mpt2sas_ioc_list); - spin_unlock(&gioc_lock); - ioc->shost = shost; - ioc->id = mpt_ids++; - sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id); - ioc->pdev = pdev; - if (id->device == MPI2_MFGPAGE_DEVID_SSS6200) { - ioc->is_warpdrive = 1; - ioc->hide_ir_msg = 1; - } else - ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS; - ioc->scsi_io_cb_idx = scsi_io_cb_idx; - ioc->tm_cb_idx = tm_cb_idx; - ioc->ctl_cb_idx = ctl_cb_idx; - ioc->base_cb_idx = base_cb_idx; - ioc->port_enable_cb_idx = port_enable_cb_idx; - ioc->transport_cb_idx = transport_cb_idx; - ioc->scsih_cb_idx = scsih_cb_idx; - ioc->config_cb_idx = config_cb_idx; - ioc->tm_tr_cb_idx = tm_tr_cb_idx; - ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx; - ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx; - ioc->logging_level = logging_level; - ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds; - /* misc semaphores and spin locks */ - mutex_init(&ioc->reset_in_progress_mutex); - /* initializing pci_access_mutex lock */ - mutex_init(&ioc->pci_access_mutex); - spin_lock_init(&ioc->ioc_reset_in_progress_lock); - spin_lock_init(&ioc->scsi_lookup_lock); - spin_lock_init(&ioc->sas_device_lock); - spin_lock_init(&ioc->sas_node_lock); - spin_lock_init(&ioc->fw_event_lock); - spin_lock_init(&ioc->raid_device_lock); - - INIT_LIST_HEAD(&ioc->sas_device_list); - INIT_LIST_HEAD(&ioc->sas_device_init_list); - INIT_LIST_HEAD(&ioc->sas_expander_list); - INIT_LIST_HEAD(&ioc->fw_event_list); - INIT_LIST_HEAD(&ioc->raid_device_list); - INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list); - INIT_LIST_HEAD(&ioc->delayed_tr_list); - INIT_LIST_HEAD(&ioc->delayed_tr_volume_list); - INIT_LIST_HEAD(&ioc->reply_queue_list); - - /* init shost parameters */ - shost->max_cmd_len = 32; - shost->max_lun = max_lun; - shost->transportt = mpt2sas_transport_template; - shost->unique_id = ioc->id; - - if (max_sectors != 0xFFFF) { - if (max_sectors < 64) { - shost->max_sectors = 64; - printk(MPT2SAS_WARN_FMT "Invalid value %d passed " - "for max_sectors, range is 64 to 32767. Assigning " - "value of 64.\n", ioc->name, max_sectors); - } else if (max_sectors > 32767) { - shost->max_sectors = 32767; - printk(MPT2SAS_WARN_FMT "Invalid value %d passed " - "for max_sectors, range is 64 to 8192. Assigning " - "default value of 32767.\n", ioc->name, - max_sectors); - } else { - shost->max_sectors = max_sectors & 0xFFFE; - printk(MPT2SAS_INFO_FMT "The max_sectors value is " - "set to %d\n", ioc->name, shost->max_sectors); - } - } - - /* register EEDP capabilities with SCSI layer */ - if (prot_mask) - scsi_host_set_prot(shost, prot_mask); - else - scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION - | SHOST_DIF_TYPE2_PROTECTION - | SHOST_DIF_TYPE3_PROTECTION); - - scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); - - /* event thread */ - snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), - "fw_event%d", ioc->id); - ioc->firmware_event_thread = create_singlethread_workqueue( - ioc->firmware_event_name); - if (!ioc->firmware_event_thread) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rv = -ENODEV; - goto out_thread_fail; - } - - ioc->is_driver_loading = 1; - if ((mpt2sas_base_attach(ioc))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rv = -ENODEV; - goto out_attach_fail; - } - - if (ioc->is_warpdrive) { - if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) - ioc->hide_drives = 0; - else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS) - ioc->hide_drives = 1; - else { - if (_scsih_get_num_volumes(ioc)) - ioc->hide_drives = 1; - else - ioc->hide_drives = 0; - } - } else - ioc->hide_drives = 0; - - rv = scsi_add_host(shost, &pdev->dev); - if (rv) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out_add_shost_fail; - } - - scsi_scan_host(shost); - - return 0; - - out_add_shost_fail: - mpt2sas_base_detach(ioc); - out_attach_fail: - destroy_workqueue(ioc->firmware_event_thread); - out_thread_fail: - spin_lock(&gioc_lock); - list_del(&ioc->list); - spin_unlock(&gioc_lock); - scsi_host_put(shost); - return rv; -} - -#ifdef CONFIG_PM -/** - * _scsih_suspend - power management suspend main entry point - * @pdev: PCI device struct - * @state: PM state change to (usually PCI_D3) - * - * Returns 0 success, anything else error. - */ -static int -_scsih_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - pci_power_t device_state; - - mpt2sas_base_stop_watchdog(ioc); - scsi_block_requests(shost); - _scsih_ir_shutdown(ioc); - device_state = pci_choose_state(pdev, state); - printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering " - "operating state [D%d]\n", ioc->name, pdev, - pci_name(pdev), device_state); - - mpt2sas_base_free_resources(ioc); - pci_save_state(pdev); - pci_set_power_state(pdev, device_state); - return 0; -} - -/** - * _scsih_resume - power management resume main entry point - * @pdev: PCI device struct - * - * Returns 0 success, anything else error. - */ -static int -_scsih_resume(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - pci_power_t device_state = pdev->current_state; - int r; - - printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous " - "operating state [D%d]\n", ioc->name, pdev, - pci_name(pdev), device_state); - - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - ioc->pdev = pdev; - r = mpt2sas_base_map_resources(ioc); - if (r) - return r; - - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET); - scsi_unblock_requests(shost); - mpt2sas_base_start_watchdog(ioc); - return 0; -} -#endif /* CONFIG_PM */ - -/** - * _scsih_pci_error_detected - Called when a PCI error is detected. - * @pdev: PCI device struct - * @state: PCI channel state - * - * Description: Called when a PCI error is detected. - * - * Return value: - * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT - */ -static pci_ers_result_t -_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n", - ioc->name, state); - - switch (state) { - case pci_channel_io_normal: - return PCI_ERS_RESULT_CAN_RECOVER; - case pci_channel_io_frozen: - /* Fatal error, prepare for slot reset */ - ioc->pci_error_recovery = 1; - scsi_block_requests(ioc->shost); - mpt2sas_base_stop_watchdog(ioc); - mpt2sas_base_free_resources(ioc); - return PCI_ERS_RESULT_NEED_RESET; - case pci_channel_io_perm_failure: - /* Permanent error, prepare for device removal */ - ioc->pci_error_recovery = 1; - mpt2sas_base_stop_watchdog(ioc); - _scsih_flush_running_cmds(ioc); - return PCI_ERS_RESULT_DISCONNECT; - } - return PCI_ERS_RESULT_NEED_RESET; -} - -/** - * _scsih_pci_slot_reset - Called when PCI slot has been reset. - * @pdev: PCI device struct - * - * Description: This routine is called by the pci error recovery - * code after the PCI slot has been reset, just before we - * should resume normal operations. - */ -static pci_ers_result_t -_scsih_pci_slot_reset(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int rc; - - printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n", - ioc->name); - - ioc->pci_error_recovery = 0; - ioc->pdev = pdev; - pci_restore_state(pdev); - rc = mpt2sas_base_map_resources(ioc); - if (rc) - return PCI_ERS_RESULT_DISCONNECT; - - - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - - printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name, - (rc == 0) ? "success" : "failed"); - - if (!rc) - return PCI_ERS_RESULT_RECOVERED; - else - return PCI_ERS_RESULT_DISCONNECT; -} - -/** - * _scsih_pci_resume() - resume normal ops after PCI reset - * @pdev: pointer to PCI device - * - * Called when the error recovery driver tells us that its - * OK to resume normal operation. Use completion to allow - * halted scsi ops to resume. - */ -static void -_scsih_pci_resume(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name); - - pci_cleanup_aer_uncorrect_error_status(pdev); - mpt2sas_base_start_watchdog(ioc); - scsi_unblock_requests(ioc->shost); -} - -/** - * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers - * @pdev: pointer to PCI device - */ -static pci_ers_result_t -_scsih_pci_mmio_enabled(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n", - ioc->name); - - /* TODO - dump whatever for debugging purposes */ - - /* Request a slot reset. */ - return PCI_ERS_RESULT_NEED_RESET; -} - -static const struct pci_error_handlers _scsih_err_handler = { - .error_detected = _scsih_pci_error_detected, - .mmio_enabled = _scsih_pci_mmio_enabled, - .slot_reset = _scsih_pci_slot_reset, - .resume = _scsih_pci_resume, -}; - -static struct pci_driver scsih_driver = { - .name = MPT2SAS_DRIVER_NAME, - .id_table = scsih_pci_table, - .probe = _scsih_probe, - .remove = _scsih_remove, - .shutdown = _scsih_shutdown, - .err_handler = &_scsih_err_handler, -#ifdef CONFIG_PM - .suspend = _scsih_suspend, - .resume = _scsih_resume, -#endif -}; - -/* raid transport support */ -static struct raid_function_template mpt2sas_raid_functions = { - .cookie = &scsih_driver_template, - .is_raid = _scsih_is_raid, - .get_resync = _scsih_get_resync, - .get_state = _scsih_get_state, -}; - -/** - * _scsih_init - main entry point for this driver. - * - * Returns 0 success, anything else error. - */ -static int __init -_scsih_init(void) -{ - int error; - - mpt_ids = 0; - printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME, - MPT2SAS_DRIVER_VERSION); - - mpt2sas_transport_template = - sas_attach_transport(&mpt2sas_transport_functions); - if (!mpt2sas_transport_template) - return -ENODEV; - /* raid transport support */ - mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions); - if (!mpt2sas_raid_template) { - sas_release_transport(mpt2sas_transport_template); - return -ENODEV; - } - - mpt2sas_base_initialize_callback_handler(); - - /* queuecommand callback hander */ - scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done); - - /* task management callback handler */ - tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done); - - /* base internal commands callback handler */ - base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done); - port_enable_cb_idx = mpt2sas_base_register_callback_handler( - mpt2sas_port_enable_done); - - /* transport internal commands callback handler */ - transport_cb_idx = mpt2sas_base_register_callback_handler( - mpt2sas_transport_done); - - /* scsih internal commands callback handler */ - scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done); - - /* configuration page API internal commands callback handler */ - config_cb_idx = mpt2sas_base_register_callback_handler( - mpt2sas_config_done); - - /* ctl module callback handler */ - ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done); - - tm_tr_cb_idx = mpt2sas_base_register_callback_handler( - _scsih_tm_tr_complete); - - tm_tr_volume_cb_idx = mpt2sas_base_register_callback_handler( - _scsih_tm_volume_tr_complete); - - tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler( - _scsih_sas_control_complete); - - mpt2sas_ctl_init(); - - error = pci_register_driver(&scsih_driver); - if (error) { - /* raid transport support */ - raid_class_release(mpt2sas_raid_template); - sas_release_transport(mpt2sas_transport_template); - } - - return error; -} - -/** - * _scsih_exit - exit point for this driver (when it is a module). - * - * Returns 0 success, anything else error. - */ -static void __exit -_scsih_exit(void) -{ - printk(KERN_INFO "mpt2sas version %s unloading\n", - MPT2SAS_DRIVER_VERSION); - - pci_unregister_driver(&scsih_driver); - - mpt2sas_ctl_exit(); - - mpt2sas_base_release_callback_handler(scsi_io_cb_idx); - mpt2sas_base_release_callback_handler(tm_cb_idx); - mpt2sas_base_release_callback_handler(base_cb_idx); - mpt2sas_base_release_callback_handler(port_enable_cb_idx); - mpt2sas_base_release_callback_handler(transport_cb_idx); - mpt2sas_base_release_callback_handler(scsih_cb_idx); - mpt2sas_base_release_callback_handler(config_cb_idx); - mpt2sas_base_release_callback_handler(ctl_cb_idx); - - mpt2sas_base_release_callback_handler(tm_tr_cb_idx); - mpt2sas_base_release_callback_handler(tm_tr_volume_cb_idx); - mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx); - - /* raid transport support */ - raid_class_release(mpt2sas_raid_template); - sas_release_transport(mpt2sas_transport_template); - -} - -module_init(_scsih_init); -module_exit(_scsih_exit); diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c deleted file mode 100644 index af8680093..000000000 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ /dev/null @@ -1,2173 +0,0 @@ -/* - * SAS Transport Layer for MPT (Message Passing Technology) based controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c - * Copyright (C) 2007-2014 LSI Corporation - * Copyright (C) 20013-2014 Avago Technologies - * (mailto: MPT-FusionLinux.pdl@avagotech.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. - * - * 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. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "mpt2sas_base.h" -/** - * _transport_sas_node_find_by_sas_address - sas node search - * @ioc: per adapter object - * @sas_address: sas address of expander or sas host - * Context: Calling function should acquire ioc->sas_node_lock. - * - * Search for either hba phys or expander device based on handle, then returns - * the sas_node object. - */ -static struct _sas_node * -_transport_sas_node_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address) -{ - if (ioc->sas_hba.sas_address == sas_address) - return &ioc->sas_hba; - else - return mpt2sas_scsih_expander_find_by_sas_address(ioc, - sas_address); -} - -/** - * _transport_convert_phy_link_rate - - * @link_rate: link rate returned from mpt firmware - * - * Convert link_rate from mpi fusion into sas_transport form. - */ -static enum sas_linkrate -_transport_convert_phy_link_rate(u8 link_rate) -{ - enum sas_linkrate rc; - - switch (link_rate) { - case MPI2_SAS_NEG_LINK_RATE_1_5: - rc = SAS_LINK_RATE_1_5_GBPS; - break; - case MPI2_SAS_NEG_LINK_RATE_3_0: - rc = SAS_LINK_RATE_3_0_GBPS; - break; - case MPI2_SAS_NEG_LINK_RATE_6_0: - rc = SAS_LINK_RATE_6_0_GBPS; - break; - case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED: - rc = SAS_PHY_DISABLED; - break; - case MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED: - rc = SAS_LINK_RATE_FAILED; - break; - case MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR: - rc = SAS_SATA_PORT_SELECTOR; - break; - case MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS: - rc = SAS_PHY_RESET_IN_PROGRESS; - break; - default: - case MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE: - case MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE: - rc = SAS_LINK_RATE_UNKNOWN; - break; - } - return rc; -} - -/** - * _transport_set_identify - set identify for phys and end devices - * @ioc: per adapter object - * @handle: device handle - * @identify: sas identify info - * - * Populates sas identify info. - * - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle, - struct sas_identify *identify) -{ - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2ConfigReply_t mpi_reply; - u32 device_info; - u32 ioc_status; - - if (ioc->shost_recovery || ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - - ioc->name, __FILE__, __LINE__, __func__); - return -ENXIO; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)" - "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status, - __FILE__, __LINE__, __func__); - return -EIO; - } - - memset(identify, 0, sizeof(struct sas_identify)); - device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); - - /* sas_address */ - identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - - /* phy number of the parent device this device is linked to */ - identify->phy_identifier = sas_device_pg0.PhyNum; - - /* device_type */ - switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { - case MPI2_SAS_DEVICE_INFO_NO_DEVICE: - identify->device_type = SAS_PHY_UNUSED; - break; - case MPI2_SAS_DEVICE_INFO_END_DEVICE: - identify->device_type = SAS_END_DEVICE; - break; - case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER: - identify->device_type = SAS_EDGE_EXPANDER_DEVICE; - break; - case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER: - identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; - break; - } - - /* initiator_port_protocols */ - if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR) - identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; - if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR) - identify->initiator_port_protocols |= SAS_PROTOCOL_STP; - if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR) - identify->initiator_port_protocols |= SAS_PROTOCOL_SMP; - if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST) - identify->initiator_port_protocols |= SAS_PROTOCOL_SATA; - - /* target_port_protocols */ - if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) - identify->target_port_protocols |= SAS_PROTOCOL_SSP; - if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) - identify->target_port_protocols |= SAS_PROTOCOL_STP; - if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) - identify->target_port_protocols |= SAS_PROTOCOL_SMP; - if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) - identify->target_port_protocols |= SAS_PROTOCOL_SATA; - - return 0; -} - -/** - * mpt2sas_transport_done - internal transport layer callback handler. - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Callback handler when sending internal generated transport cmds. - * The callback index passed is `ioc->transport_cb_idx` - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (ioc->transport_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->transport_cmds.smid != smid) - return 1; - ioc->transport_cmds.status |= MPT2_CMD_COMPLETE; - if (mpi_reply) { - memcpy(ioc->transport_cmds.reply, mpi_reply, - mpi_reply->MsgLength*4); - ioc->transport_cmds.status |= MPT2_CMD_REPLY_VALID; - } - ioc->transport_cmds.status &= ~MPT2_CMD_PENDING; - complete(&ioc->transport_cmds.done); - return 1; -} - -/* report manufacture request structure */ -struct rep_manu_request{ - u8 smp_frame_type; - u8 function; - u8 reserved; - u8 request_length; -}; - -/* report manufacture reply structure */ -struct rep_manu_reply{ - u8 smp_frame_type; /* 0x41 */ - u8 function; /* 0x01 */ - u8 function_result; - u8 response_length; - u16 expander_change_count; - u8 reserved0[2]; - u8 sas_format; - u8 reserved2[3]; - u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; - u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; - u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; - u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; - u16 component_id; - u8 component_revision_id; - u8 reserved3; - u8 vendor_specific[8]; -}; - -/** - * _transport_expander_report_manufacture - obtain SMP report_manufacture - * @ioc: per adapter object - * @sas_address: expander sas address - * @edev: the sas_expander_device object - * - * Fills in the sas_expander_device object when SMP port is created. - * - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address, struct sas_expander_device *edev) -{ - Mpi2SmpPassthroughRequest_t *mpi_request; - Mpi2SmpPassthroughReply_t *mpi_reply; - struct rep_manu_reply *manufacture_reply; - struct rep_manu_request *manufacture_request; - int rc; - u16 smid; - u32 ioc_state; - unsigned long timeleft; - void *psge; - u32 sgl_flags; - u8 issue_reset = 0; - void *data_out = NULL; - dma_addr_t data_out_dma; - u32 sz; - u16 wait_state_count; - - if (ioc->shost_recovery || ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - mutex_lock(&ioc->transport_cmds.mutex); - - if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - ioc->transport_cmds.status = MPT2_CMD_PENDING; - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - rc = 0; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->transport_cmds.smid = smid; - - sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply); - data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); - - if (!data_out) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - rc = -ENOMEM; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - - manufacture_request = data_out; - manufacture_request->smp_frame_type = 0x40; - manufacture_request->function = 1; - manufacture_request->reserved = 0; - manufacture_request->request_length = 0; - - memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(sas_address); - mpi_request->RequestDataLength = - cpu_to_le16(sizeof(struct rep_manu_request)); - psge = &mpi_request->SGL; - - /* WRITE sgel first */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct rep_manu_request), data_out_dma); - - /* incr sgel */ - psge += ioc->sge_size; - - /* READ sgel last */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct rep_manu_reply), data_out_dma + - sizeof(struct rep_manu_request)); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - " - "send to sas_addr(0x%016llx)\n", ioc->name, - (unsigned long long)sas_address)); - init_completion(&ioc->transport_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, - 10*HZ); - - if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SmpPassthroughRequest_t)/4); - if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - " - "complete\n", ioc->name)); - - if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { - u8 *tmp; - - mpi_reply = ioc->transport_cmds.reply; - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "report_manufacture - reply data transfer size(%d)\n", - ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); - - if (le16_to_cpu(mpi_reply->ResponseDataLength) != - sizeof(struct rep_manu_reply)) - goto out; - - manufacture_reply = data_out + sizeof(struct rep_manu_request); - strncpy(edev->vendor_id, manufacture_reply->vendor_id, - SAS_EXPANDER_VENDOR_ID_LEN); - strncpy(edev->product_id, manufacture_reply->product_id, - SAS_EXPANDER_PRODUCT_ID_LEN); - strncpy(edev->product_rev, manufacture_reply->product_rev, - SAS_EXPANDER_PRODUCT_REV_LEN); - edev->level = manufacture_reply->sas_format & 1; - if (edev->level) { - strncpy(edev->component_vendor_id, - manufacture_reply->component_vendor_id, - SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); - tmp = (u8 *)&manufacture_reply->component_id; - edev->component_id = tmp[0] << 8 | tmp[1]; - edev->component_revision_id = - manufacture_reply->component_revision_id; - } - } else - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "report_manufacture - no reply\n", ioc->name)); - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - out: - ioc->transport_cmds.status = MPT2_CMD_NOT_USED; - if (data_out) - pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); - - mutex_unlock(&ioc->transport_cmds.mutex); - return rc; -} - -/** - * _transport_delete_port - helper function to removing a port - * @ioc: per adapter object - * @mpt2sas_port: mpt2sas per port object - * - * Returns nothing. - */ -static void -_transport_delete_port(struct MPT2SAS_ADAPTER *ioc, - struct _sas_port *mpt2sas_port) -{ - u64 sas_address = mpt2sas_port->remote_identify.sas_address; - enum sas_device_type device_type = - mpt2sas_port->remote_identify.device_type; - - dev_printk(KERN_INFO, &mpt2sas_port->port->dev, - "remove: sas_addr(0x%016llx)\n", - (unsigned long long) sas_address); - - ioc->logging_level |= MPT_DEBUG_TRANSPORT; - if (device_type == SAS_END_DEVICE) - mpt2sas_device_remove_by_sas_address(ioc, sas_address); - else if (device_type == SAS_EDGE_EXPANDER_DEVICE || - device_type == SAS_FANOUT_EXPANDER_DEVICE) - mpt2sas_expander_remove(ioc, sas_address); - ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; -} - -/** - * _transport_delete_phy - helper function to removing single phy from port - * @ioc: per adapter object - * @mpt2sas_port: mpt2sas per port object - * @mpt2sas_phy: mpt2sas per phy object - * - * Returns nothing. - */ -static void -_transport_delete_phy(struct MPT2SAS_ADAPTER *ioc, - struct _sas_port *mpt2sas_port, struct _sas_phy *mpt2sas_phy) -{ - u64 sas_address = mpt2sas_port->remote_identify.sas_address; - - dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, - "remove: sas_addr(0x%016llx), phy(%d)\n", - (unsigned long long) sas_address, mpt2sas_phy->phy_id); - - list_del(&mpt2sas_phy->port_siblings); - mpt2sas_port->num_phys--; - sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); - mpt2sas_phy->phy_belongs_to_port = 0; -} - -/** - * _transport_add_phy - helper function to adding single phy to port - * @ioc: per adapter object - * @mpt2sas_port: mpt2sas per port object - * @mpt2sas_phy: mpt2sas per phy object - * - * Returns nothing. - */ -static void -_transport_add_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_port *mpt2sas_port, - struct _sas_phy *mpt2sas_phy) -{ - u64 sas_address = mpt2sas_port->remote_identify.sas_address; - - dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, - "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long) - sas_address, mpt2sas_phy->phy_id); - - list_add_tail(&mpt2sas_phy->port_siblings, &mpt2sas_port->phy_list); - mpt2sas_port->num_phys++; - sas_port_add_phy(mpt2sas_port->port, mpt2sas_phy->phy); - mpt2sas_phy->phy_belongs_to_port = 1; -} - -/** - * _transport_add_phy_to_an_existing_port - adding new phy to existing port - * @ioc: per adapter object - * @sas_node: sas node object (either expander or sas host) - * @mpt2sas_phy: mpt2sas per phy object - * @sas_address: sas address of device/expander were phy needs to be added to - * - * Returns nothing. - */ -static void -_transport_add_phy_to_an_existing_port(struct MPT2SAS_ADAPTER *ioc, -struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy, u64 sas_address) -{ - struct _sas_port *mpt2sas_port; - struct _sas_phy *phy_srch; - - if (mpt2sas_phy->phy_belongs_to_port == 1) - return; - - list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, - port_list) { - if (mpt2sas_port->remote_identify.sas_address != - sas_address) - continue; - list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, - port_siblings) { - if (phy_srch == mpt2sas_phy) - return; - } - _transport_add_phy(ioc, mpt2sas_port, mpt2sas_phy); - return; - } - -} - -/** - * _transport_del_phy_from_an_existing_port - delete phy from existing port - * @ioc: per adapter object - * @sas_node: sas node object (either expander or sas host) - * @mpt2sas_phy: mpt2sas per phy object - * - * Returns nothing. - */ -static void -_transport_del_phy_from_an_existing_port(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy) -{ - struct _sas_port *mpt2sas_port, *next; - struct _sas_phy *phy_srch; - - if (mpt2sas_phy->phy_belongs_to_port == 0) - return; - - list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list, - port_list) { - list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, - port_siblings) { - if (phy_srch != mpt2sas_phy) - continue; - if (mpt2sas_port->num_phys == 1) - _transport_delete_port(ioc, mpt2sas_port); - else - _transport_delete_phy(ioc, mpt2sas_port, - mpt2sas_phy); - return; - } - } -} - -/** - * _transport_sanity_check - sanity check when adding a new port - * @ioc: per adapter object - * @sas_node: sas node object (either expander or sas host) - * @sas_address: sas address of device being added - * - * See the explanation above from _transport_delete_duplicate_port - */ -static void -_transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node, - u64 sas_address) -{ - int i; - - for (i = 0; i < sas_node->num_phys; i++) { - if (sas_node->phy[i].remote_identify.sas_address != sas_address) - continue; - if (sas_node->phy[i].phy_belongs_to_port == 1) - _transport_del_phy_from_an_existing_port(ioc, sas_node, - &sas_node->phy[i]); - } -} - -/** - * mpt2sas_transport_port_add - insert port to the list - * @ioc: per adapter object - * @handle: handle of attached device - * @sas_address: sas address of parent expander or sas host - * Context: This function will acquire ioc->sas_node_lock. - * - * Adding new port object to the sas_node->sas_port_list. - * - * Returns mpt2sas_port. - */ -struct _sas_port * -mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, - u64 sas_address) -{ - struct _sas_phy *mpt2sas_phy, *next; - struct _sas_port *mpt2sas_port; - unsigned long flags; - struct _sas_node *sas_node; - struct sas_rphy *rphy; - int i; - struct sas_port *port; - - mpt2sas_port = kzalloc(sizeof(struct _sas_port), - GFP_KERNEL); - if (!mpt2sas_port) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return NULL; - } - - INIT_LIST_HEAD(&mpt2sas_port->port_list); - INIT_LIST_HEAD(&mpt2sas_port->phy_list); - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - if (!sas_node) { - printk(MPT2SAS_ERR_FMT "%s: Could not find " - "parent sas_address(0x%016llx)!\n", ioc->name, - __func__, (unsigned long long)sas_address); - goto out_fail; - } - - if ((_transport_set_identify(ioc, handle, - &mpt2sas_port->remote_identify))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out_fail; - } - - if (mpt2sas_port->remote_identify.device_type == SAS_PHY_UNUSED) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out_fail; - } - - _transport_sanity_check(ioc, sas_node, - mpt2sas_port->remote_identify.sas_address); - - for (i = 0; i < sas_node->num_phys; i++) { - if (sas_node->phy[i].remote_identify.sas_address != - mpt2sas_port->remote_identify.sas_address) - continue; - list_add_tail(&sas_node->phy[i].port_siblings, - &mpt2sas_port->phy_list); - mpt2sas_port->num_phys++; - } - - if (!mpt2sas_port->num_phys) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out_fail; - } - - port = sas_port_alloc_num(sas_node->parent_dev); - if ((sas_port_add(port))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out_fail; - } - - list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list, - port_siblings) { - if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) - dev_printk(KERN_INFO, &port->dev, "add: handle(0x%04x)" - ", sas_addr(0x%016llx), phy(%d)\n", handle, - (unsigned long long) - mpt2sas_port->remote_identify.sas_address, - mpt2sas_phy->phy_id); - sas_port_add_phy(port, mpt2sas_phy->phy); - mpt2sas_phy->phy_belongs_to_port = 1; - } - - mpt2sas_port->port = port; - if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) - rphy = sas_end_device_alloc(port); - else - rphy = sas_expander_alloc(port, - mpt2sas_port->remote_identify.device_type); - - rphy->identify = mpt2sas_port->remote_identify; - if ((sas_rphy_add(rphy))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - } - if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) - dev_printk(KERN_INFO, &rphy->dev, "add: handle(0x%04x), " - "sas_addr(0x%016llx)\n", handle, - (unsigned long long) - mpt2sas_port->remote_identify.sas_address); - mpt2sas_port->rphy = rphy; - spin_lock_irqsave(&ioc->sas_node_lock, flags); - list_add_tail(&mpt2sas_port->port_list, &sas_node->sas_port_list); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - /* fill in report manufacture */ - if (mpt2sas_port->remote_identify.device_type == - MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER || - mpt2sas_port->remote_identify.device_type == - MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) - _transport_expander_report_manufacture(ioc, - mpt2sas_port->remote_identify.sas_address, - rphy_to_expander_device(rphy)); - - return mpt2sas_port; - - out_fail: - list_for_each_entry_safe(mpt2sas_phy, next, &mpt2sas_port->phy_list, - port_siblings) - list_del(&mpt2sas_phy->port_siblings); - kfree(mpt2sas_port); - return NULL; -} - -/** - * mpt2sas_transport_port_remove - remove port from the list - * @ioc: per adapter object - * @sas_address: sas address of attached device - * @sas_address_parent: sas address of parent expander or sas host - * Context: This function will acquire ioc->sas_node_lock. - * - * Removing object and freeing associated memory from the - * ioc->sas_port_list. - * - * Return nothing. - */ -void -mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u64 sas_address_parent) -{ - int i; - unsigned long flags; - struct _sas_port *mpt2sas_port, *next; - struct _sas_node *sas_node; - u8 found = 0; - struct _sas_phy *mpt2sas_phy, *next_phy; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_node = _transport_sas_node_find_by_sas_address(ioc, - sas_address_parent); - if (!sas_node) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return; - } - list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list, - port_list) { - if (mpt2sas_port->remote_identify.sas_address != sas_address) - continue; - found = 1; - list_del(&mpt2sas_port->port_list); - goto out; - } - out: - if (!found) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return; - } - - for (i = 0; i < sas_node->num_phys; i++) { - if (sas_node->phy[i].remote_identify.sas_address == sas_address) - memset(&sas_node->phy[i].remote_identify, 0 , - sizeof(struct sas_identify)); - } - - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - list_for_each_entry_safe(mpt2sas_phy, next_phy, - &mpt2sas_port->phy_list, port_siblings) { - if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) - dev_printk(KERN_INFO, &mpt2sas_port->port->dev, - "remove: sas_addr(0x%016llx), phy(%d)\n", - (unsigned long long) - mpt2sas_port->remote_identify.sas_address, - mpt2sas_phy->phy_id); - mpt2sas_phy->phy_belongs_to_port = 0; - sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); - list_del(&mpt2sas_phy->port_siblings); - } - sas_port_delete(mpt2sas_port->port); - kfree(mpt2sas_port); -} - -/** - * mpt2sas_transport_add_host_phy - report sas_host phy to transport - * @ioc: per adapter object - * @mpt2sas_phy: mpt2sas per phy object - * @phy_pg0: sas phy page 0 - * @parent_dev: parent device class object - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy - *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev) -{ - struct sas_phy *phy; - int phy_index = mpt2sas_phy->phy_id; - - - INIT_LIST_HEAD(&mpt2sas_phy->port_siblings); - phy = sas_phy_alloc(parent_dev, phy_index); - if (!phy) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - if ((_transport_set_identify(ioc, mpt2sas_phy->handle, - &mpt2sas_phy->identify))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - phy->identify = mpt2sas_phy->identify; - mpt2sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle); - if (mpt2sas_phy->attached_handle) - _transport_set_identify(ioc, mpt2sas_phy->attached_handle, - &mpt2sas_phy->remote_identify); - phy->identify.phy_identifier = mpt2sas_phy->phy_id; - phy->negotiated_linkrate = _transport_convert_phy_link_rate( - phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); - phy->minimum_linkrate_hw = _transport_convert_phy_link_rate( - phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK); - phy->maximum_linkrate_hw = _transport_convert_phy_link_rate( - phy_pg0.HwLinkRate >> 4); - phy->minimum_linkrate = _transport_convert_phy_link_rate( - phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); - phy->maximum_linkrate = _transport_convert_phy_link_rate( - phy_pg0.ProgrammedLinkRate >> 4); - - if ((sas_phy_add(phy))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - sas_phy_free(phy); - return -1; - } - if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) - dev_printk(KERN_INFO, &phy->dev, - "add: handle(0x%04x), sas_addr(0x%016llx)\n" - "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", - mpt2sas_phy->handle, (unsigned long long) - mpt2sas_phy->identify.sas_address, - mpt2sas_phy->attached_handle, - (unsigned long long) - mpt2sas_phy->remote_identify.sas_address); - mpt2sas_phy->phy = phy; - return 0; -} - - -/** - * mpt2sas_transport_add_expander_phy - report expander phy to transport - * @ioc: per adapter object - * @mpt2sas_phy: mpt2sas per phy object - * @expander_pg1: expander page 1 - * @parent_dev: parent device class object - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy - *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev) -{ - struct sas_phy *phy; - int phy_index = mpt2sas_phy->phy_id; - - INIT_LIST_HEAD(&mpt2sas_phy->port_siblings); - phy = sas_phy_alloc(parent_dev, phy_index); - if (!phy) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - if ((_transport_set_identify(ioc, mpt2sas_phy->handle, - &mpt2sas_phy->identify))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - phy->identify = mpt2sas_phy->identify; - mpt2sas_phy->attached_handle = - le16_to_cpu(expander_pg1.AttachedDevHandle); - if (mpt2sas_phy->attached_handle) - _transport_set_identify(ioc, mpt2sas_phy->attached_handle, - &mpt2sas_phy->remote_identify); - phy->identify.phy_identifier = mpt2sas_phy->phy_id; - phy->negotiated_linkrate = _transport_convert_phy_link_rate( - expander_pg1.NegotiatedLinkRate & - MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); - phy->minimum_linkrate_hw = _transport_convert_phy_link_rate( - expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK); - phy->maximum_linkrate_hw = _transport_convert_phy_link_rate( - expander_pg1.HwLinkRate >> 4); - phy->minimum_linkrate = _transport_convert_phy_link_rate( - expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); - phy->maximum_linkrate = _transport_convert_phy_link_rate( - expander_pg1.ProgrammedLinkRate >> 4); - - if ((sas_phy_add(phy))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - sas_phy_free(phy); - return -1; - } - if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) - dev_printk(KERN_INFO, &phy->dev, - "add: handle(0x%04x), sas_addr(0x%016llx)\n" - "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", - mpt2sas_phy->handle, (unsigned long long) - mpt2sas_phy->identify.sas_address, - mpt2sas_phy->attached_handle, - (unsigned long long) - mpt2sas_phy->remote_identify.sas_address); - mpt2sas_phy->phy = phy; - return 0; -} - -/** - * mpt2sas_transport_update_links - refreshing phy link changes - * @ioc: per adapter object - * @sas_address: sas address of parent expander or sas host - * @handle: attached device handle - * @phy_numberv: phy number - * @link_rate: new link rate - * - * Returns nothing. - */ -void -mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address, u16 handle, u8 phy_number, u8 link_rate) -{ - unsigned long flags; - struct _sas_node *sas_node; - struct _sas_phy *mpt2sas_phy; - - if (ioc->shost_recovery || ioc->pci_error_recovery) - return; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); - if (!sas_node) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return; - } - - mpt2sas_phy = &sas_node->phy[phy_number]; - mpt2sas_phy->attached_handle = handle; - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) { - _transport_set_identify(ioc, handle, - &mpt2sas_phy->remote_identify); - _transport_add_phy_to_an_existing_port(ioc, sas_node, - mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address); - } else - memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct - sas_identify)); - - if (mpt2sas_phy->phy) - mpt2sas_phy->phy->negotiated_linkrate = - _transport_convert_phy_link_rate(link_rate); - - if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) - dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, - "refresh: parent sas_addr(0x%016llx),\n" - "\tlink_rate(0x%02x), phy(%d)\n" - "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", - (unsigned long long)sas_address, - link_rate, phy_number, handle, (unsigned long long) - mpt2sas_phy->remote_identify.sas_address); -} - -static inline void * -phy_to_ioc(struct sas_phy *phy) -{ - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - return shost_priv(shost); -} - -static inline void * -rphy_to_ioc(struct sas_rphy *rphy) -{ - struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); - return shost_priv(shost); -} - - -/* report phy error log structure */ -struct phy_error_log_request{ - u8 smp_frame_type; /* 0x40 */ - u8 function; /* 0x11 */ - u8 allocated_response_length; - u8 request_length; /* 02 */ - u8 reserved_1[5]; - u8 phy_identifier; - u8 reserved_2[2]; -}; - -/* report phy error log reply structure */ -struct phy_error_log_reply{ - u8 smp_frame_type; /* 0x41 */ - u8 function; /* 0x11 */ - u8 function_result; - u8 response_length; - __be16 expander_change_count; - u8 reserved_1[3]; - u8 phy_identifier; - u8 reserved_2[2]; - __be32 invalid_dword; - __be32 running_disparity_error; - __be32 loss_of_dword_sync; - __be32 phy_reset_problem; -}; - -/** - * _transport_get_expander_phy_error_log - return expander counters - * @ioc: per adapter object - * @phy: The sas phy object - * - * Returns 0 for success, non-zero for failure. - * - */ -static int -_transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc, - struct sas_phy *phy) -{ - Mpi2SmpPassthroughRequest_t *mpi_request; - Mpi2SmpPassthroughReply_t *mpi_reply; - struct phy_error_log_request *phy_error_log_request; - struct phy_error_log_reply *phy_error_log_reply; - int rc; - u16 smid; - u32 ioc_state; - unsigned long timeleft; - void *psge; - u32 sgl_flags; - u8 issue_reset = 0; - void *data_out = NULL; - dma_addr_t data_out_dma; - u32 sz; - u16 wait_state_count; - - if (ioc->shost_recovery || ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - mutex_lock(&ioc->transport_cmds.mutex); - - if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - ioc->transport_cmds.status = MPT2_CMD_PENDING; - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->transport_cmds.smid = smid; - - sz = sizeof(struct phy_error_log_request) + - sizeof(struct phy_error_log_reply); - data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); - if (!data_out) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - rc = -ENOMEM; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - - rc = -EINVAL; - memset(data_out, 0, sz); - phy_error_log_request = data_out; - phy_error_log_request->smp_frame_type = 0x40; - phy_error_log_request->function = 0x11; - phy_error_log_request->request_length = 2; - phy_error_log_request->allocated_response_length = 0; - phy_error_log_request->phy_identifier = phy->number; - - memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); - mpi_request->RequestDataLength = - cpu_to_le16(sizeof(struct phy_error_log_request)); - psge = &mpi_request->SGL; - - /* WRITE sgel first */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct phy_error_log_request), data_out_dma); - - /* incr sgel */ - psge += ioc->sge_size; - - /* READ sgel last */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct phy_error_log_reply), data_out_dma + - sizeof(struct phy_error_log_request)); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - " - "send to sas_addr(0x%016llx), phy(%d)\n", ioc->name, - (unsigned long long)phy->identify.sas_address, phy->number)); - init_completion(&ioc->transport_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, - 10*HZ); - - if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SmpPassthroughRequest_t)/4); - if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - " - "complete\n", ioc->name)); - - if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { - - mpi_reply = ioc->transport_cmds.reply; - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_error_log - reply data transfer size(%d)\n", - ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); - - if (le16_to_cpu(mpi_reply->ResponseDataLength) != - sizeof(struct phy_error_log_reply)) - goto out; - - phy_error_log_reply = data_out + - sizeof(struct phy_error_log_request); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_error_log - function_result(%d)\n", - ioc->name, phy_error_log_reply->function_result)); - - phy->invalid_dword_count = - be32_to_cpu(phy_error_log_reply->invalid_dword); - phy->running_disparity_error_count = - be32_to_cpu(phy_error_log_reply->running_disparity_error); - phy->loss_of_dword_sync_count = - be32_to_cpu(phy_error_log_reply->loss_of_dword_sync); - phy->phy_reset_problem_count = - be32_to_cpu(phy_error_log_reply->phy_reset_problem); - rc = 0; - } else - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_error_log - no reply\n", ioc->name)); - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - out: - ioc->transport_cmds.status = MPT2_CMD_NOT_USED; - if (data_out) - pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); - - mutex_unlock(&ioc->transport_cmds.mutex); - return rc; -} - -/** - * _transport_get_linkerrors - return phy counters for both hba and expanders - * @phy: The sas phy object - * - * Returns 0 for success, non-zero for failure. - * - */ -static int -_transport_get_linkerrors(struct sas_phy *phy) -{ - struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - unsigned long flags; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasPhyPage1_t phy_pg1; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return -EINVAL; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - if (phy->identify.sas_address != ioc->sas_hba.sas_address) - return _transport_get_expander_phy_error_log(ioc, phy); - - /* get hba phy error logs */ - if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1, - phy->number))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -ENXIO; - } - - if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) - printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status" - "(0x%04x), loginfo(0x%08x)\n", ioc->name, - phy->number, le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo)); - - phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount); - phy->running_disparity_error_count = - le32_to_cpu(phy_pg1.RunningDisparityErrorCount); - phy->loss_of_dword_sync_count = - le32_to_cpu(phy_pg1.LossDwordSynchCount); - phy->phy_reset_problem_count = - le32_to_cpu(phy_pg1.PhyResetProblemCount); - return 0; -} - -/** - * _transport_get_enclosure_identifier - - * @phy: The sas phy object - * - * Obtain the enclosure logical id for an expander. - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) -{ - struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy); - struct _sas_device *sas_device; - unsigned long flags; - int rc; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - rphy->identify.sas_address); - if (sas_device) { - *identifier = sas_device->enclosure_logical_id; - rc = 0; - sas_device_put(sas_device); - } else { - *identifier = 0; - rc = -ENXIO; - } - - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return rc; -} - -/** - * _transport_get_bay_identifier - - * @phy: The sas phy object - * - * Returns the slot id for a device that resides inside an enclosure. - */ -static int -_transport_get_bay_identifier(struct sas_rphy *rphy) -{ - struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy); - struct _sas_device *sas_device; - unsigned long flags; - int rc; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = __mpt2sas_get_sdev_by_addr(ioc, - rphy->identify.sas_address); - if (sas_device) { - rc = sas_device->slot; - sas_device_put(sas_device); - } else { - rc = -ENXIO; - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return rc; -} - -/* phy control request structure */ -struct phy_control_request{ - u8 smp_frame_type; /* 0x40 */ - u8 function; /* 0x91 */ - u8 allocated_response_length; - u8 request_length; /* 0x09 */ - u16 expander_change_count; - u8 reserved_1[3]; - u8 phy_identifier; - u8 phy_operation; - u8 reserved_2[13]; - u64 attached_device_name; - u8 programmed_min_physical_link_rate; - u8 programmed_max_physical_link_rate; - u8 reserved_3[6]; -}; - -/* phy control reply structure */ -struct phy_control_reply{ - u8 smp_frame_type; /* 0x41 */ - u8 function; /* 0x11 */ - u8 function_result; - u8 response_length; -}; - -#define SMP_PHY_CONTROL_LINK_RESET (0x01) -#define SMP_PHY_CONTROL_HARD_RESET (0x02) -#define SMP_PHY_CONTROL_DISABLE (0x03) - -/** - * _transport_expander_phy_control - expander phy control - * @ioc: per adapter object - * @phy: The sas phy object - * - * Returns 0 for success, non-zero for failure. - * - */ -static int -_transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc, - struct sas_phy *phy, u8 phy_operation) -{ - Mpi2SmpPassthroughRequest_t *mpi_request; - Mpi2SmpPassthroughReply_t *mpi_reply; - struct phy_control_request *phy_control_request; - struct phy_control_reply *phy_control_reply; - int rc; - u16 smid; - u32 ioc_state; - unsigned long timeleft; - void *psge; - u32 sgl_flags; - u8 issue_reset = 0; - void *data_out = NULL; - dma_addr_t data_out_dma; - u32 sz; - u16 wait_state_count; - - if (ioc->shost_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - mutex_lock(&ioc->transport_cmds.mutex); - - if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - ioc->transport_cmds.status = MPT2_CMD_PENDING; - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->transport_cmds.smid = smid; - - sz = sizeof(struct phy_control_request) + - sizeof(struct phy_control_reply); - data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); - if (!data_out) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - rc = -ENOMEM; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - - rc = -EINVAL; - memset(data_out, 0, sz); - phy_control_request = data_out; - phy_control_request->smp_frame_type = 0x40; - phy_control_request->function = 0x91; - phy_control_request->request_length = 9; - phy_control_request->allocated_response_length = 0; - phy_control_request->phy_identifier = phy->number; - phy_control_request->phy_operation = phy_operation; - phy_control_request->programmed_min_physical_link_rate = - phy->minimum_linkrate << 4; - phy_control_request->programmed_max_physical_link_rate = - phy->maximum_linkrate << 4; - - memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); - mpi_request->RequestDataLength = - cpu_to_le16(sizeof(struct phy_error_log_request)); - psge = &mpi_request->SGL; - - /* WRITE sgel first */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct phy_control_request), data_out_dma); - - /* incr sgel */ - psge += ioc->sge_size; - - /* READ sgel last */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct phy_control_reply), data_out_dma + - sizeof(struct phy_control_request)); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - " - "send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", ioc->name, - (unsigned long long)phy->identify.sas_address, phy->number, - phy_operation)); - - init_completion(&ioc->transport_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, - 10*HZ); - - if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SmpPassthroughRequest_t)/4); - if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - " - "complete\n", ioc->name)); - - if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { - - mpi_reply = ioc->transport_cmds.reply; - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_control - reply data transfer size(%d)\n", - ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); - - if (le16_to_cpu(mpi_reply->ResponseDataLength) != - sizeof(struct phy_control_reply)) - goto out; - - phy_control_reply = data_out + - sizeof(struct phy_control_request); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_control - function_result(%d)\n", - ioc->name, phy_control_reply->function_result)); - - rc = 0; - } else - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_control - no reply\n", ioc->name)); - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - out: - ioc->transport_cmds.status = MPT2_CMD_NOT_USED; - if (data_out) - pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); - - mutex_unlock(&ioc->transport_cmds.mutex); - return rc; -} - -/** - * _transport_phy_reset - - * @phy: The sas phy object - * @hard_reset: - * - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_phy_reset(struct sas_phy *phy, int hard_reset) -{ - struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - Mpi2SasIoUnitControlReply_t mpi_reply; - Mpi2SasIoUnitControlRequest_t mpi_request; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return -EINVAL; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - /* handle expander phys */ - if (phy->identify.sas_address != ioc->sas_hba.sas_address) - return _transport_expander_phy_control(ioc, phy, - (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET : - SMP_PHY_CONTROL_LINK_RESET); - - /* handle hba phys */ - memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t)); - mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; - mpi_request.Operation = hard_reset ? - MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET; - mpi_request.PhyNum = phy->number; - - if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -ENXIO; - } - - if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) - printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status" - "(0x%04x), loginfo(0x%08x)\n", ioc->name, - phy->number, le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo)); - - return 0; -} - -/** - * _transport_phy_enable - enable/disable phys - * @phy: The sas phy object - * @enable: enable phy when true - * - * Only support sas_host direct attached phys. - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_phy_enable(struct sas_phy *phy, int enable) -{ - struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; - Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; - Mpi2ConfigReply_t mpi_reply; - u16 ioc_status; - u16 sz; - int rc = 0; - unsigned long flags; - int i, discovery_active; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return -EINVAL; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - /* handle expander phys */ - if (phy->identify.sas_address != ioc->sas_hba.sas_address) - return _transport_expander_phy_control(ioc, phy, - (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET : - SMP_PHY_CONTROL_DISABLE); - - /* handle hba phys */ - - /* read sas_iounit page 0 */ - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit0PhyData_t)); - sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); - if (!sas_iounit_pg0) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -ENOMEM; - goto out; - } - if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, - sas_iounit_pg0, sz))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -ENXIO; - goto out; - } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -EIO; - goto out; - } - - /* unable to enable/disable phys when when discovery is active */ - for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) { - if (sas_iounit_pg0->PhyData[i].PortFlags & - MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) { - printk(MPT2SAS_ERR_FMT "discovery is active on " - "port = %d, phy = %d: unable to enable/disable " - "phys, try again later!\n", ioc->name, - sas_iounit_pg0->PhyData[i].Port, i); - discovery_active = 1; - } - } - - if (discovery_active) { - rc = -EAGAIN; - goto out; - } - - /* read sas_iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); - sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); - if (!sas_iounit_pg1) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -ENOMEM; - goto out; - } - if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, - sas_iounit_pg1, sz))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -ENXIO; - goto out; - } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -EIO; - goto out; - } - /* copy Port/PortFlags/PhyFlags from page 0 */ - for (i = 0; i < ioc->sas_hba.num_phys ; i++) { - sas_iounit_pg1->PhyData[i].Port = - sas_iounit_pg0->PhyData[i].Port; - sas_iounit_pg1->PhyData[i].PortFlags = - (sas_iounit_pg0->PhyData[i].PortFlags & - MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG); - sas_iounit_pg1->PhyData[i].PhyFlags = - (sas_iounit_pg0->PhyData[i].PhyFlags & - (MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED + - MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED)); - } - if (enable) - sas_iounit_pg1->PhyData[phy->number].PhyFlags - &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; - else - sas_iounit_pg1->PhyData[phy->number].PhyFlags - |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; - - mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz); - - /* link reset */ - if (enable) - _transport_phy_reset(phy, 0); - - out: - kfree(sas_iounit_pg1); - kfree(sas_iounit_pg0); - return rc; -} - -/** - * _transport_phy_speed - set phy min/max link rates - * @phy: The sas phy object - * @rates: rates defined in sas_phy_linkrates - * - * Only support sas_host direct attached phys. - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) -{ - struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; - Mpi2SasPhyPage0_t phy_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 ioc_status; - u16 sz; - int i; - int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return -EINVAL; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - if (!rates->minimum_linkrate) - rates->minimum_linkrate = phy->minimum_linkrate; - else if (rates->minimum_linkrate < phy->minimum_linkrate_hw) - rates->minimum_linkrate = phy->minimum_linkrate_hw; - - if (!rates->maximum_linkrate) - rates->maximum_linkrate = phy->maximum_linkrate; - else if (rates->maximum_linkrate > phy->maximum_linkrate_hw) - rates->maximum_linkrate = phy->maximum_linkrate_hw; - - /* handle expander phys */ - if (phy->identify.sas_address != ioc->sas_hba.sas_address) { - phy->minimum_linkrate = rates->minimum_linkrate; - phy->maximum_linkrate = rates->maximum_linkrate; - return _transport_expander_phy_control(ioc, phy, - SMP_PHY_CONTROL_LINK_RESET); - } - - /* handle hba phys */ - - /* sas_iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); - sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); - if (!sas_iounit_pg1) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -ENOMEM; - goto out; - } - if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, - sas_iounit_pg1, sz))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -ENXIO; - goto out; - } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -EIO; - goto out; - } - - for (i = 0; i < ioc->sas_hba.num_phys; i++) { - if (phy->number != i) { - sas_iounit_pg1->PhyData[i].MaxMinLinkRate = - (ioc->sas_hba.phy[i].phy->minimum_linkrate + - (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4)); - } else { - sas_iounit_pg1->PhyData[i].MaxMinLinkRate = - (rates->minimum_linkrate + - (rates->maximum_linkrate << 4)); - } - } - - if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, - sz)) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -ENXIO; - goto out; - } - - /* link reset */ - _transport_phy_reset(phy, 0); - - /* read phy page 0, then update the rates in the sas transport phy */ - if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, - phy->number)) { - phy->minimum_linkrate = _transport_convert_phy_link_rate( - phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); - phy->maximum_linkrate = _transport_convert_phy_link_rate( - phy_pg0.ProgrammedLinkRate >> 4); - phy->negotiated_linkrate = _transport_convert_phy_link_rate( - phy_pg0.NegotiatedLinkRate & - MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); - } - - out: - kfree(sas_iounit_pg1); - return rc; -} - - -/** - * _transport_smp_handler - transport portal for smp passthru - * @shost: shost object - * @rphy: sas transport rphy object - * @req: - * - * This used primarily for smp_utils. - * Example: - * smp_rep_general /sys/class/bsg/expander-5:0 - */ -static int -_transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, - struct request *req) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - Mpi2SmpPassthroughRequest_t *mpi_request; - Mpi2SmpPassthroughReply_t *mpi_reply; - int rc; - u16 smid; - u32 ioc_state; - unsigned long timeleft; - void *psge; - u32 sgl_flags; - u8 issue_reset = 0; - dma_addr_t dma_addr_in = 0; - dma_addr_t dma_addr_out = 0; - dma_addr_t pci_dma_in = 0; - dma_addr_t pci_dma_out = 0; - void *pci_addr_in = NULL; - void *pci_addr_out = NULL; - u16 wait_state_count; - struct request *rsp = req->next_rq; - struct bio_vec bvec; - struct bvec_iter iter; - - if (!rsp) { - printk(MPT2SAS_ERR_FMT "%s: the smp response space is " - "missing\n", ioc->name, __func__); - return -EINVAL; - } - if (ioc->shost_recovery || ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex); - if (rc) - return rc; - - if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", ioc->name, - __func__); - rc = -EAGAIN; - goto out; - } - ioc->transport_cmds.status = MPT2_CMD_PENDING; - - /* Check if the request is split across multiple segments */ - if (bio_multiple_segments(req->bio)) { - u32 offset = 0; - - /* Allocate memory and copy the request */ - pci_addr_out = pci_alloc_consistent(ioc->pdev, - blk_rq_bytes(req), &pci_dma_out); - if (!pci_addr_out) { - printk(MPT2SAS_INFO_FMT "%s(): PCI Addr out = NULL\n", - ioc->name, __func__); - rc = -ENOMEM; - goto out; - } - - bio_for_each_segment(bvec, req->bio, iter) { - memcpy(pci_addr_out + offset, - page_address(bvec.bv_page) + bvec.bv_offset, - bvec.bv_len); - offset += bvec.bv_len; - } - } else { - dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), - blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); - if (!dma_addr_out) { - printk(MPT2SAS_INFO_FMT "%s(): DMA Addr out = NULL\n", - ioc->name, __func__); - rc = -ENOMEM; - goto free_pci; - } - } - - /* Check if the response needs to be populated across - * multiple segments */ - if (bio_multiple_segments(rsp->bio)) { - pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp), - &pci_dma_in); - if (!pci_addr_in) { - printk(MPT2SAS_INFO_FMT "%s(): PCI Addr in = NULL\n", - ioc->name, __func__); - rc = -ENOMEM; - goto unmap; - } - } else { - dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), - blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); - if (!dma_addr_in) { - printk(MPT2SAS_INFO_FMT "%s(): DMA Addr in = NULL\n", - ioc->name, __func__); - rc = -ENOMEM; - goto unmap; - } - } - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto unmap; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto unmap; - } - - rc = 0; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->transport_cmds.smid = smid; - - memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - mpi_request->SASAddress = (rphy) ? - cpu_to_le64(rphy->identify.sas_address) : - cpu_to_le64(ioc->sas_hba.sas_address); - mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); - psge = &mpi_request->SGL; - - /* WRITE sgel first */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - if (bio_multiple_segments(req->bio)) { - ioc->base_add_sg_single(psge, sgl_flags | - (blk_rq_bytes(req) - 4), pci_dma_out); - } else { - ioc->base_add_sg_single(psge, sgl_flags | - (blk_rq_bytes(req) - 4), dma_addr_out); - } - - /* incr sgel */ - psge += ioc->sge_size; - - /* READ sgel last */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - if (bio_multiple_segments(rsp->bio)) { - ioc->base_add_sg_single(psge, sgl_flags | - (blk_rq_bytes(rsp) + 4), pci_dma_in); - } else { - ioc->base_add_sg_single(psge, sgl_flags | - (blk_rq_bytes(rsp) + 4), dma_addr_in); - } - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - " - "sending smp request\n", ioc->name, __func__)); - - init_completion(&ioc->transport_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, - 10*HZ); - - if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s : timeout\n", - __func__, ioc->name); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SmpPassthroughRequest_t)/4); - if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - " - "complete\n", ioc->name, __func__)); - - if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { - - mpi_reply = ioc->transport_cmds.reply; - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s - reply data transfer size(%d)\n", - ioc->name, __func__, - le16_to_cpu(mpi_reply->ResponseDataLength))); - - memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); - req->sense_len = sizeof(*mpi_reply); - req->resid_len = 0; - rsp->resid_len -= - le16_to_cpu(mpi_reply->ResponseDataLength); - /* check if the resp needs to be copied from the allocated - * pci mem */ - if (bio_multiple_segments(rsp->bio)) { - u32 offset = 0; - u32 bytes_to_copy = - le16_to_cpu(mpi_reply->ResponseDataLength); - bio_for_each_segment(bvec, rsp->bio, iter) { - if (bytes_to_copy <= bvec.bv_len) { - memcpy(page_address(bvec.bv_page) + - bvec.bv_offset, pci_addr_in + - offset, bytes_to_copy); - break; - } else { - memcpy(page_address(bvec.bv_page) + - bvec.bv_offset, pci_addr_in + - offset, bvec.bv_len); - bytes_to_copy -= bvec.bv_len; - } - offset += bvec.bv_len; - } - } - } else { - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s - no reply\n", ioc->name, __func__)); - rc = -ENXIO; - } - - issue_host_reset: - if (issue_reset) { - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - rc = -ETIMEDOUT; - } - - unmap: - if (dma_addr_out) - pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req), - PCI_DMA_BIDIRECTIONAL); - if (dma_addr_in) - pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp), - PCI_DMA_BIDIRECTIONAL); - - free_pci: - if (pci_addr_out) - pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out, - pci_dma_out); - - if (pci_addr_in) - pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in, - pci_dma_in); - - out: - ioc->transport_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->transport_cmds.mutex); - return rc; -} - -struct sas_function_template mpt2sas_transport_functions = { - .get_linkerrors = _transport_get_linkerrors, - .get_enclosure_identifier = _transport_get_enclosure_identifier, - .get_bay_identifier = _transport_get_bay_identifier, - .phy_reset = _transport_phy_reset, - .phy_enable = _transport_phy_enable, - .set_phy_speed = _transport_phy_speed, - .smp_handler = _transport_smp_handler, -}; - -struct scsi_transport_template *mpt2sas_transport_template; diff --git a/drivers/scsi/mpt3sas/Kconfig b/drivers/scsi/mpt3sas/Kconfig index 4d235dd74..b736dbc80 100644 --- a/drivers/scsi/mpt3sas/Kconfig +++ b/drivers/scsi/mpt3sas/Kconfig @@ -41,15 +41,15 @@ # USA. config SCSI_MPT3SAS - tristate "LSI MPT Fusion SAS 3.0 Device Driver" + tristate "LSI MPT Fusion SAS 3.0 & SAS 2.0 Device Driver" depends on PCI && SCSI select SCSI_SAS_ATTRS select RAID_ATTRS ---help--- This driver supports PCI-Express SAS 12Gb/s Host Adapters. -config SCSI_MPT3SAS_MAX_SGE - int "LSI MPT Fusion Max number of SG Entries (16 - 256)" +config SCSI_MPT2SAS_MAX_SGE + int "LSI MPT Fusion SAS 2.0 Max number of SG Entries (16 - 256)" depends on PCI && SCSI && SCSI_MPT3SAS default "128" range 16 256 @@ -60,8 +60,23 @@ config SCSI_MPT3SAS_MAX_SGE can be 256. However, it may decreased down to 16. Decreasing this parameter will reduce memory requirements on a per controller instance. -config SCSI_MPT3SAS_LOGGING - bool "LSI MPT Fusion logging facility" +config SCSI_MPT3SAS_MAX_SGE + int "LSI MPT Fusion SAS 3.0 Max number of SG Entries (16 - 256)" depends on PCI && SCSI && SCSI_MPT3SAS + default "128" + range 16 256 + ---help--- + This option allows you to specify the maximum number of scatter- + gather entries per I/O. The driver default is 128, which matches + MAX_PHYS_SEGMENTS in most kernels. However in SuSE kernels this + can be 256. However, it may decreased down to 16. Decreasing this + parameter will reduce memory requirements on a per controller instance. + +config SCSI_MPT2SAS + tristate "Legacy MPT2SAS config option" + default n + select SCSI_MPT3SAS + depends on PCI && SCSI ---help--- - This turns on a logging facility. + Dummy config option for backwards compatiblity: configure the MPT3SAS + driver instead. diff --git a/drivers/scsi/mpt3sas/Makefile b/drivers/scsi/mpt3sas/Makefile index efb0c4c2e..b7643f596 100644 --- a/drivers/scsi/mpt3sas/Makefile +++ b/drivers/scsi/mpt3sas/Makefile @@ -5,4 +5,5 @@ mpt3sas-y += mpt3sas_base.o \ mpt3sas_scsih.o \ mpt3sas_transport.o \ mpt3sas_ctl.o \ - mpt3sas_trigger_diag.o + mpt3sas_trigger_diag.o \ + mpt3sas_warpdrive.o diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index d4f1dcdb8..11393ebf1 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -108,9 +108,12 @@ _scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) if (ret) return ret; + /* global ioc spinlock to protect controller list on list operations */ pr_info("setting fwfault_debug(%d)\n", mpt3sas_fwfault_debug); + spin_lock(&gioc_lock); list_for_each_entry(ioc, &mpt3sas_ioc_list, list) ioc->fwfault_debug = mpt3sas_fwfault_debug; + spin_unlock(&gioc_lock); return 0; } module_param_call(mpt3sas_fwfault_debug, _scsih_set_fwfault_debug, @@ -157,7 +160,7 @@ _base_fault_reset_work(struct work_struct *work) spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->shost_recovery) + if (ioc->shost_recovery || ioc->pci_error_recovery) goto rearm_timer; spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); @@ -166,6 +169,20 @@ _base_fault_reset_work(struct work_struct *work) pr_err(MPT3SAS_FMT "SAS host is non-operational !!!!\n", ioc->name); + /* It may be possible that EEH recovery can resolve some of + * pci bus failure issues rather removing the dead ioc function + * by considering controller is in a non-operational state. So + * here priority is given to the EEH recovery. If it doesn't + * not resolve this issue, mpt3sas driver will consider this + * controller to non-operational state and remove the dead ioc + * function. + */ + if (ioc->non_operational_loop++ < 5) { + spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, + flags); + goto rearm_timer; + } + /* * Call _scsih_flush_pending_cmds callback so that we flush all * pending commands back to OS. This call is required to aovid @@ -181,7 +198,7 @@ _base_fault_reset_work(struct work_struct *work) ioc->remove_host = 1; /*Remove the Dead Host */ p = kthread_run(mpt3sas_remove_dead_ioc_func, ioc, - "mpt3sas_dead_ioc_%d", ioc->id); + "%s_dead_ioc_%d", ioc->driver_name, ioc->id); if (IS_ERR(p)) pr_err(MPT3SAS_FMT "%s: Running mpt3sas_dead_ioc thread failed !!!!\n", @@ -193,6 +210,8 @@ _base_fault_reset_work(struct work_struct *work) return; /* don't rearm timer */ } + ioc->non_operational_loop = 0; + if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) { rc = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP, FORCE_BIG_HAMMER); @@ -235,7 +254,8 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc) INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); snprintf(ioc->fault_reset_work_q_name, - sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id); + sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status", + ioc->driver_name, ioc->id); ioc->fault_reset_work_q = create_singlethread_workqueue(ioc->fault_reset_work_q_name); if (!ioc->fault_reset_work_q) { @@ -324,7 +344,6 @@ mpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc) panic("panic in %s\n", __func__); } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _base_sas_ioc_info - verbose translation of the ioc status * @ioc: per adapter object @@ -578,7 +597,8 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc, desc = "Device Status Change"; break; case MPI2_EVENT_IR_OPERATION_STATUS: - desc = "IR Operation Status"; + if (!ioc->hide_ir_msg) + desc = "IR Operation Status"; break; case MPI2_EVENT_SAS_DISCOVERY: { @@ -609,16 +629,20 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc, desc = "SAS Enclosure Device Status Change"; break; case MPI2_EVENT_IR_VOLUME: - desc = "IR Volume"; + if (!ioc->hide_ir_msg) + desc = "IR Volume"; break; case MPI2_EVENT_IR_PHYSICAL_DISK: - desc = "IR Physical Disk"; + if (!ioc->hide_ir_msg) + desc = "IR Physical Disk"; break; case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - desc = "IR Configuration Change List"; + if (!ioc->hide_ir_msg) + desc = "IR Configuration Change List"; break; case MPI2_EVENT_LOG_ENTRY_ADDED: - desc = "Log Entry Added"; + if (!ioc->hide_ir_msg) + desc = "Log Entry Added"; break; case MPI2_EVENT_TEMP_THRESHOLD: desc = "Temperature Threshold"; @@ -630,7 +654,6 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, desc); } -#endif /** * _base_sas_log_info - verbose translation of firmware log info @@ -675,7 +698,10 @@ _base_sas_log_info(struct MPT3SAS_ADAPTER *ioc , u32 log_info) originator_str = "PL"; break; case 2: - originator_str = "IR"; + if (!ioc->hide_ir_msg) + originator_str = "IR"; + else + originator_str = "WarpDrive"; break; } @@ -710,13 +736,13 @@ _base_display_reply_info(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, return; } ioc_status = le16_to_cpu(mpi_reply->IOCStatus); -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING + if ((ioc_status & MPI2_IOCSTATUS_MASK) && (ioc->logging_level & MPT_DEBUG_REPLY)) { _base_sas_ioc_info(ioc , mpi_reply, mpt3sas_base_get_msg_frame(ioc, smid)); } -#endif + if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { loginfo = le32_to_cpu(mpi_reply->IOCLogInfo); _base_sas_log_info(ioc, loginfo); @@ -783,9 +809,9 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply) return 1; if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION) return 1; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING + _base_display_event_data(ioc, mpi_reply); -#endif + if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED)) goto out; smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx); @@ -1009,6 +1035,12 @@ _base_interrupt(int irq, void *bus_id) } wmb(); + if (ioc->is_warpdrive) { + writel(reply_q->reply_post_host_index, + ioc->reply_post_host_index[msix_index]); + atomic_dec(&reply_q->busy); + return IRQ_HANDLED; + } /* Update Reply Post Host Index. * For those HBA's which support combined reply queue feature @@ -1319,6 +1351,149 @@ _base_build_zero_len_sge_ieee(struct MPT3SAS_ADAPTER *ioc, void *paddr) _base_add_sg_single_ieee(paddr, sgl_flags, 0, 0, -1); } +/** + * _base_build_sg_scmd - main sg creation routine + * @ioc: per adapter object + * @scmd: scsi command + * @smid: system request message index + * Context: none. + * + * The main routine that builds scatter gather table from a given + * scsi request sent via the .queuecommand main handler. + * + * Returns 0 success, anything else error + */ +static int +_base_build_sg_scmd(struct MPT3SAS_ADAPTER *ioc, + struct scsi_cmnd *scmd, u16 smid) +{ + Mpi2SCSIIORequest_t *mpi_request; + dma_addr_t chain_dma; + struct scatterlist *sg_scmd; + void *sg_local, *chain; + u32 chain_offset; + u32 chain_length; + u32 chain_flags; + int sges_left; + u32 sges_in_segment; + u32 sgl_flags; + u32 sgl_flags_last_element; + u32 sgl_flags_end_buffer; + struct chain_tracker *chain_req; + + mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); + + /* init scatter gather flags */ + sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT; + if (scmd->sc_data_direction == DMA_TO_DEVICE) + sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC; + sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT) + << MPI2_SGE_FLAGS_SHIFT; + sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT | + MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST) + << MPI2_SGE_FLAGS_SHIFT; + sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; + + sg_scmd = scsi_sglist(scmd); + sges_left = scsi_dma_map(scmd); + if (sges_left < 0) { + sdev_printk(KERN_ERR, scmd->device, + "pci_map_sg failed: request for %d bytes!\n", + scsi_bufflen(scmd)); + return -ENOMEM; + } + + sg_local = &mpi_request->SGL; + sges_in_segment = ioc->max_sges_in_main_message; + if (sges_left <= sges_in_segment) + goto fill_in_last_segment; + + mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) + + (sges_in_segment * ioc->sge_size))/4; + + /* fill in main message segment when there is a chain following */ + while (sges_in_segment) { + if (sges_in_segment == 1) + ioc->base_add_sg_single(sg_local, + sgl_flags_last_element | sg_dma_len(sg_scmd), + sg_dma_address(sg_scmd)); + else + ioc->base_add_sg_single(sg_local, sgl_flags | + sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); + sg_scmd = sg_next(sg_scmd); + sg_local += ioc->sge_size; + sges_left--; + sges_in_segment--; + } + + /* initializing the chain flags and pointers */ + chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT; + chain_req = _base_get_chain_buffer_tracker(ioc, smid); + if (!chain_req) + return -1; + chain = chain_req->chain_buffer; + chain_dma = chain_req->chain_buffer_dma; + do { + sges_in_segment = (sges_left <= + ioc->max_sges_in_chain_message) ? sges_left : + ioc->max_sges_in_chain_message; + chain_offset = (sges_left == sges_in_segment) ? + 0 : (sges_in_segment * ioc->sge_size)/4; + chain_length = sges_in_segment * ioc->sge_size; + if (chain_offset) { + chain_offset = chain_offset << + MPI2_SGE_CHAIN_OFFSET_SHIFT; + chain_length += ioc->sge_size; + } + ioc->base_add_sg_single(sg_local, chain_flags | chain_offset | + chain_length, chain_dma); + sg_local = chain; + if (!chain_offset) + goto fill_in_last_segment; + + /* fill in chain segments */ + while (sges_in_segment) { + if (sges_in_segment == 1) + ioc->base_add_sg_single(sg_local, + sgl_flags_last_element | + sg_dma_len(sg_scmd), + sg_dma_address(sg_scmd)); + else + ioc->base_add_sg_single(sg_local, sgl_flags | + sg_dma_len(sg_scmd), + sg_dma_address(sg_scmd)); + sg_scmd = sg_next(sg_scmd); + sg_local += ioc->sge_size; + sges_left--; + sges_in_segment--; + } + + chain_req = _base_get_chain_buffer_tracker(ioc, smid); + if (!chain_req) + return -1; + chain = chain_req->chain_buffer; + chain_dma = chain_req->chain_buffer_dma; + } while (1); + + + fill_in_last_segment: + + /* fill the last segment */ + while (sges_left) { + if (sges_left == 1) + ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer | + sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); + else + ioc->base_add_sg_single(sg_local, sgl_flags | + sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); + sg_scmd = sg_next(sg_scmd); + sg_local += ioc->sge_size; + sges_left--; + } + + return 0; +} + /** * _base_build_sg_scmd_ieee - main sg creation routine for IEEE format * @ioc: per adapter object @@ -1571,6 +1746,14 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc) int base; u16 message_control; + /* Check whether controller SAS2008 B0 controller, + * if it is SAS2008 B0 controller use IO-APIC instead of MSIX + */ + if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 && + ioc->pdev->revision == SAS2_PCI_DEVICE_B0_REVISION) { + return -EINVAL; + } + base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); if (!base) { dfailprintk(ioc, pr_info(MPT3SAS_FMT "msix not supported\n", @@ -1579,9 +1762,19 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc) } /* get msix vector count */ - - pci_read_config_word(ioc->pdev, base + 2, &message_control); - ioc->msix_vector_count = (message_control & 0x3FF) + 1; + /* NUMA_IO not supported for older controllers */ + if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 || + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 || + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 || + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 || + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 || + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 || + ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2) + ioc->msix_vector_count = 1; + else { + pci_read_config_word(ioc->pdev, base + 2, &message_control); + ioc->msix_vector_count = (message_control & 0x3FF) + 1; + } dinitprintk(ioc, pr_info(MPT3SAS_FMT "msix is supported, vector_count(%d)\n", ioc->name, ioc->msix_vector_count)); @@ -1643,10 +1836,10 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index, u32 vector) atomic_set(&reply_q->busy, 0); if (ioc->msix_enable) snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", - MPT3SAS_DRIVER_NAME, ioc->id, index); + ioc->driver_name, ioc->id, index); else snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", - MPT3SAS_DRIVER_NAME, ioc->id); + ioc->driver_name, ioc->id); r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name, reply_q); if (r) { @@ -1872,7 +2065,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) if (pci_request_selected_regions(pdev, ioc->bars, - MPT3SAS_DRIVER_NAME)) { + ioc->driver_name)) { pr_warn(MPT3SAS_FMT "pci_request_selected_regions: failed\n", ioc->name); ioc->bars = 0; @@ -2158,6 +2351,7 @@ mpt3sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid) } ioc->scsi_lookup[i].cb_idx = 0xFF; ioc->scsi_lookup[i].scmd = NULL; + ioc->scsi_lookup[i].direct_io = 0; list_add(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list); spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); @@ -2318,143 +2512,261 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid) } /** - * _base_display_intel_branding - Display branding string + * _base_display_OEMs_branding - Display branding string * @ioc: per adapter object * * Return nothing. */ static void -_base_display_intel_branding(struct MPT3SAS_ADAPTER *ioc) +_base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc) { if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL) return; - switch (ioc->pdev->device) { - case MPI25_MFGPAGE_DEVID_SAS3008: - switch (ioc->pdev->subsystem_device) { - case MPT3SAS_INTEL_RMS3JC080_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_INTEL_RMS3JC080_BRANDING); - break; - - case MPT3SAS_INTEL_RS3GC008_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_INTEL_RS3GC008_BRANDING); - break; - case MPT3SAS_INTEL_RS3FC044_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_INTEL_RS3FC044_BRANDING); - break; - case MPT3SAS_INTEL_RS3UC080_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_INTEL_RS3UC080_BRANDING); + switch (ioc->pdev->subsystem_vendor) { + case PCI_VENDOR_ID_INTEL: + switch (ioc->pdev->device) { + case MPI2_MFGPAGE_DEVID_SAS2008: + switch (ioc->pdev->subsystem_device) { + case MPT2SAS_INTEL_RMS2LL080_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS2LL080_BRANDING); + break; + case MPT2SAS_INTEL_RMS2LL040_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS2LL040_BRANDING); + break; + case MPT2SAS_INTEL_SSD910_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_SSD910_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Intel(R) Controller: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } + case MPI2_MFGPAGE_DEVID_SAS2308_2: + switch (ioc->pdev->subsystem_device) { + case MPT2SAS_INTEL_RS25GB008_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RS25GB008_BRANDING); + break; + case MPT2SAS_INTEL_RMS25JB080_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25JB080_BRANDING); + break; + case MPT2SAS_INTEL_RMS25JB040_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25JB040_BRANDING); + break; + case MPT2SAS_INTEL_RMS25KB080_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25KB080_BRANDING); + break; + case MPT2SAS_INTEL_RMS25KB040_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25KB040_BRANDING); + break; + case MPT2SAS_INTEL_RMS25LB040_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25LB040_BRANDING); + break; + case MPT2SAS_INTEL_RMS25LB080_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_INTEL_RMS25LB080_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Intel(R) Controller: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } + case MPI25_MFGPAGE_DEVID_SAS3008: + switch (ioc->pdev->subsystem_device) { + case MPT3SAS_INTEL_RMS3JC080_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_INTEL_RMS3JC080_BRANDING); + break; + + case MPT3SAS_INTEL_RS3GC008_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_INTEL_RS3GC008_BRANDING); + break; + case MPT3SAS_INTEL_RS3FC044_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_INTEL_RS3FC044_BRANDING); + break; + case MPT3SAS_INTEL_RS3UC080_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_INTEL_RS3UC080_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Intel(R) Controller: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } break; default: pr_info(MPT3SAS_FMT - "Intel(R) Controller: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + "Intel(R) Controller: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); break; } break; - default: - pr_info(MPT3SAS_FMT - "Intel(R) Controller: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); - break; - } -} - - - -/** - * _base_display_dell_branding - Display branding string - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_dell_branding(struct MPT3SAS_ADAPTER *ioc) -{ - if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_DELL) - return; - - switch (ioc->pdev->device) { - case MPI25_MFGPAGE_DEVID_SAS3008: - switch (ioc->pdev->subsystem_device) { - case MPT3SAS_DELL_12G_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_DELL_12G_HBA_BRANDING); + case PCI_VENDOR_ID_DELL: + switch (ioc->pdev->device) { + case MPI2_MFGPAGE_DEVID_SAS2008: + switch (ioc->pdev->subsystem_device) { + case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING); + break; + case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING); + break; + case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING); + break; + case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING); + break; + case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING); + break; + case MPT2SAS_DELL_PERC_H200_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_PERC_H200_BRANDING); + break; + case MPT2SAS_DELL_6GBPS_SAS_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_DELL_6GBPS_SAS_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Dell 6Gbps HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } + break; + case MPI25_MFGPAGE_DEVID_SAS3008: + switch (ioc->pdev->subsystem_device) { + case MPT3SAS_DELL_12G_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_DELL_12G_HBA_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } break; default: pr_info(MPT3SAS_FMT - "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", ioc->name, + "Dell HBA: Subsystem ID: 0x%X\n", ioc->name, ioc->pdev->subsystem_device); break; } break; - default: - pr_info(MPT3SAS_FMT - "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", ioc->name, - ioc->pdev->subsystem_device); - break; - } -} - -/** - * _base_display_cisco_branding - Display branding string - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_cisco_branding(struct MPT3SAS_ADAPTER *ioc) -{ - if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_CISCO) - return; - - switch (ioc->pdev->device) { - case MPI25_MFGPAGE_DEVID_SAS3008: - switch (ioc->pdev->subsystem_device) { - case MPT3SAS_CISCO_12G_8E_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_8E_HBA_BRANDING); - break; - case MPT3SAS_CISCO_12G_8I_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_8I_HBA_BRANDING); + case PCI_VENDOR_ID_CISCO: + switch (ioc->pdev->device) { + case MPI25_MFGPAGE_DEVID_SAS3008: + switch (ioc->pdev->subsystem_device) { + case MPT3SAS_CISCO_12G_8E_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_CISCO_12G_8E_HBA_BRANDING); + break; + case MPT3SAS_CISCO_12G_8I_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_CISCO_12G_8I_HBA_BRANDING); + break; + case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } break; - case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, + case MPI25_MFGPAGE_DEVID_SAS3108_1: + switch (ioc->pdev->subsystem_device) { + case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); + break; + case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING + ); + break; + default: + pr_info(MPT3SAS_FMT + "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } break; default: pr_info(MPT3SAS_FMT - "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + "Cisco SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); break; } break; - case MPI25_MFGPAGE_DEVID_SAS3108_1: - switch (ioc->pdev->subsystem_device) { - case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); - break; - case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID: - pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING); - break; + case MPT2SAS_HP_3PAR_SSVID: + switch (ioc->pdev->device) { + case MPI2_MFGPAGE_DEVID_SAS2004: + switch (ioc->pdev->subsystem_device) { + case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } + case MPI2_MFGPAGE_DEVID_SAS2308_2: + switch (ioc->pdev->subsystem_device) { + case MPT2SAS_HP_2_4_INTERNAL_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_HP_2_4_INTERNAL_BRANDING); + break; + case MPT2SAS_HP_2_4_EXTERNAL_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_HP_2_4_EXTERNAL_BRANDING); + break; + case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING); + break; + case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } default: pr_info(MPT3SAS_FMT - "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); + "HP SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); break; } - break; default: - pr_info(MPT3SAS_FMT - "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", - ioc->name, ioc->pdev->subsystem_device); break; } } @@ -2488,9 +2800,7 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) (bios_version & 0x0000FF00) >> 8, bios_version & 0x000000FF); - _base_display_intel_branding(ioc); - _base_display_dell_branding(ioc); - _base_display_cisco_branding(ioc); + _base_display_OEMs_branding(ioc); pr_info(MPT3SAS_FMT "Protocol=(", ioc->name); @@ -2508,10 +2818,12 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) pr_info("), "); pr_info("Capabilities=("); - if (ioc->facts.IOCCapabilities & + if (!ioc->hide_ir_msg) { + if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { pr_info("Raid"); i++; + } } if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) { @@ -2852,18 +3164,22 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) /* command line tunables for max sgl entries */ if (max_sgl_entries != -1) sg_tablesize = max_sgl_entries; - else - sg_tablesize = MPT3SAS_SG_DEPTH; + else { + if (ioc->hba_mpi_version_belonged == MPI2_VERSION) + sg_tablesize = MPT2SAS_SG_DEPTH; + else + sg_tablesize = MPT3SAS_SG_DEPTH; + } - if (sg_tablesize < MPT3SAS_MIN_PHYS_SEGMENTS) - sg_tablesize = MPT3SAS_MIN_PHYS_SEGMENTS; - else if (sg_tablesize > MPT3SAS_MAX_PHYS_SEGMENTS) { + if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS) + sg_tablesize = MPT_MIN_PHYS_SEGMENTS; + else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) { sg_tablesize = min_t(unsigned short, sg_tablesize, SCSI_MAX_SG_CHAIN_SEGMENTS); pr_warn(MPT3SAS_FMT "sg_tablesize(%u) is bigger than kernel" " defined SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name, - sg_tablesize, MPT3SAS_MAX_PHYS_SEGMENTS); + sg_tablesize, MPT_MAX_PHYS_SEGMENTS); } ioc->shost->sg_tablesize = sg_tablesize; @@ -4021,7 +4337,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER; mpi_request.VF_ID = 0; /* TODO */ mpi_request.VP_ID = 0; - mpi_request.MsgVersion = cpu_to_le16(MPI25_VERSION); + mpi_request.MsgVersion = cpu_to_le16(ioc->hba_mpi_version_belonged); mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); if (_base_is_controller_msix_enabled(ioc)) @@ -4655,6 +4971,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) u32 reply_address; u16 smid; struct _tr_list *delayed_tr, *delayed_tr_next; + u8 hide_flag; struct adapter_reply_queue *reply_q; long reply_post_free; u32 reply_post_free_sz, index = 0; @@ -4685,6 +5002,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) ioc->scsi_lookup[i].cb_idx = 0xFF; ioc->scsi_lookup[i].smid = smid; ioc->scsi_lookup[i].scmd = NULL; + ioc->scsi_lookup[i].direct_io = 0; list_add_tail(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list); } @@ -4787,6 +5105,16 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) if (ioc->is_driver_loading) { + + if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier + == 0x80) { + hide_flag = (u8) ( + le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) & + MFG_PAGE10_HIDE_SSDS_MASK); + if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK) + ioc->mfg_pg10_hide_flag = hide_flag; + } + ioc->wait_for_discovery_to_complete = _base_determine_wait_on_discovery(ioc); @@ -4812,6 +5140,8 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc) dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, __func__)); + /* synchronizing freeing resource with pci_access_mutex lock */ + mutex_lock(&ioc->pci_access_mutex); if (ioc->chip_phys && ioc->chip) { _base_mask_interrupts(ioc); ioc->shost_recovery = 1; @@ -4820,6 +5150,7 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc) } mpt3sas_base_unmap_resources(ioc); + mutex_unlock(&ioc->pci_access_mutex); return; } @@ -4834,7 +5165,6 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) { int r, i; int cpu_id, last_cpu_id = 0; - u8 revision; dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, __func__)); @@ -4854,19 +5184,16 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) goto out_free_resources; } - /* Check whether the controller revision is C0 or above. - * only C0 and above revision controllers support 96 MSI-X vectors. - */ - revision = ioc->pdev->revision; - - if ((ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3004 || - ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3008 || - ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_1 || - ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_2 || - ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_5 || - ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_6) && - (revision >= 0x02)) - ioc->msix96_vector = 1; + if (ioc->is_warpdrive) { + ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz, + sizeof(resource_size_t *), GFP_KERNEL); + if (!ioc->reply_post_host_index) { + dfailprintk(ioc, pr_info(MPT3SAS_FMT "allocation " + "for cpu_msix_table failed!!!\n", ioc->name)); + r = -ENOMEM; + goto out_free_resources; + } + } ioc->rdpq_array_enable_assigned = 0; ioc->dma_mask = 0; @@ -4874,23 +5201,41 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) if (r) goto out_free_resources; + if (ioc->is_warpdrive) { + ioc->reply_post_host_index[0] = (resource_size_t __iomem *) + &ioc->chip->ReplyPostHostIndex; + + for (i = 1; i < ioc->cpu_msix_table_sz; i++) + ioc->reply_post_host_index[i] = + (resource_size_t __iomem *) + ((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1) + * 4))); + } pci_set_drvdata(ioc->pdev, ioc->shost); r = _base_get_ioc_facts(ioc, CAN_SLEEP); if (r) goto out_free_resources; - /* - * In SAS3.0, - * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and - * Target Status - all require the IEEE formated scatter gather - * elements. - */ - - ioc->build_sg_scmd = &_base_build_sg_scmd_ieee; - ioc->build_sg = &_base_build_sg_ieee; - ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee; - ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t); + switch (ioc->hba_mpi_version_belonged) { + case MPI2_VERSION: + ioc->build_sg_scmd = &_base_build_sg_scmd; + ioc->build_sg = &_base_build_sg; + ioc->build_zero_len_sge = &_base_build_zero_len_sge; + break; + case MPI25_VERSION: + /* + * In SAS3.0, + * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and + * Target Status - all require the IEEE formated scatter gather + * elements. + */ + ioc->build_sg_scmd = &_base_build_sg_scmd_ieee; + ioc->build_sg = &_base_build_sg_ieee; + ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee; + ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t); + break; + } /* * These function pointers for other requests that don't @@ -5006,6 +5351,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) if (r) goto out_free_resources; + ioc->non_operational_loop = 0; return 0; out_free_resources: @@ -5016,6 +5362,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) _base_release_memory_pools(ioc); pci_set_drvdata(ioc->pdev, NULL); kfree(ioc->cpu_msix_table); + if (ioc->is_warpdrive) + kfree(ioc->reply_post_host_index); kfree(ioc->pd_handles); kfree(ioc->blocking_handles); kfree(ioc->tm_cmds.reply); @@ -5055,6 +5403,8 @@ mpt3sas_base_detach(struct MPT3SAS_ADAPTER *ioc) _base_release_memory_pools(ioc); pci_set_drvdata(ioc->pdev, NULL); kfree(ioc->cpu_msix_table); + if (ioc->is_warpdrive) + kfree(ioc->reply_post_host_index); kfree(ioc->pd_handles); kfree(ioc->blocking_handles); kfree(ioc->pfacts); diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index f0e462b08..5ad271efb 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -63,6 +63,8 @@ #include #include #include +#include +#include #include "mpt3sas_debug.h" #include "mpt3sas_trigger_diag.h" @@ -71,23 +73,37 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies " #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "09.100.00.00" +#define MPT3SAS_DRIVER_VERSION "09.102.00.00" #define MPT3SAS_MAJOR_VERSION 9 -#define MPT3SAS_MINOR_VERSION 100 +#define MPT3SAS_MINOR_VERSION 102 #define MPT3SAS_BUILD_VERSION 0 #define MPT3SAS_RELEASE_VERSION 00 +#define MPT2SAS_DRIVER_NAME "mpt2sas" +#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" +#define MPT2SAS_DRIVER_VERSION "20.102.00.00" +#define MPT2SAS_MAJOR_VERSION 20 +#define MPT2SAS_MINOR_VERSION 102 +#define MPT2SAS_BUILD_VERSION 0 +#define MPT2SAS_RELEASE_VERSION 00 + /* * Set MPT3SAS_SG_DEPTH value based on user input. */ -#define MPT3SAS_MAX_PHYS_SEGMENTS SCSI_MAX_SG_SEGMENTS -#define MPT3SAS_MIN_PHYS_SEGMENTS 16 +#define MPT_MAX_PHYS_SEGMENTS SCSI_MAX_SG_SEGMENTS +#define MPT_MIN_PHYS_SEGMENTS 16 + #ifdef CONFIG_SCSI_MPT3SAS_MAX_SGE #define MPT3SAS_SG_DEPTH CONFIG_SCSI_MPT3SAS_MAX_SGE #else -#define MPT3SAS_SG_DEPTH MPT3SAS_MAX_PHYS_SEGMENTS +#define MPT3SAS_SG_DEPTH MPT_MAX_PHYS_SEGMENTS #endif +#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE +#define MPT2SAS_SG_DEPTH CONFIG_SCSI_MPT2SAS_MAX_SGE +#else +#define MPT2SAS_SG_DEPTH MPT_MAX_PHYS_SEGMENTS +#endif /* * Generic Defines @@ -123,6 +139,16 @@ */ #define MPT3SAS_FMT "%s: " +/* + * WarpDrive Specific Log codes + */ + +#define MPT2_WARPDRIVE_LOGENTRY (0x8002) +#define MPT2_WARPDRIVE_LC_SSDT (0x41) +#define MPT2_WARPDRIVE_LC_SSDLW (0x43) +#define MPT2_WARPDRIVE_LC_SSDLF (0x44) +#define MPT2_WARPDRIVE_LC_BRMF (0x4D) + /* * per target private data */ @@ -131,9 +157,33 @@ #define MPT_TARGET_FLAGS_DELETED 0x04 #define MPT_TARGET_FASTPATH_IO 0x08 +#define SAS2_PCI_DEVICE_B0_REVISION (0x01) +#define SAS3_PCI_DEVICE_C0_REVISION (0x02) + /* * Intel HBA branding */ +#define MPT2SAS_INTEL_RMS25JB080_BRANDING \ + "Intel(R) Integrated RAID Module RMS25JB080" +#define MPT2SAS_INTEL_RMS25JB040_BRANDING \ + "Intel(R) Integrated RAID Module RMS25JB040" +#define MPT2SAS_INTEL_RMS25KB080_BRANDING \ + "Intel(R) Integrated RAID Module RMS25KB080" +#define MPT2SAS_INTEL_RMS25KB040_BRANDING \ + "Intel(R) Integrated RAID Module RMS25KB040" +#define MPT2SAS_INTEL_RMS25LB040_BRANDING \ + "Intel(R) Integrated RAID Module RMS25LB040" +#define MPT2SAS_INTEL_RMS25LB080_BRANDING \ + "Intel(R) Integrated RAID Module RMS25LB080" +#define MPT2SAS_INTEL_RMS2LL080_BRANDING \ + "Intel Integrated RAID Module RMS2LL080" +#define MPT2SAS_INTEL_RMS2LL040_BRANDING \ + "Intel Integrated RAID Module RMS2LL040" +#define MPT2SAS_INTEL_RS25GB008_BRANDING \ + "Intel(R) RAID Controller RS25GB008" +#define MPT2SAS_INTEL_SSD910_BRANDING \ + "Intel(R) SSD 910 Series" + #define MPT3SAS_INTEL_RMS3JC080_BRANDING \ "Intel(R) Integrated RAID Module RMS3JC080" #define MPT3SAS_INTEL_RS3GC008_BRANDING \ @@ -146,33 +196,62 @@ /* * Intel HBA SSDIDs */ -#define MPT3SAS_INTEL_RMS3JC080_SSDID 0x3521 -#define MPT3SAS_INTEL_RS3GC008_SSDID 0x3522 -#define MPT3SAS_INTEL_RS3FC044_SSDID 0x3523 -#define MPT3SAS_INTEL_RS3UC080_SSDID 0x3524 +#define MPT2SAS_INTEL_RMS25JB080_SSDID 0x3516 +#define MPT2SAS_INTEL_RMS25JB040_SSDID 0x3517 +#define MPT2SAS_INTEL_RMS25KB080_SSDID 0x3518 +#define MPT2SAS_INTEL_RMS25KB040_SSDID 0x3519 +#define MPT2SAS_INTEL_RMS25LB040_SSDID 0x351A +#define MPT2SAS_INTEL_RMS25LB080_SSDID 0x351B +#define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E +#define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F +#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000 +#define MPT2SAS_INTEL_SSD910_SSDID 0x3700 + +#define MPT3SAS_INTEL_RMS3JC080_SSDID 0x3521 +#define MPT3SAS_INTEL_RS3GC008_SSDID 0x3522 +#define MPT3SAS_INTEL_RS3FC044_SSDID 0x3523 +#define MPT3SAS_INTEL_RS3UC080_SSDID 0x3524 /* * Dell HBA branding */ +#define MPT2SAS_DELL_BRANDING_SIZE 32 + +#define MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING "Dell 6Gbps SAS HBA" +#define MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING "Dell PERC H200 Adapter" +#define MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING "Dell PERC H200 Integrated" +#define MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING "Dell PERC H200 Modular" +#define MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING "Dell PERC H200 Embedded" +#define MPT2SAS_DELL_PERC_H200_BRANDING "Dell PERC H200" +#define MPT2SAS_DELL_6GBPS_SAS_BRANDING "Dell 6Gbps SAS" + #define MPT3SAS_DELL_12G_HBA_BRANDING \ "Dell 12Gbps HBA" /* * Dell HBA SSDIDs */ -#define MPT3SAS_DELL_12G_HBA_SSDID 0x1F46 +#define MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID 0x1F1C +#define MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID 0x1F1D +#define MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID 0x1F1E +#define MPT2SAS_DELL_PERC_H200_MODULAR_SSDID 0x1F1F +#define MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID 0x1F20 +#define MPT2SAS_DELL_PERC_H200_SSDID 0x1F21 +#define MPT2SAS_DELL_6GBPS_SAS_SSDID 0x1F22 + +#define MPT3SAS_DELL_12G_HBA_SSDID 0x1F46 /* * Cisco HBA branding */ #define MPT3SAS_CISCO_12G_8E_HBA_BRANDING \ - "Cisco 9300-8E 12G SAS HBA" + "Cisco 9300-8E 12G SAS HBA" #define MPT3SAS_CISCO_12G_8I_HBA_BRANDING \ - "Cisco 9300-8i 12G SAS HBA" + "Cisco 9300-8i 12G SAS HBA" #define MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING \ - "Cisco 12G Modular SAS Pass through Controller" + "Cisco 12G Modular SAS Pass through Controller" #define MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING \ - "UCS C3X60 12G SAS Pass through Controller" + "UCS C3X60 12G SAS Pass through Controller" /* * Cisco HBA SSSDIDs */ @@ -188,6 +267,31 @@ #define MPT3_DIAG_BUFFER_IS_RELEASED (0x02) #define MPT3_DIAG_BUFFER_IS_DIAG_RESET (0x04) +/* + * HP HBA branding + */ +#define MPT2SAS_HP_3PAR_SSVID 0x1590 + +#define MPT2SAS_HP_2_4_INTERNAL_BRANDING \ + "HP H220 Host Bus Adapter" +#define MPT2SAS_HP_2_4_EXTERNAL_BRANDING \ + "HP H221 Host Bus Adapter" +#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING \ + "HP H222 Host Bus Adapter" +#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING \ + "HP H220i Host Bus Adapter" +#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING \ + "HP H210i Host Bus Adapter" + +/* + * HO HBA SSDIDs + */ +#define MPT2SAS_HP_2_4_INTERNAL_SSDID 0x0041 +#define MPT2SAS_HP_2_4_EXTERNAL_SSDID 0x0042 +#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID 0x0043 +#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044 +#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046 + /* * Combined Reply Queue constants, * There are twelve Supplemental Reply Post Host Index Registers @@ -243,20 +347,24 @@ struct Mpi2ManufacturingPage11_t { * struct MPT3SAS_TARGET - starget private hostdata * @starget: starget object * @sas_address: target sas address + * @raid_device: raid_device pointer to access volume data * @handle: device handle * @num_luns: number luns * @flags: MPT_TARGET_FLAGS_XXX flags * @deleted: target flaged for deletion * @tm_busy: target is busy with TM request. + * @sdev: The sas_device associated with this target */ struct MPT3SAS_TARGET { struct scsi_target *starget; u64 sas_address; + struct _raid_device *raid_device; u16 handle; int num_luns; u32 flags; u8 deleted; u8 tm_busy; + struct _sas_device *sdev; }; @@ -266,6 +374,11 @@ struct MPT3SAS_TARGET { #define MPT_DEVICE_FLAGS_INIT 0x01 #define MPT_DEVICE_TLR_ON 0x02 +#define MFG_PAGE10_HIDE_SSDS_MASK (0x00000003) +#define MFG_PAGE10_HIDE_ALL_DISKS (0x00) +#define MFG_PAGE10_EXPOSE_ALL_DISKS (0x01) +#define MFG_PAGE10_HIDE_IF_VOL_PRESENT (0x02) + /** * struct MPT3SAS_DEVICE - sdev private hostdata * @sas_target: starget private hostdata @@ -358,8 +471,24 @@ struct _sas_device { u8 pend_sas_rphy_add; u8 enclosure_level; u8 connector_name[4]; + struct kref refcount; }; +static inline void sas_device_get(struct _sas_device *s) +{ + kref_get(&s->refcount); +} + +static inline void sas_device_free(struct kref *r) +{ + kfree(container_of(r, struct _sas_device, refcount)); +} + +static inline void sas_device_put(struct _sas_device *s) +{ + kref_put(&s->refcount, sas_device_free); +} + /** * struct _raid_device - raid volume link list * @list: sas device list @@ -367,6 +496,7 @@ struct _sas_device { * @sdev: scsi device struct (volumes are single lun) * @wwid: unique identifier for the volume * @handle: device handle + * @block_size: Block size of the volume * @id: target id * @channel: target channel * @volume_type: the raid level @@ -374,6 +504,13 @@ struct _sas_device { * @num_pds: number of hidden raid components * @responding: used in _scsih_raid_device_mark_responding * @percent_complete: resync percent complete + * @direct_io_enabled: Whether direct io to PDs are allowed or not + * @stripe_exponent: X where 2powX is the stripe sz in blocks + * @block_exponent: X where 2powX is the block sz in bytes + * @max_lba: Maximum number of LBA in the volume + * @stripe_sz: Stripe Size of the volume + * @device_info: Device info of the volume member disk + * @pd_handle: Array of handles of the physical drives for direct I/O in le16 */ #define MPT_MAX_WARPDRIVE_PDS 8 struct _raid_device { @@ -382,13 +519,20 @@ struct _raid_device { struct scsi_device *sdev; u64 wwid; u16 handle; + u16 block_sz; int id; int channel; u8 volume_type; u8 num_pds; u8 responding; u8 percent_complete; + u8 direct_io_enabled; + u8 stripe_exponent; + u8 block_exponent; + u64 max_lba; + u32 stripe_sz; u32 device_info; + u16 pd_handle[MPT_MAX_WARPDRIVE_PDS]; }; /** @@ -497,12 +641,14 @@ struct chain_tracker { * @smid: system message id * @scmd: scsi request pointer * @cb_idx: callback index + * @direct_io: To indicate whether I/O is direct (WARPDRIVE) * @tracker_list: list of free request (ioc->free_list) */ struct scsiio_tracker { u16 smid; struct scsi_cmnd *scmd; u8 cb_idx; + u8 direct_io; struct list_head chain_list; struct list_head tracker_list; }; @@ -775,7 +921,13 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @replyPostRegisterIndex: index of next position in Reply Desc Post Queue * @delayed_tr_list: target reset link list * @delayed_tr_volume_list: volume target reset link list - * @@temp_sensors_count: flag to carry the number of temperature sensors + * @temp_sensors_count: flag to carry the number of temperature sensors + * @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and + * pci resource handling. PCI resource freeing will lead to free + * vital hardware/memory resource, which might be in use by cli/sysfs + * path functions resulting in Null pointer reference followed by kernel + * crash. To avoid the above race condition we use mutex syncrhonization + * which ensures the syncrhonization between cli/sysfs_show path. */ struct MPT3SAS_ADAPTER { struct list_head list; @@ -783,6 +935,7 @@ struct MPT3SAS_ADAPTER { u8 id; int cpu_count; char name[MPT_NAME_LENGTH]; + char driver_name[MPT_NAME_LENGTH]; char tmp_string[MPT_STRING_LENGTH]; struct pci_dev *pdev; Mpi2SystemInterfaceRegs_t __iomem *chip; @@ -829,8 +982,10 @@ struct MPT3SAS_ADAPTER { u16 msix_vector_count; u8 *cpu_msix_table; u16 cpu_msix_table_sz; + resource_size_t __iomem **reply_post_host_index; u32 ioc_reset_count; MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; + u32 non_operational_loop; /* internal commands, callback index */ u8 scsi_io_cb_idx; @@ -859,6 +1014,7 @@ struct MPT3SAS_ADAPTER { MPT_BUILD_SG build_sg; MPT_BUILD_ZERO_LEN_SGE build_zero_len_sge; u16 sge_size_ieee; + u16 hba_mpi_version_belonged; /* function ptr for MPI sg elements only */ MPT_BUILD_SG build_sg_mpi; @@ -987,6 +1143,7 @@ struct MPT3SAS_ADAPTER { struct list_head delayed_tr_list; struct list_head delayed_tr_volume_list; u8 temp_sensors_count; + struct mutex pci_access_mutex; /* diag buffer support */ u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT]; @@ -998,6 +1155,10 @@ struct MPT3SAS_ADAPTER { u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; u32 ring_buffer_offset; u32 ring_buffer_sz; + u8 is_warpdrive; + u8 hide_ir_msg; + u8 mfg_pg10_hide_flag; + u8 hide_drives; spinlock_t diag_trigger_lock; u8 diag_trigger_active; struct SL_WH_MASTER_TRIGGER_T diag_trigger_master; @@ -1012,6 +1173,19 @@ typedef u8 (*MPT_CALLBACK)(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, /* base shared API */ extern struct list_head mpt3sas_ioc_list; +extern char driver_name[MPT_NAME_LENGTH]; +/* spinlock on list operations over IOCs + * Case: when multiple warpdrive cards(IOCs) are in use + * Each IOC will added to the ioc list structure on initialization. + * Watchdog threads run at regular intervals to check IOC for any + * fault conditions which will trigger the dead_ioc thread to + * deallocate pci resource, resulting deleting the IOC netry from list, + * this deletion need to protected by spinlock to enusre that + * ioc removal is syncrhonized, if not synchronized it might lead to + * list_del corruption as the ioc list is traversed in cli path. + */ +extern spinlock_t gioc_lock; + void mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc); void mpt3sas_base_stop_watchdog(struct MPT3SAS_ADAPTER *ioc); @@ -1090,10 +1264,14 @@ struct _sas_node *mpt3sas_scsih_expander_find_by_handle( struct MPT3SAS_ADAPTER *ioc, u16 handle); struct _sas_node *mpt3sas_scsih_expander_find_by_sas_address( struct MPT3SAS_ADAPTER *ioc, u64 sas_address); -struct _sas_device *mpt3sas_scsih_sas_device_find_by_sas_address( - struct MPT3SAS_ADAPTER *ioc, u64 sas_address); +struct _sas_device *mpt3sas_get_sdev_by_addr( + struct MPT3SAS_ADAPTER *ioc, u64 sas_address); +struct _sas_device *__mpt3sas_get_sdev_by_addr( + struct MPT3SAS_ADAPTER *ioc, u64 sas_address); void mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc); +struct _raid_device * +mpt3sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle); /* config shared API */ u8 mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, @@ -1133,6 +1311,8 @@ int mpt3sas_config_get_sas_iounit_pg0(struct MPT3SAS_ADAPTER *ioc, u16 sz); int mpt3sas_config_get_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page); +int mpt3sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz); int mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page); int mpt3sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t @@ -1177,8 +1357,8 @@ int mpt3sas_config_get_volume_wwid(struct MPT3SAS_ADAPTER *ioc, /* ctl shared API */ extern struct device_attribute *mpt3sas_host_attrs[]; extern struct device_attribute *mpt3sas_dev_attrs[]; -void mpt3sas_ctl_init(void); -void mpt3sas_ctl_exit(void); +void mpt3sas_ctl_init(ushort hbas_to_enumerate); +void mpt3sas_ctl_exit(ushort hbas_to_enumerate); u8 mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply); void mpt3sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase); @@ -1193,6 +1373,7 @@ int mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset); /* transport shared API */ +extern struct scsi_transport_template *mpt3sas_transport_template; u8 mpt3sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply); struct _sas_port *mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, @@ -1224,4 +1405,18 @@ void mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key, u8 asc, u8 ascq); void mpt3sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status, u32 loginfo); + +/* warpdrive APIs */ +u8 mpt3sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc); +void mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, + struct _raid_device *raid_device); +u8 +mpt3sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid); +void +mpt3sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io); +void +mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, + struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, + u16 smid); + #endif /* MPT3SAS_BASE_H_INCLUDED */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index e45c4613e..a6914ec99 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -83,7 +83,6 @@ struct config_request { dma_addr_t page_dma; }; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _config_display_some_debug - debug routine * @ioc: per adapter object @@ -173,7 +172,6 @@ _config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, ioc->name, le16_to_cpu(mpi_reply->IOCStatus), le32_to_cpu(mpi_reply->IOCLogInfo)); } -#endif /** * _config_alloc_config_dma_memory - obtain physical memory @@ -255,9 +253,7 @@ mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, mpi_reply->MsgLength*4); } ioc->config_cmds.status &= ~MPT3_CMD_PENDING; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING _config_display_some_debug(ioc, smid, "config_done", mpi_reply); -#endif ioc->config_cmds.smid = USHRT_MAX; complete(&ioc->config_cmds.done); return 1; @@ -387,9 +383,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t config_request = mpt3sas_base_get_msg_frame(ioc, smid); ioc->config_cmds.smid = smid; memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t)); -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING _config_display_some_debug(ioc, smid, "config_request", NULL); -#endif init_completion(&ioc->config_cmds.done); mpt3sas_base_put_smid_default(ioc, smid); timeleft = wait_for_completion_timeout(&ioc->config_cmds.done, @@ -871,6 +865,42 @@ mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, return r; } +/** + * mpt3sas_config_get_iounit_pg3 - obtain iounit page 3 + * @ioc: per adapter object + * @mpi_reply: reply mf payload returned from firmware + * @config_page: contents of the config page + * @sz: size of buffer passed in config_page + * Context: sleep. + * + * Returns 0 for success, non-zero for failure. + */ +int +mpt3sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc, + Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz) +{ + Mpi2ConfigRequest_t mpi_request; + int r; + + memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); + mpi_request.Function = MPI2_FUNCTION_CONFIG; + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; + mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; + mpi_request.Header.PageNumber = 3; + mpi_request.Header.PageVersion = MPI2_IOUNITPAGE3_PAGEVERSION; + ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE); + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); + if (r) + goto out; + + mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; + r = _config_request(ioc, &mpi_request, mpi_reply, + MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); + out: + return r; +} + /** * mpt3sas_config_get_iounit_pg8 - obtain iounit page 8 * @ioc: per adapter object diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 080c8a76d..d8366b056 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -78,7 +78,6 @@ enum block_state { BLOCKING, }; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _ctl_sas_device_find_by_handle - sas device search * @ioc: per adapter object @@ -254,8 +253,6 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid, } } -#endif - /** * mpt3sas_ctl_done - ctl module completion routine * @ioc: per adapter object @@ -302,9 +299,7 @@ mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, } } } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); -#endif ioc->ctl_cmds.status &= ~MPT3_CMD_PENDING; complete(&ioc->ctl_cmds.done); return 1; @@ -414,20 +409,31 @@ mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, * _ctl_verify_adapter - validates ioc_number passed from application * @ioc: per adapter object * @iocpp: The ioc pointer is returned in this. + * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device & + * MPI25_VERSION for mpt3ctl ioctl device. * * Return (-1) means error, else ioc_number. */ static int -_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp) +_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp, + int mpi_version) { struct MPT3SAS_ADAPTER *ioc; - + /* global ioc lock to protect controller on list operations */ + spin_lock(&gioc_lock); list_for_each_entry(ioc, &mpt3sas_ioc_list, list) { if (ioc->id != ioc_number) continue; + /* Check whether this ioctl command is from right + * ioctl device or not, if not continue the search. + */ + if (ioc->hba_mpi_version_belonged != mpi_version) + continue; + spin_unlock(&gioc_lock); *iocpp = ioc; return ioc_number; } + spin_unlock(&gioc_lock); *iocpp = NULL; return -1; } @@ -497,7 +503,7 @@ mpt3sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) * * Called when application request fasyn callback handler. */ -static int +int _ctl_fasync(int fd, struct file *filep, int mode) { return fasync_helper(fd, filep, mode, &async_queue); @@ -509,17 +515,22 @@ _ctl_fasync(int fd, struct file *filep, int mode) * @wait - * */ -static unsigned int +unsigned int _ctl_poll(struct file *filep, poll_table *wait) { struct MPT3SAS_ADAPTER *ioc; poll_wait(filep, &ctl_poll_wait, wait); + /* global ioc lock to protect controller on list operations */ + spin_lock(&gioc_lock); list_for_each_entry(ioc, &mpt3sas_ioc_list, list) { - if (ioc->aen_event_read_flag) + if (ioc->aen_event_read_flag) { + spin_unlock(&gioc_lock); return POLLIN | POLLRDNORM; + } } + spin_unlock(&gioc_lock); return 0; } @@ -759,9 +770,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, psge = (void *)request + (karg.data_sge_offset*4); /* send command to firmware */ -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING _ctl_display_some_debug(ioc, smid, "ctl_request", NULL); -#endif init_completion(&ioc->ctl_cmds.done); switch (mpi_request->Function) { @@ -916,7 +925,6 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, mpi_reply = ioc->ctl_cmds.reply; ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT && (ioc->logging_level & MPT_DEBUG_TM)) { Mpi2SCSITaskManagementReply_t *tm_reply = @@ -929,7 +937,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, le32_to_cpu(tm_reply->IOCLogInfo), le32_to_cpu(tm_reply->TerminationCount)); } -#endif + /* copy out xdata to user */ if (data_in_sz) { if (copy_to_user(karg.data_in_buf_ptr, data_in, @@ -1023,7 +1031,6 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg) __func__)); memset(&karg, 0 , sizeof(karg)); - karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3; if (ioc->pfacts) karg.port_number = ioc->pfacts[0].PortNumber; karg.hw_rev = ioc->pdev->revision; @@ -1035,9 +1042,21 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg) karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn); karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus); karg.firmware_version = ioc->facts.FWVersion.Word; - strcpy(karg.driver_version, MPT3SAS_DRIVER_NAME); + strcpy(karg.driver_version, ioc->driver_name); strcat(karg.driver_version, "-"); - strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION); + switch (ioc->hba_mpi_version_belonged) { + case MPI2_VERSION: + if (ioc->is_warpdrive) + karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200; + else + karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; + strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION); + break; + case MPI25_VERSION: + karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3; + strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION); + break; + } karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); if (copy_to_user(arg, &karg, sizeof(karg))) { @@ -2181,12 +2200,14 @@ _ctl_compat_mpt_command(struct MPT3SAS_ADAPTER *ioc, unsigned cmd, * _ctl_ioctl_main - main ioctl entry point * @file - (struct file) * @cmd - ioctl opcode - * @arg - - * compat - handles 32 bit applications in 64bit os + * @arg - user space data buffer + * @compat - handles 32 bit applications in 64bit os + * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device & + * MPI25_VERSION for mpt3ctl ioctl device. */ static long _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, - u8 compat) + u8 compat, u16 mpi_version) { struct MPT3SAS_ADAPTER *ioc; struct mpt3_ioctl_header ioctl_header; @@ -2201,19 +2222,29 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, return -EFAULT; } - if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc) + if (_ctl_verify_adapter(ioctl_header.ioc_number, + &ioc, mpi_version) == -1 || !ioc) return -ENODEV; + /* pci_access_mutex lock acquired by ioctl path */ + mutex_lock(&ioc->pci_access_mutex); + if (ioc->shost_recovery || ioc->pci_error_recovery || - ioc->is_driver_loading) - return -EAGAIN; + ioc->is_driver_loading || ioc->remove_host) { + ret = -EAGAIN; + goto out_unlock_pciaccess; + } state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; if (state == NON_BLOCKING) { - if (!mutex_trylock(&ioc->ctl_cmds.mutex)) - return -EAGAIN; - } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) - return -ERESTARTSYS; + if (!mutex_trylock(&ioc->ctl_cmds.mutex)) { + ret = -EAGAIN; + goto out_unlock_pciaccess; + } + } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) { + ret = -ERESTARTSYS; + goto out_unlock_pciaccess; + } switch (cmd) { @@ -2294,39 +2325,78 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, } mutex_unlock(&ioc->ctl_cmds.mutex); +out_unlock_pciaccess: + mutex_unlock(&ioc->pci_access_mutex); return ret; } /** - * _ctl_ioctl - main ioctl entry point (unlocked) + * _ctl_ioctl - mpt3ctl main ioctl entry point (unlocked) * @file - (struct file) * @cmd - ioctl opcode * @arg - */ -static long +long _ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; - ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0); + /* pass MPI25_VERSION value, to indicate that this ioctl cmd + * came from mpt3ctl ioctl device. + */ + ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI25_VERSION); return ret; } +/** + * _ctl_mpt2_ioctl - mpt2ctl main ioctl entry point (unlocked) + * @file - (struct file) + * @cmd - ioctl opcode + * @arg - + */ +long +_ctl_mpt2_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + long ret; + + /* pass MPI2_VERSION value, to indicate that this ioctl cmd + * came from mpt2ctl ioctl device. + */ + ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI2_VERSION); + return ret; +} #ifdef CONFIG_COMPAT /** - * _ctl_ioctl_compat - main ioctl entry point (compat) + *_ ctl_ioctl_compat - main ioctl entry point (compat) * @file - * @cmd - * @arg - * * This routine handles 32 bit applications in 64bit os. */ -static long +long _ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) { long ret; - ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1); + ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI25_VERSION); + return ret; +} + +/** + *_ ctl_mpt2_ioctl_compat - main ioctl entry point (compat) + * @file - + * @cmd - + * @arg - + * + * This routine handles 32 bit applications in 64bit os. + */ +long +_ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) +{ + long ret; + + ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI2_VERSION); return ret; } #endif @@ -2713,6 +2783,82 @@ _ctl_ioc_reply_queue_count_show(struct device *cdev, static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show, NULL); +/** + * _ctl_BRM_status_show - Backup Rail Monitor Status + * @cdev - pointer to embedded class device + * @buf - the buffer returned + * + * This is number of reply queues + * + * A sysfs 'read-only' shost attribute. + */ +static ssize_t +_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); + Mpi2IOUnitPage3_t *io_unit_pg3 = NULL; + Mpi2ConfigReply_t mpi_reply; + u16 backup_rail_monitor_status = 0; + u16 ioc_status; + int sz; + ssize_t rc = 0; + + if (!ioc->is_warpdrive) { + pr_err(MPT3SAS_FMT "%s: BRM attribute is only for" + " warpdrive\n", ioc->name, __func__); + goto out; + } + /* pci_access_mutex lock acquired by sysfs show path */ + mutex_lock(&ioc->pci_access_mutex); + if (ioc->pci_error_recovery || ioc->remove_host) { + mutex_unlock(&ioc->pci_access_mutex); + return 0; + } + + /* allocate upto GPIOVal 36 entries */ + sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36); + io_unit_pg3 = kzalloc(sz, GFP_KERNEL); + if (!io_unit_pg3) { + pr_err(MPT3SAS_FMT "%s: failed allocating memory " + "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz); + goto out; + } + + if (mpt3sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) != + 0) { + pr_err(MPT3SAS_FMT + "%s: failed reading iounit_pg3\n", ioc->name, + __func__); + goto out; + } + + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; + if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { + pr_err(MPT3SAS_FMT "%s: iounit_pg3 failed with " + "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status); + goto out; + } + + if (io_unit_pg3->GPIOCount < 25) { + pr_err(MPT3SAS_FMT "%s: iounit_pg3->GPIOCount less than " + "25 entries, detected (%d) entries\n", ioc->name, __func__, + io_unit_pg3->GPIOCount); + goto out; + } + + /* BRM status is in bit zero of GPIOVal[24] */ + backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]); + rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1)); + + out: + kfree(io_unit_pg3); + mutex_unlock(&ioc->pci_access_mutex); + return rc; +} +static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL); + struct DIAG_BUFFER_START { __le32 Size; __le32 DiagVersion; @@ -3165,6 +3311,7 @@ struct device_attribute *mpt3sas_host_attrs[] = { &dev_attr_diag_trigger_event, &dev_attr_diag_trigger_scsi, &dev_attr_diag_trigger_mpi, + &dev_attr_BRM_status, NULL, }; @@ -3218,6 +3365,7 @@ struct device_attribute *mpt3sas_dev_attrs[] = { NULL, }; +/* file operations table for mpt3ctl device */ static const struct file_operations ctl_fops = { .owner = THIS_MODULE, .unlocked_ioctl = _ctl_ioctl, @@ -3228,23 +3376,53 @@ static const struct file_operations ctl_fops = { #endif }; +/* file operations table for mpt2ctl device */ +static const struct file_operations ctl_gen2_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = _ctl_mpt2_ioctl, + .poll = _ctl_poll, + .fasync = _ctl_fasync, +#ifdef CONFIG_COMPAT + .compat_ioctl = _ctl_mpt2_ioctl_compat, +#endif +}; + static struct miscdevice ctl_dev = { .minor = MPT3SAS_MINOR, .name = MPT3SAS_DEV_NAME, .fops = &ctl_fops, }; +static struct miscdevice gen2_ctl_dev = { + .minor = MPT2SAS_MINOR, + .name = MPT2SAS_DEV_NAME, + .fops = &ctl_gen2_fops, +}; + /** * mpt3sas_ctl_init - main entry point for ctl. * */ void -mpt3sas_ctl_init(void) +mpt3sas_ctl_init(ushort hbas_to_enumerate) { async_queue = NULL; - if (misc_register(&ctl_dev) < 0) - pr_err("%s can't register misc device [minor=%d]\n", - MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR); + + /* Don't register mpt3ctl ioctl device if + * hbas_to_enumarate is one. + */ + if (hbas_to_enumerate != 1) + if (misc_register(&ctl_dev) < 0) + pr_err("%s can't register misc device [minor=%d]\n", + MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR); + + /* Don't register mpt3ctl ioctl device if + * hbas_to_enumarate is two. + */ + if (hbas_to_enumerate != 2) + if (misc_register(&gen2_ctl_dev) < 0) + pr_err("%s can't register misc device [minor=%d]\n", + MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR); init_waitqueue_head(&ctl_poll_wait); } @@ -3254,7 +3432,7 @@ mpt3sas_ctl_init(void) * */ void -mpt3sas_ctl_exit(void) +mpt3sas_ctl_exit(ushort hbas_to_enumerate) { struct MPT3SAS_ADAPTER *ioc; int i; @@ -3279,5 +3457,8 @@ mpt3sas_ctl_exit(void) kfree(ioc->event_log); } - misc_deregister(&ctl_dev); + if (hbas_to_enumerate != 1) + misc_deregister(&ctl_dev); + if (hbas_to_enumerate != 2) + misc_deregister(&gen2_ctl_dev); } diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.h b/drivers/scsi/mpt3sas/mpt3sas_ctl.h index aee99ce67..89408356d 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.h +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.h @@ -50,10 +50,13 @@ #include #endif - +#ifndef MPT2SAS_MINOR +#define MPT2SAS_MINOR (MPT_MINOR + 1) +#endif #ifndef MPT3SAS_MINOR #define MPT3SAS_MINOR (MPT_MINOR + 2) #endif +#define MPT2SAS_DEV_NAME "mpt2ctl" #define MPT3SAS_DEV_NAME "mpt3ctl" #define MPT3_MAGIC_NUMBER 'L' #define MPT3_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */ @@ -138,6 +141,7 @@ struct mpt3_ioctl_pci_info { #define MPT2_IOCTL_INTERFACE_FC_IP (0x02) #define MPT2_IOCTL_INTERFACE_SAS (0x03) #define MPT2_IOCTL_INTERFACE_SAS2 (0x04) +#define MPT2_IOCTL_INTERFACE_SAS2_SSS6200 (0x05) #define MPT3_IOCTL_INTERFACE_SAS3 (0x06) #define MPT2_IOCTL_VERSION_LENGTH (32) diff --git a/drivers/scsi/mpt3sas/mpt3sas_debug.h b/drivers/scsi/mpt3sas/mpt3sas_debug.h index 4e8a63fdb..cceeb2c16 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_debug.h +++ b/drivers/scsi/mpt3sas/mpt3sas_debug.h @@ -68,20 +68,11 @@ #define MPT_DEBUG_TRIGGER_DIAG 0x00200000 -/* - * CONFIG_SCSI_MPT3SAS_LOGGING - enabled in Kconfig - */ - -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING #define MPT_CHECK_LOGGING(IOC, CMD, BITS) \ { \ if (IOC->logging_level & BITS) \ CMD; \ } -#else -#define MPT_CHECK_LOGGING(IOC, CMD, BITS) -#endif /* CONFIG_SCSI_MPT3SAS_LOGGING */ - /* * debug macros @@ -153,7 +144,7 @@ /* inline functions for dumping debug data*/ -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING + /** * _debug_dump_mf - print message frame contents * @mpi_request: pointer to message frame @@ -211,10 +202,5 @@ _debug_dump_config(void *mpi_request, int sz) } pr_info("\n"); } -#else -#define _debug_dump_mf(mpi_request, sz) -#define _debug_dump_reply(mpi_request, sz) -#define _debug_dump_config(mpi_request, sz) -#endif /* CONFIG_SCSI_MPT3SAS_LOGGING */ #endif /* MPT3SAS_DEBUG_H_INCLUDED */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 8ccef3852..9ab77b064 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -54,14 +54,10 @@ #include #include #include +#include #include "mpt3sas_base.h" -MODULE_AUTHOR(MPT3SAS_AUTHOR); -MODULE_DESCRIPTION(MPT3SAS_DESCRIPTION); -MODULE_LICENSE("GPL"); -MODULE_VERSION(MPT3SAS_DRIVER_VERSION); - #define RAID_CHANNEL 1 /* forward proto's */ static void _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc, @@ -75,11 +71,16 @@ static int _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, static u8 _scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid); -static void _scsih_scan_start(struct Scsi_Host *shost); -static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time); - /* global parameters */ LIST_HEAD(mpt3sas_ioc_list); +/* global ioc lock for list operations */ +DEFINE_SPINLOCK(gioc_lock); + +MODULE_AUTHOR(MPT3SAS_AUTHOR); +MODULE_DESCRIPTION(MPT3SAS_DESCRIPTION); +MODULE_LICENSE("GPL"); +MODULE_VERSION(MPT3SAS_DRIVER_VERSION); +MODULE_ALIAS("mpt2sas"); /* local parameters */ static u8 scsi_io_cb_idx = -1; @@ -90,7 +91,8 @@ static u8 port_enable_cb_idx = -1; static u8 transport_cb_idx = -1; static u8 scsih_cb_idx = -1; static u8 config_cb_idx = -1; -static int mpt_ids; +static int mpt2_ids; +static int mpt3_ids; static u8 tm_tr_cb_idx = -1 ; static u8 tm_tr_volume_cb_idx = -1 ; @@ -117,8 +119,12 @@ static u64 max_lun = MPT3SAS_MAX_LUN; module_param(max_lun, ullong, 0); MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); - - +static ushort hbas_to_enumerate; +module_param(hbas_to_enumerate, ushort, 0); +MODULE_PARM_DESC(hbas_to_enumerate, + " 0 - enumerates both SAS 2.0 & SAS 3.0 generation HBAs\n \ + 1 - enumerates only SAS 2.0 generation HBAs\n \ + 2 - enumerates only SAS 3.0 generation HBAs (default=0)"); /* diag_buffer_enable is bitwise * bit 0 set = TRACE @@ -143,8 +149,8 @@ MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 "); /* raid transport support */ - -static struct raid_template *mpt3sas_raid_template; +struct raid_template *mpt3sas_raid_template; +struct raid_template *mpt2sas_raid_template; /** @@ -191,11 +197,36 @@ struct fw_event_work { u8 VP_ID; u8 ignore; u16 event; + struct kref refcount; char event_data[0] __aligned(4); }; -/* raid transport support */ -static struct raid_template *mpt3sas_raid_template; +static void fw_event_work_free(struct kref *r) +{ + kfree(container_of(r, struct fw_event_work, refcount)); +} + +static void fw_event_work_get(struct fw_event_work *fw_work) +{ + kref_get(&fw_work->refcount); +} + +static void fw_event_work_put(struct fw_event_work *fw_work) +{ + kref_put(&fw_work->refcount, fw_event_work_free); +} + +static struct fw_event_work *alloc_fw_event_work(int len) +{ + struct fw_event_work *fw_event; + + fw_event = kzalloc(sizeof(*fw_event) + len, GFP_ATOMIC); + if (!fw_event) + return NULL; + + kref_init(&fw_event->refcount); + return fw_event; +} /** * struct _scsi_io_transfer - scsi io transfer @@ -245,28 +276,6 @@ struct _scsi_io_transfer { u32 transfer_length; }; -/* - * The pci device ids are defined in mpi/mpi2_cnfg.h. - */ -static const struct pci_device_id scsih_pci_table[] = { - /* Fury ~ 3004 and 3008 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008, - PCI_ANY_ID, PCI_ANY_ID }, - /* Invader ~ 3108 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6, - PCI_ANY_ID, PCI_ANY_ID }, - {0} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, scsih_pci_table); - /** * _scsih_set_debug_level - global setting of ioc->logging_level. * @@ -282,8 +291,10 @@ _scsih_set_debug_level(const char *val, struct kernel_param *kp) return ret; pr_info("setting logging_level(0x%08x)\n", logging_level); + spin_lock(&gioc_lock); list_for_each_entry(ioc, &mpt3sas_ioc_list, list) ioc->logging_level = logging_level; + spin_unlock(&gioc_lock); return 0; } module_param_call(logging_level, _scsih_set_debug_level, param_get_int, @@ -518,8 +529,61 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, } } +static struct _sas_device * +__mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc, + struct MPT3SAS_TARGET *tgt_priv) +{ + struct _sas_device *ret; + + assert_spin_locked(&ioc->sas_device_lock); + + ret = tgt_priv->sdev; + if (ret) + sas_device_get(ret); + + return ret; +} + +static struct _sas_device * +mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc, + struct MPT3SAS_TARGET *tgt_priv) +{ + struct _sas_device *ret; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + ret = __mpt3sas_get_sdev_from_target(ioc, tgt_priv); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + return ret; +} + + +struct _sas_device * +__mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc, + u64 sas_address) +{ + struct _sas_device *sas_device; + + assert_spin_locked(&ioc->sas_device_lock); + + list_for_each_entry(sas_device, &ioc->sas_device_list, list) + if (sas_device->sas_address == sas_address) + goto found_device; + + list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) + if (sas_device->sas_address == sas_address) + goto found_device; + + return NULL; + +found_device: + sas_device_get(sas_device); + return sas_device; +} + /** - * mpt3sas_scsih_sas_device_find_by_sas_address - sas device search + * mpt3sas_get_sdev_by_addr - sas device search * @ioc: per adapter object * @sas_address: sas address * Context: Calling function should acquire ioc->sas_device_lock @@ -528,24 +592,44 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, * object. */ struct _sas_device * -mpt3sas_scsih_sas_device_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc, +mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc, u64 sas_address) +{ + struct _sas_device *sas_device; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = __mpt3sas_get_sdev_by_addr(ioc, + sas_address); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + return sas_device; +} + +static struct _sas_device * +__mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) { struct _sas_device *sas_device; + assert_spin_locked(&ioc->sas_device_lock); + list_for_each_entry(sas_device, &ioc->sas_device_list, list) - if (sas_device->sas_address == sas_address) - return sas_device; + if (sas_device->handle == handle) + goto found_device; list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) - if (sas_device->sas_address == sas_address) - return sas_device; + if (sas_device->handle == handle) + goto found_device; return NULL; + +found_device: + sas_device_get(sas_device); + return sas_device; } /** - * _scsih_sas_device_find_by_handle - sas device search + * mpt3sas_get_sdev_by_handle - sas device search * @ioc: per adapter object * @handle: sas device handle (assigned by firmware) * Context: Calling function should acquire ioc->sas_device_lock @@ -554,19 +638,16 @@ mpt3sas_scsih_sas_device_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc, * object. */ static struct _sas_device * -_scsih_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) +mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) { struct _sas_device *sas_device; + unsigned long flags; - list_for_each_entry(sas_device, &ioc->sas_device_list, list) - if (sas_device->handle == handle) - return sas_device; - - list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) - if (sas_device->handle == handle) - return sas_device; + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return NULL; + return sas_device; } /** @@ -575,7 +656,7 @@ _scsih_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) * @sas_device: the sas_device object * Context: This function will acquire ioc->sas_device_lock. * - * Removing object and freeing associated memory from the ioc->sas_device_list. + * If sas_device is on the list, remove it and decrement its reference count. */ static void _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, @@ -602,9 +683,15 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, ioc->name, sas_device->enclosure_level, sas_device->connector_name); + /* + * The lock serializes access to the list, but we still need to verify + * that nobody removed the entry while we were waiting on the lock. + */ spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_del(&sas_device->list); - kfree(sas_device); + if (!list_empty(&sas_device->list)) { + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -625,12 +712,16 @@ _scsih_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) return; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (sas_device) - list_del(&sas_device->list); + sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle); + if (sas_device) { + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) + if (sas_device) { _scsih_remove_device(ioc, sas_device); + sas_device_put(sas_device); + } } /** @@ -651,13 +742,16 @@ mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc, return; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - sas_address); - if (sas_device) - list_del(&sas_device->list); + sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_address); + if (sas_device) { + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) + if (sas_device) { _scsih_remove_device(ioc, sas_device); + sas_device_put(sas_device); + } } /** @@ -692,6 +786,7 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc, sas_device->enclosure_level, sas_device->connector_name)); spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device_get(sas_device); list_add_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -745,6 +840,7 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc, sas_device->connector_name)); spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device_get(sas_device); list_add_tail(&sas_device->list, &ioc->sas_device_init_list); _scsih_determine_boot_device(ioc, sas_device, 0); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -778,7 +874,7 @@ _scsih_raid_device_find_by_id(struct MPT3SAS_ADAPTER *ioc, int id, int channel) } /** - * _scsih_raid_device_find_by_handle - raid device search + * mpt3sas_raid_device_find_by_handle - raid device search * @ioc: per adapter object * @handle: sas device handle (assigned by firmware) * Context: Calling function should acquire ioc->raid_device_lock @@ -786,8 +882,8 @@ _scsih_raid_device_find_by_id(struct MPT3SAS_ADAPTER *ioc, int id, int channel) * This searches for raid_device based on handle, then return raid_device * object. */ -static struct _raid_device * -_scsih_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) +struct _raid_device * +mpt3sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle) { struct _raid_device *raid_device, *r; @@ -1095,14 +1191,14 @@ _scsih_scsi_lookup_find_by_lun(struct MPT3SAS_ADAPTER *ioc, int id, } /** - * _scsih_change_queue_depth - setting device queue depth + * scsih_change_queue_depth - setting device queue depth * @sdev: scsi device struct * @qdepth: requested queue depth * * Returns queue depth. */ -static int -_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) +int +scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) { struct Scsi_Host *shost = sdev->host; int max_depth; @@ -1123,12 +1219,15 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) goto not_sata; if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) goto not_sata; + spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - sas_device_priv_data->sas_target->sas_address); - if (sas_device && sas_device->device_info & - MPI2_SAS_DEVICE_INFO_SATA_DEVICE) - max_depth = MPT3SAS_SATA_QUEUE_DEPTH; + sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data); + if (sas_device) { + if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) + max_depth = MPT3SAS_SATA_QUEUE_DEPTH; + + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); not_sata: @@ -1141,14 +1240,14 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) } /** - * _scsih_target_alloc - target add routine + * scsih_target_alloc - target add routine * @starget: scsi target struct * * Returns 0 if ok. Any other return is assumed to be an error and * the device is ignored. */ -static int -_scsih_target_alloc(struct scsi_target *starget) +int +scsih_target_alloc(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(&starget->dev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -1176,7 +1275,9 @@ _scsih_target_alloc(struct scsi_target *starget) sas_target_priv_data->handle = raid_device->handle; sas_target_priv_data->sas_address = raid_device->wwid; sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME; - raid_device->starget = starget; + sas_target_priv_data->raid_device = raid_device; + if (ioc->is_warpdrive) + raid_device->starget = starget; } spin_unlock_irqrestore(&ioc->raid_device_lock, flags); return 0; @@ -1185,12 +1286,13 @@ _scsih_target_alloc(struct scsi_target *starget) /* sas/sata devices */ spin_lock_irqsave(&ioc->sas_device_lock, flags); rphy = dev_to_rphy(starget->dev.parent); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(ioc, rphy->identify.sas_address); if (sas_device) { sas_target_priv_data->handle = sas_device->handle; sas_target_priv_data->sas_address = sas_device->sas_address; + sas_target_priv_data->sdev = sas_device; sas_device->starget = starget; sas_device->id = starget->id; sas_device->channel = starget->channel; @@ -1206,13 +1308,13 @@ _scsih_target_alloc(struct scsi_target *starget) } /** - * _scsih_target_destroy - target destroy routine + * scsih_target_destroy - target destroy routine * @starget: scsi target struct * * Returns nothing. */ -static void -_scsih_target_destroy(struct scsi_target *starget) +void +scsih_target_destroy(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(&starget->dev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -1240,13 +1342,21 @@ _scsih_target_destroy(struct scsi_target *starget) spin_lock_irqsave(&ioc->sas_device_lock, flags); rphy = dev_to_rphy(starget->dev.parent); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - rphy->identify.sas_address); + sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data); if (sas_device && (sas_device->starget == starget) && (sas_device->id == starget->id) && (sas_device->channel == starget->channel)) sas_device->starget = NULL; + if (sas_device) { + /* + * Corresponding get() is in _scsih_target_alloc() + */ + sas_target_priv_data->sdev = NULL; + sas_device_put(sas_device); + + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); out: @@ -1255,14 +1365,14 @@ _scsih_target_destroy(struct scsi_target *starget) } /** - * _scsih_slave_alloc - device add routine + * scsih_slave_alloc - device add routine * @sdev: scsi device struct * * Returns 0 if ok. Any other return is assumed to be an error and * the device is ignored. */ -static int -_scsih_slave_alloc(struct scsi_device *sdev) +int +scsih_slave_alloc(struct scsi_device *sdev) { struct Scsi_Host *shost; struct MPT3SAS_ADAPTER *ioc; @@ -1302,14 +1412,18 @@ _scsih_slave_alloc(struct scsi_device *sdev) if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_target_priv_data->sas_address); if (sas_device && (sas_device->starget == NULL)) { sdev_printk(KERN_INFO, sdev, "%s : sas_device->starget set to starget @ %d\n", - __func__, __LINE__); + __func__, __LINE__); sas_device->starget = starget; } + + if (sas_device) + sas_device_put(sas_device); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -1317,13 +1431,13 @@ _scsih_slave_alloc(struct scsi_device *sdev) } /** - * _scsih_slave_destroy - device destroy routine + * scsih_slave_destroy - device destroy routine * @sdev: scsi device struct * * Returns nothing. */ -static void -_scsih_slave_destroy(struct scsi_device *sdev) +void +scsih_slave_destroy(struct scsi_device *sdev) { struct MPT3SAS_TARGET *sas_target_priv_data; struct scsi_target *starget; @@ -1344,10 +1458,13 @@ _scsih_slave_destroy(struct scsi_device *sdev) if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - sas_target_priv_data->sas_address); + sas_device = __mpt3sas_get_sdev_from_target(ioc, + sas_target_priv_data); if (sas_device && !sas_target_priv_data->num_luns) sas_device->starget = NULL; + + if (sas_device) + sas_device_put(sas_device); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -1409,23 +1526,26 @@ _scsih_display_sata_capabilities(struct MPT3SAS_ADAPTER *ioc, */ /** - * _scsih_is_raid - return boolean indicating device is raid volume + * scsih_is_raid - return boolean indicating device is raid volume * @dev the device struct object */ -static int -_scsih_is_raid(struct device *dev) +int +scsih_is_raid(struct device *dev) { struct scsi_device *sdev = to_scsi_device(dev); + struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host); + if (ioc->is_warpdrive) + return 0; return (sdev->channel == RAID_CHANNEL) ? 1 : 0; } /** - * _scsih_get_resync - get raid volume resync percent complete + * scsih_get_resync - get raid volume resync percent complete * @dev the device struct object */ -static void -_scsih_get_resync(struct device *dev) +void +scsih_get_resync(struct device *dev) { struct scsi_device *sdev = to_scsi_device(dev); struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host); @@ -1439,6 +1559,9 @@ _scsih_get_resync(struct device *dev) percent_complete = 0; handle = 0; + if (ioc->is_warpdrive) + goto out; + spin_lock_irqsave(&ioc->raid_device_lock, flags); raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, sdev->channel); @@ -1466,15 +1589,18 @@ _scsih_get_resync(struct device *dev) percent_complete = 0; out: - raid_set_resync(mpt3sas_raid_template, dev, percent_complete); + if (ioc->hba_mpi_version_belonged == MPI2_VERSION) + raid_set_resync(mpt2sas_raid_template, dev, percent_complete); + if (ioc->hba_mpi_version_belonged == MPI25_VERSION) + raid_set_resync(mpt3sas_raid_template, dev, percent_complete); } /** - * _scsih_get_state - get raid volume level + * scsih_get_state - get raid volume level * @dev the device struct object */ -static void -_scsih_get_state(struct device *dev) +void +scsih_get_state(struct device *dev) { struct scsi_device *sdev = to_scsi_device(dev); struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host); @@ -1524,7 +1650,10 @@ _scsih_get_state(struct device *dev) break; } out: - raid_set_state(mpt3sas_raid_template, dev, state); + if (ioc->hba_mpi_version_belonged == MPI2_VERSION) + raid_set_state(mpt2sas_raid_template, dev, state); + if (ioc->hba_mpi_version_belonged == MPI25_VERSION) + raid_set_state(mpt3sas_raid_template, dev, state); } /** @@ -1533,7 +1662,8 @@ _scsih_get_state(struct device *dev) * @volume_type: volume type */ static void -_scsih_set_level(struct scsi_device *sdev, u8 volume_type) +_scsih_set_level(struct MPT3SAS_ADAPTER *ioc, + struct scsi_device *sdev, u8 volume_type) { enum raid_level level = RAID_LEVEL_UNKNOWN; @@ -1552,7 +1682,12 @@ _scsih_set_level(struct scsi_device *sdev, u8 volume_type) break; } - raid_set_level(mpt3sas_raid_template, &sdev->sdev_gendev, level); + if (ioc->hba_mpi_version_belonged == MPI2_VERSION) + raid_set_level(mpt2sas_raid_template, + &sdev->sdev_gendev, level); + if (ioc->hba_mpi_version_belonged == MPI25_VERSION) + raid_set_level(mpt3sas_raid_template, + &sdev->sdev_gendev, level); } @@ -1622,8 +1757,6 @@ _scsih_get_volume_capabilities(struct MPT3SAS_ADAPTER *ioc, return 0; } - - /** * _scsih_enable_tlr - setting TLR flags * @ioc: per adapter object @@ -1652,14 +1785,14 @@ _scsih_enable_tlr(struct MPT3SAS_ADAPTER *ioc, struct scsi_device *sdev) } /** - * _scsih_slave_configure - device configure routine. + * scsih_slave_configure - device configure routine. * @sdev: scsi device struct * * Returns 0 if ok. Any other return is assumed to be an error and * the device is ignored. */ -static int -_scsih_slave_configure(struct scsi_device *sdev) +int +scsih_slave_configure(struct scsi_device *sdev) { struct Scsi_Host *shost = sdev->host; struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -1686,7 +1819,7 @@ _scsih_slave_configure(struct scsi_device *sdev) if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) { spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle); spin_unlock_irqrestore(&ioc->raid_device_lock, flags); if (!raid_device) { dfailprintk(ioc, pr_warn(MPT3SAS_FMT @@ -1702,6 +1835,10 @@ _scsih_slave_configure(struct scsi_device *sdev) return 1; } + /* + * WARPDRIVE: Initialize the required data for Direct IO + */ + mpt3sas_init_warpdrive_properties(ioc, raid_device); /* RAID Queue Depth Support * IS volume = underlying qdepth of drive type, either @@ -1750,17 +1887,19 @@ _scsih_slave_configure(struct scsi_device *sdev) break; } - sdev_printk(KERN_INFO, sdev, - "%s: handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n", - r_level, raid_device->handle, - (unsigned long long)raid_device->wwid, - raid_device->num_pds, ds); - + if (!ioc->hide_ir_msg) + sdev_printk(KERN_INFO, sdev, + "%s: handle(0x%04x), wwid(0x%016llx)," + " pd_count(%d), type(%s)\n", + r_level, raid_device->handle, + (unsigned long long)raid_device->wwid, + raid_device->num_pds, ds); - _scsih_change_queue_depth(sdev, qdepth); + scsih_change_queue_depth(sdev, qdepth); -/* raid transport support */ - _scsih_set_level(sdev, raid_device->volume_type); + /* raid transport support */ + if (!ioc->is_warpdrive) + _scsih_set_level(ioc, sdev, raid_device->volume_type); return 0; } @@ -1783,7 +1922,7 @@ _scsih_slave_configure(struct scsi_device *sdev) } spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_device_priv_data->sas_target->sas_address); if (!sas_device) { spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -1823,13 +1962,14 @@ _scsih_slave_configure(struct scsi_device *sdev) ds, sas_device->enclosure_level, sas_device->connector_name); + sas_device_put(sas_device); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (!ssp_target) _scsih_display_sata_capabilities(ioc, handle, sdev); - _scsih_change_queue_depth(sdev, qdepth); + scsih_change_queue_depth(sdev, qdepth); if (ssp_target) { sas_read_port_mode_page(sdev); @@ -1840,7 +1980,7 @@ _scsih_slave_configure(struct scsi_device *sdev) } /** - * _scsih_bios_param - fetch head, sector, cylinder info for a disk + * scsih_bios_param - fetch head, sector, cylinder info for a disk * @sdev: scsi device struct * @bdev: pointer to block device context * @capacity: device size (in 512 byte sectors) @@ -1851,8 +1991,8 @@ _scsih_slave_configure(struct scsi_device *sdev) * * Return nothing. */ -static int -_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev, +int +scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int params[]) { int heads; @@ -2209,7 +2349,10 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) if (!priv_target) return; - device_str = "volume"; + if (ioc->hide_ir_msg) + device_str = "WarpDrive"; + else + device_str = "volume"; scsi_print_command(scmd); if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { @@ -2219,8 +2362,7 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) device_str, (unsigned long long)priv_target->sas_address); } else { spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - priv_target->sas_address); + sas_device = __mpt3sas_get_sdev_from_target(ioc, priv_target); if (sas_device) { if (priv_target->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { @@ -2246,19 +2388,21 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) "enclosure level(0x%04x),connector name(%s)\n", sas_device->enclosure_level, sas_device->connector_name); + + sas_device_put(sas_device); } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } } /** - * _scsih_abort - eh threads main abort routine + * scsih_abort - eh threads main abort routine * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ -static int -_scsih_abort(struct scsi_cmnd *scmd) +int +scsih_abort(struct scsi_cmnd *scmd) { struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT3SAS_DEVICE *sas_device_priv_data; @@ -2311,21 +2455,23 @@ _scsih_abort(struct scsi_cmnd *scmd) } /** - * _scsih_dev_reset - eh threads main device reset routine + * scsih_dev_reset - eh threads main device reset routine * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ -static int -_scsih_dev_reset(struct scsi_cmnd *scmd) +int +scsih_dev_reset(struct scsi_cmnd *scmd) { struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT3SAS_DEVICE *sas_device_priv_data; - struct _sas_device *sas_device; - unsigned long flags; + struct _sas_device *sas_device = NULL; u16 handle; int r; + struct scsi_target *starget = scmd->device->sdev_target; + struct MPT3SAS_TARGET *target_priv_data = starget->hostdata; + sdev_printk(KERN_INFO, scmd->device, "attempting device reset! scmd(%p)\n", scmd); _scsih_tm_display_info(ioc, scmd); @@ -2344,12 +2490,10 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) handle = 0; if (sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, - sas_device_priv_data->sas_target->handle); + sas_device = mpt3sas_get_sdev_from_target(ioc, + target_priv_data); if (sas_device) handle = sas_device->volume_handle; - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } else handle = sas_device_priv_data->sas_target->handle; @@ -2366,25 +2510,29 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) out: sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + + if (sas_device) + sas_device_put(sas_device); + return r; } /** - * _scsih_target_reset - eh threads main target reset routine + * scsih_target_reset - eh threads main target reset routine * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ -static int -_scsih_target_reset(struct scsi_cmnd *scmd) +int +scsih_target_reset(struct scsi_cmnd *scmd) { struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT3SAS_DEVICE *sas_device_priv_data; - struct _sas_device *sas_device; - unsigned long flags; + struct _sas_device *sas_device = NULL; u16 handle; int r; struct scsi_target *starget = scmd->device->sdev_target; + struct MPT3SAS_TARGET *target_priv_data = starget->hostdata; starget_printk(KERN_INFO, starget, "attempting target reset! scmd(%p)\n", scmd); @@ -2404,12 +2552,10 @@ _scsih_target_reset(struct scsi_cmnd *scmd) handle = 0; if (sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, - sas_device_priv_data->sas_target->handle); + sas_device = mpt3sas_get_sdev_from_target(ioc, + target_priv_data); if (sas_device) handle = sas_device->volume_handle; - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } else handle = sas_device_priv_data->sas_target->handle; @@ -2426,18 +2572,22 @@ _scsih_target_reset(struct scsi_cmnd *scmd) out: starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + + if (sas_device) + sas_device_put(sas_device); + return r; } /** - * _scsih_host_reset - eh threads main host reset routine + * scsih_host_reset - eh threads main host reset routine * @scmd: pointer to scsi command object * * Returns SUCCESS if command aborted else FAILED */ -static int -_scsih_host_reset(struct scsi_cmnd *scmd) +int +scsih_host_reset(struct scsi_cmnd *scmd) { struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host); int r, retval; @@ -2483,32 +2633,36 @@ _scsih_fw_event_add(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) return; spin_lock_irqsave(&ioc->fw_event_lock, flags); + fw_event_work_get(fw_event); INIT_LIST_HEAD(&fw_event->list); list_add_tail(&fw_event->list, &ioc->fw_event_list); INIT_WORK(&fw_event->work, _firmware_event_work); + fw_event_work_get(fw_event); queue_work(ioc->firmware_event_thread, &fw_event->work); spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } /** - * _scsih_fw_event_free - delete fw_event + * _scsih_fw_event_del_from_list - delete fw_event from the list * @ioc: per adapter object * @fw_event: object describing the event * Context: This function will acquire ioc->fw_event_lock. * - * This removes firmware event object from link list, frees associated memory. + * If the fw_event is on the fw_event_list, remove it and do a put. * * Return nothing. */ static void -_scsih_fw_event_free(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work +_scsih_fw_event_del_from_list(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { unsigned long flags; spin_lock_irqsave(&ioc->fw_event_lock, flags); - list_del(&fw_event->list); - kfree(fw_event); + if (!list_empty(&fw_event->list)) { + list_del_init(&fw_event->list); + fw_event_work_put(fw_event); + } spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } @@ -2525,17 +2679,19 @@ mpt3sas_send_trigger_data_event(struct MPT3SAS_ADAPTER *ioc, struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data) { struct fw_event_work *fw_event; + u16 sz; if (ioc->is_driver_loading) return; - fw_event = kzalloc(sizeof(*fw_event) + sizeof(*event_data), - GFP_ATOMIC); + sz = sizeof(*event_data); + fw_event = alloc_fw_event_work(sz); if (!fw_event) return; fw_event->event = MPT3SAS_PROCESS_TRIGGER_DIAG; fw_event->ioc = ioc; memcpy(fw_event->event_data, event_data, sizeof(*event_data)); _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); } /** @@ -2551,12 +2707,13 @@ _scsih_error_recovery_delete_devices(struct MPT3SAS_ADAPTER *ioc) if (ioc->is_driver_loading) return; - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); + fw_event = alloc_fw_event_work(0); if (!fw_event) return; fw_event->event = MPT3SAS_REMOVE_UNRESPONDING_DEVICES; fw_event->ioc = ioc; _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); } /** @@ -2570,12 +2727,29 @@ mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc) { struct fw_event_work *fw_event; - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); + fw_event = alloc_fw_event_work(0); if (!fw_event) return; fw_event->event = MPT3SAS_PORT_ENABLE_COMPLETE; fw_event->ioc = ioc; _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); +} + +static struct fw_event_work *dequeue_next_fw_event(struct MPT3SAS_ADAPTER *ioc) +{ + unsigned long flags; + struct fw_event_work *fw_event = NULL; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + if (!list_empty(&ioc->fw_event_list)) { + fw_event = list_first_entry(&ioc->fw_event_list, + struct fw_event_work, list); + list_del_init(&fw_event->list); + } + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + + return fw_event; } /** @@ -2590,17 +2764,25 @@ mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc) static void _scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc) { - struct fw_event_work *fw_event, *next; + struct fw_event_work *fw_event; if (list_empty(&ioc->fw_event_list) || !ioc->firmware_event_thread || in_interrupt()) return; - list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { - if (cancel_delayed_work_sync(&fw_event->delayed_work)) { - _scsih_fw_event_free(ioc, fw_event); - continue; - } + while ((fw_event = dequeue_next_fw_event(ioc))) { + /* + * Wait on the fw_event to complete. If this returns 1, then + * the event was never executed, and we need a put for the + * reference the delayed_work had on the fw_event. + * + * If it did execute, we wait for it to finish, and the put will + * happen from _firmware_event_work() + */ + if (cancel_delayed_work_sync(&fw_event->delayed_work)) + fw_event_work_put(fw_event); + + fw_event_work_put(fw_event); } } @@ -2763,7 +2945,7 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) struct scsi_device *sdev; struct _sas_device *sas_device; - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = mpt3sas_get_sdev_by_handle(ioc, handle); if (!sas_device) return; @@ -2779,6 +2961,8 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) continue; _scsih_internal_device_block(sdev, sas_device_priv_data); } + + sas_device_put(sas_device); } /** @@ -2807,12 +2991,13 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT3SAS_ADAPTER *ioc, if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = - mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - mpt3sas_port->remote_identify.sas_address); - if (sas_device) + sas_device = __mpt3sas_get_sdev_by_addr(ioc, + mpt3sas_port->remote_identify.sas_address); + if (sas_device) { set_bit(sas_device->handle, - ioc->blocking_handles); + ioc->blocking_handles); + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } } @@ -2880,7 +3065,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) { Mpi2SCSITaskManagementRequest_t *mpi_request; u16 smid; - struct _sas_device *sas_device; + struct _sas_device *sas_device = NULL; struct MPT3SAS_TARGET *sas_target_priv_data = NULL; u64 sas_address = 0; unsigned long flags; @@ -2913,7 +3098,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) return; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle); if (sas_device && sas_device->starget && sas_device->starget->hostdata) { sas_target_priv_data = sas_device->starget->hostdata; @@ -2947,14 +3132,14 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) if (!smid) { delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); if (!delayed_tr) - return; + goto out; INIT_LIST_HEAD(&delayed_tr->list); delayed_tr->handle = handle; list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); dewtprintk(ioc, pr_info(MPT3SAS_FMT "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name, handle)); - return; + goto out; } dewtprintk(ioc, pr_info(MPT3SAS_FMT @@ -2968,6 +3153,10 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; mpt3sas_base_put_smid_hi_priority(ioc, smid); mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL); + +out: + if (sas_device) + sas_device_put(sas_device); } /** @@ -3337,7 +3526,7 @@ _scsih_set_volume_delete_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle) unsigned long flags; spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle); if (raid_device && raid_device->starget && raid_device->starget->hostdata) { sas_target_priv_data = @@ -3398,6 +3587,9 @@ _scsih_check_ir_config_unhide_events(struct MPT3SAS_ADAPTER *ioc, a = 0; b = 0; + if (ioc->is_warpdrive) + return; + /* Volume Resets for Deleted or Removed */ element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; for (i = 0; i < event_data->NumElements; i++, element++) { @@ -3634,8 +3826,9 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) } + /** - * _scsih_qcmd - main scsi request entry point + * scsih_qcmd - main scsi request entry point * @scmd: pointer to scsi command object * @done: function pointer to be invoked on completion * @@ -3645,21 +3838,20 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full */ -static int -_scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) +int +scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) { struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); struct MPT3SAS_DEVICE *sas_device_priv_data; struct MPT3SAS_TARGET *sas_target_priv_data; + struct _raid_device *raid_device; Mpi2SCSIIORequest_t *mpi_request; u32 mpi_control; u16 smid; u16 handle; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_SCSI) scsi_print_command(scmd); -#endif sas_device_priv_data = scmd->device->hostdata; if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { @@ -3709,8 +3901,11 @@ _scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) /* set tags */ mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; - if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) && - scmd->cmd_len != 32) + /* Make sure Device is not raid volume. + * We do not expose raid functionality to upper layer for warpdrive. + */ + if (!ioc->is_warpdrive && !scsih_is_raid(&scmd->device->sdev_gendev) + && sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32) mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; smid = mpt3sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd); @@ -3752,13 +3947,19 @@ _scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) } else ioc->build_zero_len_sge(ioc, &mpi_request->SGL); + raid_device = sas_target_priv_data->raid_device; + if (raid_device && raid_device->direct_io_enabled) + mpt3sas_setup_direct_io(ioc, scmd, raid_device, mpi_request, + smid); + if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) { if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) { mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len | MPI25_SCSIIO_IOFLAGS_FAST_PATH); mpt3sas_base_put_smid_fast_path(ioc, smid, handle); } else - mpt3sas_base_put_smid_scsi_io(ioc, smid, handle); + mpt3sas_base_put_smid_scsi_io(ioc, smid, + le16_to_cpu(mpi_request->DevHandle)); } else mpt3sas_base_put_smid_default(ioc, smid); return 0; @@ -3790,7 +3991,6 @@ _scsih_normalize_sense(char *sense_buffer, struct sense_info *data) } } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request * @ioc: per adapter object @@ -3818,14 +4018,16 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, char *desc_scsi_state = ioc->tmp_string; u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo); struct _sas_device *sas_device = NULL; - unsigned long flags; struct scsi_target *starget = scmd->device->sdev_target; struct MPT3SAS_TARGET *priv_target = starget->hostdata; char *device_str = NULL; if (!priv_target) return; - device_str = "volume"; + if (ioc->hide_ir_msg) + device_str = "WarpDrive"; + else + device_str = "volume"; if (log_info == 0x31170000) return; @@ -3946,9 +4148,7 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, pr_warn(MPT3SAS_FMT "\t%s wwid(0x%016llx)\n", ioc->name, device_str, (unsigned long long)priv_target->sas_address); } else { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - priv_target->sas_address); + sas_device = mpt3sas_get_sdev_from_target(ioc, priv_target); if (sas_device) { pr_warn(MPT3SAS_FMT "\tsas_address(0x%016llx), phy(%d)\n", @@ -3967,8 +4167,9 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, " connector name( %s)\n", ioc->name, sas_device->enclosure_level, sas_device->connector_name); + + sas_device_put(sas_device); } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } pr_warn(MPT3SAS_FMT @@ -4003,7 +4204,6 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, _scsih_response_code(ioc, response_bytes[0]); } } -#endif /** * _scsih_turn_on_pfa_led - illuminate PFA LED @@ -4020,7 +4220,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) Mpi2SepRequest_t mpi_request; struct _sas_device *sas_device; - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = mpt3sas_get_sdev_by_handle(ioc, handle); if (!sas_device) return; @@ -4035,7 +4235,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) &mpi_request)) != 0) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); - return; + goto out; } sas_device->pfa_led_on = 1; @@ -4044,9 +4244,12 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply.IOCStatus), le32_to_cpu(mpi_reply.IOCLogInfo))); - return; + goto out; } +out: + sas_device_put(sas_device); } + /** * _scsih_turn_off_pfa_led - turn off Fault LED * @ioc: per adapter object @@ -4085,6 +4288,7 @@ _scsih_turn_off_pfa_led(struct MPT3SAS_ADAPTER *ioc, return; } } + /** * _scsih_send_event_to_turn_on_pfa_led - fire delayed event * @ioc: per adapter object @@ -4098,13 +4302,14 @@ _scsih_send_event_to_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle) { struct fw_event_work *fw_event; - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); + fw_event = alloc_fw_event_work(0); if (!fw_event) return; fw_event->event = MPT3SAS_TURN_ON_PFA_LED; fw_event->device_handle = handle; fw_event->ioc = ioc; _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); } /** @@ -4128,19 +4333,17 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) /* only handle non-raid devices */ spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle); + if (!sas_device) + goto out_unlock; + starget = sas_device->starget; sas_target_priv_data = starget->hostdata; if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) || - ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) + goto out_unlock; + if (sas_device->enclosure_handle != 0) starget_printk(KERN_INFO, starget, "predicted fault, " "enclosure logical id(0x%016llx), slot(%d)\n", @@ -4163,7 +4366,7 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) if (!event_reply) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); - return; + goto out; } event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; @@ -4180,6 +4383,14 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address); mpt3sas_ctl_add_to_event_log(ioc, event_reply); kfree(event_reply); +out: + if (sas_device) + sas_device_put(sas_device); + return; + +out_unlock: + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + goto out; } /** @@ -4207,6 +4418,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) u32 log_info; struct MPT3SAS_DEVICE *sas_device_priv_data; u32 response_code = 0; + unsigned long flags; mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); scmd = _scsih_scsi_lookup_get_clear(ioc, smid); @@ -4228,6 +4440,24 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) } ioc_status = le16_to_cpu(mpi_reply->IOCStatus); + /* + * WARPDRIVE: If direct_io is set then it is directIO, + * the failed direct I/O should be redirected to volume + */ + if (mpt3sas_scsi_direct_io_get(ioc, smid) && + ((ioc_status & MPI2_IOCSTATUS_MASK) + != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) { + spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); + ioc->scsi_lookup[smid - 1].scmd = scmd; + spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); + mpt3sas_scsi_direct_io_set(ioc, smid, 0); + memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); + mpi_request->DevHandle = + cpu_to_le16(sas_device_priv_data->sas_target->handle); + mpt3sas_base_put_smid_scsi_io(ioc, smid, + sas_device_priv_data->sas_target->handle); + return 0; + } /* turning off TLR */ scsi_state = mpi_reply->SCSIState; if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) @@ -4235,10 +4465,13 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; if (!sas_device_priv_data->tlr_snoop_check) { sas_device_priv_data->tlr_snoop_check++; - if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) && - response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) - sas_device_priv_data->flags &= - ~MPT_DEVICE_TLR_ON; + if (!ioc->is_warpdrive && + !scsih_is_raid(&scmd->device->sdev_gendev) && + sas_is_tlr_enabled(scmd->device) && + response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) { + sas_disable_tlr(scmd->device); + sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n"); + } } xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); @@ -4271,13 +4504,11 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) le16_to_cpu(mpi_reply->DevHandle)); mpt3sas_trigger_scsi(ioc, data.skey, data.asc, data.ascq); -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (!(ioc->logging_level & MPT_DEBUG_REPLY) && ((scmd->sense_buffer[2] == UNIT_ATTENTION) || (scmd->sense_buffer[2] == MEDIUM_ERROR) || (scmd->sense_buffer[2] == HARDWARE_ERROR))) _scsih_scsi_ioc_info(ioc, scmd, mpi_reply, smid); -#endif } switch (ioc_status) { case MPI2_IOCSTATUS_BUSY: @@ -4384,10 +4615,8 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY)) _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid); -#endif out: @@ -4933,13 +5162,11 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_address); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + if (!sas_device) + goto out_unlock; if (unlikely(sas_device->handle != handle)) { starget = sas_device->starget; @@ -4967,20 +5194,25 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, pr_err(MPT3SAS_FMT "device is not present handle(0x%04x), flags!!!\n", ioc->name, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; + goto out_unlock; } /* check if there were any issues with discovery */ if (_scsih_check_access_status(ioc, sas_address, handle, - sas_device_pg0.AccessStatus)) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + sas_device_pg0.AccessStatus)) + goto out_unlock; spin_unlock_irqrestore(&ioc->sas_device_lock, flags); _scsih_ublock_io_device(ioc, sas_address); + if (sas_device) + sas_device_put(sas_device); + return; + +out_unlock: + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (sas_device) + sas_device_put(sas_device); } /** @@ -5005,7 +5237,6 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u32 ioc_status; u64 sas_address; u32 device_info; - unsigned long flags; if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { @@ -5041,13 +5272,12 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, sas_device_pg0.AccessStatus)) return -1; - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, - sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (sas_device) + sas_device = mpt3sas_get_sdev_by_addr(ioc, + sas_address); + if (sas_device) { + sas_device_put(sas_device); return -1; + } sas_device = kzalloc(sizeof(struct _sas_device), GFP_KERNEL); @@ -5057,6 +5287,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, return 0; } + kref_init(&sas_device->refcount); sas_device->handle = handle; if (_scsih_get_sas_address(ioc, le16_to_cpu(sas_device_pg0.ParentDevHandle), @@ -5098,6 +5329,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, else _scsih_sas_device_add(ioc, sas_device); + sas_device_put(sas_device); return 0; } @@ -5144,7 +5376,9 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; } - mpt3sas_transport_port_remove(ioc, + + if (!ioc->hide_drives) + mpt3sas_transport_port_remove(ioc, sas_device->sas_address, sas_device->sas_address_parent); @@ -5180,11 +5414,8 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, "%s: exit: enclosure level(0x%04x), connector name(%s)\n", ioc->name, __func__, sas_device->enclosure_level, sas_device->connector_name)); - - kfree(sas_device); } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _scsih_sas_topology_change_event_debug - debug for topology event * @ioc: per adapter object @@ -5262,7 +5493,6 @@ _scsih_sas_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc, } } -#endif /** * _scsih_sas_topology_change_event - handle topology changes @@ -5287,10 +5517,8 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, (Mpi2EventDataSasTopologyChangeList_t *) fw_event->event_data; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) _scsih_sas_topology_change_event_debug(ioc, event_data); -#endif if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery) return 0; @@ -5396,7 +5624,6 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc, return 0; } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _scsih_sas_device_status_change_event_debug - debug for device event * @event_data: event data payload @@ -5464,7 +5691,6 @@ _scsih_sas_device_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc, event_data->ASC, event_data->ASCQ); pr_info("\n"); } -#endif /** * _scsih_sas_device_status_change_event - handle device status change @@ -5486,11 +5712,9 @@ _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc, (Mpi2EventDataSasDeviceStatusChange_t *) fw_event->event_data; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) _scsih_sas_device_status_change_event_debug(ioc, event_data); -#endif /* In MPI Revision K (0xC), the internal device reset complete was * implemented, so avoid setting tm_busy flag for older firmware. @@ -5506,29 +5730,30 @@ _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc, spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_address = le64_to_cpu(event_data->SASAddress); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_address); - if (!sas_device || !sas_device->starget) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + if (!sas_device || !sas_device->starget) + goto out; target_priv_data = sas_device->starget->hostdata; - if (!target_priv_data) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + if (!target_priv_data) + goto out; if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET) target_priv_data->tm_busy = 1; else target_priv_data->tm_busy = 0; + +out: + if (sas_device) + sas_device_put(sas_device); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure * event @@ -5563,7 +5788,6 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc, (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID), le16_to_cpu(event_data->StartSlot)); } -#endif /** * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events @@ -5577,12 +5801,10 @@ static void _scsih_sas_enclosure_dev_status_change_event(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) _scsih_sas_enclosure_dev_status_change_event_debug(ioc, (Mpi2EventDataSasEnclDevStatusChange_t *) fw_event->event_data); -#endif } /** @@ -5762,17 +5984,15 @@ _scsih_sas_discovery_event(struct MPT3SAS_ADAPTER *ioc, Mpi2EventDataSasDiscovery_t *event_data = (Mpi2EventDataSasDiscovery_t *) fw_event->event_data; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { pr_info(MPT3SAS_FMT "discovery event: (%s)", ioc->name, (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? "start" : "stop"); - if (event_data->DiscoveryStatus) - pr_info("discovery_status(0x%08x)", - le32_to_cpu(event_data->DiscoveryStatus)); - pr_info("\n"); + if (event_data->DiscoveryStatus) + pr_info("discovery_status(0x%08x)", + le32_to_cpu(event_data->DiscoveryStatus)); + pr_info("\n"); } -#endif if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED && !ioc->sas_hba.num_phys) { @@ -5804,6 +6024,8 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num) u16 ioc_status; u32 log_info; + if (ioc->hba_mpi_version_belonged == MPI2_VERSION) + return rc; mutex_lock(&ioc->scsih_cmds.mutex); @@ -5971,7 +6193,7 @@ _scsih_sas_volume_delete(struct MPT3SAS_ADAPTER *ioc, u16 handle) struct scsi_target *starget = NULL; spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle); if (raid_device) { if (raid_device->starget) { starget = raid_device->starget; @@ -6008,7 +6230,7 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc, u16 handle = le16_to_cpu(element->PhysDiskDevHandle); spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle); if (sas_device) { sas_device->volume_handle = 0; sas_device->volume_wwid = 0; @@ -6027,6 +6249,8 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc, /* exposing raid component */ if (starget) starget_for_each_device(starget, NULL, _scsih_reprobe_lun); + + sas_device_put(sas_device); } /** @@ -6055,7 +6279,7 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc, &volume_wwid); spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle); if (sas_device) { set_bit(handle, ioc->pd_handles); if (sas_device->starget && sas_device->starget->hostdata) { @@ -6073,8 +6297,11 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc, /* hiding raid component */ _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum); + if (starget) starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun); + + sas_device_put(sas_device); } /** @@ -6107,7 +6334,6 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc, Mpi2EventIrConfigElement_t *element) { struct _sas_device *sas_device; - unsigned long flags; u16 handle = le16_to_cpu(element->PhysDiskDevHandle); Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t sas_device_pg0; @@ -6117,11 +6343,10 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc, set_bit(handle, ioc->pd_handles); - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + sas_device = mpt3sas_get_sdev_by_handle(ioc, handle); if (sas_device) { _scsih_ir_fastpath(ioc, handle, element->PhysDiskNum); + sas_device_put(sas_device); return; } @@ -6149,7 +6374,6 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc, _scsih_add_device(ioc, handle, 0, 1); } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events * @ioc: per adapter object @@ -6229,7 +6453,6 @@ _scsih_sas_ir_config_change_event_debug(struct MPT3SAS_ADAPTER *ioc, element->PhysDiskNum); } } -#endif /** * _scsih_sas_ir_config_change_event - handle ir configuration change events @@ -6250,18 +6473,16 @@ _scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc, (Mpi2EventDataIrConfigChangeList_t *) fw_event->event_data; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) && + (!ioc->hide_ir_msg)) _scsih_sas_ir_config_change_event_debug(ioc, event_data); -#endif - foreign_config = (le32_to_cpu(event_data->Flags) & MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - if (ioc->shost_recovery) { - + if (ioc->shost_recovery && + ioc->hba_mpi_version_belonged != MPI2_VERSION) { for (i = 0; i < event_data->NumElements; i++, element++) { if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_HIDE) _scsih_ir_fastpath(ioc, @@ -6270,6 +6491,7 @@ _scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc, } return; } + for (i = 0; i < event_data->NumElements; i++, element++) { switch (element->ReasonCode) { @@ -6285,16 +6507,20 @@ _scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc, le16_to_cpu(element->VolDevHandle)); break; case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: - _scsih_sas_pd_hide(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_hide(ioc, element); break; case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: - _scsih_sas_pd_expose(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_expose(ioc, element); break; case MPI2_EVENT_IR_CHANGE_RC_HIDE: - _scsih_sas_pd_add(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_add(ioc, element); break; case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: - _scsih_sas_pd_delete(ioc, element); + if (!ioc->is_warpdrive) + _scsih_sas_pd_delete(ioc, element); break; } } @@ -6329,10 +6555,11 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc, handle = le16_to_cpu(event_data->VolDevHandle); state = le32_to_cpu(event_data->NewValue); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", - ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); + if (!ioc->hide_ir_msg) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", + ioc->name, __func__, handle, + le32_to_cpu(event_data->PreviousValue), state)); switch (state) { case MPI2_RAID_VOL_STATE_MISSING: case MPI2_RAID_VOL_STATE_FAILED: @@ -6344,7 +6571,7 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc, case MPI2_RAID_VOL_STATE_OPTIMAL: spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle); spin_unlock_irqrestore(&ioc->raid_device_lock, flags); if (raid_device) @@ -6398,7 +6625,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, u16 handle, parent_handle; u32 state; struct _sas_device *sas_device; - unsigned long flags; Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t sas_device_pg0; u32 ioc_status; @@ -6415,10 +6641,12 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, handle = le16_to_cpu(event_data->PhysDiskDevHandle); state = le32_to_cpu(event_data->NewValue); - dewtprintk(ioc, pr_info(MPT3SAS_FMT - "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", - ioc->name, __func__, handle, + if (!ioc->hide_ir_msg) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n", + ioc->name, __func__, handle, le32_to_cpu(event_data->PreviousValue), state)); + switch (state) { case MPI2_RAID_PD_STATE_ONLINE: case MPI2_RAID_PD_STATE_DEGRADED: @@ -6426,13 +6654,14 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, case MPI2_RAID_PD_STATE_OPTIMAL: case MPI2_RAID_PD_STATE_HOT_SPARE: - set_bit(handle, ioc->pd_handles); - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (!ioc->is_warpdrive) + set_bit(handle, ioc->pd_handles); - if (sas_device) + sas_device = mpt3sas_get_sdev_by_handle(ioc, handle); + if (sas_device) { + sas_device_put(sas_device); return; + } if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, @@ -6467,7 +6696,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc, } } -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING /** * _scsih_sas_ir_operation_status_event_debug - debug for IR op event * @ioc: per adapter object @@ -6509,7 +6737,6 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT3SAS_ADAPTER *ioc, le16_to_cpu(event_data->VolDevHandle), event_data->PercentComplete); } -#endif /** * _scsih_sas_ir_operation_status_event - handle RAID operation events @@ -6530,18 +6757,17 @@ _scsih_sas_ir_operation_status_event(struct MPT3SAS_ADAPTER *ioc, unsigned long flags; u16 handle; -#ifdef CONFIG_SCSI_MPT3SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) + if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) && + (!ioc->hide_ir_msg)) _scsih_sas_ir_operation_status_event_debug(ioc, event_data); -#endif /* code added for raid transport support */ if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) { spin_lock_irqsave(&ioc->raid_device_lock, flags); handle = le16_to_cpu(event_data->VolDevHandle); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); + raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle); if (raid_device) raid_device->percent_complete = event_data->PercentComplete; @@ -6703,7 +6929,7 @@ static void _scsih_mark_responding_raid_device(struct MPT3SAS_ADAPTER *ioc, u64 wwid, u16 handle) { - struct MPT3SAS_TARGET *sas_target_priv_data; + struct MPT3SAS_TARGET *sas_target_priv_data = NULL; struct scsi_target *starget; struct _raid_device *raid_device; unsigned long flags; @@ -6722,6 +6948,13 @@ _scsih_mark_responding_raid_device(struct MPT3SAS_ADAPTER *ioc, u64 wwid, starget_printk(KERN_INFO, raid_device->starget, "handle(0x%04x), wwid(0x%016llx)\n", handle, (unsigned long long)raid_device->wwid); + + /* + * WARPDRIVE: The handles of the PDs might have changed + * across the host reset so re-initialize the + * required data for Direct IO + */ + mpt3sas_init_warpdrive_properties(ioc, raid_device); spin_lock_irqsave(&ioc->raid_device_lock, flags); if (raid_device->handle == handle) { spin_unlock_irqrestore(&ioc->raid_device_lock, @@ -6791,6 +7024,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc) } /* refresh the pd_handles */ + if (!ioc->is_warpdrive) { phys_disk_num = 0xFF; memset(ioc->pd_handles, 0, ioc->pd_handles_sz); while (!(mpt3sas_config_get_phys_disk_pg0(ioc, &mpi_reply, @@ -6804,6 +7038,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc) handle = le16_to_cpu(pd_pg0.DevHandle); set_bit(handle, ioc->pd_handles); } + } out: pr_info(MPT3SAS_FMT "search for responding raid volumes: complete\n", ioc->name); @@ -6906,6 +7141,7 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc) struct _raid_device *raid_device, *raid_device_next; struct list_head tmp_list; unsigned long flags; + LIST_HEAD(head); pr_info(MPT3SAS_FMT "removing unresponding devices: start\n", ioc->name); @@ -6913,14 +7149,28 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc) /* removing unresponding end devices */ pr_info(MPT3SAS_FMT "removing unresponding devices: end-devices\n", ioc->name); + /* + * Iterate, pulling off devices marked as non-responding. We become the + * owner for the reference the list had on any object we prune. + */ + spin_lock_irqsave(&ioc->sas_device_lock, flags); list_for_each_entry_safe(sas_device, sas_device_next, &ioc->sas_device_list, list) { if (!sas_device->responding) - mpt3sas_device_remove_by_sas_address(ioc, - sas_device->sas_address); + list_move_tail(&sas_device->list, &head); else sas_device->responding = 0; } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + /* + * Now, uninitialize and remove the unresponding devices we pruned. + */ + list_for_each_entry_safe(sas_device, sas_device_next, &head, list) { + _scsih_remove_device(ioc, sas_device); + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } /* removing unresponding volumes */ if (ioc->ir_firmware) { @@ -7074,11 +7324,11 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) } phys_disk_num = pd_pg0.PhysDiskNum; handle = le16_to_cpu(pd_pg0.DevHandle); - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) + sas_device = mpt3sas_get_sdev_by_handle(ioc, handle); + if (sas_device) { + sas_device_put(sas_device); continue; + } if (mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle) != 0) @@ -7199,12 +7449,12 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) if (!(_scsih_is_end_device( le32_to_cpu(sas_device_pg0.DeviceInfo)))) continue; - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = mpt3sas_get_sdev_by_addr(ioc, le64_to_cpu(sas_device_pg0.SASAddress)); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) + if (sas_device) { + sas_device_put(sas_device); continue; + } parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) { pr_info(MPT3SAS_FMT "\tBEFORE adding end device: " \ @@ -7296,10 +7546,11 @@ mpt3sas_scsih_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase) static void _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { + _scsih_fw_event_del_from_list(ioc, fw_event); + /* the queue is being flushed so ignore this event */ - if (ioc->remove_host || - ioc->pci_error_recovery) { - _scsih_fw_event_free(ioc, fw_event); + if (ioc->remove_host || ioc->pci_error_recovery) { + fw_event_work_put(fw_event); return; } @@ -7310,8 +7561,16 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) fw_event->event_data); break; case MPT3SAS_REMOVE_UNRESPONDING_DEVICES: - while (scsi_host_in_recovery(ioc->shost) || ioc->shost_recovery) + while (scsi_host_in_recovery(ioc->shost) || + ioc->shost_recovery) { + /* + * If we're unloading, bail. Otherwise, this can become + * an infinite loop. + */ + if (ioc->remove_host) + goto out; ssleep(1); + } _scsih_remove_unresponding_sas_devices(ioc); _scsih_scan_for_devices_after_reset(ioc); break; @@ -7356,7 +7615,8 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event) _scsih_sas_ir_operation_status_event(ioc, fw_event); break; } - _scsih_fw_event_free(ioc, fw_event); +out: + fw_event_work_put(fw_event); } /** @@ -7453,7 +7713,53 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, (Mpi2EventDataIrVolume_t *) mpi_reply->EventData); break; + case MPI2_EVENT_LOG_ENTRY_ADDED: + { + Mpi2EventDataLogEntryAdded_t *log_entry; + u32 *log_code; + + if (!ioc->is_warpdrive) + break; + + log_entry = (Mpi2EventDataLogEntryAdded_t *) + mpi_reply->EventData; + log_code = (u32 *)log_entry->LogData; + if (le16_to_cpu(log_entry->LogEntryQualifier) + != MPT2_WARPDRIVE_LOGENTRY) + break; + + switch (le32_to_cpu(*log_code)) { + case MPT2_WARPDRIVE_LC_SSDT: + pr_warn(MPT3SAS_FMT "WarpDrive Warning: " + "IO Throttling has occurred in the WarpDrive " + "subsystem. Check WarpDrive documentation for " + "additional details.\n", ioc->name); + break; + case MPT2_WARPDRIVE_LC_SSDLW: + pr_warn(MPT3SAS_FMT "WarpDrive Warning: " + "Program/Erase Cycles for the WarpDrive subsystem " + "in degraded range. Check WarpDrive documentation " + "for additional details.\n", ioc->name); + break; + case MPT2_WARPDRIVE_LC_SSDLF: + pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: " + "There are no Program/Erase Cycles for the " + "WarpDrive subsystem. The storage device will be " + "in read-only mode. Check WarpDrive documentation " + "for additional details.\n", ioc->name); + break; + case MPT2_WARPDRIVE_LC_BRMF: + pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: " + "The Backup Rail Monitor has failed on the " + "WarpDrive subsystem. Check WarpDrive " + "documentation for additional details.\n", + ioc->name); + break; + } + + break; + } case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: case MPI2_EVENT_IR_OPERATION_STATUS: case MPI2_EVENT_SAS_DISCOVERY: @@ -7472,7 +7778,7 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, } sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; - fw_event = kzalloc(sizeof(*fw_event) + sz, GFP_ATOMIC); + fw_event = alloc_fw_event_work(sz); if (!fw_event) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); @@ -7485,39 +7791,10 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, fw_event->VP_ID = mpi_reply->VP_ID; fw_event->event = event; _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); return 1; } -/* shost template */ -static struct scsi_host_template scsih_driver_template = { - .module = THIS_MODULE, - .name = "Fusion MPT SAS Host", - .proc_name = MPT3SAS_DRIVER_NAME, - .queuecommand = _scsih_qcmd, - .target_alloc = _scsih_target_alloc, - .slave_alloc = _scsih_slave_alloc, - .slave_configure = _scsih_slave_configure, - .target_destroy = _scsih_target_destroy, - .slave_destroy = _scsih_slave_destroy, - .scan_finished = _scsih_scan_finished, - .scan_start = _scsih_scan_start, - .change_queue_depth = _scsih_change_queue_depth, - .eh_abort_handler = _scsih_abort, - .eh_device_reset_handler = _scsih_dev_reset, - .eh_target_reset_handler = _scsih_target_reset, - .eh_host_reset_handler = _scsih_host_reset, - .bios_param = _scsih_bios_param, - .can_queue = 1, - .this_id = -1, - .sg_tablesize = MPT3SAS_SG_DEPTH, - .max_sectors = 32767, - .cmd_per_lun = 7, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = mpt3sas_host_attrs, - .sdev_attrs = mpt3sas_dev_attrs, - .track_queue_depth = 1, -}; - /** * _scsih_expander_node_remove - removing expander device from list. * @ioc: per adapter object @@ -7613,7 +7890,8 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc) mpi_request->Function = MPI2_FUNCTION_RAID_ACTION; mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; - pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name); + if (!ioc->hide_ir_msg) + pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name); init_completion(&ioc->scsih_cmds.done); mpt3sas_base_put_smid_default(ioc, smid); wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); @@ -7626,10 +7904,11 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc) if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) { mpi_reply = ioc->scsih_cmds.reply; - pr_info(MPT3SAS_FMT - "IR shutdown (complete): ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); + if (!ioc->hide_ir_msg) + pr_info(MPT3SAS_FMT "IR shutdown " + "(complete): ioc_status(0x%04x), loginfo(0x%08x)\n", + ioc->name, le16_to_cpu(mpi_reply->IOCStatus), + le32_to_cpu(mpi_reply->IOCLogInfo)); } out: @@ -7638,13 +7917,13 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc) } /** - * _scsih_remove - detach and remove add host + * scsih_remove - detach and remove add host * @pdev: PCI device struct * * Routine called when unloading the driver. * Return nothing. */ -static void _scsih_remove(struct pci_dev *pdev) +void scsih_remove(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -7705,18 +7984,20 @@ static void _scsih_remove(struct pci_dev *pdev) sas_remove_host(shost); scsi_remove_host(shost); mpt3sas_base_detach(ioc); + spin_lock(&gioc_lock); list_del(&ioc->list); + spin_unlock(&gioc_lock); scsi_host_put(shost); } /** - * _scsih_shutdown - routine call during system shutdown + * scsih_shutdown - routine call during system shutdown * @pdev: PCI device struct * * Return nothing. */ -static void -_scsih_shutdown(struct pci_dev *pdev) +void +scsih_shutdown(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -7794,6 +8075,8 @@ _scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc) list_move_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (ioc->hide_drives) + return; if (!mpt3sas_transport_port_add(ioc, handle, sas_address_parent)) { _scsih_sas_device_remove(ioc, sas_device); @@ -7831,6 +8114,48 @@ _scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc) } } +static struct _sas_device *get_next_sas_device(struct MPT3SAS_ADAPTER *ioc) +{ + struct _sas_device *sas_device = NULL; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + if (!list_empty(&ioc->sas_device_init_list)) { + sas_device = list_first_entry(&ioc->sas_device_init_list, + struct _sas_device, list); + sas_device_get(sas_device); + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + return sas_device; +} + +static void sas_device_make_active(struct MPT3SAS_ADAPTER *ioc, + struct _sas_device *sas_device) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + + /* + * Since we dropped the lock during the call to port_add(), we need to + * be careful here that somebody else didn't move or delete this item + * while we were busy with other things. + * + * If it was on the list, we need a put() for the reference the list + * had. Either way, we need a get() for the destination list. + */ + if (!list_empty(&sas_device->list)) { + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } + + sas_device_get(sas_device); + list_add_tail(&sas_device->list, &ioc->sas_device_list); + + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +} + /** * _scsih_probe_sas - reporting sas devices to sas transport * @ioc: per adapter object @@ -7840,17 +8165,16 @@ _scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc) static void _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc) { - struct _sas_device *sas_device, *next; - unsigned long flags; + struct _sas_device *sas_device; - /* SAS Device List */ - list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list, - list) { + if (ioc->hide_drives) + return; + while ((sas_device = get_next_sas_device(ioc))) { if (!mpt3sas_transport_port_add(ioc, sas_device->handle, sas_device->sas_address_parent)) { - list_del(&sas_device->list); - kfree(sas_device); + _scsih_sas_device_remove(ioc, sas_device); + sas_device_put(sas_device); continue; } else if (!sas_device->starget) { /* @@ -7863,15 +8187,13 @@ _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc) mpt3sas_transport_port_remove(ioc, sas_device->sas_address, sas_device->sas_address_parent); - list_del(&sas_device->list); - kfree(sas_device); + _scsih_sas_device_remove(ioc, sas_device); + sas_device_put(sas_device); continue; } } - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_move_tail(&sas_device->list, &ioc->sas_device_list); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + sas_device_make_active(ioc, sas_device); + sas_device_put(sas_device); } } @@ -7908,15 +8230,15 @@ _scsih_probe_devices(struct MPT3SAS_ADAPTER *ioc) } /** - * _scsih_scan_start - scsi lld callback for .scan_start + * scsih_scan_start - scsi lld callback for .scan_start * @shost: SCSI host pointer * * The shost has the ability to discover targets on its own instead * of scanning the entire bus. In our implemention, we will kick off * firmware discovery. */ -static void -_scsih_scan_start(struct Scsi_Host *shost) +void +scsih_scan_start(struct Scsi_Host *shost) { struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); int rc; @@ -7934,7 +8256,7 @@ _scsih_scan_start(struct Scsi_Host *shost) } /** - * _scsih_scan_finished - scsi lld callback for .scan_finished + * scsih_scan_finished - scsi lld callback for .scan_finished * @shost: SCSI host pointer * @time: elapsed time of the scan in jiffies * @@ -7942,8 +8264,8 @@ _scsih_scan_start(struct Scsi_Host *shost) * scsi_host and the elapsed time of the scan in jiffies. In our implemention, * we wait for firmware discovery to complete, then return 1. */ -static int -_scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) +int +scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) { struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -7987,6 +8309,124 @@ _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) return 1; } +/* shost template for SAS 2.0 HBA devices */ +static struct scsi_host_template mpt2sas_driver_template = { + .module = THIS_MODULE, + .name = "Fusion MPT SAS Host", + .proc_name = MPT2SAS_DRIVER_NAME, + .queuecommand = scsih_qcmd, + .target_alloc = scsih_target_alloc, + .slave_alloc = scsih_slave_alloc, + .slave_configure = scsih_slave_configure, + .target_destroy = scsih_target_destroy, + .slave_destroy = scsih_slave_destroy, + .scan_finished = scsih_scan_finished, + .scan_start = scsih_scan_start, + .change_queue_depth = scsih_change_queue_depth, + .eh_abort_handler = scsih_abort, + .eh_device_reset_handler = scsih_dev_reset, + .eh_target_reset_handler = scsih_target_reset, + .eh_host_reset_handler = scsih_host_reset, + .bios_param = scsih_bios_param, + .can_queue = 1, + .this_id = -1, + .sg_tablesize = MPT2SAS_SG_DEPTH, + .max_sectors = 32767, + .cmd_per_lun = 7, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = mpt3sas_host_attrs, + .sdev_attrs = mpt3sas_dev_attrs, + .track_queue_depth = 1, +}; + +/* raid transport support for SAS 2.0 HBA devices */ +static struct raid_function_template mpt2sas_raid_functions = { + .cookie = &mpt2sas_driver_template, + .is_raid = scsih_is_raid, + .get_resync = scsih_get_resync, + .get_state = scsih_get_state, +}; + +/* shost template for SAS 3.0 HBA devices */ +static struct scsi_host_template mpt3sas_driver_template = { + .module = THIS_MODULE, + .name = "Fusion MPT SAS Host", + .proc_name = MPT3SAS_DRIVER_NAME, + .queuecommand = scsih_qcmd, + .target_alloc = scsih_target_alloc, + .slave_alloc = scsih_slave_alloc, + .slave_configure = scsih_slave_configure, + .target_destroy = scsih_target_destroy, + .slave_destroy = scsih_slave_destroy, + .scan_finished = scsih_scan_finished, + .scan_start = scsih_scan_start, + .change_queue_depth = scsih_change_queue_depth, + .eh_abort_handler = scsih_abort, + .eh_device_reset_handler = scsih_dev_reset, + .eh_target_reset_handler = scsih_target_reset, + .eh_host_reset_handler = scsih_host_reset, + .bios_param = scsih_bios_param, + .can_queue = 1, + .this_id = -1, + .sg_tablesize = MPT3SAS_SG_DEPTH, + .max_sectors = 32767, + .cmd_per_lun = 7, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = mpt3sas_host_attrs, + .sdev_attrs = mpt3sas_dev_attrs, + .track_queue_depth = 1, +}; + +/* raid transport support for SAS 3.0 HBA devices */ +static struct raid_function_template mpt3sas_raid_functions = { + .cookie = &mpt3sas_driver_template, + .is_raid = scsih_is_raid, + .get_resync = scsih_get_resync, + .get_state = scsih_get_state, +}; + +/** + * _scsih_determine_hba_mpi_version - determine in which MPI version class + * this device belongs to. + * @pdev: PCI device struct + * + * return MPI2_VERSION for SAS 2.0 HBA devices, + * MPI25_VERSION for SAS 3.0 HBA devices. + */ +u16 +_scsih_determine_hba_mpi_version(struct pci_dev *pdev) +{ + + switch (pdev->device) { + case MPI2_MFGPAGE_DEVID_SSS6200: + case MPI2_MFGPAGE_DEVID_SAS2004: + case MPI2_MFGPAGE_DEVID_SAS2008: + case MPI2_MFGPAGE_DEVID_SAS2108_1: + case MPI2_MFGPAGE_DEVID_SAS2108_2: + case MPI2_MFGPAGE_DEVID_SAS2108_3: + case MPI2_MFGPAGE_DEVID_SAS2116_1: + case MPI2_MFGPAGE_DEVID_SAS2116_2: + case MPI2_MFGPAGE_DEVID_SAS2208_1: + case MPI2_MFGPAGE_DEVID_SAS2208_2: + case MPI2_MFGPAGE_DEVID_SAS2208_3: + case MPI2_MFGPAGE_DEVID_SAS2208_4: + case MPI2_MFGPAGE_DEVID_SAS2208_5: + case MPI2_MFGPAGE_DEVID_SAS2208_6: + case MPI2_MFGPAGE_DEVID_SAS2308_1: + case MPI2_MFGPAGE_DEVID_SAS2308_2: + case MPI2_MFGPAGE_DEVID_SAS2308_3: + return MPI2_VERSION; + case MPI25_MFGPAGE_DEVID_SAS3004: + case MPI25_MFGPAGE_DEVID_SAS3008: + case MPI25_MFGPAGE_DEVID_SAS3108_1: + case MPI25_MFGPAGE_DEVID_SAS3108_2: + case MPI25_MFGPAGE_DEVID_SAS3108_5: + case MPI25_MFGPAGE_DEVID_SAS3108_6: + return MPI25_VERSION; + } + return 0; +} + /** * _scsih_probe - attach and add scsi host * @pdev: PCI device struct @@ -7994,26 +8434,72 @@ _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) * * Returns 0 success, anything else error. */ -static int +int _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct MPT3SAS_ADAPTER *ioc; - struct Scsi_Host *shost; + struct Scsi_Host *shost = NULL; int rv; + u16 hba_mpi_version; - shost = scsi_host_alloc(&scsih_driver_template, - sizeof(struct MPT3SAS_ADAPTER)); - if (!shost) + /* Determine in which MPI version class this pci device belongs */ + hba_mpi_version = _scsih_determine_hba_mpi_version(pdev); + if (hba_mpi_version == 0) return -ENODEV; - /* init local params */ - ioc = shost_priv(shost); - memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER)); + /* Enumerate only SAS 2.0 HBA's if hbas_to_enumerate is one, + * for other generation HBA's return with -ENODEV + */ + if ((hbas_to_enumerate == 1) && (hba_mpi_version != MPI2_VERSION)) + return -ENODEV; + + /* Enumerate only SAS 3.0 HBA's if hbas_to_enumerate is two, + * for other generation HBA's return with -ENODEV + */ + if ((hbas_to_enumerate == 2) && (hba_mpi_version != MPI25_VERSION)) + return -ENODEV; + + switch (hba_mpi_version) { + case MPI2_VERSION: + /* Use mpt2sas driver host template for SAS 2.0 HBA's */ + shost = scsi_host_alloc(&mpt2sas_driver_template, + sizeof(struct MPT3SAS_ADAPTER)); + if (!shost) + return -ENODEV; + ioc = shost_priv(shost); + memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER)); + ioc->hba_mpi_version_belonged = hba_mpi_version; + ioc->id = mpt2_ids++; + sprintf(ioc->driver_name, "%s", MPT2SAS_DRIVER_NAME); + if (pdev->device == MPI2_MFGPAGE_DEVID_SSS6200) { + ioc->is_warpdrive = 1; + ioc->hide_ir_msg = 1; + } else + ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS; + break; + case MPI25_VERSION: + /* Use mpt3sas driver host template for SAS 3.0 HBA's */ + shost = scsi_host_alloc(&mpt3sas_driver_template, + sizeof(struct MPT3SAS_ADAPTER)); + if (!shost) + return -ENODEV; + ioc = shost_priv(shost); + memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER)); + ioc->hba_mpi_version_belonged = hba_mpi_version; + ioc->id = mpt3_ids++; + sprintf(ioc->driver_name, "%s", MPT3SAS_DRIVER_NAME); + if (pdev->revision >= SAS3_PCI_DEVICE_C0_REVISION) + ioc->msix96_vector = 1; + break; + default: + return -ENODEV; + } + INIT_LIST_HEAD(&ioc->list); + spin_lock(&gioc_lock); list_add_tail(&ioc->list, &mpt3sas_ioc_list); + spin_unlock(&gioc_lock); ioc->shost = shost; - ioc->id = mpt_ids++; - sprintf(ioc->name, "%s%d", MPT3SAS_DRIVER_NAME, ioc->id); ioc->pdev = pdev; ioc->scsi_io_cb_idx = scsi_io_cb_idx; ioc->tm_cb_idx = tm_cb_idx; @@ -8030,6 +8516,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds; /* misc semaphores and spin locks */ mutex_init(&ioc->reset_in_progress_mutex); + /* initializing pci_access_mutex lock */ + mutex_init(&ioc->pci_access_mutex); spin_lock_init(&ioc->ioc_reset_in_progress_lock); spin_lock_init(&ioc->scsi_lookup_lock); spin_lock_init(&ioc->sas_device_lock); @@ -8048,6 +8536,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&ioc->delayed_tr_volume_list); INIT_LIST_HEAD(&ioc->reply_queue_list); + sprintf(ioc->name, "%s_cm%d", ioc->driver_name, ioc->id); + /* init shost parameters */ shost->max_cmd_len = 32; shost->max_lun = max_lun; @@ -8086,7 +8576,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* event thread */ snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), - "fw_event%d", ioc->id); + "fw_event_%s%d", ioc->driver_name, ioc->id); ioc->firmware_event_thread = alloc_ordered_workqueue( ioc->firmware_event_name, WQ_MEM_RECLAIM); if (!ioc->firmware_event_thread) { @@ -8103,6 +8593,21 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) rv = -ENODEV; goto out_attach_fail; } + + if (ioc->is_warpdrive) { + if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) + ioc->hide_drives = 0; + else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS) + ioc->hide_drives = 1; + else { + if (mpt3sas_get_num_volumes(ioc)) + ioc->hide_drives = 1; + else + ioc->hide_drives = 0; + } + } else + ioc->hide_drives = 0; + rv = scsi_add_host(shost, &pdev->dev); if (rv) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", @@ -8117,21 +8622,23 @@ out_add_shost_fail: out_attach_fail: destroy_workqueue(ioc->firmware_event_thread); out_thread_fail: + spin_lock(&gioc_lock); list_del(&ioc->list); + spin_unlock(&gioc_lock); scsi_host_put(shost); return rv; } #ifdef CONFIG_PM /** - * _scsih_suspend - power management suspend main entry point + * scsih_suspend - power management suspend main entry point * @pdev: PCI device struct * @state: PM state change to (usually PCI_D3) * * Returns 0 success, anything else error. */ -static int -_scsih_suspend(struct pci_dev *pdev, pm_message_t state) +int +scsih_suspend(struct pci_dev *pdev, pm_message_t state) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -8152,13 +8659,13 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state) } /** - * _scsih_resume - power management resume main entry point + * scsih_resume - power management resume main entry point * @pdev: PCI device struct * * Returns 0 success, anything else error. */ -static int -_scsih_resume(struct pci_dev *pdev) +int +scsih_resume(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -8185,7 +8692,7 @@ _scsih_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ /** - * _scsih_pci_error_detected - Called when a PCI error is detected. + * scsih_pci_error_detected - Called when a PCI error is detected. * @pdev: PCI device struct * @state: PCI channel state * @@ -8194,8 +8701,8 @@ _scsih_resume(struct pci_dev *pdev) * Return value: * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT */ -static pci_ers_result_t -_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) +pci_ers_result_t +scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -8224,15 +8731,15 @@ _scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) } /** - * _scsih_pci_slot_reset - Called when PCI slot has been reset. + * scsih_pci_slot_reset - Called when PCI slot has been reset. * @pdev: PCI device struct * * Description: This routine is called by the pci error recovery * code after the PCI slot has been reset, just before we * should resume normal operations. */ -static pci_ers_result_t -_scsih_pci_slot_reset(struct pci_dev *pdev) +pci_ers_result_t +scsih_pci_slot_reset(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -8261,15 +8768,15 @@ _scsih_pci_slot_reset(struct pci_dev *pdev) } /** - * _scsih_pci_resume() - resume normal ops after PCI reset + * scsih_pci_resume() - resume normal ops after PCI reset * @pdev: pointer to PCI device * * Called when the error recovery driver tells us that its * OK to resume normal operation. Use completion to allow * halted scsi ops to resume. */ -static void -_scsih_pci_resume(struct pci_dev *pdev) +void +scsih_pci_resume(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -8282,11 +8789,11 @@ _scsih_pci_resume(struct pci_dev *pdev) } /** - * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers + * scsih_pci_mmio_enabled - Enable MMIO and dump debug registers * @pdev: pointer to PCI device */ -static pci_ers_result_t -_scsih_pci_mmio_enabled(struct pci_dev *pdev) +pci_ers_result_t +scsih_pci_mmio_enabled(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); @@ -8300,61 +8807,99 @@ _scsih_pci_mmio_enabled(struct pci_dev *pdev) return PCI_ERS_RESULT_NEED_RESET; } -/* raid transport support */ -static struct raid_function_template mpt3sas_raid_functions = { - .cookie = &scsih_driver_template, - .is_raid = _scsih_is_raid, - .get_resync = _scsih_get_resync, - .get_state = _scsih_get_state, +/* + * The pci device ids are defined in mpi/mpi2_cnfg.h. + */ +static const struct pci_device_id mpt3sas_pci_table[] = { + /* Spitfire ~ 2004 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004, + PCI_ANY_ID, PCI_ANY_ID }, + /* Falcon ~ 2008 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008, + PCI_ANY_ID, PCI_ANY_ID }, + /* Liberator ~ 2108 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3, + PCI_ANY_ID, PCI_ANY_ID }, + /* Meteor ~ 2116 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2, + PCI_ANY_ID, PCI_ANY_ID }, + /* Thunderbolt ~ 2208 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, + PCI_ANY_ID, PCI_ANY_ID }, + /* Mustang ~ 2308 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, + PCI_ANY_ID, PCI_ANY_ID }, + /* SSS6200 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200, + PCI_ANY_ID, PCI_ANY_ID }, + /* Fury ~ 3004 and 3008 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008, + PCI_ANY_ID, PCI_ANY_ID }, + /* Invader ~ 3108 */ + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5, + PCI_ANY_ID, PCI_ANY_ID }, + { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6, + PCI_ANY_ID, PCI_ANY_ID }, + {0} /* Terminating entry */ }; +MODULE_DEVICE_TABLE(pci, mpt3sas_pci_table); -static struct pci_error_handlers _scsih_err_handler = { - .error_detected = _scsih_pci_error_detected, - .mmio_enabled = _scsih_pci_mmio_enabled, - .slot_reset = _scsih_pci_slot_reset, - .resume = _scsih_pci_resume, +static struct pci_error_handlers _mpt3sas_err_handler = { + .error_detected = scsih_pci_error_detected, + .mmio_enabled = scsih_pci_mmio_enabled, + .slot_reset = scsih_pci_slot_reset, + .resume = scsih_pci_resume, }; -static struct pci_driver scsih_driver = { +static struct pci_driver mpt3sas_driver = { .name = MPT3SAS_DRIVER_NAME, - .id_table = scsih_pci_table, + .id_table = mpt3sas_pci_table, .probe = _scsih_probe, - .remove = _scsih_remove, - .shutdown = _scsih_shutdown, - .err_handler = &_scsih_err_handler, + .remove = scsih_remove, + .shutdown = scsih_shutdown, + .err_handler = &_mpt3sas_err_handler, #ifdef CONFIG_PM - .suspend = _scsih_suspend, - .resume = _scsih_resume, + .suspend = scsih_suspend, + .resume = scsih_resume, #endif }; - /** - * _scsih_init - main entry point for this driver. + * scsih_init - main entry point for this driver. * * Returns 0 success, anything else error. */ -static int __init -_scsih_init(void) +int +scsih_init(void) { - int error; - - mpt_ids = 0; - - pr_info("%s version %s loaded\n", MPT3SAS_DRIVER_NAME, - MPT3SAS_DRIVER_VERSION); - - mpt3sas_transport_template = - sas_attach_transport(&mpt3sas_transport_functions); - if (!mpt3sas_transport_template) - return -ENODEV; - -/* raid transport support */ - mpt3sas_raid_template = raid_class_attach(&mpt3sas_raid_functions); - if (!mpt3sas_raid_template) { - sas_release_transport(mpt3sas_transport_template); - return -ENODEV; - } + mpt2_ids = 0; + mpt3_ids = 0; mpt3sas_base_initialize_callback_handler(); @@ -8392,33 +8937,17 @@ _scsih_init(void) tm_sas_control_cb_idx = mpt3sas_base_register_callback_handler( _scsih_sas_control_complete); - mpt3sas_ctl_init(); - - error = pci_register_driver(&scsih_driver); - if (error) { - /* raid transport support */ - raid_class_release(mpt3sas_raid_template); - sas_release_transport(mpt3sas_transport_template); - } - - return error; + return 0; } /** - * _scsih_exit - exit point for this driver (when it is a module). + * scsih_exit - exit point for this driver (when it is a module). * * Returns 0 success, anything else error. */ -static void __exit -_scsih_exit(void) +void +scsih_exit(void) { - pr_info("mpt3sas version %s unloading\n", - MPT3SAS_DRIVER_VERSION); - - mpt3sas_ctl_exit(); - - pci_unregister_driver(&scsih_driver); - mpt3sas_base_release_callback_handler(scsi_io_cb_idx); mpt3sas_base_release_callback_handler(tm_cb_idx); @@ -8434,9 +8963,86 @@ _scsih_exit(void) mpt3sas_base_release_callback_handler(tm_sas_control_cb_idx); /* raid transport support */ - raid_class_release(mpt3sas_raid_template); + if (hbas_to_enumerate != 1) + raid_class_release(mpt3sas_raid_template); + if (hbas_to_enumerate != 2) + raid_class_release(mpt2sas_raid_template); sas_release_transport(mpt3sas_transport_template); } -module_init(_scsih_init); -module_exit(_scsih_exit); +/** + * _mpt3sas_init - main entry point for this driver. + * + * Returns 0 success, anything else error. + */ +static int __init +_mpt3sas_init(void) +{ + int error; + + pr_info("%s version %s loaded\n", MPT3SAS_DRIVER_NAME, + MPT3SAS_DRIVER_VERSION); + + mpt3sas_transport_template = + sas_attach_transport(&mpt3sas_transport_functions); + if (!mpt3sas_transport_template) + return -ENODEV; + + /* No need attach mpt3sas raid functions template + * if hbas_to_enumarate value is one. + */ + if (hbas_to_enumerate != 1) { + mpt3sas_raid_template = + raid_class_attach(&mpt3sas_raid_functions); + if (!mpt3sas_raid_template) { + sas_release_transport(mpt3sas_transport_template); + return -ENODEV; + } + } + + /* No need to attach mpt2sas raid functions template + * if hbas_to_enumarate value is two + */ + if (hbas_to_enumerate != 2) { + mpt2sas_raid_template = + raid_class_attach(&mpt2sas_raid_functions); + if (!mpt2sas_raid_template) { + sas_release_transport(mpt3sas_transport_template); + return -ENODEV; + } + } + + error = scsih_init(); + if (error) { + scsih_exit(); + return error; + } + + mpt3sas_ctl_init(hbas_to_enumerate); + + error = pci_register_driver(&mpt3sas_driver); + if (error) + scsih_exit(); + + return error; +} + +/** + * _mpt3sas_exit - exit point for this driver (when it is a module). + * + */ +static void __exit +_mpt3sas_exit(void) +{ + pr_info("mpt3sas version %s unloading\n", + MPT3SAS_DRIVER_VERSION); + + pci_unregister_driver(&mpt3sas_driver); + + mpt3sas_ctl_exit(hbas_to_enumerate); + + scsih_exit(); +} + +module_init(_mpt3sas_init); +module_exit(_mpt3sas_exit); diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index 70fd019e7..ca36d7ea0 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -734,7 +734,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, rphy->identify = mpt3sas_port->remote_identify; if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = mpt3sas_get_sdev_by_addr(ioc, mpt3sas_port->remote_identify.sas_address); if (!sas_device) { dfailprintk(ioc, printk(MPT3SAS_FMT @@ -750,8 +750,10 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, ioc->name, __FILE__, __LINE__, __func__); } - if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) + if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { sas_device->pend_sas_rphy_add = 0; + sas_device_put(sas_device); + } if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) dev_printk(KERN_INFO, &rphy->dev, @@ -1324,15 +1326,17 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) int rc; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(ioc, rphy->identify.sas_address); if (sas_device) { *identifier = sas_device->enclosure_logical_id; rc = 0; + sas_device_put(sas_device); } else { *identifier = 0; rc = -ENXIO; } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); return rc; } @@ -1352,12 +1356,14 @@ _transport_get_bay_identifier(struct sas_rphy *rphy) int rc; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt3sas_get_sdev_by_addr(ioc, rphy->identify.sas_address); - if (sas_device) + if (sas_device) { rc = sas_device->slot; - else + sas_device_put(sas_device); + } else { rc = -ENXIO; + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); return rc; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c new file mode 100644 index 000000000..540bd5005 --- /dev/null +++ b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c @@ -0,0 +1,344 @@ +/* + * Scsi Host Layer for MPT (Message Passing Technology) based controllers + * + * Copyright (C) 2012-2014 LSI Corporation + * Copyright (C) 2013-2015 Avago Technologies + * (mailto: MPT-FusionLinux.pdl@avagotech.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. + * + * 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. + * + * NO WARRANTY + * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + * solely responsible for determining the appropriateness of using and + * distributing the Program and assumes all risks associated with its + * exercise of rights under this Agreement, including but not limited to + * the risks and costs of program errors, damage to or loss of data, + * programs or equipment, and unavailability or interruption of operations. + + * DISCLAIMER OF LIABILITY + * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + * You should have received a copy of the GNU General Public License + * along with this program. + */ +#include +#include +#include +#include +#include + +#include "mpt3sas_base.h" + +/** + * _warpdrive_disable_ddio - Disable direct I/O for all the volumes + * @ioc: per adapter object + */ +static void +_warpdrive_disable_ddio(struct MPT3SAS_ADAPTER *ioc) +{ + Mpi2RaidVolPage1_t vol_pg1; + Mpi2ConfigReply_t mpi_reply; + struct _raid_device *raid_device; + u16 handle; + u16 ioc_status; + unsigned long flags; + + handle = 0xFFFF; + while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply, + &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + handle = le16_to_cpu(vol_pg1.DevHandle); + spin_lock_irqsave(&ioc->raid_device_lock, flags); + raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle); + if (raid_device) + raid_device->direct_io_enabled = 0; + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); + } + return; +} + + +/** + * mpt3sas_get_num_volumes - Get number of volumes in the ioc + * @ioc: per adapter object + */ +u8 +mpt3sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc) +{ + Mpi2RaidVolPage1_t vol_pg1; + Mpi2ConfigReply_t mpi_reply; + u16 handle; + u8 vol_cnt = 0; + u16 ioc_status; + + handle = 0xFFFF; + while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply, + &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { + ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & + MPI2_IOCSTATUS_MASK; + if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) + break; + vol_cnt++; + handle = le16_to_cpu(vol_pg1.DevHandle); + } + return vol_cnt; +} + + +/** + * mpt3sas_init_warpdrive_properties - Set properties for warpdrive direct I/O. + * @ioc: per adapter object + * @raid_device: the raid_device object + */ +void +mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, + struct _raid_device *raid_device) +{ + Mpi2RaidVolPage0_t *vol_pg0; + Mpi2RaidPhysDiskPage0_t pd_pg0; + Mpi2ConfigReply_t mpi_reply; + u16 sz; + u8 num_pds, count; + unsigned long stripe_sz, block_sz; + u8 stripe_exp, block_exp; + u64 dev_max_lba; + + if (!ioc->is_warpdrive) + return; + + if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "globally as drives are exposed\n", ioc->name); + return; + } + if (mpt3sas_get_num_volumes(ioc) > 1) { + _warpdrive_disable_ddio(ioc); + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "globally as number of drives > 1\n", ioc->name); + return; + } + if ((mpt3sas_config_get_number_pds(ioc, raid_device->handle, + &num_pds)) || !num_pds) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "Failure in computing number of drives\n", ioc->name); + return; + } + + sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * + sizeof(Mpi2RaidVol0PhysDisk_t)); + vol_pg0 = kzalloc(sz, GFP_KERNEL); + if (!vol_pg0) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "Memory allocation failure for RVPG0\n", ioc->name); + return; + } + + if ((mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, + MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "Failure in retrieving RVPG0\n", ioc->name); + kfree(vol_pg0); + return; + } + + /* + * WARPDRIVE:If number of physical disks in a volume exceeds the max pds + * assumed for WARPDRIVE, disable direct I/O + */ + if (num_pds > MPT_MAX_WARPDRIVE_PDS) { + pr_warn(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x): num_mem=%d, " + "max_mem_allowed=%d\n", ioc->name, raid_device->handle, + num_pds, MPT_MAX_WARPDRIVE_PDS); + kfree(vol_pg0); + return; + } + for (count = 0; count < num_pds; count++) { + if (mpt3sas_config_get_phys_disk_pg0(ioc, &mpi_reply, + &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, + vol_pg0->PhysDisk[count].PhysDiskNum) || + pd_pg0.DevHandle == MPT3SAS_INVALID_DEVICE_HANDLE) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is " + "disabled for the drive with handle(0x%04x) member" + "handle retrieval failed for member number=%d\n", + ioc->name, raid_device->handle, + vol_pg0->PhysDisk[count].PhysDiskNum); + goto out_error; + } + /* Disable direct I/O if member drive lba exceeds 4 bytes */ + dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA); + if (dev_max_lba >> 32) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is " + "disabled for the drive with handle(0x%04x) member" + " handle (0x%04x) unsupported max lba 0x%016llx\n", + ioc->name, raid_device->handle, + le16_to_cpu(pd_pg0.DevHandle), + (unsigned long long)dev_max_lba); + goto out_error; + } + + raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle); + } + + /* + * Assumption for WD: Direct I/O is not supported if the volume is + * not RAID0 + */ + if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x): type=%d, " + "s_sz=%uK, blk_size=%u\n", ioc->name, + raid_device->handle, raid_device->volume_type, + (le32_to_cpu(vol_pg0->StripeSize) * + le16_to_cpu(vol_pg0->BlockSize)) / 1024, + le16_to_cpu(vol_pg0->BlockSize)); + goto out_error; + } + + stripe_sz = le32_to_cpu(vol_pg0->StripeSize); + stripe_exp = find_first_bit(&stripe_sz, 32); + if (stripe_exp == 32) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x) invalid stripe sz %uK\n", + ioc->name, raid_device->handle, + (le32_to_cpu(vol_pg0->StripeSize) * + le16_to_cpu(vol_pg0->BlockSize)) / 1024); + goto out_error; + } + raid_device->stripe_exponent = stripe_exp; + block_sz = le16_to_cpu(vol_pg0->BlockSize); + block_exp = find_first_bit(&block_sz, 16); + if (block_exp == 16) { + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled " + "for the drive with handle(0x%04x) invalid block sz %u\n", + ioc->name, raid_device->handle, + le16_to_cpu(vol_pg0->BlockSize)); + goto out_error; + } + raid_device->block_exponent = block_exp; + raid_device->direct_io_enabled = 1; + + pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is Enabled for the drive" + " with handle(0x%04x)\n", ioc->name, raid_device->handle); + /* + * WARPDRIVE: Though the following fields are not used for direct IO, + * stored for future purpose: + */ + raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA); + raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize); + raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize); + + + kfree(vol_pg0); + return; + +out_error: + raid_device->direct_io_enabled = 0; + for (count = 0; count < num_pds; count++) + raid_device->pd_handle[count] = 0; + kfree(vol_pg0); + return; +} + +/** + * mpt3sas_scsi_direct_io_get - returns direct io flag + * @ioc: per adapter object + * @smid: system request message index + * + * Returns the smid stored scmd pointer. + */ +inline u8 +mpt3sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid) +{ + return ioc->scsi_lookup[smid - 1].direct_io; +} + +/** + * mpt3sas_scsi_direct_io_set - sets direct io flag + * @ioc: per adapter object + * @smid: system request message index + * @direct_io: Zero or non-zero value to set in the direct_io flag + * + * Returns Nothing. + */ +inline void +mpt3sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io) +{ + ioc->scsi_lookup[smid - 1].direct_io = direct_io; +} + +/** + * mpt3sas_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O + * @ioc: per adapter object + * @scmd: pointer to scsi command object + * @raid_device: pointer to raid device data structure + * @mpi_request: pointer to the SCSI_IO reqest message frame + * @smid: system request message index + * + * Returns nothing + */ +void +mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, + struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, + u16 smid) +{ + sector_t v_lba, p_lba, stripe_off, column, io_size; + u32 stripe_sz, stripe_exp; + u8 num_pds, cmd = scmd->cmnd[0]; + + if (cmd != READ_10 && cmd != WRITE_10 && + cmd != READ_16 && cmd != WRITE_16) + return; + + if (cmd == READ_10 || cmd == WRITE_10) + v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]); + else + v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]); + + io_size = scsi_bufflen(scmd) >> raid_device->block_exponent; + + if (v_lba + io_size - 1 > raid_device->max_lba) + return; + + stripe_sz = raid_device->stripe_sz; + stripe_exp = raid_device->stripe_exponent; + stripe_off = v_lba & (stripe_sz - 1); + + /* Return unless IO falls within a stripe */ + if (stripe_off + io_size > stripe_sz) + return; + + num_pds = raid_device->num_pds; + p_lba = v_lba >> stripe_exp; + column = sector_div(p_lba, num_pds); + p_lba = (p_lba << stripe_exp) + stripe_off; + mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]); + + if (cmd == READ_10 || cmd == WRITE_10) + put_unaligned_be32(lower_32_bits(p_lba), + &mpi_request->CDB.CDB32[2]); + else + put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]); + + mpt3sas_scsi_direct_io_set(ioc, smid, 1); +} diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c index e2d555c1b..675e7fab0 100644 --- a/drivers/scsi/mvsas/mv_init.c +++ b/drivers/scsi/mvsas/mv_init.c @@ -65,7 +65,6 @@ static struct scsi_host_template mvs_sht = { .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, .shost_attrs = mvst_host_attrs, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -641,9 +640,9 @@ static void mvs_pci_remove(struct pci_dev *pdev) tasklet_kill(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet); #endif + scsi_remove_host(mvi->shost); sas_unregister_ha(sha); sas_remove_host(mvi->shost); - scsi_remove_host(mvi->shost); MVS_CHIP_DISP->interrupt_disable(mvi); free_irq(mvi->pdev->irq, sha); @@ -759,7 +758,7 @@ mvs_store_interrupt_coalescing(struct device *cdev, struct device_attribute *attr, const char *buffer, size_t size) { - int val = 0; + unsigned int val = 0; struct mvs_info *mvi = NULL; struct Scsi_Host *shost = class_to_shost(cdev); struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); @@ -767,7 +766,7 @@ mvs_store_interrupt_coalescing(struct device *cdev, if (buffer == NULL) return size; - if (sscanf(buffer, "%d", &val) != 1) + if (sscanf(buffer, "%u", &val) != 1) return -EINVAL; if (val >= 0x10000) { diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c index 3e6b86675..02360de6b 100644 --- a/drivers/scsi/mvumi.c +++ b/drivers/scsi/mvumi.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -858,8 +859,8 @@ static void mvumi_hs_build_page(struct mvumi_hba *mhba, struct mvumi_hs_page2 *hs_page2; struct mvumi_hs_page4 *hs_page4; struct mvumi_hs_page3 *hs_page3; - struct timeval time; - unsigned int local_time; + u64 time; + u64 local_time; switch (hs_header->page_code) { case HS_PAGE_HOST_INFO: @@ -877,9 +878,8 @@ static void mvumi_hs_build_page(struct mvumi_hba *mhba, hs_page2->slot_number = 0; hs_page2->intr_level = 0; hs_page2->intr_vector = 0; - do_gettimeofday(&time); - local_time = (unsigned int) (time.tv_sec - - (sys_tz.tz_minuteswest * 60)); + time = ktime_get_real_seconds(); + local_time = (time - (sys_tz.tz_minuteswest * 60)); hs_page2->seconds_since1970 = local_time; hs_header->checksum = mvumi_calculate_checksum(hs_header, hs_header->frame_length); diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h index f14ec6e04..199527dba 100644 --- a/drivers/scsi/pm8001/pm8001_defs.h +++ b/drivers/scsi/pm8001/pm8001_defs.h @@ -51,6 +51,8 @@ enum chip_flavors { chip_8076, chip_8077, chip_8006, + chip_8070, + chip_8072 }; enum phy_speed { diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 5c0356fb6..062ab34b8 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -58,6 +58,8 @@ static const struct pm8001_chip_info pm8001_chips[] = { [chip_8076] = {0, 16, &pm8001_80xx_dispatch,}, [chip_8077] = {0, 16, &pm8001_80xx_dispatch,}, [chip_8006] = {0, 16, &pm8001_80xx_dispatch,}, + [chip_8070] = {0, 8, &pm8001_80xx_dispatch,}, + [chip_8072] = {0, 16, &pm8001_80xx_dispatch,}, }; static int pm8001_id; @@ -88,7 +90,6 @@ static struct scsi_host_template pm8001_sht = { .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, .shost_attrs = pm8001_host_attrs, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -480,7 +481,8 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, #ifdef PM8001_USE_TASKLET /* Tasklet for non msi-x interrupt handler */ - if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001)) + if ((!pdev->msix_cap || !pci_msi_enabled()) + || (pm8001_ha->chip_id == chip_8001)) tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet, (unsigned long)&(pm8001_ha->irq_vector[0])); else @@ -634,6 +636,11 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) payload.minor_function = 0; payload.length = 128; } + } else if ((pm8001_ha->chip_id == chip_8070 || + pm8001_ha->chip_id == chip_8072) && + pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ATTO) { + payload.minor_function = 4; + payload.length = 4096; } else { payload.minor_function = 1; payload.length = 4096; @@ -660,6 +667,11 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) else if (deviceid == 0x0042) pm8001_ha->sas_addr[j] = payload.func_specific[0x010 + i]; + } else if ((pm8001_ha->chip_id == chip_8070 || + pm8001_ha->chip_id == chip_8072) && + pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ATTO) { + pm8001_ha->sas_addr[j] = + payload.func_specific[0x010 + i]; } else pm8001_ha->sas_addr[j] = payload.func_specific[0x804 + i]; @@ -720,6 +732,153 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha) return 0; } +struct pm8001_mpi3_phy_pg_trx_config { + u32 LaneLosCfg; + u32 LanePgaCfg1; + u32 LanePisoCfg1; + u32 LanePisoCfg2; + u32 LanePisoCfg3; + u32 LanePisoCfg4; + u32 LanePisoCfg5; + u32 LanePisoCfg6; + u32 LaneBctCtrl; +}; + +/** + * pm8001_get_internal_phy_settings : Retrieves the internal PHY settings + * @pm8001_ha : our adapter + * @phycfg : PHY config page to populate + */ +static +void pm8001_get_internal_phy_settings(struct pm8001_hba_info *pm8001_ha, + struct pm8001_mpi3_phy_pg_trx_config *phycfg) +{ + phycfg->LaneLosCfg = 0x00000132; + phycfg->LanePgaCfg1 = 0x00203949; + phycfg->LanePisoCfg1 = 0x000000FF; + phycfg->LanePisoCfg2 = 0xFF000001; + phycfg->LanePisoCfg3 = 0xE7011300; + phycfg->LanePisoCfg4 = 0x631C40C0; + phycfg->LanePisoCfg5 = 0xF8102036; + phycfg->LanePisoCfg6 = 0xF74A1000; + phycfg->LaneBctCtrl = 0x00FB33F8; +} + +/** + * pm8001_get_external_phy_settings : Retrieves the external PHY settings + * @pm8001_ha : our adapter + * @phycfg : PHY config page to populate + */ +static +void pm8001_get_external_phy_settings(struct pm8001_hba_info *pm8001_ha, + struct pm8001_mpi3_phy_pg_trx_config *phycfg) +{ + phycfg->LaneLosCfg = 0x00000132; + phycfg->LanePgaCfg1 = 0x00203949; + phycfg->LanePisoCfg1 = 0x000000FF; + phycfg->LanePisoCfg2 = 0xFF000001; + phycfg->LanePisoCfg3 = 0xE7011300; + phycfg->LanePisoCfg4 = 0x63349140; + phycfg->LanePisoCfg5 = 0xF8102036; + phycfg->LanePisoCfg6 = 0xF80D9300; + phycfg->LaneBctCtrl = 0x00FB33F8; +} + +/** + * pm8001_get_phy_mask : Retrieves the mask that denotes if a PHY is int/ext + * @pm8001_ha : our adapter + * @phymask : The PHY mask + */ +static +void pm8001_get_phy_mask(struct pm8001_hba_info *pm8001_ha, int *phymask) +{ + switch (pm8001_ha->pdev->subsystem_device) { + case 0x0070: /* H1280 - 8 external 0 internal */ + case 0x0072: /* H12F0 - 16 external 0 internal */ + *phymask = 0x0000; + break; + + case 0x0071: /* H1208 - 0 external 8 internal */ + case 0x0073: /* H120F - 0 external 16 internal */ + *phymask = 0xFFFF; + break; + + case 0x0080: /* H1244 - 4 external 4 internal */ + *phymask = 0x00F0; + break; + + case 0x0081: /* H1248 - 4 external 8 internal */ + *phymask = 0x0FF0; + break; + + case 0x0082: /* H1288 - 8 external 8 internal */ + *phymask = 0xFF00; + break; + + default: + PM8001_INIT_DBG(pm8001_ha, + pm8001_printk("Unknown subsystem device=0x%.04x", + pm8001_ha->pdev->subsystem_device)); + } +} + +/** + * pm8001_set_phy_settings_ven_117c_12Gb : Configure ATTO 12Gb PHY settings + * @pm8001_ha : our adapter + */ +static +int pm8001_set_phy_settings_ven_117c_12G(struct pm8001_hba_info *pm8001_ha) +{ + struct pm8001_mpi3_phy_pg_trx_config phycfg_int; + struct pm8001_mpi3_phy_pg_trx_config phycfg_ext; + int phymask = 0; + int i = 0; + + memset(&phycfg_int, 0, sizeof(phycfg_int)); + memset(&phycfg_ext, 0, sizeof(phycfg_ext)); + + pm8001_get_internal_phy_settings(pm8001_ha, &phycfg_int); + pm8001_get_external_phy_settings(pm8001_ha, &phycfg_ext); + pm8001_get_phy_mask(pm8001_ha, &phymask); + + for (i = 0; i < pm8001_ha->chip->n_phy; i++) { + if (phymask & (1 << i)) {/* Internal PHY */ + pm8001_set_phy_profile_single(pm8001_ha, i, + sizeof(phycfg_int) / sizeof(u32), + (u32 *)&phycfg_int); + + } else { /* External PHY */ + pm8001_set_phy_profile_single(pm8001_ha, i, + sizeof(phycfg_ext) / sizeof(u32), + (u32 *)&phycfg_ext); + } + } + + return 0; +} + +/** + * pm8001_configure_phy_settings : Configures PHY settings based on vendor ID. + * @pm8001_ha : our hba. + */ +static int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha) +{ + switch (pm8001_ha->pdev->subsystem_vendor) { + case PCI_VENDOR_ID_ATTO: + if (pm8001_ha->pdev->device == 0x0042) /* 6Gb */ + return 0; + else + return pm8001_set_phy_settings_ven_117c_12G(pm8001_ha); + + case PCI_VENDOR_ID_ADAPTEC2: + case 0: + return 0; + + default: + return pm8001_get_phy_settings_info(pm8001_ha); + } +} + #ifdef PM8001_USE_MSIX /** * pm8001_setup_msix - enable MSI-X interrupt @@ -792,7 +951,7 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) pdev = pm8001_ha->pdev; #ifdef PM8001_USE_MSIX - if (pdev->msix_cap) + if (pdev->msix_cap && pci_msi_enabled()) return pm8001_setup_msix(pm8001_ha); else { PM8001_INIT_DBG(pm8001_ha, @@ -803,6 +962,8 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) intx: /* initialize the INT-X interrupt */ + pm8001_ha->irq_vector[0].irq_id = 0; + pm8001_ha->irq_vector[0].drv_inst = pm8001_ha; rc = request_irq(pdev->irq, pm8001_interrupt_handler_intx, IRQF_SHARED, DRV_NAME, SHOST_TO_SAS_HA(pm8001_ha->shost)); return rc; @@ -902,12 +1063,9 @@ static int pm8001_pci_probe(struct pci_dev *pdev, pm8001_init_sas_add(pm8001_ha); /* phy setting support for motherboard controller */ - if (pdev->subsystem_vendor != PCI_VENDOR_ID_ADAPTEC2 && - pdev->subsystem_vendor != 0) { - rc = pm8001_get_phy_settings_info(pm8001_ha); - if (rc) - goto err_out_shost; - } + if (pm8001_configure_phy_settings(pm8001_ha)) + goto err_out_shost; + pm8001_post_sas_ha_init(shost, chip); rc = sas_register_ha(SHOST_TO_SAS_HA(shost)); if (rc) @@ -937,10 +1095,10 @@ static void pm8001_pci_remove(struct pci_dev *pdev) struct pm8001_hba_info *pm8001_ha; int i, j; pm8001_ha = sha->lldd_ha; + scsi_remove_host(pm8001_ha->shost); sas_unregister_ha(sha); sas_remove_host(pm8001_ha->shost); list_del(&pm8001_ha->list); - scsi_remove_host(pm8001_ha->shost); PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF); PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha); @@ -956,7 +1114,8 @@ static void pm8001_pci_remove(struct pci_dev *pdev) #endif #ifdef PM8001_USE_TASKLET /* For non-msix and msix interrupts */ - if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001)) + if ((!pdev->msix_cap || !pci_msi_enabled()) || + (pm8001_ha->chip_id == chip_8001)) tasklet_kill(&pm8001_ha->tasklet[0]); else for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) @@ -1005,7 +1164,8 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state) #endif #ifdef PM8001_USE_TASKLET /* For non-msix and msix interrupts */ - if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001)) + if ((!pdev->msix_cap || !pci_msi_enabled()) || + (pm8001_ha->chip_id == chip_8001)) tasklet_kill(&pm8001_ha->tasklet[0]); else for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) @@ -1074,7 +1234,8 @@ static int pm8001_pci_resume(struct pci_dev *pdev) goto err_out_disable; #ifdef PM8001_USE_TASKLET /* Tasklet for non msi-x interrupt handler */ - if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001)) + if ((!pdev->msix_cap || !pci_msi_enabled()) || + (pm8001_ha->chip_id == chip_8001)) tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet, (unsigned long)&(pm8001_ha->irq_vector[0])); else @@ -1087,6 +1248,19 @@ static int pm8001_pci_resume(struct pci_dev *pdev) for (i = 1; i < pm8001_ha->number_of_intr; i++) PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, i); } + + /* Chip documentation for the 8070 and 8072 SPCv */ + /* states that a 500ms minimum delay is required */ + /* before issuing commands. Otherwise, the firmare */ + /* will enter an unrecoverable state. */ + + if (pm8001_ha->chip_id == chip_8070 || + pm8001_ha->chip_id == chip_8072) { + mdelay(500); + } + + /* Spin up the PHYs */ + pm8001_ha->flags = PM8001F_RUN_TIME; for (i = 0; i < pm8001_ha->chip->n_phy; i++) { pm8001_ha->phy[i].enable_completion = &completion; @@ -1165,6 +1339,20 @@ static struct pci_device_id pm8001_pci_table[] = { PCI_VENDOR_ID_ADAPTEC2, 0x0808, 0, 0, chip_8077 }, { PCI_VENDOR_ID_ADAPTEC2, 0x8074, PCI_VENDOR_ID_ADAPTEC2, 0x0404, 0, 0, chip_8074 }, + { PCI_VENDOR_ID_ATTO, 0x8070, + PCI_VENDOR_ID_ATTO, 0x0070, 0, 0, chip_8070 }, + { PCI_VENDOR_ID_ATTO, 0x8070, + PCI_VENDOR_ID_ATTO, 0x0071, 0, 0, chip_8070 }, + { PCI_VENDOR_ID_ATTO, 0x8072, + PCI_VENDOR_ID_ATTO, 0x0072, 0, 0, chip_8072 }, + { PCI_VENDOR_ID_ATTO, 0x8072, + PCI_VENDOR_ID_ATTO, 0x0073, 0, 0, chip_8072 }, + { PCI_VENDOR_ID_ATTO, 0x8070, + PCI_VENDOR_ID_ATTO, 0x0080, 0, 0, chip_8070 }, + { PCI_VENDOR_ID_ATTO, 0x8072, + PCI_VENDOR_ID_ATTO, 0x0081, 0, 0, chip_8072 }, + { PCI_VENDOR_ID_ATTO, 0x8072, + PCI_VENDOR_ID_ATTO, 0x0082, 0, 0, chip_8072 }, {} /* terminate list */ }; @@ -1220,7 +1408,7 @@ MODULE_AUTHOR("Anand Kumar Santhanam "); MODULE_AUTHOR("Sangeetha Gnanasekaran "); MODULE_AUTHOR("Nikith Ganigarakoppal "); MODULE_DESCRIPTION( - "PMC-Sierra PM8001/8006/8081/8088/8089/8074/8076/8077 " + "PMC-Sierra PM8001/8006/8081/8088/8089/8074/8076/8077/8070/8072 " "SAS/SATA controller driver"); MODULE_VERSION(DRV_VERSION); MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index e2e97db38..6628cc383 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -106,7 +106,9 @@ do { \ #define DEV_IS_EXPANDER(type) ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE)) #define IS_SPCV_12G(dev) ((dev->device == 0X8074) \ || (dev->device == 0X8076) \ - || (dev->device == 0X8077)) + || (dev->device == 0X8077) \ + || (dev->device == 0X8070) \ + || (dev->device == 0X8072)) #define PM8001_NAME_LENGTH 32/* generic length of strings */ extern struct list_head hba_list; @@ -708,6 +710,8 @@ int pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha); int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, u32 length, u8 *buf); +void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha, + u32 phy, u32 length, u32 *buf); int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); ssize_t pm80xx_get_fatal_dump(struct device *cdev, struct device_attribute *attr, char *buf); diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 9a389f150..eb4fee61d 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -1267,6 +1267,8 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) /* check iButton feature support for motherboard controller */ if (pm8001_ha->pdev->subsystem_vendor != PCI_VENDOR_ID_ADAPTEC2 && + pm8001_ha->pdev->subsystem_vendor != + PCI_VENDOR_ID_ATTO && pm8001_ha->pdev->subsystem_vendor != 0) { ibutton0 = pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_6); @@ -4576,6 +4578,38 @@ void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, } PM8001_INIT_DBG(pm8001_ha, pm8001_printk("phy settings completed\n")); } + +void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha, + u32 phy, u32 length, u32 *buf) +{ + u32 tag, opc; + int rc, i; + struct set_phy_profile_req payload; + struct inbound_queue_table *circularQ; + + memset(&payload, 0, sizeof(payload)); + + rc = pm8001_tag_alloc(pm8001_ha, &tag); + if (rc) + PM8001_INIT_DBG(pm8001_ha, pm8001_printk("Invalid tag")); + + circularQ = &pm8001_ha->inbnd_q_tbl[0]; + opc = OPC_INB_SET_PHY_PROFILE; + + payload.tag = cpu_to_le32(tag); + payload.ppc_phyid = (((SAS_PHY_ANALOG_SETTINGS_PAGE & 0xF) << 8) + | (phy & 0xFF)); + + for (i = 0; i < length; i++) + payload.reserved[i] = cpu_to_le32(*(buf + i)); + + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + if (rc) + pm8001_tag_free(pm8001_ha, tag); + + PM8001_INIT_DBG(pm8001_ha, + pm8001_printk("PHY %d settings applied", phy)); +} const struct pm8001_dispatch pm8001_80xx_dispatch = { .name = "pmc80xx", .chip_init = pm80xx_chip_init, diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c index ed31d8cc6..b2a88200f 100644 --- a/drivers/scsi/pmcraid.c +++ b/drivers/scsi/pmcraid.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -4254,7 +4255,6 @@ static struct scsi_host_template pmcraid_host_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = pmcraid_host_attrs, .proc_name = PMCRAID_DRIVER_NAME, - .use_blk_tags = 1, }; /* @@ -5563,11 +5563,9 @@ static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd) __be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN); struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; - struct timeval tv; __le64 timestamp; - do_gettimeofday(&tv); - timestamp = tv.tv_sec * 1000; + timestamp = ktime_get_real_seconds() * 1000; pinstance->timestamp_data->timestamp[0] = (__u8)(timestamp); pinstance->timestamp_data->timestamp[1] = (__u8)((timestamp) >> 8); diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index eb0cc5475..b6b4cfdd7 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -433,7 +433,7 @@ qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong off_in, if (off_in < QLA82XX_PCI_CRBSPACE) return -1; - *off_out = (void __iomem *)(off_in - QLA82XX_PCI_CRBSPACE); + off_in -= QLA82XX_PCI_CRBSPACE; /* Try direct map */ m = &crb_128M_2M_map[CRB_BLK(off_in)].sub_block[CRB_SUBBLK(off_in)]; @@ -443,6 +443,7 @@ qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong off_in, return 0; } /* Not in direct map, use crb window */ + *off_out = (void __iomem *)off_in; return 1; } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index df307f4d3..25a8f470d 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -267,7 +267,6 @@ struct scsi_host_template qla2xxx_driver_template = { .shost_attrs = qla2x00_host_attrs, .supported_mode = MODE_INITIATOR, - .use_blk_tags = 1, .track_queue_depth = 1, }; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index ac65cb7b4..81af294f1 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -43,8 +43,6 @@ #include #include #include -#include -#include #include "qla_def.h" #include "qla_target.h" @@ -729,23 +727,23 @@ static int tcm_qla2xxx_init_nodeacl(struct se_node_acl *se_nacl, #define DEF_QLA_TPG_ATTRIB(name) \ \ -static ssize_t tcm_qla2xxx_tpg_attrib_show_##name( \ - struct se_portal_group *se_tpg, \ - char *page) \ +static ssize_t tcm_qla2xxx_tpg_attrib_##name##_show( \ + struct config_item *item, char *page) \ { \ + struct se_portal_group *se_tpg = attrib_to_tpg(item); \ struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, \ struct tcm_qla2xxx_tpg, se_tpg); \ \ return sprintf(page, "%u\n", tpg->tpg_attrib.name); \ } \ \ -static ssize_t tcm_qla2xxx_tpg_attrib_store_##name( \ - struct se_portal_group *se_tpg, \ - const char *page, \ - size_t count) \ +static ssize_t tcm_qla2xxx_tpg_attrib_##name##_store( \ + struct config_item *item, const char *page, size_t count) \ { \ + struct se_portal_group *se_tpg = attrib_to_tpg(item); \ struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, \ struct tcm_qla2xxx_tpg, se_tpg); \ + struct tcm_qla2xxx_tpg_attrib *a = &tpg->tpg_attrib; \ unsigned long val; \ int ret; \ \ @@ -755,81 +753,39 @@ static ssize_t tcm_qla2xxx_tpg_attrib_store_##name( \ " ret: %d\n", ret); \ return -EINVAL; \ } \ - ret = tcm_qla2xxx_set_attrib_##name(tpg, val); \ - \ - return (!ret) ? count : -EINVAL; \ -} - -#define DEF_QLA_TPG_ATTR_BOOL(_name) \ - \ -static int tcm_qla2xxx_set_attrib_##_name( \ - struct tcm_qla2xxx_tpg *tpg, \ - unsigned long val) \ -{ \ - struct tcm_qla2xxx_tpg_attrib *a = &tpg->tpg_attrib; \ \ if ((val != 0) && (val != 1)) { \ pr_err("Illegal boolean value %lu\n", val); \ return -EINVAL; \ } \ \ - a->_name = val; \ - return 0; \ -} - -#define QLA_TPG_ATTR(_name, _mode) \ - TF_TPG_ATTRIB_ATTR(tcm_qla2xxx, _name, _mode); + a->name = val; \ + \ + return count; \ +} \ +CONFIGFS_ATTR(tcm_qla2xxx_tpg_attrib_, name) -/* - * Define tcm_qla2xxx_tpg_attrib_s_generate_node_acls - */ -DEF_QLA_TPG_ATTR_BOOL(generate_node_acls); DEF_QLA_TPG_ATTRIB(generate_node_acls); -QLA_TPG_ATTR(generate_node_acls, S_IRUGO | S_IWUSR); - -/* - Define tcm_qla2xxx_attrib_s_cache_dynamic_acls - */ -DEF_QLA_TPG_ATTR_BOOL(cache_dynamic_acls); DEF_QLA_TPG_ATTRIB(cache_dynamic_acls); -QLA_TPG_ATTR(cache_dynamic_acls, S_IRUGO | S_IWUSR); - -/* - * Define tcm_qla2xxx_tpg_attrib_s_demo_mode_write_protect - */ -DEF_QLA_TPG_ATTR_BOOL(demo_mode_write_protect); DEF_QLA_TPG_ATTRIB(demo_mode_write_protect); -QLA_TPG_ATTR(demo_mode_write_protect, S_IRUGO | S_IWUSR); - -/* - * Define tcm_qla2xxx_tpg_attrib_s_prod_mode_write_protect - */ -DEF_QLA_TPG_ATTR_BOOL(prod_mode_write_protect); DEF_QLA_TPG_ATTRIB(prod_mode_write_protect); -QLA_TPG_ATTR(prod_mode_write_protect, S_IRUGO | S_IWUSR); - -/* - * Define tcm_qla2xxx_tpg_attrib_s_demo_mode_login_only - */ -DEF_QLA_TPG_ATTR_BOOL(demo_mode_login_only); DEF_QLA_TPG_ATTRIB(demo_mode_login_only); -QLA_TPG_ATTR(demo_mode_login_only, S_IRUGO | S_IWUSR); static struct configfs_attribute *tcm_qla2xxx_tpg_attrib_attrs[] = { - &tcm_qla2xxx_tpg_attrib_generate_node_acls.attr, - &tcm_qla2xxx_tpg_attrib_cache_dynamic_acls.attr, - &tcm_qla2xxx_tpg_attrib_demo_mode_write_protect.attr, - &tcm_qla2xxx_tpg_attrib_prod_mode_write_protect.attr, - &tcm_qla2xxx_tpg_attrib_demo_mode_login_only.attr, + &tcm_qla2xxx_tpg_attrib_attr_generate_node_acls, + &tcm_qla2xxx_tpg_attrib_attr_cache_dynamic_acls, + &tcm_qla2xxx_tpg_attrib_attr_demo_mode_write_protect, + &tcm_qla2xxx_tpg_attrib_attr_prod_mode_write_protect, + &tcm_qla2xxx_tpg_attrib_attr_demo_mode_login_only, NULL, }; /* End items for tcm_qla2xxx_tpg_attrib_cit */ -static ssize_t tcm_qla2xxx_tpg_show_enable( - struct se_portal_group *se_tpg, - char *page) +static ssize_t tcm_qla2xxx_tpg_enable_show(struct config_item *item, + char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, struct tcm_qla2xxx_tpg, se_tpg); @@ -865,11 +821,10 @@ static void tcm_qla2xxx_undepend_tpg(struct work_struct *work) complete(&base_tpg->tpg_base_comp); } -static ssize_t tcm_qla2xxx_tpg_store_enable( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t tcm_qla2xxx_tpg_enable_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, struct tcm_qla2xxx_tpg, se_tpg); unsigned long op; @@ -909,22 +864,16 @@ static ssize_t tcm_qla2xxx_tpg_store_enable( return count; } -TF_TPG_BASE_ATTR(tcm_qla2xxx, enable, S_IRUGO | S_IWUSR); - -static ssize_t tcm_qla2xxx_tpg_show_dynamic_sessions( - struct se_portal_group *se_tpg, - char *page) +static ssize_t tcm_qla2xxx_tpg_dynamic_sessions_show(struct config_item *item, + char *page) { - return target_show_dynamic_sessions(se_tpg, page); + return target_show_dynamic_sessions(to_tpg(item), page); } -TF_TPG_BASE_ATTR_RO(tcm_qla2xxx, dynamic_sessions); - -static ssize_t tcm_qla2xxx_tpg_store_fabric_prot_type( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t tcm_qla2xxx_tpg_fabric_prot_type_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, struct tcm_qla2xxx_tpg, se_tpg); unsigned long val; @@ -943,21 +892,24 @@ static ssize_t tcm_qla2xxx_tpg_store_fabric_prot_type( return count; } -static ssize_t tcm_qla2xxx_tpg_show_fabric_prot_type( - struct se_portal_group *se_tpg, - char *page) +static ssize_t tcm_qla2xxx_tpg_fabric_prot_type_show(struct config_item *item, + char *page) { + struct se_portal_group *se_tpg = to_tpg(item); struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, struct tcm_qla2xxx_tpg, se_tpg); return sprintf(page, "%d\n", tpg->tpg_attrib.fabric_prot_type); } -TF_TPG_BASE_ATTR(tcm_qla2xxx, fabric_prot_type, S_IRUGO | S_IWUSR); + +CONFIGFS_ATTR(tcm_qla2xxx_tpg_, enable); +CONFIGFS_ATTR_RO(tcm_qla2xxx_tpg_, dynamic_sessions); +CONFIGFS_ATTR(tcm_qla2xxx_tpg_, fabric_prot_type); static struct configfs_attribute *tcm_qla2xxx_tpg_attrs[] = { - &tcm_qla2xxx_tpg_enable.attr, - &tcm_qla2xxx_tpg_dynamic_sessions.attr, - &tcm_qla2xxx_tpg_fabric_prot_type.attr, + &tcm_qla2xxx_tpg_attr_enable, + &tcm_qla2xxx_tpg_attr_dynamic_sessions, + &tcm_qla2xxx_tpg_attr_fabric_prot_type, NULL, }; @@ -1030,18 +982,16 @@ static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg) kfree(tpg); } -static ssize_t tcm_qla2xxx_npiv_tpg_show_enable( - struct se_portal_group *se_tpg, - char *page) +static ssize_t tcm_qla2xxx_npiv_tpg_enable_show(struct config_item *item, + char *page) { - return tcm_qla2xxx_tpg_show_enable(se_tpg, page); + return tcm_qla2xxx_tpg_enable_show(item, page); } -static ssize_t tcm_qla2xxx_npiv_tpg_store_enable( - struct se_portal_group *se_tpg, - const char *page, - size_t count) +static ssize_t tcm_qla2xxx_npiv_tpg_enable_store(struct config_item *item, + const char *page, size_t count) { + struct se_portal_group *se_tpg = to_tpg(item); struct se_wwn *se_wwn = se_tpg->se_tpg_wwn; struct tcm_qla2xxx_lport *lport = container_of(se_wwn, struct tcm_qla2xxx_lport, lport_wwn); @@ -1077,10 +1027,10 @@ static ssize_t tcm_qla2xxx_npiv_tpg_store_enable( return count; } -TF_TPG_BASE_ATTR(tcm_qla2xxx_npiv, enable, S_IRUGO | S_IWUSR); +CONFIGFS_ATTR(tcm_qla2xxx_npiv_tpg_, enable); static struct configfs_attribute *tcm_qla2xxx_npiv_tpg_attrs[] = { - &tcm_qla2xxx_npiv_tpg_enable.attr, + &tcm_qla2xxx_npiv_tpg_attr_enable, NULL, }; @@ -1783,9 +1733,8 @@ static void tcm_qla2xxx_npiv_drop_lport(struct se_wwn *wwn) } -static ssize_t tcm_qla2xxx_wwn_show_attr_version( - struct target_fabric_configfs *tf, - char *page) +static ssize_t tcm_qla2xxx_wwn_version_show(struct config_item *item, + char *page) { return sprintf(page, "TCM QLOGIC QLA2XXX NPIV capable fabric module %s on %s/%s on " @@ -1793,10 +1742,10 @@ static ssize_t tcm_qla2xxx_wwn_show_attr_version( utsname()->machine); } -TF_WWN_ATTR_RO(tcm_qla2xxx, version); +CONFIGFS_ATTR_RO(tcm_qla2xxx_wwn_, version); static struct configfs_attribute *tcm_qla2xxx_wwn_attrs[] = { - &tcm_qla2xxx_wwn_version.attr, + &tcm_qla2xxx_wwn_attr_version, NULL, }; diff --git a/drivers/scsi/qla4xxx/ql4_nx.c b/drivers/scsi/qla4xxx/ql4_nx.c index 7c3365864..ae87d6c19 100644 --- a/drivers/scsi/qla4xxx/ql4_nx.c +++ b/drivers/scsi/qla4xxx/ql4_nx.c @@ -12,7 +12,7 @@ #include "ql4_glbl.h" #include "ql4_inline.h" -#include +#include #define TIMEOUT_100_MS 100 #define MASK(n) DMA_BIT_MASK(n) diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 6d25879d8..01c3610a6 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -212,7 +212,6 @@ static struct scsi_host_template qla4xxx_driver_template = { .shost_attrs = qla4xxx_host_attrs, .host_reset = qla4xxx_host_reset, .vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC, - .use_blk_tags = 1, }; static struct iscsi_transport qla4xxx_iscsi_transport = { @@ -8697,13 +8696,6 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev, host->can_queue = MAX_SRBS ; host->transportt = qla4xxx_scsi_transport; - ret = scsi_init_shared_tag_map(host, MAX_SRBS); - if (ret) { - ql4_printk(KERN_WARNING, ha, - "%s: scsi_init_shared_tag_map failed\n", __func__); - goto probe_failed; - } - pci_set_drvdata(pdev, ha); ret = scsi_add_host(host, &pdev->dev); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 207d6a7a1..d07fb653f 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -616,32 +616,11 @@ void scsi_finish_command(struct scsi_cmnd *cmd) */ int scsi_change_queue_depth(struct scsi_device *sdev, int depth) { - unsigned long flags; - - if (depth <= 0) - goto out; - - spin_lock_irqsave(sdev->request_queue->queue_lock, flags); - - /* - * Check to see if the queue is managed by the block layer. - * If it is, and we fail to adjust the depth, exit. - * - * Do not resize the tag map if it is a host wide share bqt, - * because the size should be the hosts's can_queue. If there - * is more IO than the LLD's can_queue (so there are not enuogh - * tags) request_fn's host queue ready check will handle it. - */ - if (!shost_use_blk_mq(sdev->host) && !sdev->host->bqt) { - if (blk_queue_tagged(sdev->request_queue) && - blk_queue_resize_tags(sdev->request_queue, depth) != 0) - goto out_unlock; + if (depth > 0) { + sdev->queue_depth = depth; + wmb(); } - sdev->queue_depth = depth; -out_unlock: - spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); -out: return sdev->queue_depth; } EXPORT_SYMBOL(scsi_change_queue_depth); diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index dfcc45bb0..d09d60293 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -465,8 +465,9 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { 0} }, {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, - {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* VERIFY */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */ + {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, + 0, 0, 0, 0, 0, 0} }, {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0, vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */ @@ -477,8 +478,8 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, /* 20 */ - {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ALLOW REMOVAL */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, + {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ + {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 9f77d2323..2c1160c7e 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -390,25 +390,57 @@ int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model, EXPORT_SYMBOL(scsi_dev_info_list_add_keyed); /** - * scsi_dev_info_list_del_keyed - remove one dev_info list entry. + * scsi_dev_info_list_find - find a matching dev_info list entry. * @vendor: vendor string * @model: model (product) string * @key: specify list to use * * Description: - * Remove and destroy one dev_info entry for @vendor, @model + * Finds the first dev_info entry matching @vendor, @model * in list specified by @key. * - * Returns: 0 OK, -error on failure. + * Returns: pointer to matching entry, or ERR_PTR on failure. **/ -int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key) +static struct scsi_dev_info_list *scsi_dev_info_list_find(const char *vendor, + const char *model, int key) { - struct scsi_dev_info_list *devinfo, *found = NULL; + struct scsi_dev_info_list *devinfo; struct scsi_dev_info_list_table *devinfo_table = scsi_devinfo_lookup_by_key(key); + size_t vmax, mmax; + const char *vskip, *mskip; if (IS_ERR(devinfo_table)) - return PTR_ERR(devinfo_table); + return (struct scsi_dev_info_list *) devinfo_table; + + /* Prepare for "compatible" matches */ + + /* + * XXX why skip leading spaces? If an odd INQUIRY + * value, that should have been part of the + * scsi_static_device_list[] entry, such as " FOO" + * rather than "FOO". Since this code is already + * here, and we don't know what device it is + * trying to work with, leave it as-is. + */ + vmax = 8; /* max length of vendor */ + vskip = vendor; + while (vmax > 0 && *vskip == ' ') { + vmax--; + vskip++; + } + /* Also skip trailing spaces */ + while (vmax > 0 && vskip[vmax - 1] == ' ') + --vmax; + + mmax = 16; /* max length of model */ + mskip = model; + while (mmax > 0 && *mskip == ' ') { + mmax--; + mskip++; + } + while (mmax > 0 && mskip[mmax - 1] == ' ') + --mmax; list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list, dev_info_list) { @@ -416,61 +448,48 @@ int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key) /* * Behave like the older version of get_device_flags. */ - size_t max; - /* - * XXX why skip leading spaces? If an odd INQUIRY - * value, that should have been part of the - * scsi_static_device_list[] entry, such as " FOO" - * rather than "FOO". Since this code is already - * here, and we don't know what device it is - * trying to work with, leave it as-is. - */ - max = 8; /* max length of vendor */ - while ((max > 0) && *vendor == ' ') { - max--; - vendor++; - } - /* - * XXX removing the following strlen() would be - * good, using it means that for a an entry not in - * the list, we scan every byte of every vendor - * listed in scsi_static_device_list[], and never match - * a single one (and still have to compare at - * least the first byte of each vendor). - */ - if (memcmp(devinfo->vendor, vendor, - min(max, strlen(devinfo->vendor)))) + if (memcmp(devinfo->vendor, vskip, vmax) || + devinfo->vendor[vmax]) continue; - /* - * Skip spaces again. - */ - max = 16; /* max length of model */ - while ((max > 0) && *model == ' ') { - max--; - model++; - } - if (memcmp(devinfo->model, model, - min(max, strlen(devinfo->model)))) + if (memcmp(devinfo->model, mskip, mmax) || + devinfo->model[mmax]) continue; - found = devinfo; + return devinfo; } else { if (!memcmp(devinfo->vendor, vendor, sizeof(devinfo->vendor)) && !memcmp(devinfo->model, model, sizeof(devinfo->model))) - found = devinfo; + return devinfo; } - if (found) - break; } - if (found) { - list_del(&found->dev_info_list); - kfree(found); - return 0; - } + return ERR_PTR(-ENOENT); +} + +/** + * scsi_dev_info_list_del_keyed - remove one dev_info list entry. + * @vendor: vendor string + * @model: model (product) string + * @key: specify list to use + * + * Description: + * Remove and destroy one dev_info entry for @vendor, @model + * in list specified by @key. + * + * Returns: 0 OK, -error on failure. + **/ +int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key) +{ + struct scsi_dev_info_list *found; - return -ENOENT; + found = scsi_dev_info_list_find(vendor, model, key); + if (IS_ERR(found)) + return PTR_ERR(found); + + list_del(&found->dev_info_list); + kfree(found); + return 0; } EXPORT_SYMBOL(scsi_dev_info_list_del_keyed); @@ -565,64 +584,16 @@ int scsi_get_device_flags_keyed(struct scsi_device *sdev, int key) { struct scsi_dev_info_list *devinfo; - struct scsi_dev_info_list_table *devinfo_table; + int err; - devinfo_table = scsi_devinfo_lookup_by_key(key); + devinfo = scsi_dev_info_list_find(vendor, model, key); + if (!IS_ERR(devinfo)) + return devinfo->flags; - if (IS_ERR(devinfo_table)) - return PTR_ERR(devinfo_table); + err = PTR_ERR(devinfo); + if (err != -ENOENT) + return err; - list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list, - dev_info_list) { - if (devinfo->compatible) { - /* - * Behave like the older version of get_device_flags. - */ - size_t max; - /* - * XXX why skip leading spaces? If an odd INQUIRY - * value, that should have been part of the - * scsi_static_device_list[] entry, such as " FOO" - * rather than "FOO". Since this code is already - * here, and we don't know what device it is - * trying to work with, leave it as-is. - */ - max = 8; /* max length of vendor */ - while ((max > 0) && *vendor == ' ') { - max--; - vendor++; - } - /* - * XXX removing the following strlen() would be - * good, using it means that for a an entry not in - * the list, we scan every byte of every vendor - * listed in scsi_static_device_list[], and never match - * a single one (and still have to compare at - * least the first byte of each vendor). - */ - if (memcmp(devinfo->vendor, vendor, - min(max, strlen(devinfo->vendor)))) - continue; - /* - * Skip spaces again. - */ - max = 16; /* max length of model */ - while ((max > 0) && *model == ' ') { - max--; - model++; - } - if (memcmp(devinfo->model, model, - min(max, strlen(devinfo->model)))) - continue; - return devinfo->flags; - } else { - if (!memcmp(devinfo->vendor, vendor, - sizeof(devinfo->vendor)) && - !memcmp(devinfo->model, model, - sizeof(devinfo->model))) - return devinfo->flags; - } - } /* nothing found, return nothing */ if (key != SCSI_DEVINFO_GLOBAL) return 0; diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 66a96cd98..984ddcb47 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1970,7 +1970,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev) struct request *req; /* - * blk_get_request with GFP_KERNEL (__GFP_WAIT) sleeps until a + * blk_get_request with GFP_KERNEL (__GFP_RECLAIM) sleeps until a * request becomes available */ req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 126a48c64..dd8ad2a44 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -222,13 +222,13 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, int write = (data_direction == DMA_TO_DEVICE); int ret = DRIVER_ERROR << 24; - req = blk_get_request(sdev->request_queue, write, __GFP_WAIT); + req = blk_get_request(sdev->request_queue, write, __GFP_RECLAIM); if (IS_ERR(req)) return ret; blk_rq_set_block_pc(req); if (bufflen && blk_rq_map_kern(sdev->request_queue, req, - buffer, bufflen, __GFP_WAIT)) + buffer, bufflen, __GFP_RECLAIM)) goto out; req->cmd_len = COMMAND_SIZE(cmd[0]); diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index e4b799837..459abe1dc 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -219,13 +219,13 @@ static int sdev_runtime_suspend(struct device *dev) struct scsi_device *sdev = to_scsi_device(dev); int err = 0; - if (pm && pm->runtime_suspend) { - err = blk_pre_runtime_suspend(sdev->request_queue); - if (err) - return err; + err = blk_pre_runtime_suspend(sdev->request_queue); + if (err) + return err; + if (pm && pm->runtime_suspend) err = pm->runtime_suspend(dev); - blk_post_runtime_suspend(sdev->request_queue, err); - } + blk_post_runtime_suspend(sdev->request_queue, err); + return err; } @@ -248,11 +248,11 @@ static int sdev_runtime_resume(struct device *dev) const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; int err = 0; - if (pm && pm->runtime_resume) { - blk_pre_runtime_resume(sdev->request_queue); + blk_pre_runtime_resume(sdev->request_queue); + if (pm && pm->runtime_resume) err = pm->runtime_resume(dev); - blk_post_runtime_resume(sdev->request_queue, err); - } + blk_post_runtime_resume(sdev->request_queue, err); + return err; } diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index f9f3f8203..054923e33 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -55,6 +55,7 @@ * Default timeout */ #define SCSI_TIMEOUT (2*HZ) +#define SCSI_REPORT_LUNS_TIMEOUT (30*HZ) /* * Prefix values for the SCSI id's (stored in sysfs name field) @@ -274,8 +275,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, WARN_ON_ONCE(!blk_get_queue(sdev->request_queue)); sdev->request_queue->queuedata = sdev; - if (!shost_use_blk_mq(sdev->host) && - (shost->bqt || shost->hostt->use_blk_tags)) { + if (!shost_use_blk_mq(sdev->host)) { blk_queue_init_tags(sdev->request_queue, sdev->host->cmd_per_lun, shost->bqt, shost->hostt->tag_alloc_policy); @@ -701,9 +701,12 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, * strings. */ if (sdev->inquiry_len < 36) { - sdev_printk(KERN_INFO, sdev, - "scsi scan: INQUIRY result too short (%d)," - " using 36\n", sdev->inquiry_len); + if (!sdev->host->short_inquiry) { + shost_printk(KERN_INFO, sdev->host, + "scsi scan: INQUIRY result too short (%d)," + " using 36\n", sdev->inquiry_len); + sdev->host->short_inquiry = 1; + } sdev->inquiry_len = 36; } @@ -1383,7 +1386,7 @@ retry: result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, lun_data, length, &sshdr, - SCSI_TIMEOUT + 4 * HZ, 3, NULL); + SCSI_REPORT_LUNS_TIMEOUT, 3, NULL); SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev, "scsi scan: REPORT LUNS" @@ -1712,8 +1715,7 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) return NULL; if (shost->async_scan) { - shost_printk(KERN_INFO, shost, "%s called twice\n", __func__); - dump_stack(); + shost_printk(KERN_DEBUG, shost, "%s called twice\n", __func__); return NULL; } diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index dff8fafb7..21930c9ac 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -775,6 +775,29 @@ static struct bin_attribute dev_attr_vpd_##_page = { \ sdev_vpd_pg_attr(pg83); sdev_vpd_pg_attr(pg80); +static ssize_t show_inquiry(struct file *filep, 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 scsi_device *sdev = to_scsi_device(dev); + + if (!sdev->inquiry) + return -EINVAL; + + return memory_read_from_buffer(buf, count, &off, sdev->inquiry, + sdev->inquiry_len); +} + +static struct bin_attribute dev_attr_inquiry = { + .attr = { + .name = "inquiry", + .mode = S_IRUGO, + }, + .size = 0, + .read = show_inquiry, +}; + static ssize_t show_iostat_counterbits(struct device *dev, struct device_attribute *attr, char *buf) @@ -900,7 +923,7 @@ sdev_store_queue_ramp_up_period(struct device *dev, return -EINVAL; sdev->queue_ramp_up_period = msecs_to_jiffies(period); - return period; + return count; } static DEVICE_ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR, @@ -959,6 +982,7 @@ static struct attribute *scsi_sdev_attrs[] = { static struct bin_attribute *scsi_sdev_bin_attrs[] = { &dev_attr_vpd_pg83, &dev_attr_vpd_pg80, + &dev_attr_inquiry, NULL }; static struct attribute_group scsi_sdev_attr_group = { @@ -1078,6 +1102,14 @@ void __scsi_remove_device(struct scsi_device *sdev) { struct device *dev = &sdev->sdev_gendev; + /* + * This cleanup path is not reentrant and while it is impossible + * to get a new reference with scsi_device_get() someone can still + * hold a previously acquired one. + */ + if (sdev->sdev_state == SDEV_DEL) + return; + if (sdev->is_visible) { if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0) return; @@ -1160,31 +1192,23 @@ static void __scsi_remove_target(struct scsi_target *starget) void scsi_remove_target(struct device *dev) { struct Scsi_Host *shost = dev_to_shost(dev->parent); - struct scsi_target *starget, *last = NULL; + struct scsi_target *starget; unsigned long flags; - /* remove targets being careful to lookup next entry before - * deleting the last - */ +restart: spin_lock_irqsave(shost->host_lock, flags); list_for_each_entry(starget, &shost->__targets, siblings) { if (starget->state == STARGET_DEL) continue; if (starget->dev.parent == dev || &starget->dev == dev) { - /* assuming new targets arrive at the end */ kref_get(&starget->reap_ref); spin_unlock_irqrestore(shost->host_lock, flags); - if (last) - scsi_target_reap(last); - last = starget; __scsi_remove_target(starget); - spin_lock_irqsave(shost->host_lock, flags); + scsi_target_reap(starget); + goto restart; } } spin_unlock_irqrestore(shost->host_lock, flags); - - if (last) - scsi_target_reap(last); } EXPORT_SYMBOL(scsi_remove_target); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3f370228b..4e08d1cd7 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -204,6 +205,7 @@ cache_type_store(struct device *dev, struct device_attribute *attr, buffer_data[2] &= ~0x05; buffer_data[2] |= wce << 2 | rcd; sp = buffer_data[0] & 0x80 ? 1 : 0; + buffer_data[0] &= ~0x80; if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT, SD_MAX_RETRIES, &data, &sshdr)) { @@ -636,11 +638,24 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) unsigned int max_blocks = 0; q->limits.discard_zeroes_data = 0; - q->limits.discard_alignment = sdkp->unmap_alignment * - logical_block_size; - q->limits.discard_granularity = - max(sdkp->physical_block_size, - sdkp->unmap_granularity * logical_block_size); + + /* + * When LBPRZ is reported, discard alignment and granularity + * must be fixed to the logical block size. Otherwise the block + * layer will drop misaligned portions of the request which can + * lead to data corruption. If LBPRZ is not set, we honor the + * device preference. + */ + if (sdkp->lbprz) { + q->limits.discard_alignment = 0; + q->limits.discard_granularity = 1; + } else { + q->limits.discard_alignment = sdkp->unmap_alignment * + logical_block_size; + q->limits.discard_granularity = + max(sdkp->physical_block_size, + sdkp->unmap_granularity * logical_block_size); + } sdkp->provisioning_mode = mode; @@ -1535,6 +1550,100 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, } #endif +static char sd_pr_type(enum pr_type type) +{ + switch (type) { + case PR_WRITE_EXCLUSIVE: + return 0x01; + case PR_EXCLUSIVE_ACCESS: + return 0x03; + case PR_WRITE_EXCLUSIVE_REG_ONLY: + return 0x05; + case PR_EXCLUSIVE_ACCESS_REG_ONLY: + return 0x06; + case PR_WRITE_EXCLUSIVE_ALL_REGS: + return 0x07; + case PR_EXCLUSIVE_ACCESS_ALL_REGS: + return 0x08; + default: + return 0; + } +}; + +static int sd_pr_command(struct block_device *bdev, u8 sa, + u64 key, u64 sa_key, u8 type, u8 flags) +{ + struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device; + struct scsi_sense_hdr sshdr; + int result; + u8 cmd[16] = { 0, }; + u8 data[24] = { 0, }; + + cmd[0] = PERSISTENT_RESERVE_OUT; + cmd[1] = sa; + cmd[2] = type; + put_unaligned_be32(sizeof(data), &cmd[5]); + + put_unaligned_be64(key, &data[0]); + put_unaligned_be64(sa_key, &data[8]); + data[20] = flags; + + result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, &data, sizeof(data), + &sshdr, SD_TIMEOUT, SD_MAX_RETRIES, NULL); + + if ((driver_byte(result) & DRIVER_SENSE) && + (scsi_sense_valid(&sshdr))) { + sdev_printk(KERN_INFO, sdev, "PR command failed: %d\n", result); + scsi_print_sense_hdr(sdev, NULL, &sshdr); + } + + return result; +} + +static int sd_pr_register(struct block_device *bdev, u64 old_key, u64 new_key, + u32 flags) +{ + if (flags & ~PR_FL_IGNORE_KEY) + return -EOPNOTSUPP; + return sd_pr_command(bdev, (flags & PR_FL_IGNORE_KEY) ? 0x06 : 0x00, + old_key, new_key, 0, + (1 << 0) /* APTPL */ | + (1 << 2) /* ALL_TG_PT */); +} + +static int sd_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type, + u32 flags) +{ + if (flags) + return -EOPNOTSUPP; + return sd_pr_command(bdev, 0x01, key, 0, sd_pr_type(type), 0); +} + +static int sd_pr_release(struct block_device *bdev, u64 key, enum pr_type type) +{ + return sd_pr_command(bdev, 0x02, key, 0, sd_pr_type(type), 0); +} + +static int sd_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key, + enum pr_type type, bool abort) +{ + return sd_pr_command(bdev, abort ? 0x05 : 0x04, old_key, new_key, + sd_pr_type(type), 0); +} + +static int sd_pr_clear(struct block_device *bdev, u64 key) +{ + return sd_pr_command(bdev, 0x03, key, 0, 0, 0); +} + +static const struct pr_ops sd_pr_ops = { + .pr_register = sd_pr_register, + .pr_reserve = sd_pr_reserve, + .pr_release = sd_pr_release, + .pr_preempt = sd_pr_preempt, + .pr_clear = sd_pr_clear, +}; + static const struct block_device_operations sd_fops = { .owner = THIS_MODULE, .open = sd_open, @@ -1547,6 +1656,7 @@ static const struct block_device_operations sd_fops = { .check_events = sd_check_events, .revalidate_disk = sd_revalidate_disk, .unlock_native_capacity = sd_unlock_native_capacity, + .pr_ops = &sd_pr_ops, }; /** @@ -2224,11 +2334,8 @@ got_data: } } - if (sdkp->capacity > 0xffffffff) { + if (sdkp->capacity > 0xffffffff) sdp->use_16_for_rw = 1; - sdkp->max_xfer_blocks = SD_MAX_XFER_BLOCKS; - } else - sdkp->max_xfer_blocks = SD_DEF_XFER_BLOCKS; /* Rescale capacity to 512-byte units */ if (sector_size == 4096) @@ -2545,7 +2652,6 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) { unsigned int sector_sz = sdkp->device->sector_size; const int vpd_len = 64; - u32 max_xfer_length; unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL); if (!buffer || @@ -2553,14 +2659,11 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len)) goto out; - max_xfer_length = get_unaligned_be32(&buffer[8]); - if (max_xfer_length) - sdkp->max_xfer_blocks = max_xfer_length; - blk_queue_io_min(sdkp->disk->queue, get_unaligned_be16(&buffer[6]) * sector_sz); - blk_queue_io_opt(sdkp->disk->queue, - get_unaligned_be32(&buffer[12]) * sector_sz); + + sdkp->max_xfer_blocks = get_unaligned_be32(&buffer[8]); + sdkp->opt_xfer_blocks = get_unaligned_be32(&buffer[12]); if (buffer[3] == 0x3c) { unsigned int lba_count, desc_count; @@ -2709,6 +2812,11 @@ static int sd_try_extended_inquiry(struct scsi_device *sdp) return 0; } +static inline u32 logical_to_sectors(struct scsi_device *sdev, u32 blocks) +{ + return blocks << (ilog2(sdev->sector_size) - 9); +} + /** * sd_revalidate_disk - called the first time a new disk is seen, * performs disk spin up, read_capacity, etc. @@ -2718,8 +2826,9 @@ static int sd_revalidate_disk(struct gendisk *disk) { struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; + struct request_queue *q = sdkp->disk->queue; unsigned char *buffer; - unsigned int max_xfer; + unsigned int dev_max, rw_max; SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_revalidate_disk\n")); @@ -2767,11 +2876,29 @@ static int sd_revalidate_disk(struct gendisk *disk) */ sd_set_flush_flag(sdkp); - max_xfer = sdkp->max_xfer_blocks; - max_xfer <<= ilog2(sdp->sector_size) - 9; + /* Initial block count limit based on CDB TRANSFER LENGTH field size. */ + dev_max = sdp->use_16_for_rw ? SD_MAX_XFER_BLOCKS : SD_DEF_XFER_BLOCKS; + + /* Some devices report a maximum block count for READ/WRITE requests. */ + dev_max = min_not_zero(dev_max, sdkp->max_xfer_blocks); + q->limits.max_dev_sectors = logical_to_sectors(sdp, dev_max); + + /* + * Use the device's preferred I/O size for reads and writes + * unless the reported value is unreasonably small, large, or + * garbage. + */ + if (sdkp->opt_xfer_blocks && + sdkp->opt_xfer_blocks <= dev_max && + sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS && + sdkp->opt_xfer_blocks * sdp->sector_size >= PAGE_CACHE_SIZE) + rw_max = q->limits.io_opt = + logical_to_sectors(sdp, sdkp->opt_xfer_blocks); + else + rw_max = BLK_DEF_MAX_SECTORS; - sdkp->disk->queue->limits.max_sectors = - min_not_zero(queue_max_hw_sectors(sdkp->disk->queue), max_xfer); + /* Combine with controller limits */ + q->limits.max_sectors = min(rw_max, queue_max_hw_sectors(q)); set_capacity(disk, sdkp->capacity); sd_config_write_same(sdkp); @@ -3068,7 +3195,6 @@ static void scsi_disk_release(struct device *dev) ida_remove(&sd_index_ida, sdkp->index); spin_unlock(&sd_index_lock); - blk_integrity_unregister(disk); disk->private_data = NULL; put_disk(disk); put_device(&sdkp->device->sdev_gendev); diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 63ba5ca7f..5f2a84aff 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -67,6 +67,7 @@ struct scsi_disk { atomic_t openers; sector_t capacity; /* size in 512-byte sectors */ u32 max_xfer_blocks; + u32 opt_xfer_blocks; u32 max_ws_blocks; u32 max_unmap_blocks; u32 unmap_granularity; diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c index 5c06d292b..987bf392c 100644 --- a/drivers/scsi/sd_dif.c +++ b/drivers/scsi/sd_dif.c @@ -43,6 +43,7 @@ void sd_dif_config_host(struct scsi_disk *sdkp) struct scsi_device *sdp = sdkp->device; struct gendisk *disk = sdkp->disk; u8 type = sdkp->protection_type; + struct blk_integrity bi; int dif, dix; dif = scsi_host_dif_capable(sdp->host, type); @@ -55,39 +56,43 @@ void sd_dif_config_host(struct scsi_disk *sdkp) if (!dix) return; + memset(&bi, 0, sizeof(bi)); + /* Enable DMA of protection information */ if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) { if (type == SD_DIF_TYPE3_PROTECTION) - blk_integrity_register(disk, &t10_pi_type3_ip); + bi.profile = &t10_pi_type3_ip; else - blk_integrity_register(disk, &t10_pi_type1_ip); + bi.profile = &t10_pi_type1_ip; - disk->integrity->flags |= BLK_INTEGRITY_IP_CHECKSUM; + bi.flags |= BLK_INTEGRITY_IP_CHECKSUM; } else if (type == SD_DIF_TYPE3_PROTECTION) - blk_integrity_register(disk, &t10_pi_type3_crc); + bi.profile = &t10_pi_type3_crc; else - blk_integrity_register(disk, &t10_pi_type1_crc); + bi.profile = &t10_pi_type1_crc; + bi.tuple_size = sizeof(struct t10_pi_tuple); sd_printk(KERN_NOTICE, sdkp, - "Enabling DIX %s protection\n", disk->integrity->name); + "Enabling DIX %s protection\n", bi.profile->name); - /* Signal to block layer that we support sector tagging */ if (dif && type) { - - disk->integrity->flags |= BLK_INTEGRITY_DEVICE_CAPABLE; + bi.flags |= BLK_INTEGRITY_DEVICE_CAPABLE; if (!sdkp->ATO) - return; + goto out; if (type == SD_DIF_TYPE3_PROTECTION) - disk->integrity->tag_size = sizeof(u16) + sizeof(u32); + bi.tag_size = sizeof(u16) + sizeof(u32); else - disk->integrity->tag_size = sizeof(u16); + bi.tag_size = sizeof(u16); sd_printk(KERN_NOTICE, sdkp, "DIF application tag size %u\n", - disk->integrity->tag_size); + bi.tag_size); } + +out: + blk_integrity_register(disk, &bi); } /* diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index dcb0d76d7..044d06410 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -84,6 +84,7 @@ static void init_device_slot_control(unsigned char *dest_desc, static int ses_recv_diag(struct scsi_device *sdev, int page_code, void *buf, int bufflen) { + int ret; unsigned char cmd[] = { RECEIVE_DIAGNOSTIC, 1, /* Set PCV bit */ @@ -92,9 +93,26 @@ static int ses_recv_diag(struct scsi_device *sdev, int page_code, bufflen & 0xff, 0 }; + unsigned char recv_page_code; - return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen, + ret = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen, NULL, SES_TIMEOUT, SES_RETRIES, NULL); + if (unlikely(!ret)) + return ret; + + recv_page_code = ((unsigned char *)buf)[0]; + + if (likely(recv_page_code == page_code)) + return ret; + + /* successful diagnostic but wrong page code. This happens to some + * USB devices, just print a message and pretend there was an error */ + + sdev_printk(KERN_ERR, sdev, + "Wrong diagnostic page; asked for %d got %u\n", + page_code, recv_page_code); + + return -EINVAL; } static int ses_send_diag(struct scsi_device *sdev, int page_code, @@ -541,7 +559,15 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, if (desc_ptr) desc_ptr += len; - if (addl_desc_ptr) + if (addl_desc_ptr && + /* only find additional descriptions for specific devices */ + (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || + type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE || + type_ptr[0] == ENCLOSURE_COMPONENT_SAS_EXPANDER || + /* these elements are optional */ + type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_TARGET_PORT || + type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_INITIATOR_PORT || + type_ptr[0] == ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS)) addl_desc_ptr += addl_desc_ptr[1] + 2; } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 9d7b7db75..503ab8b46 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -787,8 +787,14 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, return k; /* probably out of space --> ENOMEM */ } if (atomic_read(&sdp->detaching)) { - if (srp->bio) + if (srp->bio) { + if (srp->rq->cmd != srp->rq->__cmd) + kfree(srp->rq->cmd); + blk_end_request_all(srp->rq, -EIO); + srp->rq = NULL; + } + sg_finish_rem_req(srp); return -ENODEV; } diff --git a/drivers/scsi/snic/snic_main.c b/drivers/scsi/snic/snic_main.c index b2b87cef0..2b3c25371 100644 --- a/drivers/scsi/snic/snic_main.c +++ b/drivers/scsi/snic/snic_main.c @@ -124,7 +124,6 @@ static struct scsi_host_template snic_host_template = { .sg_tablesize = SNIC_MAX_SG_DESC_CNT, .max_sectors = 0x800, .shost_attrs = snic_attrs, - .use_blk_tags = 1, .track_queue_depth = 1, .cmd_size = sizeof(struct snic_internal_io_state), .proc_name = "snic_scsi", @@ -533,15 +532,6 @@ snic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) snic->max_tag_id = shost->can_queue; - ret = scsi_init_shared_tag_map(shost, snic->max_tag_id); - if (ret) { - SNIC_HOST_ERR(shost, - "Unable to alloc shared tag map. %d\n", - ret); - - goto err_dev_close; - } - shost->max_lun = snic->config.luns_per_tgt; shost->max_id = SNIC_MAX_TARGET; diff --git a/drivers/scsi/snic/snic_trc.c b/drivers/scsi/snic/snic_trc.c index 28a40a7ad..f00ebf471 100644 --- a/drivers/scsi/snic/snic_trc.c +++ b/drivers/scsi/snic/snic_trc.c @@ -148,7 +148,7 @@ snic_trc_init(void) trc->max_idx = (tbuf_sz / SNIC_TRC_ENTRY_SZ); trc->rd_idx = trc->wr_idx = 0; - trc->enable = 1; + trc->enable = true; SNIC_INFO("Trace Facility Enabled.\n Trace Buffer SZ %lu Pages.\n", tbuf_sz / PAGE_SIZE); ret = 0; @@ -169,7 +169,7 @@ snic_trc_free(void) { struct snic_trc *trc = &snic_glob->trc; - trc->enable = 0; + trc->enable = false; snic_trc_debugfs_term(); if (trc->buf) { diff --git a/drivers/scsi/snic/snic_trc.h b/drivers/scsi/snic/snic_trc.h index 427faee5f..b37f8867b 100644 --- a/drivers/scsi/snic/snic_trc.h +++ b/drivers/scsi/snic/snic_trc.h @@ -45,7 +45,7 @@ struct snic_trc { u32 max_idx; /* Max Index into trace buffer */ u32 rd_idx; u32 wr_idx; - u32 enable; /* Control Variable for Tracing */ + bool enable; /* Control Variable for Tracing */ struct dentry *trc_enable; /* debugfs file object */ struct dentry *trc_file; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index b37b9b00c..2e522951b 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4083,6 +4083,7 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew) } cdev->owner = THIS_MODULE; cdev->ops = &st_fops; + STm->cdevs[rew] = cdev; error = cdev_add(cdev, cdev_devno, 1); if (error) { @@ -4091,7 +4092,6 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew) pr_err("st%d: Device not attached.\n", dev_num); goto out_free; } - STm->cdevs[rew] = cdev; i = mode << (4 - ST_NBR_MODE_BITS); snprintf(name, 10, "%s%s%s", rew ? "n" : "", @@ -4110,8 +4110,9 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew) return 0; out_free: cdev_del(STm->cdevs[rew]); - STm->cdevs[rew] = NULL; out: + STm->cdevs[rew] = NULL; + STm->devs[rew] = NULL; return error; } @@ -4452,11 +4453,41 @@ static ssize_t version_show(struct device_driver *ddd, char *buf) } static DRIVER_ATTR_RO(version); +#if DEBUG +static ssize_t debug_flag_store(struct device_driver *ddp, + const char *buf, size_t count) +{ +/* We only care what the first byte of the data is the rest is unused. + * if it's a '1' we turn on debug and if it's a '0' we disable it. All + * other values have -EINVAL returned if they are passed in. + */ + if (count > 0) { + if (buf[0] == '0') { + debugging = NO_DEBUG; + return count; + } else if (buf[0] == '1') { + debugging = 1; + return count; + } + } + return -EINVAL; +} + +static ssize_t debug_flag_show(struct device_driver *ddp, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", debugging); +} +static DRIVER_ATTR_RW(debug_flag); +#endif + static struct attribute *st_drv_attrs[] = { &driver_attr_try_direct_io.attr, &driver_attr_fixed_buffer_size.attr, &driver_attr_max_sg_segs.attr, &driver_attr_version.attr, +#if DEBUG + &driver_attr_debug_flag.attr, +#endif NULL, }; ATTRIBUTE_GROUPS(st_drv); diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 98a62bc15..2de28d7a0 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -362,14 +363,6 @@ MODULE_DESCRIPTION("Promise Technology SuperTrak EX Controllers"); MODULE_LICENSE("GPL"); MODULE_VERSION(ST_DRIVER_VERSION); -static void stex_gettime(__le64 *time) -{ - struct timeval tv; - - do_gettimeofday(&tv); - *time = cpu_to_le64(tv.tv_sec); -} - static struct status_msg *stex_get_status(struct st_hba *hba) { struct status_msg *status = hba->status_buffer + hba->status_tail; @@ -1002,7 +995,7 @@ static int stex_common_handshake(struct st_hba *hba) h->req_cnt = cpu_to_le16(hba->rq_count+1); h->status_sz = cpu_to_le16(sizeof(struct status_msg)); h->status_cnt = cpu_to_le16(hba->sts_count+1); - stex_gettime(&h->hosttime); + h->hosttime = cpu_to_le64(ktime_get_real_seconds()); h->partner_type = HMU_PARTNER_TYPE; if (hba->extra_offset) { h->extra_offset = cpu_to_le32(hba->extra_offset); @@ -1076,7 +1069,7 @@ static int stex_ss_handshake(struct st_hba *hba) h->req_cnt = cpu_to_le16(hba->rq_count+1); h->status_sz = cpu_to_le16(sizeof(struct status_msg)); h->status_cnt = cpu_to_le16(hba->sts_count+1); - stex_gettime(&h->hosttime); + h->hosttime = cpu_to_le64(ktime_get_real_seconds()); h->partner_type = HMU_PARTNER_TYPE; h->extra_offset = h->extra_size = 0; scratch_size = (hba->sts_count+1)*sizeof(u32); @@ -1374,7 +1367,6 @@ static struct scsi_host_template driver_template = { .eh_abort_handler = stex_abort, .eh_host_reset_handler = stex_reset, .this_id = -1, - .use_blk_tags = 1, }; static struct pci_device_id stex_pci_tbl[] = { @@ -1659,13 +1651,6 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (err) goto out_free_irq; - err = scsi_init_shared_tag_map(host, host->can_queue); - if (err) { - printk(KERN_ERR DRV_NAME "(%s): init shared queue failed\n", - pci_name(pdev)); - goto out_free_irq; - } - pci_set_drvdata(pdev, hba); err = scsi_add_host(host, &pdev->dev); diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 40c43aeb4..3fba42ad9 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -349,11 +349,14 @@ enum storvsc_request_type { */ #define SRB_STATUS_AUTOSENSE_VALID 0x80 +#define SRB_STATUS_QUEUE_FROZEN 0x40 #define SRB_STATUS_INVALID_LUN 0x20 #define SRB_STATUS_SUCCESS 0x01 #define SRB_STATUS_ABORTED 0x02 #define SRB_STATUS_ERROR 0x04 +#define SRB_STATUS(status) \ + (status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN)) /* * This is the end of Protocol specific defines. */ @@ -393,9 +396,6 @@ static void storvsc_on_channel_callback(void *context); struct storvsc_cmd_request { struct scsi_cmnd *cmd; - unsigned int bounce_sgl_count; - struct scatterlist *bounce_sgl; - struct hv_device *device; /* Synchronize the request/response if needed */ @@ -586,241 +586,6 @@ get_in_err: } -static void destroy_bounce_buffer(struct scatterlist *sgl, - unsigned int sg_count) -{ - int i; - struct page *page_buf; - - for (i = 0; i < sg_count; i++) { - page_buf = sg_page((&sgl[i])); - if (page_buf != NULL) - __free_page(page_buf); - } - - kfree(sgl); -} - -static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count) -{ - int i; - - /* No need to check */ - if (sg_count < 2) - return -1; - - /* We have at least 2 sg entries */ - for (i = 0; i < sg_count; i++) { - if (i == 0) { - /* make sure 1st one does not have hole */ - if (sgl[i].offset + sgl[i].length != PAGE_SIZE) - return i; - } else if (i == sg_count - 1) { - /* make sure last one does not have hole */ - if (sgl[i].offset != 0) - return i; - } else { - /* make sure no hole in the middle */ - if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0) - return i; - } - } - return -1; -} - -static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl, - unsigned int sg_count, - unsigned int len, - int write) -{ - int i; - int num_pages; - struct scatterlist *bounce_sgl; - struct page *page_buf; - unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE); - - num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT; - - bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist), GFP_ATOMIC); - if (!bounce_sgl) - return NULL; - - sg_init_table(bounce_sgl, num_pages); - for (i = 0; i < num_pages; i++) { - page_buf = alloc_page(GFP_ATOMIC); - if (!page_buf) - goto cleanup; - sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0); - } - - return bounce_sgl; - -cleanup: - destroy_bounce_buffer(bounce_sgl, num_pages); - return NULL; -} - -/* Assume the original sgl has enough room */ -static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, - struct scatterlist *bounce_sgl, - unsigned int orig_sgl_count, - unsigned int bounce_sgl_count) -{ - int i; - int j = 0; - unsigned long src, dest; - unsigned int srclen, destlen, copylen; - unsigned int total_copied = 0; - unsigned long bounce_addr = 0; - unsigned long dest_addr = 0; - unsigned long flags; - struct scatterlist *cur_dest_sgl; - struct scatterlist *cur_src_sgl; - - local_irq_save(flags); - cur_dest_sgl = orig_sgl; - cur_src_sgl = bounce_sgl; - for (i = 0; i < orig_sgl_count; i++) { - dest_addr = (unsigned long) - kmap_atomic(sg_page(cur_dest_sgl)) + - cur_dest_sgl->offset; - dest = dest_addr; - destlen = cur_dest_sgl->length; - - if (bounce_addr == 0) - bounce_addr = (unsigned long)kmap_atomic( - sg_page(cur_src_sgl)); - - while (destlen) { - src = bounce_addr + cur_src_sgl->offset; - srclen = cur_src_sgl->length - cur_src_sgl->offset; - - copylen = min(srclen, destlen); - memcpy((void *)dest, (void *)src, copylen); - - total_copied += copylen; - cur_src_sgl->offset += copylen; - destlen -= copylen; - dest += copylen; - - if (cur_src_sgl->offset == cur_src_sgl->length) { - /* full */ - kunmap_atomic((void *)bounce_addr); - j++; - - /* - * It is possible that the number of elements - * in the bounce buffer may not be equal to - * the number of elements in the original - * scatter list. Handle this correctly. - */ - - if (j == bounce_sgl_count) { - /* - * We are done; cleanup and return. - */ - kunmap_atomic((void *)(dest_addr - - cur_dest_sgl->offset)); - local_irq_restore(flags); - return total_copied; - } - - /* if we need to use another bounce buffer */ - if (destlen || i != orig_sgl_count - 1) { - cur_src_sgl = sg_next(cur_src_sgl); - bounce_addr = (unsigned long) - kmap_atomic( - sg_page(cur_src_sgl)); - } - } else if (destlen == 0 && i == orig_sgl_count - 1) { - /* unmap the last bounce that is < PAGE_SIZE */ - kunmap_atomic((void *)bounce_addr); - } - } - - kunmap_atomic((void *)(dest_addr - cur_dest_sgl->offset)); - cur_dest_sgl = sg_next(cur_dest_sgl); - } - - local_irq_restore(flags); - - return total_copied; -} - -/* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */ -static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl, - struct scatterlist *bounce_sgl, - unsigned int orig_sgl_count) -{ - int i; - int j = 0; - unsigned long src, dest; - unsigned int srclen, destlen, copylen; - unsigned int total_copied = 0; - unsigned long bounce_addr = 0; - unsigned long src_addr = 0; - unsigned long flags; - struct scatterlist *cur_src_sgl; - struct scatterlist *cur_dest_sgl; - - local_irq_save(flags); - - cur_src_sgl = orig_sgl; - cur_dest_sgl = bounce_sgl; - - for (i = 0; i < orig_sgl_count; i++) { - src_addr = (unsigned long) - kmap_atomic(sg_page(cur_src_sgl)) + - cur_src_sgl->offset; - src = src_addr; - srclen = cur_src_sgl->length; - - if (bounce_addr == 0) - bounce_addr = (unsigned long) - kmap_atomic(sg_page(cur_dest_sgl)); - - while (srclen) { - /* assume bounce offset always == 0 */ - dest = bounce_addr + cur_dest_sgl->length; - destlen = PAGE_SIZE - cur_dest_sgl->length; - - copylen = min(srclen, destlen); - memcpy((void *)dest, (void *)src, copylen); - - total_copied += copylen; - cur_dest_sgl->length += copylen; - srclen -= copylen; - src += copylen; - - if (cur_dest_sgl->length == PAGE_SIZE) { - /* full..move to next entry */ - kunmap_atomic((void *)bounce_addr); - bounce_addr = 0; - j++; - } - - /* if we need to use another bounce buffer */ - if (srclen && bounce_addr == 0) { - cur_dest_sgl = sg_next(cur_dest_sgl); - bounce_addr = (unsigned long) - kmap_atomic( - sg_page(cur_dest_sgl)); - } - - } - - kunmap_atomic((void *)(src_addr - cur_src_sgl->offset)); - cur_src_sgl = sg_next(cur_src_sgl); - } - - if (bounce_addr) - kunmap_atomic((void *)bounce_addr); - - local_irq_restore(flags); - - return total_copied; -} - static void handle_sc_creation(struct vmbus_channel *new_sc) { struct hv_device *device = new_sc->primary_channel->device_obj; @@ -1096,7 +861,7 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb, void (*process_err_fn)(struct work_struct *work); bool do_work = false; - switch (vm_srb->srb_status) { + switch (SRB_STATUS(vm_srb->srb_status)) { case SRB_STATUS_ERROR: /* * If there is an error; offline the device since all @@ -1171,15 +936,6 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) host = stor_dev->host; vm_srb = &cmd_request->vstor_packet.vm_srb; - if (cmd_request->bounce_sgl_count) { - if (vm_srb->data_in == READ_TYPE) - copy_from_bounce_buffer(scsi_sglist(scmnd), - cmd_request->bounce_sgl, - scsi_sg_count(scmnd), - cmd_request->bounce_sgl_count); - destroy_bounce_buffer(cmd_request->bounce_sgl, - cmd_request->bounce_sgl_count); - } scmnd->result = vm_srb->scsi_status; @@ -1474,6 +1230,9 @@ static int storvsc_device_configure(struct scsi_device *sdevice) blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ)); + /* Ensure there are no gaps in presented sgls */ + blk_queue_virt_boundary(sdevice->request_queue, PAGE_SIZE - 1); + sdevice->no_write_same = 1; /* @@ -1647,8 +1406,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) vm_srb->win8_extension.time_out_value = 60; vm_srb->win8_extension.srb_flags |= - (SRB_FLAGS_QUEUE_ACTION_ENABLE | - SRB_FLAGS_DISABLE_SYNCH_TRANSFER); + SRB_FLAGS_DISABLE_SYNCH_TRANSFER; /* Build the SRB */ switch (scmnd->sc_data_direction) { @@ -1692,40 +1450,13 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) payload_sz = sizeof(cmd_request->mpb); if (sg_count) { - /* check if we need to bounce the sgl */ - if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) { - cmd_request->bounce_sgl = - create_bounce_buffer(sgl, sg_count, - length, - vm_srb->data_in); - if (!cmd_request->bounce_sgl) - return SCSI_MLQUEUE_HOST_BUSY; - - cmd_request->bounce_sgl_count = - ALIGN(length, PAGE_SIZE) >> PAGE_SHIFT; - - if (vm_srb->data_in == WRITE_TYPE) - copy_to_bounce_buffer(sgl, - cmd_request->bounce_sgl, sg_count); - - sgl = cmd_request->bounce_sgl; - sg_count = cmd_request->bounce_sgl_count; - } - - if (sg_count > MAX_PAGE_BUFFER_COUNT) { payload_sz = (sg_count * sizeof(void *) + sizeof(struct vmbus_packet_mpb_array)); payload = kmalloc(payload_sz, GFP_ATOMIC); - if (!payload) { - if (cmd_request->bounce_sgl_count) - destroy_bounce_buffer( - cmd_request->bounce_sgl, - cmd_request->bounce_sgl_count); - - return SCSI_MLQUEUE_DEVICE_BUSY; - } + if (!payload) + return SCSI_MLQUEUE_DEVICE_BUSY; } payload->range.len = length; @@ -1754,11 +1485,6 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) if (ret == -EAGAIN) { /* no more space */ - - if (cmd_request->bounce_sgl_count) - destroy_bounce_buffer(cmd_request->bounce_sgl, - cmd_request->bounce_sgl_count); - return SCSI_MLQUEUE_DEVICE_BUSY; } diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index e94538362..5f4530744 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -72,7 +72,7 @@ config SCSI_UFSHCD_PLATFORM If unsure, say N. config SCSI_UFS_QCOM - bool "QCOM specific hooks to UFS controller platform driver" + tristate "QCOM specific hooks to UFS controller platform driver" depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM select PHY_QCOM_UFS help diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 4cdffa46d..4f38d008b 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -19,16 +19,44 @@ #include #include "ufshcd.h" +#include "ufshcd-pltfrm.h" #include "unipro.h" #include "ufs-qcom.h" #include "ufshci.h" +#define UFS_QCOM_DEFAULT_DBG_PRINT_EN \ + (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) + +enum { + TSTBUS_UAWM, + TSTBUS_UARM, + TSTBUS_TXUC, + TSTBUS_RXUC, + TSTBUS_DFC, + TSTBUS_TRLUT, + TSTBUS_TMRLUT, + TSTBUS_OCSC, + TSTBUS_UTP_HCI, + TSTBUS_COMBINED, + TSTBUS_WRAPPER, + TSTBUS_UNIPRO, + TSTBUS_MAX, +}; static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS]; -static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result); -static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, - const char *speed_mode); static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote); +static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); +static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, + u32 clk_cycles); + +static void ufs_qcom_dump_regs(struct ufs_hba *hba, int offset, int len, + char *prefix) +{ + print_hex_dump(KERN_ERR, prefix, + len > 4 ? DUMP_PREFIX_OFFSET : DUMP_PREFIX_NONE, + 16, 4, (void __force *)hba->mmio_base + offset, + len * 4, false); +} static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes) { @@ -149,13 +177,14 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk", &host->tx_l1_sync_clk); + out: return err; } static int ufs_qcom_link_startup_post_change(struct ufs_hba *hba) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct phy *phy = host->generic_phy; u32 tx_lanes; int err = 0; @@ -181,7 +210,9 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba) do { err = ufshcd_dme_get(hba, - UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val); + UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, + UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), + &tx_fsm_val); if (err || tx_fsm_val == TX_FSM_HIBERN8) break; @@ -195,7 +226,9 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba) */ if (time_after(jiffies, timeout)) err = ufshcd_dme_get(hba, - UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val); + UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE, + UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)), + &tx_fsm_val); if (err) { dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n", @@ -209,9 +242,18 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba) return err; } +static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host) +{ + ufshcd_rmwl(host->hba, QUNIPRO_SEL, + ufs_qcom_cap_qunipro(host) ? QUNIPRO_SEL : 0, + REG_UFS_CFG1); + /* make sure above configuration is applied before we return */ + mb(); +} + static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) { - struct ufs_qcom_host *host = hba->priv; + 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) @@ -223,9 +265,11 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) usleep_range(1000, 1100); ret = ufs_qcom_phy_calibrate_phy(phy, is_rate_B); + if (ret) { - dev_err(hba->dev, "%s: ufs_qcom_phy_calibrate_phy() failed, ret = %d\n", - __func__, ret); + dev_err(hba->dev, + "%s: ufs_qcom_phy_calibrate_phy()failed, ret = %d\n", + __func__, ret); goto out; } @@ -246,9 +290,12 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) ret = ufs_qcom_phy_is_pcs_ready(phy); if (ret) - dev_err(hba->dev, "%s: is_physical_coding_sublayer_ready() failed, ret = %d\n", + dev_err(hba->dev, + "%s: is_physical_coding_sublayer_ready() failed, ret = %d\n", __func__, ret); + ufs_qcom_select_unipro_mode(host); + out: return ret; } @@ -271,9 +318,10 @@ static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba) mb(); } -static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status) +static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); int err = 0; switch (status) { @@ -301,13 +349,13 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status) } /** - * Returns non-zero for success (which rate of core_clk) and 0 - * in case of a failure + * Returns zero for success and non-zero in case of a failure */ -static unsigned long -ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) +static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, + u32 hs, u32 rate, bool update_link_startup_timer) { - struct ufs_qcom_host *host = hba->priv; + int ret = 0; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct ufs_clk_info *clki; u32 core_clk_period_in_ns; u32 tx_clk_cycles_per_us = 0; @@ -324,11 +372,13 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) static u32 hs_fr_table_rA[][2] = { {UFS_HS_G1, 0x1F}, {UFS_HS_G2, 0x3e}, + {UFS_HS_G3, 0x7D}, }; static u32 hs_fr_table_rB[][2] = { {UFS_HS_G1, 0x24}, {UFS_HS_G2, 0x49}, + {UFS_HS_G3, 0x92}, }; /* @@ -356,7 +406,17 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) core_clk_rate = DEFAULT_CLK_RATE_HZ; core_clk_cycles_per_us = core_clk_rate / USEC_PER_SEC; - ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US); + if (ufshcd_readl(hba, REG_UFS_SYS1CLK_1US) != core_clk_cycles_per_us) { + ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US); + /* + * make sure above write gets applied before we return from + * this function. + */ + mb(); + } + + if (ufs_qcom_cap_qunipro(host)) + goto out; core_clk_period_in_ns = NSEC_PER_SEC / core_clk_rate; core_clk_period_in_ns <<= OFFSET_CLK_NS_REG; @@ -406,35 +466,59 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate) goto out_error; } - /* this register 2 fields shall be written at once */ - ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us, - REG_UFS_TX_SYMBOL_CLK_NS_US); + if (ufshcd_readl(hba, REG_UFS_TX_SYMBOL_CLK_NS_US) != + (core_clk_period_in_ns | tx_clk_cycles_per_us)) { + /* this register 2 fields shall be written at once */ + ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us, + REG_UFS_TX_SYMBOL_CLK_NS_US); + /* + * make sure above write gets applied before we return from + * this function. + */ + mb(); + } + + if (update_link_startup_timer) { + ufshcd_writel(hba, ((core_clk_rate / MSEC_PER_SEC) * 100), + REG_UFS_PA_LINK_STARTUP_TIMER); + /* + * make sure that this configuration is applied before + * we return + */ + mb(); + } goto out; out_error: - core_clk_rate = 0; + ret = -EINVAL; out: - return core_clk_rate; + return ret; } -static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status) +static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) { - unsigned long core_clk_rate = 0; - u32 core_clk_cycles_per_100ms; + int err = 0; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); switch (status) { case PRE_CHANGE: - core_clk_rate = ufs_qcom_cfg_timers(hba, UFS_PWM_G1, - SLOWAUTO_MODE, 0); - if (!core_clk_rate) { + if (ufs_qcom_cfg_timers(hba, UFS_PWM_G1, SLOWAUTO_MODE, + 0, true)) { dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", __func__); - return -EINVAL; + err = -EINVAL; + goto out; } - core_clk_cycles_per_100ms = - (core_clk_rate / MSEC_PER_SEC) * 100; - ufshcd_writel(hba, core_clk_cycles_per_100ms, - REG_UFS_PA_LINK_STARTUP_TIMER); + + if (ufs_qcom_cap_qunipro(host)) + /* + * set unipro core clock cycles to 150 & clear clock + * divider + */ + err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, + 150); + break; case POST_CHANGE: ufs_qcom_link_startup_post_change(hba); @@ -443,12 +527,13 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status) break; } - return 0; +out: + return err; } static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct phy *phy = host->generic_phy; int ret = 0; @@ -470,8 +555,10 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) * If UniPro link is not active, PHY ref_clk, main PHY analog power * rail and low noise analog power rail for PLL can be switched off. */ - if (!ufs_qcom_is_link_active(hba)) + if (!ufs_qcom_is_link_active(hba)) { + ufs_qcom_disable_lane_clks(host); phy_power_off(phy); + } out: return ret; @@ -479,7 +566,7 @@ out: static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct phy *phy = host->generic_phy; int err; @@ -490,6 +577,10 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) goto out; } + err = ufs_qcom_enable_lane_clks(host); + if (err) + goto out; + hba->is_sys_suspended = false; out: @@ -594,6 +685,81 @@ static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param, return 0; } +#ifdef CONFIG_MSM_BUS_SCALING +static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, + const char *speed_mode) +{ + struct device *dev = host->hba->dev; + struct device_node *np = dev->of_node; + int err; + const char *key = "qcom,bus-vector-names"; + + if (!speed_mode) { + err = -EINVAL; + goto out; + } + + if (host->bus_vote.is_max_bw_needed && !!strcmp(speed_mode, "MIN")) + err = of_property_match_string(np, key, "MAX"); + else + err = of_property_match_string(np, key, speed_mode); + +out: + if (err < 0) + dev_err(dev, "%s: Invalid %s mode %d\n", + __func__, speed_mode, err); + return err; +} + +static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result) +{ + int gear = max_t(u32, p->gear_rx, p->gear_tx); + int lanes = max_t(u32, p->lane_rx, p->lane_tx); + int pwr; + + /* default to PWM Gear 1, Lane 1 if power mode is not initialized */ + if (!gear) + gear = 1; + + if (!lanes) + lanes = 1; + + if (!p->pwr_rx && !p->pwr_tx) { + pwr = SLOWAUTO_MODE; + snprintf(result, BUS_VECTOR_NAME_LEN, "MIN"); + } else if (p->pwr_rx == FAST_MODE || p->pwr_rx == FASTAUTO_MODE || + p->pwr_tx == FAST_MODE || p->pwr_tx == FASTAUTO_MODE) { + pwr = FAST_MODE; + snprintf(result, BUS_VECTOR_NAME_LEN, "%s_R%s_G%d_L%d", "HS", + p->hs_rate == PA_HS_MODE_B ? "B" : "A", gear, lanes); + } else { + pwr = SLOW_MODE; + snprintf(result, BUS_VECTOR_NAME_LEN, "%s_G%d_L%d", + "PWM", gear, lanes); + } +} + +static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) +{ + int err = 0; + + if (vote != host->bus_vote.curr_vote) { + err = msm_bus_scale_client_update_request( + host->bus_vote.client_handle, vote); + if (err) { + dev_err(host->hba->dev, + "%s: msm_bus_scale_client_update_request() failed: bus_client_handle=0x%x, vote=%d, err=%d\n", + __func__, host->bus_vote.client_handle, + vote, err); + goto out; + } + + host->bus_vote.curr_vote = vote; + } +out: + return err; +} + static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) { int vote; @@ -615,13 +781,137 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) return err; } +static ssize_t +show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + + return snprintf(buf, PAGE_SIZE, "%u\n", + host->bus_vote.is_max_bw_needed); +} + +static ssize_t +store_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + uint32_t value; + + if (!kstrtou32(buf, 0, &value)) { + host->bus_vote.is_max_bw_needed = !!value; + ufs_qcom_update_bus_bw_vote(host); + } + + return count; +} + +static int ufs_qcom_bus_register(struct ufs_qcom_host *host) +{ + int err; + struct msm_bus_scale_pdata *bus_pdata; + struct device *dev = host->hba->dev; + struct platform_device *pdev = to_platform_device(dev); + struct device_node *np = dev->of_node; + + bus_pdata = msm_bus_cl_get_pdata(pdev); + if (!bus_pdata) { + dev_err(dev, "%s: failed to get bus vectors\n", __func__); + err = -ENODATA; + goto out; + } + + err = of_property_count_strings(np, "qcom,bus-vector-names"); + if (err < 0 || err != bus_pdata->num_usecases) { + dev_err(dev, "%s: qcom,bus-vector-names not specified correctly %d\n", + __func__, err); + goto out; + } + + host->bus_vote.client_handle = msm_bus_scale_register_client(bus_pdata); + if (!host->bus_vote.client_handle) { + dev_err(dev, "%s: msm_bus_scale_register_client failed\n", + __func__); + err = -EFAULT; + goto out; + } + + /* cache the vote index for minimum and maximum bandwidth */ + host->bus_vote.min_bw_vote = ufs_qcom_get_bus_vote(host, "MIN"); + host->bus_vote.max_bw_vote = ufs_qcom_get_bus_vote(host, "MAX"); + + host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw; + host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw; + sysfs_attr_init(&host->bus_vote.max_bus_bw.attr); + host->bus_vote.max_bus_bw.attr.name = "max_bus_bw"; + host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR; + err = device_create_file(dev, &host->bus_vote.max_bus_bw); +out: + return err; +} +#else /* CONFIG_MSM_BUS_SCALING */ +static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) +{ + return 0; +} + +static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) +{ + return 0; +} + +static int ufs_qcom_bus_register(struct ufs_qcom_host *host) +{ + return 0; +} +#endif /* CONFIG_MSM_BUS_SCALING */ + +static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable) +{ + if (host->dev_ref_clk_ctrl_mmio && + (enable ^ host->is_dev_ref_clk_enabled)) { + u32 temp = readl_relaxed(host->dev_ref_clk_ctrl_mmio); + + if (enable) + temp |= host->dev_ref_clk_en_mask; + else + temp &= ~host->dev_ref_clk_en_mask; + + /* + * If we are here to disable this clock it might be immediately + * after entering into hibern8 in which case we need to make + * sure that device ref_clk is active at least 1us after the + * hibern8 enter. + */ + if (!enable) + udelay(1); + + writel_relaxed(temp, host->dev_ref_clk_ctrl_mmio); + + /* ensure that ref_clk is enabled/disabled before we return */ + wmb(); + + /* + * If we call hibern8 exit after this, we need to make sure that + * device ref_clk is stable for at least 1us before the hibern8 + * exit command. + */ + if (enable) + udelay(1); + + host->is_dev_ref_clk_enabled = enable; + } +} + static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, - bool status, + enum ufs_notify_change_status status, struct ufs_pa_layer_attr *dev_max_params, struct ufs_pa_layer_attr *dev_req_params) { u32 val; - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct phy *phy = host->generic_phy; struct ufs_qcom_dev_params ufs_qcom_cap; int ret = 0; @@ -649,6 +939,20 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, ufs_qcom_cap.desired_working_mode = UFS_QCOM_LIMIT_DESIRED_MODE; + if (host->hw_ver.major == 0x1) { + /* + * HS-G3 operations may not reliably work on legacy QCOM + * UFS host controller hardware even though capability + * exchange during link startup phase may end up + * negotiating maximum supported gear as G3. + * Hence downgrade the maximum supported gear to HS-G2. + */ + if (ufs_qcom_cap.hs_tx_gear > UFS_HS_G2) + ufs_qcom_cap.hs_tx_gear = UFS_HS_G2; + if (ufs_qcom_cap.hs_rx_gear > UFS_HS_G2) + ufs_qcom_cap.hs_rx_gear = UFS_HS_G2; + } + ret = ufs_qcom_get_pwr_dev_param(&ufs_qcom_cap, dev_max_params, dev_req_params); @@ -660,9 +964,9 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, break; case POST_CHANGE: - if (!ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, + if (ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, dev_req_params->pwr_rx, - dev_req_params->hs_rate)) { + dev_req_params->hs_rate, false)) { dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n", __func__); /* @@ -696,7 +1000,7 @@ out: static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); if (host->hw_ver.major == 0x1) return UFSHCI_VERSION_11; @@ -715,7 +1019,7 @@ static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba) */ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); if (host->hw_ver.major == 0x01) { hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS @@ -724,10 +1028,11 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) if (host->hw_ver.minor == 0x0001 && host->hw_ver.step == 0x0001) hba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR; + + hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC; } if (host->hw_ver.major >= 0x2) { - hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC; hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION; if (!ufs_qcom_cap_qunipro(host)) @@ -740,79 +1045,29 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) static void ufs_qcom_set_caps(struct ufs_hba *hba) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); - if (host->hw_ver.major >= 0x2) - host->caps = UFS_QCOM_CAP_QUNIPRO; -} - -static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, - const char *speed_mode) -{ - struct device *dev = host->hba->dev; - struct device_node *np = dev->of_node; - int err; - const char *key = "qcom,bus-vector-names"; - - if (!speed_mode) { - err = -EINVAL; - goto out; - } - - if (host->bus_vote.is_max_bw_needed && !!strcmp(speed_mode, "MIN")) - err = of_property_match_string(np, key, "MAX"); - else - err = of_property_match_string(np, key, speed_mode); - -out: - if (err < 0) - dev_err(dev, "%s: Invalid %s mode %d\n", - __func__, speed_mode, err); - return err; -} - -static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) -{ - int err = 0; - - if (vote != host->bus_vote.curr_vote) - host->bus_vote.curr_vote = vote; - - return err; -} - -static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result) -{ - int gear = max_t(u32, p->gear_rx, p->gear_tx); - int lanes = max_t(u32, p->lane_rx, p->lane_tx); - int pwr; - - /* default to PWM Gear 1, Lane 1 if power mode is not initialized */ - if (!gear) - gear = 1; - - if (!lanes) - lanes = 1; + hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_HIBERN8_WITH_CLK_GATING; + hba->caps |= UFSHCD_CAP_CLK_SCALING; + hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; - if (!p->pwr_rx && !p->pwr_tx) { - pwr = SLOWAUTO_MODE; - snprintf(result, BUS_VECTOR_NAME_LEN, "MIN"); - } else if (p->pwr_rx == FAST_MODE || p->pwr_rx == FASTAUTO_MODE || - p->pwr_tx == FAST_MODE || p->pwr_tx == FASTAUTO_MODE) { - pwr = FAST_MODE; - snprintf(result, BUS_VECTOR_NAME_LEN, "%s_R%s_G%d_L%d", "HS", - p->hs_rate == PA_HS_MODE_B ? "B" : "A", gear, lanes); - } else { - pwr = SLOW_MODE; - snprintf(result, BUS_VECTOR_NAME_LEN, "%s_G%d_L%d", - "PWM", gear, lanes); + if (host->hw_ver.major >= 0x2) { + host->caps = UFS_QCOM_CAP_QUNIPRO | + UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE; } } +/** + * ufs_qcom_setup_clocks - enables/disable clocks + * @hba: host controller instance + * @on: If true, enable clocks else disable them. + * + * Returns 0 on success, non-zero on failure. + */ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on) { - struct ufs_qcom_host *host = hba->priv; - int err = 0; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + int err; int vote = 0; /* @@ -835,20 +1090,18 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on) ufs_qcom_phy_disable_iface_clk(host->generic_phy); goto out; } - /* enable the device ref clock */ - ufs_qcom_phy_enable_dev_ref_clk(host->generic_phy); vote = host->bus_vote.saved_vote; if (vote == host->bus_vote.min_bw_vote) ufs_qcom_update_bus_bw_vote(host); + } else { + /* M-PHY RMMI interface clocks can be turned off */ ufs_qcom_phy_disable_iface_clk(host->generic_phy); - if (!ufs_qcom_is_link_active(hba)) { - /* turn off UFS local PHY ref_clk */ - ufs_qcom_phy_disable_ref_clk(host->generic_phy); + if (!ufs_qcom_is_link_active(hba)) /* disable device ref_clk */ - ufs_qcom_phy_disable_dev_ref_clk(host->generic_phy); - } + ufs_qcom_dev_ref_clk_ctrl(host, false); + vote = host->bus_vote.min_bw_vote; } @@ -861,68 +1114,17 @@ out: return err; } -static ssize_t -show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ufs_hba *hba = dev_get_drvdata(dev); - struct ufs_qcom_host *host = hba->priv; - - return snprintf(buf, PAGE_SIZE, "%u\n", - host->bus_vote.is_max_bw_needed); -} - -static ssize_t -store_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ufs_hba *hba = dev_get_drvdata(dev); - struct ufs_qcom_host *host = hba->priv; - uint32_t value; - - if (!kstrtou32(buf, 0, &value)) { - host->bus_vote.is_max_bw_needed = !!value; - ufs_qcom_update_bus_bw_vote(host); - } - - return count; -} - -static int ufs_qcom_bus_register(struct ufs_qcom_host *host) -{ - int err; - struct device *dev = host->hba->dev; - struct device_node *np = dev->of_node; - - err = of_property_count_strings(np, "qcom,bus-vector-names"); - if (err < 0 ) { - dev_err(dev, "%s: qcom,bus-vector-names not specified correctly %d\n", - __func__, err); - goto out; - } - - /* cache the vote index for minimum and maximum bandwidth */ - host->bus_vote.min_bw_vote = ufs_qcom_get_bus_vote(host, "MIN"); - host->bus_vote.max_bw_vote = ufs_qcom_get_bus_vote(host, "MAX"); - - host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw; - host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw; - sysfs_attr_init(&host->bus_vote.max_bus_bw.attr); - host->bus_vote.max_bus_bw.attr.name = "max_bus_bw"; - host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR; - err = device_create_file(dev, &host->bus_vote.max_bus_bw); -out: - return err; -} - #define ANDROID_BOOT_DEV_MAX 30 static char android_boot_dev[ANDROID_BOOT_DEV_MAX]; -static int get_android_boot_dev(char *str) + +#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 @@ -938,7 +1140,9 @@ static int ufs_qcom_init(struct ufs_hba *hba) { int err; struct device *dev = hba->dev; + struct platform_device *pdev = to_platform_device(dev); struct ufs_qcom_host *host; + struct resource *res; if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev))) return -ENODEV; @@ -950,9 +1154,15 @@ static int ufs_qcom_init(struct ufs_hba *hba) goto out; } + /* Make a two way bind between the qcom host and the hba */ host->hba = hba; - hba->priv = (void *)host; + ufshcd_set_variant(hba, host); + /* + * 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 (IS_ERR(host->generic_phy)) { @@ -968,6 +1178,30 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_get_controller_revision(hba, &host->hw_ver.major, &host->hw_ver.minor, &host->hw_ver.step); + /* + * for newer controllers, device reference clock control bit has + * moved inside UFS controller register address space itself. + */ + if (host->hw_ver.major >= 0x02) { + host->dev_ref_clk_ctrl_mmio = hba->mmio_base + REG_UFS_CFG1; + host->dev_ref_clk_en_mask = BIT(26); + } else { + /* "dev_ref_clk_ctrl_mem" is optional resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) { + host->dev_ref_clk_ctrl_mmio = + devm_ioremap_resource(dev, res); + if (IS_ERR(host->dev_ref_clk_ctrl_mmio)) { + dev_warn(dev, + "%s: could not map dev_ref_clk_ctrl_mmio, err %ld\n", + __func__, + PTR_ERR(host->dev_ref_clk_ctrl_mmio)); + host->dev_ref_clk_ctrl_mmio = NULL; + } + host->dev_ref_clk_en_mask = BIT(5); + } + } + /* update phy revision information before calling phy_init() */ ufs_qcom_phy_save_controller_version(host->generic_phy, host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step); @@ -984,14 +1218,20 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_set_caps(hba); ufs_qcom_advertise_quirks(hba); - hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_CLK_SCALING; - hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; - ufs_qcom_setup_clocks(hba, true); if (hba->dev->id < MAX_UFS_QCOM_HOSTS) ufs_qcom_hosts[hba->dev->id] = host; + host->dbg_print_en |= UFS_QCOM_DEFAULT_DBG_PRINT_EN; + ufs_qcom_get_default_testbus_cfg(host); + err = ufs_qcom_testbus_config(host); + if (err) { + dev_warn(dev, "%s: failed to configure the testbus %d\n", + __func__, err); + err = 0; + } + goto out; out_disable_phy: @@ -1000,40 +1240,266 @@ out_unregister_bus: phy_exit(host->generic_phy); out_host_free: devm_kfree(dev, host); - hba->priv = NULL; + ufshcd_set_variant(hba, NULL); out: return err; } static void ufs_qcom_exit(struct ufs_hba *hba) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); ufs_qcom_disable_lane_clks(host); phy_power_off(host->generic_phy); } -static -void ufs_qcom_clk_scale_notify(struct ufs_hba *hba) +static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, + u32 clk_cycles) +{ + int err; + u32 core_clk_ctrl_reg; + + if (clk_cycles > DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK) + return -EINVAL; + + err = ufshcd_dme_get(hba, + UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), + &core_clk_ctrl_reg); + if (err) + goto out; + + core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK; + core_clk_ctrl_reg |= clk_cycles; + + /* Clear CORE_CLK_DIV_EN */ + core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT; + + err = ufshcd_dme_set(hba, + UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), + core_clk_ctrl_reg); +out: + return err; +} + +static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba) +{ + /* nothing to do as of now */ + return 0; +} + +static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + + if (!ufs_qcom_cap_qunipro(host)) + return 0; + + /* set unipro core clock cycles to 150 and clear clock divider */ + return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150); +} + +static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + int err; + u32 core_clk_ctrl_reg; + + if (!ufs_qcom_cap_qunipro(host)) + return 0; + + err = ufshcd_dme_get(hba, + UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), + &core_clk_ctrl_reg); + + /* make sure CORE_CLK_DIV_EN is cleared */ + if (!err && + (core_clk_ctrl_reg & DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT)) { + core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT; + err = ufshcd_dme_set(hba, + UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), + core_clk_ctrl_reg); + } + + return err; +} + +static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba) +{ + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + + if (!ufs_qcom_cap_qunipro(host)) + return 0; + + /* set unipro core clock cycles to 75 and clear clock divider */ + return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 75); +} + +static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, + bool scale_up, enum ufs_notify_change_status status) { - struct ufs_qcom_host *host = hba->priv; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params; + int err = 0; - if (!dev_req_params) - return; + if (status == PRE_CHANGE) { + if (scale_up) + err = ufs_qcom_clk_scale_up_pre_change(hba); + else + err = ufs_qcom_clk_scale_down_pre_change(hba); + } else { + if (scale_up) + err = ufs_qcom_clk_scale_up_post_change(hba); + else + err = ufs_qcom_clk_scale_down_post_change(hba); - ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx, - dev_req_params->pwr_rx, - dev_req_params->hs_rate); + if (err || !dev_req_params) + goto out; + + ufs_qcom_cfg_timers(hba, + dev_req_params->gear_rx, + dev_req_params->pwr_rx, + dev_req_params->hs_rate, + false); + ufs_qcom_update_bus_bw_vote(host); + } + +out: + return err; } +static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host) +{ + /* provide a legal default configuration */ + host->testbus.select_major = TSTBUS_UAWM; + host->testbus.select_minor = 1; +} + +static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host) +{ + if (host->testbus.select_major >= TSTBUS_MAX) { + dev_err(host->hba->dev, + "%s: UFS_CFG1[TEST_BUS_SEL} may not equal 0x%05X\n", + __func__, host->testbus.select_major); + return false; + } + + /* + * Not performing check for each individual select_major + * mappings of select_minor, since there is no harm in + * configuring a non-existent select_minor + */ + if (host->testbus.select_minor > 0x1F) { + dev_err(host->hba->dev, + "%s: 0x%05X is not a legal testbus option\n", + __func__, host->testbus.select_minor); + return false; + } + + return true; +} + +int ufs_qcom_testbus_config(struct ufs_qcom_host *host) +{ + int reg; + int offset; + u32 mask = TEST_BUS_SUB_SEL_MASK; + + if (!host) + return -EINVAL; + + if (!ufs_qcom_testbus_cfg_is_ok(host)) + return -EPERM; + + switch (host->testbus.select_major) { + case TSTBUS_UAWM: + reg = UFS_TEST_BUS_CTRL_0; + offset = 24; + break; + case TSTBUS_UARM: + reg = UFS_TEST_BUS_CTRL_0; + offset = 16; + break; + case TSTBUS_TXUC: + reg = UFS_TEST_BUS_CTRL_0; + offset = 8; + break; + case TSTBUS_RXUC: + reg = UFS_TEST_BUS_CTRL_0; + offset = 0; + break; + case TSTBUS_DFC: + reg = UFS_TEST_BUS_CTRL_1; + offset = 24; + break; + case TSTBUS_TRLUT: + reg = UFS_TEST_BUS_CTRL_1; + offset = 16; + break; + case TSTBUS_TMRLUT: + reg = UFS_TEST_BUS_CTRL_1; + offset = 8; + break; + case TSTBUS_OCSC: + reg = UFS_TEST_BUS_CTRL_1; + offset = 0; + break; + case TSTBUS_WRAPPER: + reg = UFS_TEST_BUS_CTRL_2; + offset = 16; + break; + case TSTBUS_COMBINED: + reg = UFS_TEST_BUS_CTRL_2; + offset = 8; + break; + case TSTBUS_UTP_HCI: + reg = UFS_TEST_BUS_CTRL_2; + offset = 0; + break; + case TSTBUS_UNIPRO: + reg = UFS_UNIPRO_CFG; + offset = 1; + break; + /* + * No need for a default case, since + * ufs_qcom_testbus_cfg_is_ok() checks that the configuration + * is legal + */ + } + mask <<= offset; + + pm_runtime_get_sync(host->hba->dev); + ufshcd_hold(host->hba, false); + ufshcd_rmwl(host->hba, TEST_BUS_SEL, + (u32)host->testbus.select_major << 19, + REG_UFS_CFG1); + ufshcd_rmwl(host->hba, mask, + (u32)host->testbus.select_minor << offset, + reg); + ufshcd_release(host->hba); + pm_runtime_put_sync(host->hba->dev); + + return 0; +} + +static void ufs_qcom_testbus_read(struct ufs_hba *hba) +{ + ufs_qcom_dump_regs(hba, UFS_TEST_BUS, 1, "UFS_TEST_BUS "); +} + +static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba) +{ + ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16, + "HCI Vendor Specific Registers "); + + ufs_qcom_testbus_read(hba); +} /** * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations * * The variant operations configure the necessary controller and PHY * handshake during initialization. */ -static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { +static struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .name = "qcom", .init = ufs_qcom_init, .exit = ufs_qcom_exit, @@ -1045,5 +1511,66 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .pwr_change_notify = ufs_qcom_pwr_change_notify, .suspend = ufs_qcom_suspend, .resume = ufs_qcom_resume, + .dbg_register_dump = ufs_qcom_dump_dbg_regs, +}; + +/** + * ufs_qcom_probe - probe routine of the driver + * @pdev: pointer to Platform device handle + * + * Return zero for success and non-zero for failure + */ +static int ufs_qcom_probe(struct platform_device *pdev) +{ + int err; + struct device *dev = &pdev->dev; + + /* Perform generic probe */ + err = ufshcd_pltfrm_init(pdev, &ufs_hba_qcom_vops); + if (err) + dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err); + + return err; +} + +/** + * ufs_qcom_remove - set driver_data of the device to NULL + * @pdev: pointer to platform device handle + * + * Always return 0 + */ +static int ufs_qcom_remove(struct platform_device *pdev) +{ + struct ufs_hba *hba = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&(pdev)->dev); + ufshcd_remove(hba); + return 0; +} + +static const struct of_device_id ufs_qcom_of_match[] = { + { .compatible = "qcom,ufshc"}, + {}, +}; + +static const struct dev_pm_ops ufs_qcom_pm_ops = { + .suspend = ufshcd_pltfrm_suspend, + .resume = ufshcd_pltfrm_resume, + .runtime_suspend = ufshcd_pltfrm_runtime_suspend, + .runtime_resume = ufshcd_pltfrm_runtime_resume, + .runtime_idle = ufshcd_pltfrm_runtime_idle, }; -EXPORT_SYMBOL(ufs_hba_qcom_vops); + +static struct platform_driver ufs_qcom_pltform = { + .probe = ufs_qcom_probe, + .remove = ufs_qcom_remove, + .shutdown = ufshcd_pltfrm_shutdown, + .driver = { + .name = "ufshcd-qcom", + .pm = &ufs_qcom_pm_ops, + .of_match_table = of_match_ptr(ufs_qcom_of_match), + }, +}; +module_platform_driver(ufs_qcom_pltform); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index db2c0a00e..36249b35f 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -35,8 +35,8 @@ #define UFS_QCOM_LIMIT_NUM_LANES_RX 2 #define UFS_QCOM_LIMIT_NUM_LANES_TX 2 -#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G2 -#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G2 +#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G3 +#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G3 #define UFS_QCOM_LIMIT_PWMGEAR_RX UFS_PWM_G4 #define UFS_QCOM_LIMIT_PWMGEAR_TX UFS_PWM_G4 #define UFS_QCOM_LIMIT_RX_PWR_PWM SLOW_MODE @@ -58,6 +58,21 @@ enum { REG_UFS_CFG2 = 0xE0, REG_UFS_HW_VERSION = 0xE4, + UFS_TEST_BUS = 0xE8, + UFS_TEST_BUS_CTRL_0 = 0xEC, + UFS_TEST_BUS_CTRL_1 = 0xF0, + UFS_TEST_BUS_CTRL_2 = 0xF4, + UFS_UNIPRO_CFG = 0xF8, + + /* + * QCOM UFS host controller vendor specific registers + * added in HW Version 3.0.0 + */ + UFS_AH8_CFG = 0xFC, +}; + +/* QCOM UFS host controller vendor specific debug registers */ +enum { UFS_DBG_RD_REG_UAWM = 0x100, UFS_DBG_RD_REG_UARM = 0x200, UFS_DBG_RD_REG_TXUC = 0x300, @@ -73,6 +88,14 @@ enum { UFS_UFS_DBG_RD_EDTL_RAM = 0x1900, }; +#define UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(x) (0x000 + x) +#define UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(x) (0x400 + x) + +/* bit definitions for REG_UFS_CFG1 register */ +#define QUNIPRO_SEL UFS_BIT(0) +#define TEST_BUS_EN BIT(18) +#define TEST_BUS_SEL GENMASK(22, 19) + /* bit definitions for REG_UFS_CFG2 register */ #define UAWM_HW_CGC_EN (1 << 0) #define UARM_HW_CGC_EN (1 << 1) @@ -83,6 +106,9 @@ enum { #define TMRLUT_HW_CGC_EN (1 << 6) #define OCSC_HW_CGC_EN (1 << 7) +/* bit definition for UFS_UFS_TEST_BUS_CTRL_n */ +#define TEST_BUS_SUB_SEL_MASK 0x1F /* All XXX_SEL fields are 5 bits wide */ + #define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\ TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\ DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\ @@ -106,6 +132,21 @@ enum ufs_qcom_phy_init_type { UFS_PHY_INIT_CFG_RESTORE, }; +/* QCOM UFS debug print bit mask */ +#define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0) +#define UFS_QCOM_DBG_PRINT_ICE_REGS_EN BIT(1) +#define UFS_QCOM_DBG_PRINT_TEST_BUS_EN BIT(2) + +#define UFS_QCOM_DBG_PRINT_ALL \ + (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_ICE_REGS_EN | \ + UFS_QCOM_DBG_PRINT_TEST_BUS_EN) + +/* QUniPro Vendor specific attributes */ +#define DME_VS_CORE_CLK_CTRL 0xD002 +/* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */ +#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) +#define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK 0xFF + static inline void ufs_qcom_get_controller_revision(struct ufs_hba *hba, u8 *major, u16 *minor, u16 *step) @@ -157,8 +198,13 @@ struct ufs_hw_version { u16 minor; u8 major; }; -struct ufs_qcom_host { +struct ufs_qcom_testbus { + u8 select_major; + u8 select_minor; +}; + +struct ufs_qcom_host { /* * Set this capability if host controller supports the QUniPro mode * and if driver wants the Host controller to operate in QUniPro mode. @@ -166,6 +212,12 @@ struct ufs_qcom_host { * controller supports the QUniPro mode. */ #define UFS_QCOM_CAP_QUNIPRO UFS_BIT(0) + + /* + * Set this capability if host controller can retain the secure + * configuration even after UFS controller core power collapse. + */ + #define UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE UFS_BIT(1) u32 caps; struct phy *generic_phy; @@ -178,13 +230,23 @@ struct ufs_qcom_host { struct clk *tx_l1_sync_clk; bool is_lane_clks_enabled; + void __iomem *dev_ref_clk_ctrl_mmio; + bool is_dev_ref_clk_enabled; struct ufs_hw_version hw_ver; + + u32 dev_ref_clk_en_mask; + + /* Bitmask for enabling debug prints */ + u32 dbg_print_en; + struct ufs_qcom_testbus testbus; }; #define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba) #define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba) #define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba) +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) diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index 7db9564f5..9714f2a8b 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -38,20 +38,7 @@ #include #include "ufshcd.h" - -static const struct of_device_id ufs_of_match[]; -static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev) -{ - if (dev->of_node) { - const struct of_device_id *match; - - match = of_match_node(ufs_of_match, dev->of_node); - if (match) - return (struct ufs_hba_variant_ops *)match->data; - } - - return NULL; -} +#include "ufshcd-pltfrm.h" static int ufshcd_parse_clock_info(struct ufs_hba *hba) { @@ -245,10 +232,11 @@ out: * Returns 0 if successful * Returns non-zero otherwise */ -static int ufshcd_pltfrm_suspend(struct device *dev) +int ufshcd_pltfrm_suspend(struct device *dev) { return ufshcd_system_suspend(dev_get_drvdata(dev)); } +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_suspend); /** * ufshcd_pltfrm_resume - resume power management function @@ -257,43 +245,47 @@ static int ufshcd_pltfrm_suspend(struct device *dev) * Returns 0 if successful * Returns non-zero otherwise */ -static int ufshcd_pltfrm_resume(struct device *dev) +int ufshcd_pltfrm_resume(struct device *dev) { return ufshcd_system_resume(dev_get_drvdata(dev)); } +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_resume); -static int ufshcd_pltfrm_runtime_suspend(struct device *dev) +int ufshcd_pltfrm_runtime_suspend(struct device *dev) { return ufshcd_runtime_suspend(dev_get_drvdata(dev)); } -static int ufshcd_pltfrm_runtime_resume(struct device *dev) +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_suspend); + +int ufshcd_pltfrm_runtime_resume(struct device *dev) { return ufshcd_runtime_resume(dev_get_drvdata(dev)); } -static int ufshcd_pltfrm_runtime_idle(struct device *dev) +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_resume); + +int ufshcd_pltfrm_runtime_idle(struct device *dev) { return ufshcd_runtime_idle(dev_get_drvdata(dev)); } -#else /* !CONFIG_PM */ -#define ufshcd_pltfrm_suspend NULL -#define ufshcd_pltfrm_resume NULL -#define ufshcd_pltfrm_runtime_suspend NULL -#define ufshcd_pltfrm_runtime_resume NULL -#define ufshcd_pltfrm_runtime_idle NULL +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_idle); + #endif /* CONFIG_PM */ -static void ufshcd_pltfrm_shutdown(struct platform_device *pdev) +void ufshcd_pltfrm_shutdown(struct platform_device *pdev) { ufshcd_shutdown((struct ufs_hba *)platform_get_drvdata(pdev)); } +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_shutdown); /** - * ufshcd_pltfrm_probe - probe routine of the driver + * ufshcd_pltfrm_init - probe routine of the driver * @pdev: pointer to Platform device handle + * @vops: pointer to variant ops * * Returns 0 on success, non-zero value on failure */ -static int ufshcd_pltfrm_probe(struct platform_device *pdev) +int ufshcd_pltfrm_init(struct platform_device *pdev, + struct ufs_hba_variant_ops *vops) { struct ufs_hba *hba; void __iomem *mmio_base; @@ -321,19 +313,19 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev) goto out; } - hba->vops = get_variant_ops(&pdev->dev); + hba->vops = vops; err = ufshcd_parse_clock_info(hba); if (err) { dev_err(&pdev->dev, "%s: clock parse failed %d\n", __func__, err); - goto out; + goto dealloc_host; } err = ufshcd_parse_regulator_info(hba); if (err) { dev_err(&pdev->dev, "%s: regulator init failed %d\n", __func__, err); - goto out; + goto dealloc_host; } pm_runtime_set_active(&pdev->dev); @@ -352,50 +344,12 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev) out_disable_rpm: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); +dealloc_host: + ufshcd_dealloc_host(hba); out: return err; } - -/** - * ufshcd_pltfrm_remove - remove platform driver routine - * @pdev: pointer to platform device handle - * - * Returns 0 on success, non-zero value on failure - */ -static int ufshcd_pltfrm_remove(struct platform_device *pdev) -{ - struct ufs_hba *hba = platform_get_drvdata(pdev); - - pm_runtime_get_sync(&(pdev)->dev); - ufshcd_remove(hba); - return 0; -} - -static const struct of_device_id ufs_of_match[] = { - { .compatible = "jedec,ufs-1.1"}, - {}, -}; - -static const struct dev_pm_ops ufshcd_dev_pm_ops = { - .suspend = ufshcd_pltfrm_suspend, - .resume = ufshcd_pltfrm_resume, - .runtime_suspend = ufshcd_pltfrm_runtime_suspend, - .runtime_resume = ufshcd_pltfrm_runtime_resume, - .runtime_idle = ufshcd_pltfrm_runtime_idle, -}; - -static struct platform_driver ufshcd_pltfrm_driver = { - .probe = ufshcd_pltfrm_probe, - .remove = ufshcd_pltfrm_remove, - .shutdown = ufshcd_pltfrm_shutdown, - .driver = { - .name = "ufshcd", - .pm = &ufshcd_dev_pm_ops, - .of_match_table = ufs_of_match, - }, -}; - -module_platform_driver(ufshcd_pltfrm_driver); +EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init); MODULE_AUTHOR("Santosh Yaragnavi "); MODULE_AUTHOR("Vinayak Holikatti "); diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.h b/drivers/scsi/ufs/ufshcd-pltfrm.h new file mode 100644 index 000000000..df64c4180 --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-pltfrm.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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. + * + */ + +#ifndef UFSHCD_PLTFRM_H_ +#define UFSHCD_PLTFRM_H_ + +#include "ufshcd.h" + +int ufshcd_pltfrm_init(struct platform_device *pdev, + struct ufs_hba_variant_ops *vops); +void ufshcd_pltfrm_shutdown(struct platform_device *pdev); + +#ifdef CONFIG_PM + +int ufshcd_pltfrm_suspend(struct device *dev); +int ufshcd_pltfrm_resume(struct device *dev); +int ufshcd_pltfrm_runtime_suspend(struct device *dev); +int ufshcd_pltfrm_runtime_resume(struct device *dev); +int ufshcd_pltfrm_runtime_idle(struct device *dev); + +#else /* !CONFIG_PM */ + +#define ufshcd_pltfrm_suspend NULL +#define ufshcd_pltfrm_resume NULL +#define ufshcd_pltfrm_runtime_suspend NULL +#define ufshcd_pltfrm_runtime_resume NULL +#define ufshcd_pltfrm_runtime_idle NULL + +#endif /* CONFIG_PM */ + +#endif /* UFSHCD_PLTFRM_H_ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index b0ade73f8..85cd2564c 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -271,10 +271,8 @@ static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) */ static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba) { - if (hba->quirks & UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION) { - if (hba->vops && hba->vops->get_ufs_hci_version) - return hba->vops->get_ufs_hci_version(hba); - } + if (hba->quirks & UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION) + return ufshcd_vops_get_ufs_hci_version(hba); return ufshcd_readl(hba, REG_UFS_VERSION); } @@ -627,6 +625,7 @@ start: out: return rc; } +EXPORT_SYMBOL_GPL(ufshcd_hold); static void ufshcd_gate_work(struct work_struct *work) { @@ -714,6 +713,7 @@ void ufshcd_release(struct ufs_hba *hba) __ufshcd_release(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); } +EXPORT_SYMBOL_GPL(ufshcd_release); static ssize_t ufshcd_clkgate_delay_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -2473,9 +2473,8 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba, dev_err(hba->dev, "%s: power mode change failed %d\n", __func__, ret); } else { - if (hba->vops && hba->vops->pwr_change_notify) - hba->vops->pwr_change_notify(hba, - POST_CHANGE, NULL, pwr_mode); + ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL, + pwr_mode); memcpy(&hba->pwr_info, pwr_mode, sizeof(struct ufs_pa_layer_attr)); @@ -2495,10 +2494,10 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr final_params = { 0 }; int ret; - if (hba->vops && hba->vops->pwr_change_notify) - hba->vops->pwr_change_notify(hba, - PRE_CHANGE, desired_pwr_mode, &final_params); - else + ret = ufshcd_vops_pwr_change_notify(hba, PRE_CHANGE, + desired_pwr_mode, &final_params); + + if (ret) memcpy(&final_params, desired_pwr_mode, sizeof(final_params)); ret = ufshcd_change_power_mode(hba, &final_params); @@ -2647,8 +2646,7 @@ static int ufshcd_hba_enable(struct ufs_hba *hba) /* UniPro link is disabled at this point */ ufshcd_set_link_off(hba); - if (hba->vops && hba->vops->hce_enable_notify) - hba->vops->hce_enable_notify(hba, PRE_CHANGE); + ufshcd_vops_hce_enable_notify(hba, PRE_CHANGE); /* start controller initialization sequence */ ufshcd_hba_start(hba); @@ -2681,8 +2679,7 @@ static int ufshcd_hba_enable(struct ufs_hba *hba) /* enable UIC related interrupts */ ufshcd_enable_intr(hba, UFSHCD_UIC_MASK); - if (hba->vops && hba->vops->hce_enable_notify) - hba->vops->hce_enable_notify(hba, POST_CHANGE); + ufshcd_vops_hce_enable_notify(hba, POST_CHANGE); return 0; } @@ -2735,8 +2732,7 @@ static int ufshcd_link_startup(struct ufs_hba *hba) int retries = DME_LINKSTARTUP_RETRIES; do { - if (hba->vops && hba->vops->link_startup_notify) - hba->vops->link_startup_notify(hba, PRE_CHANGE); + ufshcd_vops_link_startup_notify(hba, PRE_CHANGE); ret = ufshcd_dme_link_startup(hba); @@ -2767,11 +2763,9 @@ static int ufshcd_link_startup(struct ufs_hba *hba) } /* Include any host controller configuration via UIC commands */ - if (hba->vops && hba->vops->link_startup_notify) { - ret = hba->vops->link_startup_notify(hba, POST_CHANGE); - if (ret) - goto out; - } + ret = ufshcd_vops_link_startup_notify(hba, POST_CHANGE); + if (ret) + goto out; ret = ufshcd_make_hba_operational(hba); out: @@ -4355,7 +4349,6 @@ static struct scsi_host_template ufshcd_driver_template = { .cmd_per_lun = UFSHCD_CMD_PER_LUN, .can_queue = UFSHCD_CAN_QUEUE, .max_host_blocked = 1, - .use_blk_tags = 1, .track_queue_depth = 1, }; @@ -4578,8 +4571,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on, } } - if (hba->vops && hba->vops->setup_clocks) - ret = hba->vops->setup_clocks(hba, on); + ret = ufshcd_vops_setup_clocks(hba, on); out: if (ret) { list_for_each_entry(clki, head, list) { @@ -4645,27 +4637,22 @@ static int ufshcd_variant_hba_init(struct ufs_hba *hba) if (!hba->vops) goto out; - if (hba->vops->init) { - err = hba->vops->init(hba); - if (err) - goto out; - } + err = ufshcd_vops_init(hba); + if (err) + goto out; - if (hba->vops->setup_regulators) { - err = hba->vops->setup_regulators(hba, true); - if (err) - goto out_exit; - } + err = ufshcd_vops_setup_regulators(hba, true); + if (err) + goto out_exit; goto out; out_exit: - if (hba->vops->exit) - hba->vops->exit(hba); + ufshcd_vops_exit(hba); out: if (err) dev_err(hba->dev, "%s: variant %s init failed err %d\n", - __func__, hba->vops ? hba->vops->name : "", err); + __func__, ufshcd_get_var_name(hba), err); return err; } @@ -4674,14 +4661,11 @@ static void ufshcd_variant_hba_exit(struct ufs_hba *hba) if (!hba->vops) return; - if (hba->vops->setup_clocks) - hba->vops->setup_clocks(hba, false); + ufshcd_vops_setup_clocks(hba, false); - if (hba->vops->setup_regulators) - hba->vops->setup_regulators(hba, false); + ufshcd_vops_setup_regulators(hba, false); - if (hba->vops->exit) - hba->vops->exit(hba); + ufshcd_vops_exit(hba); } static int ufshcd_hba_init(struct ufs_hba *hba) @@ -5058,17 +5042,13 @@ disable_clks: * vendor specific host controller register space call them before the * host clocks are ON. */ - if (hba->vops && hba->vops->suspend) { - ret = hba->vops->suspend(hba, pm_op); - if (ret) - goto set_link_active; - } + ret = ufshcd_vops_suspend(hba, pm_op); + if (ret) + goto set_link_active; - if (hba->vops && hba->vops->setup_clocks) { - ret = hba->vops->setup_clocks(hba, false); - if (ret) - goto vops_resume; - } + ret = ufshcd_vops_setup_clocks(hba, false); + if (ret) + goto vops_resume; if (!ufshcd_is_link_active(hba)) ufshcd_setup_clocks(hba, false); @@ -5079,7 +5059,7 @@ disable_clks: hba->clk_gating.state = CLKS_OFF; /* * Disable the host irq as host controller as there won't be any - * host controller trasanction expected till resume. + * host controller transaction expected till resume. */ ufshcd_disable_irq(hba); /* Put the host controller in low power mode if possible */ @@ -5087,8 +5067,7 @@ disable_clks: goto out; vops_resume: - if (hba->vops && hba->vops->resume) - hba->vops->resume(hba, pm_op); + ufshcd_vops_resume(hba, pm_op); set_link_active: ufshcd_vreg_set_hpm(hba); if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba)) @@ -5144,11 +5123,9 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) * vendor specific host controller register space call them when the * host clocks are ON. */ - if (hba->vops && hba->vops->resume) { - ret = hba->vops->resume(hba, pm_op); - if (ret) - goto disable_vreg; - } + ret = ufshcd_vops_resume(hba, pm_op); + if (ret) + goto disable_vreg; if (ufshcd_is_link_hibern8(hba)) { ret = ufshcd_uic_hibern8_exit(hba); @@ -5189,8 +5166,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) set_old_link_state: ufshcd_link_state_transition(hba, old_link_state, 0); vendor_suspend: - if (hba->vops && hba->vops->suspend) - hba->vops->suspend(hba, pm_op); + ufshcd_vops_suspend(hba, pm_op); disable_vreg: ufshcd_vreg_set_lpm(hba); disable_irq_and_vops_clks: @@ -5372,6 +5348,16 @@ void ufshcd_remove(struct ufs_hba *hba) } EXPORT_SYMBOL_GPL(ufshcd_remove); +/** + * ufshcd_dealloc_host - deallocate Host Bus Adapter (HBA) + * @hba: pointer to Host Bus Adapter (HBA) + */ +void ufshcd_dealloc_host(struct ufs_hba *hba) +{ + scsi_host_put(hba->host); +} +EXPORT_SYMBOL_GPL(ufshcd_dealloc_host); + /** * ufshcd_set_dma_mask - Set dma mask based on the controller * addressing capability @@ -5433,6 +5419,10 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) if (!head || list_empty(head)) goto out; + ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE); + if (ret) + return ret; + list_for_each_entry(clki, head, list) { if (!IS_ERR_OR_NULL(clki->clk)) { if (scale_up && clki->max_freq) { @@ -5463,8 +5453,9 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up) dev_dbg(hba->dev, "%s: clk: %s, rate: %lu\n", __func__, clki->name, clk_get_rate(clki->clk)); } - if (hba->vops->clk_scale_notify) - hba->vops->clk_scale_notify(hba); + + ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE); + out: return ret; } @@ -5619,13 +5610,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) hba->is_irq_enabled = true; } - /* Enable SCSI tag mapping */ - err = scsi_init_shared_tag_map(host, host->can_queue); - if (err) { - dev_err(hba->dev, "init shared queue failed\n"); - goto exit_gating; - } - err = scsi_add_host(host, hba->dev); if (err) { dev_err(hba->dev, "scsi_add_host failed\n"); diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index c40a0e78a..2570d9477 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -223,8 +223,10 @@ struct ufs_clk_info { bool enabled; }; -#define PRE_CHANGE 0 -#define POST_CHANGE 1 +enum ufs_notify_change_status { + PRE_CHANGE, + POST_CHANGE, +}; struct ufs_pa_layer_attr { u32 gear_rx; @@ -259,22 +261,28 @@ struct ufs_pwr_mode_info { * to be set. * @suspend: called during host controller PM callback * @resume: called during host controller PM callback + * @dbg_register_dump: used to dump controller debug information */ struct ufs_hba_variant_ops { const char *name; int (*init)(struct ufs_hba *); void (*exit)(struct ufs_hba *); u32 (*get_ufs_hci_version)(struct ufs_hba *); - void (*clk_scale_notify)(struct ufs_hba *); - int (*setup_clocks)(struct ufs_hba *, bool); + int (*clk_scale_notify)(struct ufs_hba *, bool, + enum ufs_notify_change_status); + int (*setup_clocks)(struct ufs_hba *, bool); int (*setup_regulators)(struct ufs_hba *, bool); - int (*hce_enable_notify)(struct ufs_hba *, bool); - int (*link_startup_notify)(struct ufs_hba *, bool); + int (*hce_enable_notify)(struct ufs_hba *, + enum ufs_notify_change_status); + int (*link_startup_notify)(struct ufs_hba *, + enum ufs_notify_change_status); int (*pwr_change_notify)(struct ufs_hba *, - bool, struct ufs_pa_layer_attr *, + enum ufs_notify_change_status status, + struct ufs_pa_layer_attr *, struct ufs_pa_layer_attr *); int (*suspend)(struct ufs_hba *, enum ufs_pm_op); int (*resume)(struct ufs_hba *, enum ufs_pm_op); + void (*dbg_register_dump)(struct ufs_hba *hba); }; /* clock gating state */ @@ -576,6 +584,7 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg) } int ufshcd_alloc_host(struct device *, struct ufs_hba **); +void ufshcd_dealloc_host(struct ufs_hba *); int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int); void ufshcd_remove(struct ufs_hba *); @@ -594,6 +603,27 @@ static inline void check_upiu_size(void) GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE); } +/** + * ufshcd_set_variant - set variant specific data to the hba + * @hba - per adapter instance + * @variant - pointer to variant specific data + */ +static inline void ufshcd_set_variant(struct ufs_hba *hba, void *variant) +{ + BUG_ON(!hba); + hba->priv = variant; +} + +/** + * ufshcd_get_variant - get variant specific data from the hba + * @hba - per adapter instance + */ +static inline void *ufshcd_get_variant(struct ufs_hba *hba) +{ + BUG_ON(!hba); + return hba->priv; +} + extern int ufshcd_runtime_suspend(struct ufs_hba *hba); extern int ufshcd_runtime_resume(struct ufs_hba *hba); extern int ufshcd_runtime_idle(struct ufs_hba *hba); @@ -653,4 +683,109 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba, int ufshcd_hold(struct ufs_hba *hba, bool async); void ufshcd_release(struct ufs_hba *hba); + +/* 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) + return hba->vops->init(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 int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on) +{ + if (hba->vops && hba->vops->setup_clocks) + return hba->vops->setup_clocks(hba, on); + return 0; +} + +static inline int ufshcd_vops_setup_regulators(struct ufs_hba *hba, bool status) +{ + if (hba->vops && hba->vops->setup_regulators) + return hba->vops->setup_regulators(hba, 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, + bool 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 int ufshcd_vops_suspend(struct ufs_hba *hba, enum ufs_pm_op op) +{ + if (hba->vops && hba->vops->suspend) + return hba->vops->suspend(hba, op); + + 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); +} + #endif /* End of Header */ -- cgit v1.2.3