summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2010-07-15 11:06:27 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2010-07-15 11:06:27 +1000
commit2e68f96ef937205e87fc609d6ed75d4891c66ef9 (patch)
treeed208c1179687c3c68877ee4767946d3ef8e1708 /drivers
parent68fbeba012e3460dc2eebb1b8e981da8a5d9bee7 (diff)
parent482ae21a54dab3a7e0cd377514745650b9667dd3 (diff)
Merge remote branch 'scsi/master'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/message/fusion/mptbase.c6
-rw-r--r--drivers/message/fusion/mptbase.h8
-rw-r--r--drivers/message/fusion/mptctl.c14
-rw-r--r--drivers/message/fusion/mptsas.c131
-rw-r--r--drivers/message/fusion/mptsas.h1
-rw-r--r--drivers/message/fusion/mptscsih.c8
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h135
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c1225
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c123
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.h2
-rw-r--r--drivers/scsi/be2iscsi/be_main.c7
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_ddp.c2
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_offload.c5
-rw-r--r--drivers/scsi/dpt_i2o.c15
-rw-r--r--drivers/scsi/fcoe/libfcoe.c221
-rw-r--r--drivers/scsi/fnic/fnic_scsi.c22
-rw-r--r--drivers/scsi/hpsa.c754
-rw-r--r--drivers/scsi/hpsa.h1
-rw-r--r--drivers/scsi/hpsa_cmd.h4
-rw-r--r--drivers/scsi/hptiop.c2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c85
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.h6
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c157
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.h4
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c16
-rw-r--r--drivers/scsi/ipr.c75
-rw-r--r--drivers/scsi/ipr.h22
-rw-r--r--drivers/scsi/libfc/fc_fcp.c2
-rw-r--r--drivers/scsi/libfc/fc_rport.c175
-rw-r--r--drivers/scsi/lpfc/lpfc.h14
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c84
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c9
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h11
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c83
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c189
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h17
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c257
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c21
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c31
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c33
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c298
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h7
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c2
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h17
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h193
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_init.h17
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h119
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c159
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h32
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_config.c4
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c407
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c701
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c569
-rw-r--r--drivers/scsi/pmcraid.c886
-rw-r--r--drivers/scsi/pmcraid.h305
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c196
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.h7
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h9
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h6
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c71
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c54
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c152
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c228
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.h38
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c42
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h6
72 files changed, 6251 insertions, 2268 deletions
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index a6a57011ba6c..c36d5b9ff663 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1770,7 +1770,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */
ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
- ioc->pcidev = pdev;
spin_lock_init(&ioc->taskmgmt_lock);
mutex_init(&ioc->internal_cmds.mutex);
@@ -1913,6 +1912,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->msi_enable = 0;
break;
}
+
+ ioc->fw_events_off = 1;
+
if (ioc->errata_flag_1064)
pci_disable_io_access(pdev);
@@ -2051,7 +2053,6 @@ mpt_detach(struct pci_dev *pdev)
mpt_adapter_dispose(ioc);
- pci_set_drvdata(pdev, NULL);
}
/**************************************************************************
@@ -6971,6 +6972,7 @@ mpt_SoftResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
if (ioc->taskmgmt_in_progress) {
+ ioc->ioc_reset_in_progress = 0;
spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
return -1;
}
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index b613eb3d4706..0d149c82e764 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -76,8 +76,8 @@
#define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.04.15"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.15"
+#define MPT_LINUX_VERSION_COMMON "3.04.16"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.16"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
@@ -580,6 +580,7 @@ struct mptfc_rport_info
typedef void (*MPT_ADD_SGE)(void *pAddr, u32 flagslength, dma_addr_t dma_addr);
typedef void (*MPT_ADD_CHAIN)(void *pAddr, u8 next, u16 length,
dma_addr_t dma_addr);
+typedef void (*MPT_SCHEDULE_TARGET_RESET)(void *ioc);
/*
* Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS
@@ -601,7 +602,7 @@ typedef struct _MPT_ADAPTER
u16 nvdata_version_default;
int debug_level;
u8 io_missing_delay;
- u8 device_missing_delay;
+ u16 device_missing_delay;
SYSIF_REGS __iomem *chip; /* == c8817000 (mmap) */
SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */
u8 bus_type;
@@ -738,6 +739,7 @@ typedef struct _MPT_ADAPTER
int taskmgmt_in_progress;
u8 taskmgmt_quiesce_io;
u8 ioc_reset_in_progress;
+ MPT_SCHEDULE_TARGET_RESET schedule_target_reset;
struct work_struct sas_persist_task;
struct work_struct fc_setup_reset_work;
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index f06b29193b4e..9bd89cebb5a9 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -261,10 +261,16 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply)
/* We are done, issue wake up
*/
if (ioc->ioctl_cmds.status & MPT_MGMT_STATUS_PENDING) {
- if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT)
+ if (req->u.hdr.Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
mpt_clear_taskmgmt_in_progress_flag(ioc);
- ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
- complete(&ioc->ioctl_cmds.done);
+ ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+ complete(&ioc->ioctl_cmds.done);
+ if (ioc->bus_type == SAS)
+ ioc->schedule_target_reset(ioc);
+ } else {
+ ioc->ioctl_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
+ complete(&ioc->ioctl_cmds.done);
+ }
}
out_continuation:
@@ -298,6 +304,8 @@ mptctl_taskmgmt_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
mpt_clear_taskmgmt_in_progress_flag(ioc);
ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
complete(&ioc->taskmgmt_cmds.done);
+ if (ioc->bus_type == SAS)
+ ioc->schedule_target_reset(ioc);
return 1;
}
return 0;
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index ac000e83db0e..f42781b92bdd 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -126,6 +126,7 @@ static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
+void mptsas_schedule_target_reset(void *ioc);
static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
@@ -1139,6 +1140,44 @@ mptsas_target_reset_queue(MPT_ADAPTER *ioc,
}
/**
+ * mptsas_schedule_target_reset- send pending target reset
+ * @iocp: per adapter object
+ *
+ * This function will delete scheduled target reset from the list and
+ * try to send next target reset. This will be called from completion
+ * context of any Task managment command.
+ */
+
+void
+mptsas_schedule_target_reset(void *iocp)
+{
+ MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp);
+ MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
+ struct list_head *head = &hd->target_reset_list;
+ struct mptsas_target_reset_event *target_reset_list;
+ u8 id, channel;
+ /*
+ * issue target reset to next device in the queue
+ */
+
+ head = &hd->target_reset_list;
+ if (list_empty(head))
+ return;
+
+ target_reset_list = list_entry(head->next,
+ struct mptsas_target_reset_event, list);
+
+ id = target_reset_list->sas_event_data.TargetID;
+ channel = target_reset_list->sas_event_data.Bus;
+ target_reset_list->time_count = jiffies;
+
+ if (mptsas_target_reset(ioc, channel, id))
+ target_reset_list->target_reset_issued = 1;
+ return;
+}
+
+
+/**
* mptsas_taskmgmt_complete - complete SAS task management function
* @ioc: Pointer to MPT_ADAPTER structure
*
@@ -1227,23 +1266,7 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
&target_reset_list->sas_event_data);
- /*
- * issue target reset to next device in the queue
- */
-
- head = &hd->target_reset_list;
- if (list_empty(head))
- return 1;
-
- target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
- list);
-
- id = target_reset_list->sas_event_data.TargetID;
- channel = target_reset_list->sas_event_data.Bus;
- target_reset_list->time_count = jiffies;
-
- if (mptsas_target_reset(ioc, channel, id))
- target_reset_list->target_reset_issued = 1;
+ ioc->schedule_target_reset(ioc);
return 1;
}
@@ -2364,7 +2387,7 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
SasIOUnitPage1_t *buffer;
dma_addr_t dma_handle;
int error;
- u16 device_missing_delay;
+ u8 device_missing_delay;
memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
memset(&cfg, 0, sizeof(CONFIGPARMS));
@@ -2401,7 +2424,7 @@ mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
ioc->io_missing_delay =
le16_to_cpu(buffer->IODeviceMissingDelay);
- device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
+ device_missing_delay = buffer->ReportDeviceMissingDelay;
ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
(device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
@@ -2549,6 +2572,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
device_info->sas_address = le64_to_cpu(sas_address);
device_info->device_info =
le32_to_cpu(buffer->DeviceInfo);
+ device_info->flags = le16_to_cpu(buffer->Flags);
out_free_consistent:
pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
@@ -3840,6 +3864,13 @@ mptsas_probe_devices(MPT_ADAPTER *ioc)
MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
continue;
+ /* If there is no FW B_T mapping for this device then continue
+ * */
+ if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+ || !(sas_device.flags &
+ MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+ continue;
+
phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
if (!phy_info)
continue;
@@ -4149,6 +4180,14 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
phys_disk.PhysDiskID))
continue;
+ /* If there is no FW B_T mapping for this device then continue
+ * */
+ if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+ || !(sas_device.flags &
+ MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+ continue;
+
+
phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
sas_device.sas_address);
mptsas_add_end_device(ioc, phy_info);
@@ -4171,6 +4210,7 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
struct mptsas_devinfo sas_device;
VirtTarget *vtarget;
int i;
+ struct mptsas_portinfo *port_info;
switch (hot_plug_info->event_type) {
@@ -4199,12 +4239,47 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
(hot_plug_info->channel << 8) +
hot_plug_info->id);
+ /* If there is no FW B_T mapping for this device then break
+ * */
+ if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+ || !(sas_device.flags &
+ MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+ break;
+
if (!sas_device.handle)
return;
phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
- if (!phy_info)
+ /* Only For SATA Device ADD */
+ if (!phy_info && (sas_device.device_info &
+ MPI_SAS_DEVICE_INFO_SATA_DEVICE)) {
+ devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+ "%s %d SATA HOT PLUG: "
+ "parent handle of device %x\n", ioc->name,
+ __func__, __LINE__, sas_device.handle_parent));
+ port_info = mptsas_find_portinfo_by_handle(ioc,
+ sas_device.handle_parent);
+
+ if (port_info == ioc->hba_port_info)
+ mptsas_probe_hba_phys(ioc);
+ else if (port_info)
+ mptsas_expander_refresh(ioc, port_info);
+ else {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "%s %d port info is NULL\n",
+ ioc->name, __func__, __LINE__));
+ break;
+ }
+ phy_info = mptsas_refreshing_device_handles
+ (ioc, &sas_device);
+ }
+
+ if (!phy_info) {
+ dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
+ "%s %d phy info is NULL\n",
+ ioc->name, __func__, __LINE__));
break;
+ }
if (mptsas_get_rphy(phy_info))
break;
@@ -4241,6 +4316,13 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
break;
}
+ /* If there is no FW B_T mapping for this device then break
+ * */
+ if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+ || !(sas_device.flags &
+ MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+ break;
+
phy_info = mptsas_find_phyinfo_by_sas_address(
ioc, sas_device.sas_address);
@@ -4294,6 +4376,13 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
break;
}
+ /* If there is no FW B_T mapping for this device then break
+ * */
+ if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
+ || !(sas_device.flags &
+ MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
+ break;
+
phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
sas_device.sas_address);
if (!phy_info) {
@@ -4924,7 +5013,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->DoneCtx = mptsasDoneCtx;
ioc->TaskCtx = mptsasTaskCtx;
ioc->InternalCtx = mptsasInternalCtx;
-
+ ioc->schedule_target_reset = &mptsas_schedule_target_reset;
/* Added sanity check on readiness of the MPT adapter.
*/
if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
diff --git a/drivers/message/fusion/mptsas.h b/drivers/message/fusion/mptsas.h
index 7b249edbda78..57e86ab77661 100644
--- a/drivers/message/fusion/mptsas.h
+++ b/drivers/message/fusion/mptsas.h
@@ -140,6 +140,7 @@ struct mptsas_devinfo {
u64 sas_address; /* WWN of this device,
SATA is assigned by HBA,expander */
u32 device_info; /* bitfield detailed info about this device */
+ u16 flags; /* sas device pg0 flags */
};
/*
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 5c53624e0e87..c5c8fb811f54 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -742,7 +742,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
if ((log_info & SAS_LOGINFO_MASK)
== SAS_LOGINFO_NEXUS_LOSS) {
- sc->result = (DID_BUS_BUSY << 16);
+ sc->result =
+ (DID_TRANSPORT_DISRUPTED
+ << 16);
break;
}
}
@@ -2132,6 +2134,8 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf,
mpt_clear_taskmgmt_in_progress_flag(ioc);
ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
complete(&ioc->taskmgmt_cmds.done);
+ if (ioc->bus_type == SAS)
+ ioc->schedule_target_reset(ioc);
return 1;
}
return 0;
@@ -2459,6 +2463,8 @@ mptscsih_slave_configure(struct scsi_device *sdev)
ioc->name,sdev->tagged_supported, sdev->simple_tags,
sdev->ordered_tags));
+ blk_queue_dma_alignment (sdev->request_queue, 512 - 1);
+
return 0;
}
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index ce5371b3cdd5..c0861c05cd49 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -48,16 +48,22 @@ struct device_attribute;
/*The limit of outstanding scsi command that firmware can handle*/
#define ARCMSR_MAX_OUTSTANDING_CMD 256
#define ARCMSR_MAX_FREECCB_NUM 320
-#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2008/11/03"
+#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2009/12/09"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
#define ARCMSR_MAX_XFER_SECTORS_B 4096
+#define ARCMSR_MAX_XFER_SECTORS_C 304
#define ARCMSR_MAX_TARGETID 17
#define ARCMSR_MAX_TARGETLUN 8
#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD
#define ARCMSR_MAX_QBUFFER 4096
-#define ARCMSR_MAX_SG_ENTRIES 38
+#define ARCMSR_DEFAULT_SG_ENTRIES 38
#define ARCMSR_MAX_HBB_POSTQUEUE 264
+#define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */
+#define ARCMSR_CDB_SG_PAGE_LENGTH 256
+#ifndef PCI_DEVICE_ID_ARECA_1880
+#define PCI_DEVICE_ID_ARECA_1880 0x1880
+ #endif
/*
**********************************************************************************
**
@@ -141,26 +147,19 @@ struct CMD_MESSAGE_FIELD
** structure for holding DMA address data
*************************************************************
*/
+#define IS_DMA64 (sizeof(dma_addr_t) == 8)
#define IS_SG64_ADDR 0x01000000 /* bit24 */
struct SG32ENTRY
{
__le32 length;
__le32 address;
-};
+} __attribute__ ((packed));
struct SG64ENTRY
{
__le32 length;
__le32 address;
__le32 addresshigh;
-};
-struct SGENTRY_UNION
-{
- union
- {
- struct SG32ENTRY sg32entry;
- struct SG64ENTRY sg64entry;
- }u;
-};
+} __attribute__ ((packed));
/*
********************************************************************
** Q Buffer of IOP Message Transfer
@@ -187,6 +186,9 @@ struct FIRMWARE_INFO
char model[8]; /*15, 60-67*/
char firmware_ver[16]; /*17, 68-83*/
char device_map[16]; /*21, 84-99*/
+ uint32_t cfgVersion; /*25,100-103 Added for checking of new firmware capability*/
+ uint8_t cfgSerial[16]; /*26,104-119*/
+ uint32_t cfgPicStatus; /*30,120-123*/
};
/* signature of set and get firmware config */
#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060
@@ -213,6 +215,8 @@ struct FIRMWARE_INFO
#define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000
/* outbound firmware ok */
#define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000
+/* ARC-1680 Bus Reset*/
+#define ARCMSR_ARC1680_BUS_RESET 0x00000003
/*
************************************************************************
@@ -264,11 +268,11 @@ struct FIRMWARE_INFO
/* data tunnel buffer between user space program and its firmware */
/* user space data to iop 128bytes */
-#define ARCMSR_IOCTL_WBUFFER 0x0000fe00
+#define ARCMSR_MESSAGE_WBUFFER 0x0000fe00
/* iop data to user space 128bytes */
-#define ARCMSR_IOCTL_RBUFFER 0x0000ff00
+#define ARCMSR_MESSAGE_RBUFFER 0x0000ff00
/* iop message_rwbuffer for message command */
-#define ARCMSR_MSGCODE_RWBUFFER 0x0000fa00
+#define ARCMSR_MESSAGE_RWBUFFER 0x0000fa00
/*
*******************************************************************************
** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
@@ -290,7 +294,7 @@ struct ARCMSR_CDB
#define ARCMSR_CDB_FLAG_HEADQ 0x08
#define ARCMSR_CDB_FLAG_ORDEREDQ 0x10
- uint8_t Reserved1;
+ uint8_t msgPages;
uint32_t Context;
uint32_t DataLength;
uint8_t Cdb[16];
@@ -303,10 +307,10 @@ struct ARCMSR_CDB
uint8_t SenseData[15];
union
{
- struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES];
- struct SG64ENTRY sg64entry[ARCMSR_MAX_SG_ENTRIES];
+ struct SG32ENTRY sg32entry[1];
+ struct SG64ENTRY sg64entry[1];
} u;
-};
+} __attribute__ ((packed));
/*
*******************************************************************************
** Messaging Unit (MU) of the Intel R 80331 I/O processor(Type A) and Type B processor
@@ -344,13 +348,13 @@ struct MessageUnit_B
uint32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
uint32_t postq_index;
uint32_t doneq_index;
- uint32_t __iomem *drv2iop_doorbell_reg;
- uint32_t __iomem *drv2iop_doorbell_mask_reg;
- uint32_t __iomem *iop2drv_doorbell_reg;
- uint32_t __iomem *iop2drv_doorbell_mask_reg;
- uint32_t __iomem *msgcode_rwbuffer_reg;
- uint32_t __iomem *ioctl_wbuffer_reg;
- uint32_t __iomem *ioctl_rbuffer_reg;
+ uint32_t __iomem *drv2iop_doorbell;
+ uint32_t __iomem *drv2iop_doorbell_mask;
+ uint32_t __iomem *iop2drv_doorbell;
+ uint32_t __iomem *iop2drv_doorbell_mask;
+ uint32_t __iomem *message_rwbuffer;
+ uint32_t __iomem *message_wbuffer;
+ uint32_t __iomem *message_rbuffer;
};
/*
@@ -370,14 +374,17 @@ struct AdapterControlBlock
unsigned long vir2phy_offset;
/* Offset is used in making arc cdb physical to virtual calculations */
uint32_t outbound_int_enable;
-
+ spinlock_t eh_lock;
+ spinlock_t ccblist_lock;
union {
struct MessageUnit_A __iomem * pmuA;
struct MessageUnit_B * pmuB;
};
/* message unit ATU inbound base address0 */
-
+ void __iomem *mem_base0;
+ void __iomem *mem_base1;
uint32_t acb_flags;
+ u16 dev_id;
uint8_t adapter_index;
#define ACB_F_SCSISTOPADAPTER 0x0001
#define ACB_F_MSG_STOP_BGRB 0x0002
@@ -394,6 +401,7 @@ struct AdapterControlBlock
#define ACB_F_BUS_RESET 0x0080
#define ACB_F_IOP_INITED 0x0100
/* iop init */
+ #define ACB_F_ABORT 0x0200
#define ACB_F_FIRMWARE_TRAP 0x0400
struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM];
/* used for memory free */
@@ -408,7 +416,8 @@ struct AdapterControlBlock
/* dma_coherent used for memory free */
dma_addr_t dma_coherent_handle;
/* dma_coherent_handle used for memory free */
-
+ dma_addr_t dma_coherent_handle_hbb_mu;
+ unsigned int uncache_size;
uint8_t rqbuffer[ARCMSR_MAX_QBUFFER];
/* data collection buffer for read from 80331 */
int32_t rqbuf_firstindex;
@@ -432,14 +441,18 @@ struct AdapterControlBlock
uint32_t firm_numbers_queue;
uint32_t firm_sdram_size;
uint32_t firm_hd_channels;
+ uint32_t firm_cfg_version;
char firm_model[12];
char firm_version[20];
char device_map[20]; /*21,84-99*/
struct work_struct arcmsr_do_message_isr_bh;
struct timer_list eternal_timer;
- unsigned short fw_state;
+ unsigned short fw_flag;
+ #define FW_NORMAL 0x0000
+ #define FW_BOG 0x0001
+ #define FW_DEADLOCK 0x0010
atomic_t rq_map_token;
- int ante_token_value;
+ atomic_t ante_token_value;
};/* HW_DEVICE_EXTENSION */
/*
*******************************************************************************
@@ -449,65 +462,31 @@ struct AdapterControlBlock
*/
struct CommandControlBlock
{
- struct ARCMSR_CDB arcmsr_cdb;
- /*
- ** 0-503 (size of CDB = 504):
- ** arcmsr messenger scsi command descriptor size 504 bytes
- */
- uint32_t cdb_shifted_phyaddr;
- /* 504-507 */
- uint32_t reserved1;
- /* 508-511 */
-#if BITS_PER_LONG == 64
- /* ======================512+64 bytes======================== */
- struct list_head list;
- /* 512-527 16 bytes next/prev ptrs for ccb lists */
- struct scsi_cmnd * pcmd;
- /* 528-535 8 bytes pointer of linux scsi command */
- struct AdapterControlBlock * acb;
- /* 536-543 8 bytes pointer of acb */
-
- uint16_t ccb_flags;
- /* 544-545 */
+ /*x32:sizeof struct_CCB=(32+60)byte, x64:sizeof struct_CCB=(64+60)byte*/
+ struct list_head list; /*x32: 8byte, x64: 16byte*/
+ struct scsi_cmnd *pcmd; /*8 bytes pointer of linux scsi command */
+ struct AdapterControlBlock *acb; /*x32: 4byte, x64: 8byte*/
+ uint32_t shifted_cdb_phyaddr; /*x32: 4byte, x64: 4byte*/
+ uint16_t ccb_flags; /*x32: 2byte, x64: 2byte*/
#define CCB_FLAG_READ 0x0000
#define CCB_FLAG_WRITE 0x0001
#define CCB_FLAG_ERROR 0x0002
#define CCB_FLAG_FLUSHCACHE 0x0004
#define CCB_FLAG_MASTER_ABORTED 0x0008
- uint16_t startdone;
- /* 546-547 */
+ uint16_t startdone; /*x32:2byte,x32:2byte*/
#define ARCMSR_CCB_DONE 0x0000
#define ARCMSR_CCB_START 0x55AA
#define ARCMSR_CCB_ABORTED 0xAA55
#define ARCMSR_CCB_ILLEGAL 0xFFFF
- uint32_t reserved2[7];
- /* 548-551 552-555 556-559 560-563 564-567 568-571 572-575 */
+ #if BITS_PER_LONG == 64
+ /* ======================512+64 bytes======================== */
+ uint32_t reserved[6]; /*24 byte*/
#else
/* ======================512+32 bytes======================== */
- struct list_head list;
- /* 512-519 8 bytes next/prev ptrs for ccb lists */
- struct scsi_cmnd * pcmd;
- /* 520-523 4 bytes pointer of linux scsi command */
- struct AdapterControlBlock * acb;
- /* 524-527 4 bytes pointer of acb */
-
- uint16_t ccb_flags;
- /* 528-529 */
- #define CCB_FLAG_READ 0x0000
- #define CCB_FLAG_WRITE 0x0001
- #define CCB_FLAG_ERROR 0x0002
- #define CCB_FLAG_FLUSHCACHE 0x0004
- #define CCB_FLAG_MASTER_ABORTED 0x0008
- uint16_t startdone;
- /* 530-531 */
- #define ARCMSR_CCB_DONE 0x0000
- #define ARCMSR_CCB_START 0x55AA
- #define ARCMSR_CCB_ABORTED 0xAA55
- #define ARCMSR_CCB_ILLEGAL 0xFFFF
- uint32_t reserved2[3];
- /* 532-535 536-539 540-543 */
+ uint32_t reserved[2]; /*8 byte*/
#endif
- /* ========================================================== */
+ /* ======================================================= */
+ struct ARCMSR_CDB arcmsr_cdb;
};
/*
*******************************************************************************
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index ffa54792bb33..ba33473b27a1 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -58,7 +58,6 @@
#include <linux/timer.h>
#include <linux/pci.h>
#include <linux/aer.h>
-#include <linux/slab.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -71,20 +70,13 @@
#include <scsi/scsi_transport.h>
#include <scsi/scsicam.h>
#include "arcmsr.h"
-
-#ifdef CONFIG_SCSI_ARCMSR_RESET
- static int sleeptime = 20;
- static int retrycount = 12;
- module_param(sleeptime, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(sleeptime, "The waiting period for FW ready while bus reset");
- module_param(retrycount, int, S_IRUGO|S_IWUSR);
- MODULE_PARM_DESC(retrycount, "The retry count for FW ready while bus reset");
-#endif
-MODULE_AUTHOR("Erich Chen <support@areca.com.tw>");
-MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Bus Adapter");
+MODULE_AUTHOR("Nick Cheng <support@areca.com.tw>");
+MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx) SATA/SAS RAID Host Bus Adapter");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(ARCMSR_DRIVER_VERSION);
-
+static int sleeptime = 20;
+static int retrycount = 12;
+wait_queue_head_t wait_q;
static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
struct scsi_cmnd *cmd);
static int arcmsr_iop_confirm(struct AdapterControlBlock *acb);
@@ -108,7 +100,7 @@ static void arcmsr_request_device_map(unsigned long pacb);
static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb);
static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb);
static void arcmsr_message_isr_bh_fn(struct work_struct *work);
-static void *arcmsr_get_firmware_spec(struct AdapterControlBlock *acb, int mode);
+static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb);
static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
@@ -135,10 +127,10 @@ static struct scsi_host_template arcmsr_scsi_host_template = {
.eh_bus_reset_handler = arcmsr_bus_reset,
.bios_param = arcmsr_bios_param,
.change_queue_depth = arcmsr_adjust_disk_queue_depth,
- .can_queue = ARCMSR_MAX_OUTSTANDING_CMD,
+ .can_queue = ARCMSR_MAX_FREECCB_NUM,
.this_id = ARCMSR_SCSI_INITIATOR_ID,
- .sg_tablesize = ARCMSR_MAX_SG_ENTRIES,
- .max_sectors = ARCMSR_MAX_XFER_SECTORS,
+ .sg_tablesize = ARCMSR_DEFAULT_SG_ENTRIES,
+ .max_sectors = ARCMSR_MAX_XFER_SECTORS_C,
.cmd_per_lun = ARCMSR_MAX_CMD_PERLUN,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = arcmsr_host_attrs,
@@ -162,6 +154,7 @@ static struct pci_device_id arcmsr_device_id_table[] = {
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880)},
{0, 0}, /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table);
@@ -173,15 +166,72 @@ static struct pci_driver arcmsr_pci_driver = {
.shutdown = arcmsr_shutdown,
};
+static void arcmsr_free_mu(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A:
+ break;
+ case ACB_ADAPTER_TYPE_B:{
+ struct MessageUnit_B *reg = acb->pmuB;
+ dma_free_coherent(&acb->pdev->dev,
+ sizeof(struct MessageUnit_B),
+ reg, acb->dma_coherent_handle_hbb_mu);
+ }
+ }
+}
+
+static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb)
+{
+ struct pci_dev *pdev = acb->pdev;
+
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A:{
+ acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+ if (!acb->pmuA) {
+ printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+ return false;
+ }
+ break;
+ }
+ case ACB_ADAPTER_TYPE_B:{
+ void __iomem *mem_base0, *mem_base1;
+ mem_base0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+ if (!mem_base0) {
+ printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+ return false;
+ }
+ mem_base1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
+ if (!mem_base1) {
+ iounmap(mem_base0);
+ printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+ return false;
+ }
+ acb->mem_base0 = mem_base0;
+ acb->mem_base1 = mem_base1;
+ }
+ }
+ return true;
+}
+
+static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb)
+{
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A:{
+ iounmap(acb->pmuA);
+ }
+ case ACB_ADAPTER_TYPE_B:{
+ iounmap(acb->mem_base0);
+ iounmap(acb->mem_base1);
+ }
+ }
+}
+
static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
{
irqreturn_t handle_state;
struct AdapterControlBlock *acb = dev_id;
- spin_lock(acb->host->host_lock);
handle_state = arcmsr_interrupt(acb);
- spin_unlock(acb->host->host_lock);
-
return handle_state;
}
@@ -218,6 +268,7 @@ static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb)
struct pci_dev *pdev = acb->pdev;
u16 dev_id;
pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
+ acb->dev_id = dev_id;
switch (dev_id) {
case 0x1201 : {
acb->adapter_type = ACB_ADAPTER_TYPE_B;
@@ -228,141 +279,210 @@ static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb)
}
}
-static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
+static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ uint32_t Index;
+ uint8_t Retries = 0x00;
+
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(&reg->outbound_intstatus) &
+ ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
+ writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
+ &reg->outbound_intstatus);
+ return 0x00;
+ }
+ msleep(10);
+ } /*max 1 seconds*/
+
+ } while (Retries++ < 20);/*max 20 sec*/
+ return 0xff;
+}
+
+static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
{
+ struct MessageUnit_B *reg = acb->pmuB;
+ uint32_t Index;
+ uint8_t Retries = 0x00;
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(reg->iop2drv_doorbell)
+ & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
+ , reg->iop2drv_doorbell);
+ writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
+ return 0x00;
+ }
+ msleep(10);
+ } /*max 1 seconds*/
+
+ } while (Retries++ < 20);/*max 20 sec*/
+ return 0xff;
+}
+
+static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
+ int retry_count = 30;
+
+ writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
+ do {
+ if (!arcmsr_hba_wait_msgint_ready(acb))
+ break;
+ else {
+ retry_count--;
+ printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+ timeout, retry count down = %d \n", acb->host->host_no, retry_count);
+ }
+ } while (retry_count != 0);
+}
+
+static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = acb->pmuB;
+ int retry_count = 30;
+
+ writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell);
+ do {
+ if (!arcmsr_hbb_wait_msgint_ready(acb))
+ break;
+ else {
+ retry_count--;
+ printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
+ timeout,retry count down = %d \n", acb->host->host_no, retry_count);
+ }
+ } while (retry_count != 0);
+}
+
+static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
+{
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
- struct pci_dev *pdev = acb->pdev;
- void *dma_coherent;
- dma_addr_t dma_coherent_handle, dma_addr;
- struct CommandControlBlock *ccb_tmp;
- int i, j;
+ arcmsr_flush_hba_cache(acb);
+ }
+ break;
- acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
- if (!acb->pmuA) {
- printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n",
- acb->host->host_no);
- return -ENOMEM;
+ case ACB_ADAPTER_TYPE_B: {
+ arcmsr_flush_hbb_cache(acb);
}
+ }
+}
- dma_coherent = dma_alloc_coherent(&pdev->dev,
- ARCMSR_MAX_FREECCB_NUM *
- sizeof (struct CommandControlBlock) + 0x20,
- &dma_coherent_handle, GFP_KERNEL);
+static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
+{
+ struct pci_dev *pdev = acb->pdev;
+ switch (acb->adapter_type) {
+ case ACB_ADAPTER_TYPE_A: {
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle;
+ struct CommandControlBlock *ccb_tmp;
+ int i = 0, j = 0;
+ dma_addr_t cdb_phyaddr;
+ unsigned long roundup_ccbsize = 0;
+ unsigned long max_xfer_len;
+ unsigned long max_sg_entrys;
+ uint32_t firm_config_version;
+
+ for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+ for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+ acb->devstate[i][j] = ARECA_RAID_GONE;
+
+ max_xfer_len = ARCMSR_MAX_XFER_LEN;
+ max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
+ firm_config_version = acb->firm_cfg_version;
+ if ((firm_config_version & 0xFF) >= 3) {
+ max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */
+ max_sg_entrys = (max_xfer_len/4096);
+ }
+ acb->host->max_sectors = max_xfer_len/512;
+ acb->host->sg_tablesize = max_sg_entrys;
+ roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + max_sg_entrys * sizeof(struct SG64ENTRY), 32);
+ acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM;
+ dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL);
if (!dma_coherent) {
- iounmap(acb->pmuA);
+ printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error \n", acb->host->host_no);
return -ENOMEM;
}
-
+ memset(dma_coherent, 0, acb->uncache_size);
acb->dma_coherent = dma_coherent;
acb->dma_coherent_handle = dma_coherent_handle;
-
- if (((unsigned long)dma_coherent & 0x1F)) {
- dma_coherent = dma_coherent +
- (0x20 - ((unsigned long)dma_coherent & 0x1F));
- dma_coherent_handle = dma_coherent_handle +
- (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
- }
-
- dma_addr = dma_coherent_handle;
ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+ acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle;
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
- ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
- ccb_tmp->acb = acb;
+ cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb);
+ ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5;
acb->pccb_pool[i] = ccb_tmp;
+ ccb_tmp->acb = acb;
+ INIT_LIST_HEAD(&ccb_tmp->list);
list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
- dma_addr = dma_addr + sizeof(struct CommandControlBlock);
- ccb_tmp++;
- }
-
- acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;
- for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
- for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
- acb->devstate[i][j] = ARECA_RAID_GONE;
+ ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize);
+ dma_coherent_handle = dma_coherent_handle + roundup_ccbsize;
}
break;
-
+ }
case ACB_ADAPTER_TYPE_B: {
- struct pci_dev *pdev = acb->pdev;
- struct MessageUnit_B *reg;
- void __iomem *mem_base0, *mem_base1;
void *dma_coherent;
- dma_addr_t dma_coherent_handle, dma_addr;
+ dma_addr_t dma_coherent_handle;
struct CommandControlBlock *ccb_tmp;
- int i, j;
-
- dma_coherent = dma_alloc_coherent(&pdev->dev,
- ((ARCMSR_MAX_FREECCB_NUM *
- sizeof(struct CommandControlBlock) + 0x20) +
- sizeof(struct MessageUnit_B)),
+ uint32_t cdb_phyaddr;
+ unsigned int roundup_ccbsize = 0;
+ unsigned long max_xfer_len;
+ unsigned long max_sg_entrys;
+ unsigned long firm_config_version;
+ unsigned long max_freeccb_num = 0;
+ int i = 0, j = 0;
+
+ max_freeccb_num = ARCMSR_MAX_FREECCB_NUM;
+ max_xfer_len = ARCMSR_MAX_XFER_LEN;
+ max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
+ firm_config_version = acb->firm_cfg_version;
+ if ((firm_config_version & 0xFF) >= 3) {
+ max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH <<
+ ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */
+ max_sg_entrys = (max_xfer_len/4096);/* max 4097 sg entry*/
+ }
+ acb->host->max_sectors = max_xfer_len / 512;
+ acb->host->sg_tablesize = max_sg_entrys;
+ roundup_ccbsize = roundup(sizeof(struct CommandControlBlock)+
+ (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
+ acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM;
+ dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size,
&dma_coherent_handle, GFP_KERNEL);
- if (!dma_coherent)
- return -ENOMEM;
+ if (!dma_coherent) {
+ printk(KERN_NOTICE "DMA allocation failed...........................\n");
+ return -ENOMEM;
+ }
+ memset(dma_coherent, 0, acb->uncache_size);
acb->dma_coherent = dma_coherent;
acb->dma_coherent_handle = dma_coherent_handle;
-
- if (((unsigned long)dma_coherent & 0x1F)) {
- dma_coherent = dma_coherent +
- (0x20 - ((unsigned long)dma_coherent & 0x1F));
- dma_coherent_handle = dma_coherent_handle +
- (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
- }
-
- dma_addr = dma_coherent_handle;
ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+ acb->vir2phy_offset = (unsigned long)dma_coherent -
+ (unsigned long)dma_coherent_handle;
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
- ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
- ccb_tmp->acb = acb;
+ cdb_phyaddr = dma_coherent_handle +
+ offsetof(struct CommandControlBlock, arcmsr_cdb);
+ ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5;
acb->pccb_pool[i] = ccb_tmp;
+ ccb_tmp->acb = acb;
+ INIT_LIST_HEAD(&ccb_tmp->list);
list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
- dma_addr = dma_addr + sizeof(struct CommandControlBlock);
- ccb_tmp++;
- }
-
- reg = (struct MessageUnit_B *)(dma_coherent +
- ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));
- acb->pmuB = reg;
- mem_base0 = ioremap(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- if (!mem_base0)
- goto out;
-
- mem_base1 = ioremap(pci_resource_start(pdev, 2),
- pci_resource_len(pdev, 2));
- if (!mem_base1) {
- iounmap(mem_base0);
- goto out;
+ ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp +
+ roundup_ccbsize);
+ dma_coherent_handle = dma_coherent_handle + roundup_ccbsize;
}
-
- reg->drv2iop_doorbell_reg = mem_base0 + ARCMSR_DRV2IOP_DOORBELL;
- reg->drv2iop_doorbell_mask_reg = mem_base0 +
- ARCMSR_DRV2IOP_DOORBELL_MASK;
- reg->iop2drv_doorbell_reg = mem_base0 + ARCMSR_IOP2DRV_DOORBELL;
- reg->iop2drv_doorbell_mask_reg = mem_base0 +
- ARCMSR_IOP2DRV_DOORBELL_MASK;
- reg->ioctl_wbuffer_reg = mem_base1 + ARCMSR_IOCTL_WBUFFER;
- reg->ioctl_rbuffer_reg = mem_base1 + ARCMSR_IOCTL_RBUFFER;
- reg->msgcode_rwbuffer_reg = mem_base1 + ARCMSR_MSGCODE_RWBUFFER;
-
- acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr;
for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
- acb->devstate[i][j] = ARECA_RAID_GOOD;
+ acb->devstate[i][j] = ARECA_RAID_GONE;
}
break;
}
return 0;
-
-out:
- dma_free_coherent(&acb->pdev->dev,
- (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 +
- sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle);
- return -ENOMEM;
}
static void arcmsr_message_isr_bh_fn(struct work_struct *work)
{
@@ -411,8 +531,8 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work)
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
char *acb_dev_map = (char *)acb->device_map;
- uint32_t __iomem *signature = (uint32_t __iomem *)(&reg->msgcode_rwbuffer_reg[0]);
- char __iomem *devicemap = (char __iomem *)(&reg->msgcode_rwbuffer_reg[21]);
+ uint32_t __iomem *signature = (uint32_t __iomem *)(&reg->message_rwbuffer[0]);
+ char __iomem *devicemap = (char __iomem *)(&reg->message_rwbuffer[21]);
int target, lun;
struct scsi_device *psdev;
char diff;
@@ -447,8 +567,7 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work)
}
}
-static int arcmsr_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
+static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct Scsi_Host *host;
struct AdapterControlBlock *acb;
@@ -456,19 +575,13 @@ static int arcmsr_probe(struct pci_dev *pdev,
int error;
error = pci_enable_device(pdev);
- if (error)
- goto out;
- pci_set_master(pdev);
-
- host = scsi_host_alloc(&arcmsr_scsi_host_template,
- sizeof(struct AdapterControlBlock));
+ if (error) {
+ return -ENODEV;
+ }
+ host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock));
if (!host) {
- error = -ENOMEM;
- goto out_disable_device;
+ goto pci_disable_dev;
}
- acb = (struct AdapterControlBlock *)host->hostdata;
- memset(acb, 0, sizeof (struct AdapterControlBlock));
-
error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
if (error) {
error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
@@ -476,126 +589,90 @@ static int arcmsr_probe(struct pci_dev *pdev,
printk(KERN_WARNING
"scsi%d: No suitable DMA mask available\n",
host->host_no);
- goto out_host_put;
+ goto scsi_host_release;
}
}
+ init_waitqueue_head(&wait_q);
bus = pdev->bus->number;
dev_fun = pdev->devfn;
- acb->host = host;
+ acb = (struct AdapterControlBlock *) host->hostdata;
+ memset(acb, 0, sizeof(struct AdapterControlBlock));
acb->pdev = pdev;
- host->max_sectors = ARCMSR_MAX_XFER_SECTORS;
+ acb->host = host;
host->max_lun = ARCMSR_MAX_TARGETLUN;
host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/
host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/
- host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES;
host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */
host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;
host->this_id = ARCMSR_SCSI_INITIATOR_ID;
host->unique_id = (bus << 8) | dev_fun;
- host->irq = pdev->irq;
+ pci_set_drvdata(pdev, host);
+ pci_set_master(pdev);
error = pci_request_regions(pdev, "arcmsr");
if (error) {
- goto out_host_put;
+ goto scsi_host_release;
}
- arcmsr_define_adapter_type(acb);
-
+ spin_lock_init(&acb->eh_lock);
+ spin_lock_init(&acb->ccblist_lock);
acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
ACB_F_MESSAGE_RQBUFFER_CLEARED |
ACB_F_MESSAGE_WQBUFFER_READED);
acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
INIT_LIST_HEAD(&acb->ccb_free_list);
- INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
+ arcmsr_define_adapter_type(acb);
+ error = arcmsr_remap_pciregion(acb);
+ if (!error) {
+ goto pci_release_regs;
+ }
+ error = arcmsr_get_firmware_spec(acb);
+ if (!error) {
+ goto unmap_pci_region;
+ }
error = arcmsr_alloc_ccb_pool(acb);
- if (error)
- goto out_release_regions;
-
+ if (error) {
+ goto free_hbb_mu;
+ }
arcmsr_iop_init(acb);
- error = request_irq(pdev->irq, arcmsr_do_interrupt,
- IRQF_SHARED, "arcmsr", acb);
- if (error)
- goto out_free_ccb_pool;
-
- pci_set_drvdata(pdev, host);
- if (strncmp(acb->firm_version, "V1.42", 5) >= 0)
- host->max_sectors= ARCMSR_MAX_XFER_SECTORS_B;
-
error = scsi_add_host(host, &pdev->dev);
- if (error)
- goto out_free_irq;
-
- error = arcmsr_alloc_sysfs_attr(acb);
- if (error)
- goto out_free_sysfs;
-
+ if (error) {
+ goto RAID_controller_stop;
+ }
+ error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb);
+ if (error) {
+ goto scsi_host_remove;
+ }
+ host->irq = pdev->irq;
scsi_scan_host(host);
- #ifdef CONFIG_SCSI_ARCMSR_AER
- pci_enable_pcie_error_reporting(pdev);
- #endif
+ INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
atomic_set(&acb->rq_map_token, 16);
- acb->fw_state = true;
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
init_timer(&acb->eternal_timer);
- acb->eternal_timer.expires = jiffies + msecs_to_jiffies(10*HZ);
+ acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ);
acb->eternal_timer.data = (unsigned long) acb;
acb->eternal_timer.function = &arcmsr_request_device_map;
add_timer(&acb->eternal_timer);
-
+ if (arcmsr_alloc_sysfs_attr(acb))
+ goto out_free_sysfs;
return 0;
out_free_sysfs:
- out_free_irq:
- free_irq(pdev->irq, acb);
- out_free_ccb_pool:
+scsi_host_remove:
+ scsi_remove_host(host);
+RAID_controller_stop:
+ arcmsr_stop_adapter_bgrb(acb);
+ arcmsr_flush_adapter_cache(acb);
arcmsr_free_ccb_pool(acb);
- out_release_regions:
+free_hbb_mu:
+ arcmsr_free_mu(acb);
+unmap_pci_region:
+ arcmsr_unmap_pciregion(acb);
+pci_release_regs:
pci_release_regions(pdev);
- out_host_put:
+scsi_host_release:
scsi_host_put(host);
- out_disable_device:
+pci_disable_dev:
pci_disable_device(pdev);
- out:
- return error;
-}
-
-static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
-{
- struct MessageUnit_A __iomem *reg = acb->pmuA;
- uint32_t Index;
- uint8_t Retries = 0x00;
-
- do {
- for (Index = 0; Index < 100; Index++) {
- if (readl(&reg->outbound_intstatus) &
- ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
- writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
- &reg->outbound_intstatus);
- return 0x00;
- }
- msleep(10);
- }/*max 1 seconds*/
-
- } while (Retries++ < 20);/*max 20 sec*/
- return 0xff;
-}
-
-static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
-{
- struct MessageUnit_B *reg = acb->pmuB;
- uint32_t Index;
- uint8_t Retries = 0x00;
-
- do {
- for (Index = 0; Index < 100; Index++) {
- if (readl(reg->iop2drv_doorbell_reg)
- & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
- writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
- , reg->iop2drv_doorbell_reg);
- writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
- return 0x00;
- }
- msleep(10);
- }/*max 1 seconds*/
-
- } while (Retries++ < 20);/*max 20 sec*/
- return 0xff;
+ return -ENODEV;
}
static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
@@ -616,7 +693,7 @@ static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
{
struct MessageUnit_B *reg = acb->pmuB;
- writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell);
if (arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
"arcmsr%d: wait 'abort all outstanding command' timeout \n"
@@ -642,76 +719,41 @@ static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
return rtnval;
}
+static bool arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb)
+{
+ struct MessageUnit_B *reg = pacb->pmuB;
+
+ writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
+ if (arcmsr_hbb_wait_msgint_ready(pacb)) {
+ printk(KERN_ERR "arcmsr%d: can't set driver mode. \n", pacb->host->host_no);
+ return false;
+}
+ return true;
+}
+
static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
{
struct scsi_cmnd *pcmd = ccb->pcmd;
scsi_dma_unmap(pcmd);
-}
+ }
-static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag)
+static void arcmsr_ccb_complete(struct CommandControlBlock *ccb)
{
struct AdapterControlBlock *acb = ccb->acb;
struct scsi_cmnd *pcmd = ccb->pcmd;
+ unsigned long flags;
+ atomic_dec(&acb->ccboutstandingcount);
arcmsr_pci_unmap_dma(ccb);
- if (stand_flag == 1)
- atomic_dec(&acb->ccboutstandingcount);
ccb->startdone = ARCMSR_CCB_DONE;
ccb->ccb_flags = 0;
+ spin_lock_irqsave(&acb->ccblist_lock, flags);
list_add_tail(&ccb->list, &acb->ccb_free_list);
+ spin_unlock_irqrestore(&acb->ccblist_lock, flags);
pcmd->scsi_done(pcmd);
}
-static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
-{
- struct MessageUnit_A __iomem *reg = acb->pmuA;
- int retry_count = 30;
-
- writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
- do {
- if (!arcmsr_hba_wait_msgint_ready(acb))
- break;
- else {
- retry_count--;
- printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
- timeout, retry count down = %d \n", acb->host->host_no, retry_count);
- }
- } while (retry_count != 0);
-}
-
-static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb)
-{
- struct MessageUnit_B *reg = acb->pmuB;
- int retry_count = 30;
-
- writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell_reg);
- do {
- if (!arcmsr_hbb_wait_msgint_ready(acb))
- break;
- else {
- retry_count--;
- printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
- timeout,retry count down = %d \n", acb->host->host_no, retry_count);
- }
- } while (retry_count != 0);
-}
-
-static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
-{
- switch (acb->adapter_type) {
-
- case ACB_ADAPTER_TYPE_A: {
- arcmsr_flush_hba_cache(acb);
- }
- break;
-
- case ACB_ADAPTER_TYPE_B: {
- arcmsr_flush_hbb_cache(acb);
- }
- }
-}
-
static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
{
@@ -745,15 +787,15 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B : {
struct MessageUnit_B *reg = acb->pmuB;
- orig_mask = readl(reg->iop2drv_doorbell_mask_reg);
- writel(0, reg->iop2drv_doorbell_mask_reg);
+ orig_mask = readl(reg->iop2drv_doorbell_mask);
+ writel(0, reg->iop2drv_doorbell_mask);
}
break;
}
return orig_mask;
}
-static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \
+static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb,
struct CommandControlBlock *ccb, uint32_t flag_ccb)
{
@@ -764,13 +806,13 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \
if (acb->devstate[id][lun] == ARECA_RAID_GONE)
acb->devstate[id][lun] = ARECA_RAID_GOOD;
ccb->pcmd->result = DID_OK << 16;
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_ccb_complete(ccb);
} else {
switch (ccb->arcmsr_cdb.DeviceStatus) {
case ARCMSR_DEV_SELECT_TIMEOUT: {
acb->devstate[id][lun] = ARECA_RAID_GONE;
ccb->pcmd->result = DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_ccb_complete(ccb);
}
break;
@@ -779,14 +821,14 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \
case ARCMSR_DEV_INIT_FAIL: {
acb->devstate[id][lun] = ARECA_RAID_GONE;
ccb->pcmd->result = DID_BAD_TARGET << 16;
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_ccb_complete(ccb);
}
break;
case ARCMSR_DEV_CHECK_CONDITION: {
acb->devstate[id][lun] = ARECA_RAID_GOOD;
arcmsr_report_sense_info(ccb);
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_ccb_complete(ccb);
}
break;
@@ -801,7 +843,7 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \
, ccb->arcmsr_cdb.DeviceStatus);
acb->devstate[id][lun] = ARECA_RAID_GONE;
ccb->pcmd->result = DID_NO_CONNECT << 16;
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_ccb_complete(ccb);
break;
}
}
@@ -811,14 +853,19 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t fla
{
struct CommandControlBlock *ccb;
+ struct ARCMSR_CDB *arcmsr_cdb;
+ int id, lun;
- ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5));
+ arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
+ ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
if (ccb->startdone == ARCMSR_CCB_ABORTED) {
struct scsi_cmnd *abortcmd = ccb->pcmd;
if (abortcmd) {
+ id = abortcmd->device->id;
+ lun = abortcmd->device->lun;
abortcmd->result |= DID_ABORT << 16;
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_ccb_complete(ccb);
printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \
isr got aborted command \n", acb->host->host_no, ccb);
}
@@ -883,6 +930,7 @@ static void arcmsr_remove(struct pci_dev *pdev)
int poll_count = 0;
arcmsr_free_sysfs_attr(acb);
scsi_remove_host(host);
+ scsi_host_put(host);
flush_scheduled_work();
del_timer_sync(&acb->eternal_timer);
arcmsr_disable_outbound_ints(acb);
@@ -908,17 +956,14 @@ static void arcmsr_remove(struct pci_dev *pdev)
if (ccb->startdone == ARCMSR_CCB_START) {
ccb->startdone = ARCMSR_CCB_ABORTED;
ccb->pcmd->result = DID_ABORT << 16;
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_ccb_complete(ccb);
}
}
}
-
free_irq(pdev->irq, acb);
arcmsr_free_ccb_pool(acb);
+ arcmsr_free_mu(acb);
pci_release_regions(pdev);
-
- scsi_host_put(host);
-
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
@@ -973,7 +1018,7 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
ARCMSR_IOP2DRV_DATA_READ_OK |
ARCMSR_IOP2DRV_CDB_DONE |
ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
- writel(mask, reg->iop2drv_doorbell_mask_reg);
+ writel(mask, reg->iop2drv_doorbell_mask);
acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
}
}
@@ -986,6 +1031,9 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
int8_t *psge = (int8_t *)&arcmsr_cdb->u;
__le32 address_lo, address_hi;
int arccdbsize = 0x30;
+ __le32 length = 0;
+ int i, cdb_sgcount = 0;
+ struct scatterlist *sg;
int nseg;
ccb->pcmd = pcmd;
@@ -995,19 +1043,12 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
arcmsr_cdb->LUN = pcmd->device->lun;
arcmsr_cdb->Function = 1;
arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len;
- arcmsr_cdb->Context = (unsigned long)arcmsr_cdb;
+ arcmsr_cdb->Context = 0;
memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
nseg = scsi_dma_map(pcmd);
- if (nseg > ARCMSR_MAX_SG_ENTRIES)
+ if (nseg > acb->host->sg_tablesize || nseg < 0)
return FAILED;
- BUG_ON(nseg < 0);
-
- if (nseg) {
- __le32 length;
- int i, cdb_sgcount = 0;
- struct scatterlist *sg;
-
/* map stor port SG list to our iop SG List. */
scsi_for_each_sg(pcmd, sg, nseg, i) {
/* Get the physical address of the current data pointer */
@@ -1034,10 +1075,10 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
}
arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
+ arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0);
if ( arccdbsize > 256)
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
- }
- if (pcmd->sc_data_direction == DMA_TO_DEVICE ) {
+ if (pcmd->cmnd[0]|WRITE_6 || pcmd->cmnd[0] | WRITE_10 || pcmd->cmnd[0]|WRITE_12) {
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
ccb->ccb_flags |= CCB_FLAG_WRITE;
}
@@ -1046,7 +1087,7 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
{
- uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr;
+ uint32_t shifted_cdb_phyaddr = ccb->shifted_cdb_phyaddr;
struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
atomic_inc(&acb->ccboutstandingcount);
ccb->startdone = ARCMSR_CCB_START;
@@ -1056,10 +1097,10 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr
struct MessageUnit_A __iomem *reg = acb->pmuA;
if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
- writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+ writel(shifted_cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
&reg->inbound_queueport);
else {
- writel(cdb_shifted_phyaddr, &reg->inbound_queueport);
+ writel(shifted_cdb_phyaddr, &reg->inbound_queueport);
}
}
break;
@@ -1071,16 +1112,16 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr
ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE);
writel(0, &reg->post_qbuffer[ending_index]);
if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
- writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\
+ writel(shifted_cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\
&reg->post_qbuffer[index]);
}
else {
- writel(cdb_shifted_phyaddr, &reg->post_qbuffer[index]);
+ writel(shifted_cdb_phyaddr, &reg->post_qbuffer[index]);
}
index++;
index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */
reg->postq_index = index;
- writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell);
}
break;
}
@@ -1103,7 +1144,7 @@ static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb)
{
struct MessageUnit_B *reg = acb->pmuB;
acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
- writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell);
if (arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
@@ -1131,23 +1172,14 @@ static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
+ dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
iounmap(acb->pmuA);
- dma_free_coherent(&acb->pdev->dev,
- ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20,
- acb->dma_coherent,
- acb->dma_coherent_handle);
- break;
}
+ break;
case ACB_ADAPTER_TYPE_B: {
- struct MessageUnit_B *reg = acb->pmuB;
- iounmap((u8 *)reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL);
- iounmap((u8 *)reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER);
- dma_free_coherent(&acb->pdev->dev,
- (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 +
- sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle);
+ dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
}
}
-
}
void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
@@ -1161,7 +1193,7 @@ void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
- writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
}
break;
}
@@ -1186,7 +1218,7 @@ static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
** push inbound doorbell tell iop, driver data write ok
** and wait reply on next hwinterrupt for next Qbuffer post
*/
- writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell);
}
break;
}
@@ -1206,7 +1238,7 @@ struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
- qbuffer = (struct QBUFFER __iomem *)reg->ioctl_rbuffer_reg;
+ qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer;
}
break;
}
@@ -1227,7 +1259,7 @@ static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBloc
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
- pqbuffer = (struct QBUFFER __iomem *)reg->ioctl_wbuffer_reg;
+ pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer;
}
break;
}
@@ -1362,7 +1394,7 @@ static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb)
struct MessageUnit_B *reg = acb->pmuB;
/*clear interrupt and message state*/
- writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
+ writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
schedule_work(&acb->arcmsr_do_message_isr_bh);
}
static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
@@ -1394,16 +1426,16 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
uint32_t outbound_doorbell;
struct MessageUnit_B *reg = acb->pmuB;
- outbound_doorbell = readl(reg->iop2drv_doorbell_reg) &
+ outbound_doorbell = readl(reg->iop2drv_doorbell) &
acb->outbound_int_enable;
if (!outbound_doorbell)
return 1;
- writel(~outbound_doorbell, reg->iop2drv_doorbell_reg);
+ writel(~outbound_doorbell, reg->iop2drv_doorbell);
/*in case the last action of doorbell interrupt clearance is cached,
this action can push HW to write down the clear bit*/
- readl(reg->iop2drv_doorbell_reg);
- writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
+ readl(reg->iop2drv_doorbell);
+ writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) {
arcmsr_iop2drv_data_wrote_handle(acb);
}
@@ -1523,12 +1555,6 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
goto message_out;
}
- if (!acb->fw_state) {
- pcmdmessagefld->cmdmessage.ReturnCode =
- ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
- }
-
ptmpQbuffer = ver_addr;
while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
&& (allxfer_len < 1031)) {
@@ -1560,7 +1586,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
}
memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len);
pcmdmessagefld->cmdmessage.Length = allxfer_len;
+ if (acb->fw_flag == FW_DEADLOCK) {
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+ } else {
pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
kfree(ver_addr);
}
break;
@@ -1575,12 +1605,13 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
}
- if (!acb->fw_state) {
+ if (acb->fw_flag == FW_DEADLOCK) {
pcmdmessagefld->cmdmessage.ReturnCode =
ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
+ } else {
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
}
-
ptmpuserbuffer = ver_addr;
user_len = pcmdmessagefld->cmdmessage.Length;
memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
@@ -1633,12 +1664,6 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
uint8_t *pQbuffer = acb->rqbuffer;
- if (!acb->fw_state) {
- pcmdmessagefld->cmdmessage.ReturnCode =
- ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
- }
-
if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
arcmsr_iop_message_read(acb);
@@ -1647,16 +1672,24 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
acb->rqbuf_firstindex = 0;
acb->rqbuf_lastindex = 0;
memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ if (acb->fw_flag == FW_DEADLOCK) {
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+ } else {
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
}
break;
case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
uint8_t *pQbuffer = acb->wqbuffer;
- if (!acb->fw_state) {
+ if (acb->fw_flag == FW_DEADLOCK) {
pcmdmessagefld->cmdmessage.ReturnCode =
ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
+ } else {
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
}
if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
@@ -1669,18 +1702,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
acb->wqbuf_firstindex = 0;
acb->wqbuf_lastindex = 0;
memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
- pcmdmessagefld->cmdmessage.ReturnCode =
- ARCMSR_MESSAGE_RETURNCODE_OK;
}
break;
case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
uint8_t *pQbuffer;
- if (!acb->fw_state) {
- pcmdmessagefld->cmdmessage.ReturnCode =
- ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
- }
if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
@@ -1698,47 +1724,52 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
memset(pQbuffer, 0, sizeof(struct QBUFFER));
pQbuffer = acb->wqbuffer;
memset(pQbuffer, 0, sizeof(struct QBUFFER));
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ if (acb->fw_flag == FW_DEADLOCK) {
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+ } else {
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
}
break;
case ARCMSR_MESSAGE_RETURN_CODE_3F: {
- if (!acb->fw_state) {
+ if (acb->fw_flag == FW_DEADLOCK) {
pcmdmessagefld->cmdmessage.ReturnCode =
ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
- }
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
+ } else {
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_3F;
}
break;
-
+ }
case ARCMSR_MESSAGE_SAY_HELLO: {
int8_t *hello_string = "Hello! I am ARCMSR";
- if (!acb->fw_state) {
+ if (acb->fw_flag == FW_DEADLOCK) {
pcmdmessagefld->cmdmessage.ReturnCode =
ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
+ } else {
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
}
memcpy(pcmdmessagefld->messagedatabuffer, hello_string
, (int16_t)strlen(hello_string));
- pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
}
break;
case ARCMSR_MESSAGE_SAY_GOODBYE:
- if (!acb->fw_state) {
+ if (acb->fw_flag == FW_DEADLOCK) {
pcmdmessagefld->cmdmessage.ReturnCode =
ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
}
arcmsr_iop_parking(acb);
break;
case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
- if (!acb->fw_state) {
+ if (acb->fw_flag == FW_DEADLOCK) {
pcmdmessagefld->cmdmessage.ReturnCode =
ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
- goto message_out;
}
arcmsr_flush_adapter_cache(acb);
break;
@@ -1756,11 +1787,16 @@ static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock
{
struct list_head *head = &acb->ccb_free_list;
struct CommandControlBlock *ccb = NULL;
-
+ unsigned long flags;
+ spin_lock_irqsave(&acb->ccblist_lock, flags);
if (!list_empty(head)) {
ccb = list_entry(head->next, struct CommandControlBlock, list);
- list_del(head->next);
+ list_del_init(&ccb->list);
+ } else {
+ spin_unlock_irqrestore(&acb->ccblist_lock, flags);
+ return 0;
}
+ spin_unlock_irqrestore(&acb->ccblist_lock, flags);
return ccb;
}
@@ -1835,66 +1871,12 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
return 0;
}
- if (acb->acb_flags & ACB_F_BUS_RESET) {
- switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A: {
- struct MessageUnit_A __iomem *reg = acb->pmuA;
- uint32_t intmask_org, outbound_doorbell;
-
- if ((readl(&reg->outbound_msgaddr1) &
- ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
- printk(KERN_NOTICE "arcmsr%d: bus reset and return busy\n",
- acb->host->host_no);
- return SCSI_MLQUEUE_HOST_BUSY;
- }
-
- acb->acb_flags &= ~ACB_F_FIRMWARE_TRAP;
- printk(KERN_NOTICE "arcmsr%d: hardware bus reset and reset ok\n",
- acb->host->host_no);
- /* disable all outbound interrupt */
- intmask_org = arcmsr_disable_outbound_ints(acb);
- arcmsr_get_firmware_spec(acb, 1);
- /*start background rebuild*/
- arcmsr_start_adapter_bgrb(acb);
- /* clear Qbuffer if door bell ringed */
- outbound_doorbell = readl(&reg->outbound_doorbell);
- /*clear interrupt */
- writel(outbound_doorbell, &reg->outbound_doorbell);
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
- &reg->inbound_doorbell);
- /* enable outbound Post Queue,outbound doorbell Interrupt */
- arcmsr_enable_outbound_ints(acb, intmask_org);
- acb->acb_flags |= ACB_F_IOP_INITED;
- acb->acb_flags &= ~ACB_F_BUS_RESET;
- }
- break;
- case ACB_ADAPTER_TYPE_B: {
- }
- }
- }
-
if (target == 16) {
/* virtual device for iop message transfer */
arcmsr_handle_virtual_command(acb, cmd);
return 0;
}
- if (acb->devstate[target][lun] == ARECA_RAID_GONE) {
- uint8_t block_cmd;
- block_cmd = cmd->cmnd[0] & 0x0f;
- if (block_cmd == 0x08 || block_cmd == 0x0a) {
- printk(KERN_NOTICE
- "arcmsr%d: block 'read/write'"
- "command with gone raid volume"
- " Cmd = %2x, TargetId = %d, Lun = %d \n"
- , acb->host->host_no
- , cmd->cmnd[0]
- , target, lun);
- cmd->result = (DID_NO_CONNECT << 16);
- cmd->scsi_done(cmd);
- return 0;
- }
- }
if (atomic_read(&acb->ccboutstandingcount) >=
ARCMSR_MAX_OUTSTANDING_CMD)
return SCSI_MLQUEUE_HOST_BUSY;
@@ -1911,7 +1893,7 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
return 0;
}
-static void *arcmsr_get_hba_config(struct AdapterControlBlock *acb, int mode)
+static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb)
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
char *acb_firm_model = acb->firm_model;
@@ -1926,10 +1908,8 @@ static void *arcmsr_get_hba_config(struct AdapterControlBlock *acb, int mode)
if (arcmsr_hba_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
miscellaneous data' timeout \n", acb->host->host_no);
- return NULL;
+ return false;
}
-
- if (mode == 1) {
count = 8;
while (count) {
*acb_firm_model = readb(iop_firm_model);
@@ -1953,53 +1933,68 @@ static void *arcmsr_get_hba_config(struct AdapterControlBlock *acb, int mode)
iop_device_map++;
count--;
}
-
- printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
- , acb->host->host_no
- , acb->firm_version);
+ printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n",
+ acb->host->host_no,
+ acb->firm_version,
+ acb->firm_model);
acb->signature = readl(&reg->message_rwbuffer[0]);
acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
+ acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/
+ return true;
}
- return reg->message_rwbuffer;
-}
-static void __iomem *arcmsr_get_hbb_config(struct AdapterControlBlock *acb, int mode)
+static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
{
struct MessageUnit_B *reg = acb->pmuB;
- uint32_t __iomem *lrwbuffer = reg->msgcode_rwbuffer_reg;
+ struct pci_dev *pdev = acb->pdev;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle;
char *acb_firm_model = acb->firm_model;
char *acb_firm_version = acb->firm_version;
char *acb_device_map = acb->device_map;
- char __iomem *iop_firm_model = (char __iomem *)(&lrwbuffer[15]);
+ char __iomem *iop_firm_model;
/*firm_model,15,60-67*/
- char __iomem *iop_firm_version = (char __iomem *)(&lrwbuffer[17]);
+ char __iomem *iop_firm_version;
/*firm_version,17,68-83*/
- char __iomem *iop_device_map = (char __iomem *) (&lrwbuffer[21]);
+ char __iomem *iop_device_map;
/*firm_version,21,84-99*/
int count;
-
- writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg);
+ dma_coherent = dma_alloc_coherent(&pdev->dev, sizeof(struct MessageUnit_B), &dma_coherent_handle, GFP_KERNEL);
+ if (!dma_coherent) {
+ printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error for hbb mu\n", acb->host->host_no);
+ return false;
+ }
+ acb->dma_coherent_handle_hbb_mu = dma_coherent_handle;
+ reg = (struct MessageUnit_B *)dma_coherent;
+ acb->pmuB = reg;
+ reg->drv2iop_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL);
+ reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK);
+ reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL);
+ reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK);
+ reg->message_wbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_WBUFFER);
+ reg->message_rbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RBUFFER);
+ reg->message_rwbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RWBUFFER);
+ iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]); /*firm_model,15,60-67*/
+ iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]); /*firm_version,17,68-83*/
+ iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]); /*firm_version,21,84-99*/
+
+ writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
if (arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
miscellaneous data' timeout \n", acb->host->host_no);
- return NULL;
+ return false;
}
-
- if (mode == 1) {
count = 8;
- while (count)
- {
+ while (count) {
*acb_firm_model = readb(iop_firm_model);
acb_firm_model++;
iop_firm_model++;
count--;
}
-
count = 16;
- while (count)
- {
+ while (count) {
*acb_firm_version = readb(iop_firm_version);
acb_firm_version++;
iop_firm_version++;
@@ -2014,46 +2009,41 @@ static void __iomem *arcmsr_get_hbb_config(struct AdapterControlBlock *acb, int
count--;
}
- printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n",
+ printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n",
acb->host->host_no,
- acb->firm_version);
+ acb->firm_version,
+ acb->firm_model);
- acb->signature = readl(lrwbuffer++);
+ acb->signature = readl(&reg->message_rwbuffer[1]);
/*firm_signature,1,00-03*/
- acb->firm_request_len = readl(lrwbuffer++);
+ acb->firm_request_len = readl(&reg->message_rwbuffer[2]);
/*firm_request_len,1,04-07*/
- acb->firm_numbers_queue = readl(lrwbuffer++);
+ acb->firm_numbers_queue = readl(&reg->message_rwbuffer[3]);
/*firm_numbers_queue,2,08-11*/
- acb->firm_sdram_size = readl(lrwbuffer++);
+ acb->firm_sdram_size = readl(&reg->message_rwbuffer[4]);
/*firm_sdram_size,3,12-15*/
- acb->firm_hd_channels = readl(lrwbuffer);
+ acb->firm_hd_channels = readl(&reg->message_rwbuffer[5]);
/*firm_ide_channels,4,16-19*/
+ acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/
+ /*firm_ide_channels,4,16-19*/
+ return true;
}
- return reg->msgcode_rwbuffer_reg;
-}
-static void *arcmsr_get_firmware_spec(struct AdapterControlBlock *acb, int mode)
+static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
{
- void *rtnval = 0;
- switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A: {
- rtnval = arcmsr_get_hba_config(acb, mode);
- }
- break;
-
- case ACB_ADAPTER_TYPE_B: {
- rtnval = arcmsr_get_hbb_config(acb, mode);
- }
- break;
- }
- return rtnval;
+ if (acb->adapter_type == ACB_ADAPTER_TYPE_A)
+ return arcmsr_get_hba_config(acb);
+ else
+ return arcmsr_get_hbb_config(acb);
}
-static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
+static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
struct CommandControlBlock *ccb;
+ struct ARCMSR_CDB *arcmsr_cdb;
uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
+ int rtn;
polling_hba_ccb_retry:
poll_count++;
@@ -2061,16 +2051,19 @@ static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
while (1) {
if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF) {
- if (poll_ccb_done)
+ if (poll_ccb_done) {
+ rtn = SUCCESS;
break;
- else {
- msleep(25);
- if (poll_count > 100)
+ } else {
+ if (poll_count > 100) {
+ rtn = FAILED;
break;
+ }
goto polling_hba_ccb_retry;
}
}
- ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5));
+ arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
+ ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
poll_ccb_done = (ccb == poll_ccb) ? 1:0;
if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
@@ -2081,8 +2074,7 @@ static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
, ccb->pcmd->device->lun
, ccb);
ccb->pcmd->result = DID_ABORT << 16;
- arcmsr_ccb_complete(ccb, 1);
- poll_ccb_done = 1;
+ arcmsr_ccb_complete(ccb);
continue;
}
printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
@@ -2092,32 +2084,38 @@ static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
, ccb
, atomic_read(&acb->ccboutstandingcount));
continue;
- }
+ } else {
arcmsr_report_ccb_state(acb, ccb, flag_ccb);
}
}
+ return rtn;
+}
-static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
+static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
struct MessageUnit_B *reg = acb->pmuB;
+ struct ARCMSR_CDB *arcmsr_cdb;
struct CommandControlBlock *ccb;
uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
- int index;
+ int index, rtn;
polling_hbb_ccb_retry:
poll_count++;
/* clear doorbell interrupt */
- writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
+ writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
while (1) {
index = reg->doneq_index;
if ((flag_ccb = readl(&reg->done_qbuffer[index])) == 0) {
- if (poll_ccb_done)
+ if (poll_ccb_done) {
+ rtn = SUCCESS;
break;
- else {
+ } else {
msleep(25);
- if (poll_count > 100)
+ if (poll_count > 100) {
+ rtn = FAILED;
break;
+ }
goto polling_hbb_ccb_retry;
}
}
@@ -2127,19 +2125,19 @@ static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
index %= ARCMSR_MAX_HBB_POSTQUEUE;
reg->doneq_index = index;
/* check ifcommand done with no error*/
- ccb = (struct CommandControlBlock *)\
- (acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/
+ arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
+ ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
poll_ccb_done = (ccb == poll_ccb) ? 1:0;
if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
- printk(KERN_NOTICE "arcmsr%d: \
- scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n"
+ printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
+ " poll command abort successfully \n"
,acb->host->host_no
,ccb->pcmd->device->id
,ccb->pcmd->device->lun
,ccb);
ccb->pcmd->result = DID_ABORT << 16;
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_ccb_complete(ccb);
continue;
}
printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
@@ -2149,30 +2147,34 @@ static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
, ccb
, atomic_read(&acb->ccboutstandingcount));
continue;
- }
+ } else {
arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+ }
} /*drain reply FIFO*/
+ return rtn;
}
-static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
+static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
+ int rtn = 0;
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
- arcmsr_polling_hba_ccbdone(acb,poll_ccb);
+ rtn = arcmsr_polling_hba_ccbdone(acb, poll_ccb);
}
break;
case ACB_ADAPTER_TYPE_B: {
- arcmsr_polling_hbb_ccbdone(acb,poll_ccb);
+ rtn = arcmsr_polling_hbb_ccbdone(acb, poll_ccb);
}
}
+ return rtn;
}
static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
{
- uint32_t cdb_phyaddr, ccb_phyaddr_hi32;
+ uint32_t cdb_phyaddr, cdb_phyaddr_hi32;
dma_addr_t dma_coherent_handle;
/*
********************************************************************
@@ -2182,7 +2184,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
*/
dma_coherent_handle = acb->dma_coherent_handle;
cdb_phyaddr = (uint32_t)(dma_coherent_handle);
- ccb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+ cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
/*
***********************************************************************
** if adapter type B, set window of "post command Q"
@@ -2191,13 +2193,13 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
- if (ccb_phyaddr_hi32 != 0) {
+ if (cdb_phyaddr_hi32 != 0) {
struct MessageUnit_A __iomem *reg = acb->pmuA;
uint32_t intmask_org;
intmask_org = arcmsr_disable_outbound_ints(acb);
writel(ARCMSR_SIGNATURE_SET_CONFIG, \
&reg->message_rwbuffer[0]);
- writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);
+ writel(cdb_phyaddr_hi32, &reg->message_rwbuffer[1]);
writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \
&reg->inbound_msgaddr0);
if (arcmsr_hba_wait_msgint_ready(acb)) {
@@ -2220,19 +2222,18 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
intmask_org = arcmsr_disable_outbound_ints(acb);
reg->postq_index = 0;
reg->doneq_index = 0;
- writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell);
if (arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \
acb->host->host_no);
return 1;
}
- post_queue_phyaddr = cdb_phyaddr + ARCMSR_MAX_FREECCB_NUM * \
- sizeof(struct CommandControlBlock) + offsetof(struct MessageUnit_B, post_qbuffer) ;
- rwbuffer = reg->msgcode_rwbuffer_reg;
+ post_queue_phyaddr = acb->dma_coherent_handle_hbb_mu;
+ rwbuffer = reg->message_rwbuffer;
/* driver "set config" signature */
writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
/* normal should be zero */
- writel(ccb_phyaddr_hi32, rwbuffer++);
+ writel(cdb_phyaddr_hi32, rwbuffer++);
/* postQ size (256 + 8)*4 */
writel(post_queue_phyaddr, rwbuffer++);
/* doneQ size (256 + 8)*4 */
@@ -2240,19 +2241,13 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
/* ccb maxQ size must be --> [(256 + 8)*4]*/
writel(1056, rwbuffer);
- writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell);
if (arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
timeout \n",acb->host->host_no);
return 1;
}
-
- writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell_reg);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
- printk(KERN_NOTICE "arcmsr%d: 'can not set diver mode \n"\
- ,acb->host->host_no);
- return 1;
- }
+ arcmsr_hbb_enable_driver_mode(acb);
arcmsr_enable_outbound_ints(acb, intmask_org);
}
break;
@@ -2277,9 +2272,9 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
do {
- firmware_state = readl(reg->iop2drv_doorbell_reg);
+ firmware_state = readl(reg->iop2drv_doorbell);
} while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
- writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
}
break;
}
@@ -2288,22 +2283,19 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb)
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
-
- if (unlikely(atomic_read(&acb->rq_map_token) == 0)) {
- acb->fw_state = false;
+ if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) {
+ return;
} else {
- /*to prevent rq_map_token from changing by other interrupt, then
- avoid the dead-lock*/
- acb->fw_state = true;
- atomic_dec(&acb->rq_map_token);
- if (!(acb->fw_state) ||
- (acb->ante_token_value == atomic_read(&acb->rq_map_token))) {
+ acb->fw_flag = FW_NORMAL;
+ if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
atomic_set(&acb->rq_map_token, 16);
}
- acb->ante_token_value = atomic_read(&acb->rq_map_token);
+ atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+ if (atomic_dec_and_test(&acb->rq_map_token))
+ return;
writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
+ mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
}
- mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6000));
return;
}
@@ -2311,21 +2303,19 @@ static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb)
{
struct MessageUnit_B __iomem *reg = acb->pmuB;
- if (unlikely(atomic_read(&acb->rq_map_token) == 0)) {
- acb->fw_state = false;
+ if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) {
+ return;
} else {
- /*to prevent rq_map_token from changing by other interrupt, then
- avoid the dead-lock*/
- acb->fw_state = true;
- atomic_dec(&acb->rq_map_token);
- if (!(acb->fw_state) ||
- (acb->ante_token_value == atomic_read(&acb->rq_map_token))) {
+ acb->fw_flag = FW_NORMAL;
+ if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
atomic_set(&acb->rq_map_token, 16);
}
- acb->ante_token_value = atomic_read(&acb->rq_map_token);
- writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg);
+ atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+ if (atomic_dec_and_test(&acb->rq_map_token))
+ return;
+ writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
+ mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
}
- mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6000));
return;
}
@@ -2360,7 +2350,7 @@ static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb)
{
struct MessageUnit_B *reg = acb->pmuB;
acb->acb_flags |= ACB_F_MSG_START_BGRB;
- writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell);
if (arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
rebulid' timeout \n",acb->host->host_no);
@@ -2396,8 +2386,8 @@ static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
/*clear interrupt and message state*/
- writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
- writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
+ writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
/* let IOP know data has been read */
}
break;
@@ -2412,7 +2402,7 @@ static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_B:
{
struct MessageUnit_B *reg = acb->pmuB;
- writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell_reg);
+ writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell);
if(arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT");
return;
@@ -2427,13 +2417,19 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
{
uint8_t value[64];
int i;
+ struct MessageUnit_A __iomem *reg = acb->pmuA;
/* backup pci config data */
+ printk(KERN_ERR "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no);
for (i = 0; i < 64; i++) {
pci_read_config_byte(acb->pdev, i, &value[i]);
}
/* hardware reset signal */
+ if ((acb->dev_id == 0x1680)) {
+ writel(ARCMSR_ARC1680_BUS_RESET, &reg->reserved1[0]);
+ } else {
pci_write_config_byte(acb->pdev, 0x84, 0x20);
+ }
msleep(1000);
/* write back pci config data */
for (i = 0; i < 64; i++) {
@@ -2446,37 +2442,25 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
****************************************************************************
****************************************************************************
*/
-#ifdef CONFIG_SCSI_ARCMSR_RESET
int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
{
struct Scsi_Host *shost = NULL;
- spinlock_t *host_lock = NULL;
int i, isleep;
shost = cmd->device->host;
- host_lock = shost->host_lock;
-
- printk(KERN_NOTICE "Host %d bus reset over, sleep %d seconds (busy %d, can queue %d) ...........\n",
- shost->host_no, sleeptime, shost->host_busy, shost->can_queue);
isleep = sleeptime / 10;
- spin_unlock_irq(host_lock);
if (isleep > 0) {
for (i = 0; i < isleep; i++) {
msleep(10000);
- printk(KERN_NOTICE "^%d^\n", i);
}
}
isleep = sleeptime % 10;
if (isleep > 0) {
msleep(isleep * 1000);
- printk(KERN_NOTICE "^v^\n");
}
- spin_lock_irq(host_lock);
- printk(KERN_NOTICE "***** wake up *****\n");
return 0;
}
-#endif
static void arcmsr_iop_init(struct AdapterControlBlock *acb)
{
uint32_t intmask_org;
@@ -2485,7 +2469,6 @@ static void arcmsr_iop_init(struct AdapterControlBlock *acb)
intmask_org = arcmsr_disable_outbound_ints(acb);
arcmsr_wait_firmware_ready(acb);
arcmsr_iop_confirm(acb);
- arcmsr_get_firmware_spec(acb, 1);
/*start background rebuild*/
arcmsr_start_adapter_bgrb(acb);
/* empty doorbell Qbuffer if door bell ringed */
@@ -2508,14 +2491,12 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
intmask_org = arcmsr_disable_outbound_ints(acb);
/* talk to iop 331 outstanding command aborted */
rtnval = arcmsr_abort_allcmd(acb);
- /* wait for 3 sec for all command aborted*/
- ssleep(3);
/* clear all outbound posted Q */
arcmsr_done4abort_postqueue(acb);
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
ccb = acb->pccb_pool[i];
if (ccb->startdone == ARCMSR_CCB_START) {
- arcmsr_ccb_complete(ccb, 1);
+ arcmsr_ccb_complete(ccb);
}
}
atomic_set(&acb->ccboutstandingcount, 0);
@@ -2530,54 +2511,49 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
{
struct AdapterControlBlock *acb =
(struct AdapterControlBlock *)cmd->device->host->hostdata;
- int retry = 0;
-
- if (acb->acb_flags & ACB_F_BUS_RESET)
- return SUCCESS;
+ uint32_t intmask_org, outbound_doorbell;
+ int retry_count = 0;
+ int rtn = FAILED;
- printk(KERN_NOTICE "arcmsr%d: bus reset ..... \n", acb->adapter_index);
- acb->acb_flags |= ACB_F_BUS_RESET;
+ acb = (struct AdapterControlBlock *) cmd->device->host->hostdata;
+ printk(KERN_ERR "arcmsr: executing eh bus reset .....num_resets = %d, \
+ num_aborts = %d \n", acb->num_resets, acb->num_aborts);
acb->num_resets++;
- while (atomic_read(&acb->ccboutstandingcount) != 0 && retry < 4) {
- arcmsr_interrupt(acb);
- retry++;
- }
- if (arcmsr_iop_reset(acb)) {
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A: {
- printk(KERN_NOTICE "arcmsr%d: do hardware bus reset, num_resets = %d num_aborts = %d \n",
- acb->adapter_index, acb->num_resets, acb->num_aborts);
+ if (acb->acb_flags & ACB_F_BUS_RESET) {
+ long timeout;
+ timeout = wait_event_timeout(wait_q,
+ (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
+ if (timeout) {
+ return SUCCESS;
+ }
+ }
+ acb->acb_flags |= ACB_F_BUS_RESET;
+ if (arcmsr_iop_reset(acb)) {
+ struct MessageUnit_A __iomem *reg;
+ reg = acb->pmuA;
arcmsr_hardware_reset(acb);
- acb->acb_flags |= ACB_F_FIRMWARE_TRAP;
acb->acb_flags &= ~ACB_F_IOP_INITED;
- #ifdef CONFIG_SCSI_ARCMSR_RESET
- struct MessageUnit_A __iomem *reg = acb->pmuA;
- uint32_t intmask_org, outbound_doorbell;
- int retry_count = 0;
sleep_again:
arcmsr_sleep_for_bus_reset(cmd);
- if ((readl(&reg->outbound_msgaddr1) &
- ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
- printk(KERN_NOTICE "arcmsr%d: hardware bus reset and return busy, retry=%d \n",
- acb->host->host_no, retry_count);
+ if ((readl(&reg->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \
+ retry=%d \n", acb->host->host_no, retry_count);
if (retry_count > retrycount) {
- printk(KERN_NOTICE "arcmsr%d: hardware bus reset and return busy, retry aborted \n",
- acb->host->host_no);
- return SUCCESS;
+ acb->fw_flag = FW_DEADLOCK;
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \
+ RETRY TERMINATED!! \n", acb->host->host_no);
+ return FAILED;
}
retry_count++;
goto sleep_again;
}
- acb->acb_flags &= ~ACB_F_FIRMWARE_TRAP;
acb->acb_flags |= ACB_F_IOP_INITED;
- acb->acb_flags &= ~ACB_F_BUS_RESET;
- printk(KERN_NOTICE "arcmsr%d: hardware bus reset and reset ok \n",
- acb->host->host_no);
/* disable all outbound interrupt */
intmask_org = arcmsr_disable_outbound_ints(acb);
- arcmsr_get_firmware_spec(acb, 1);
- /*start background rebuild*/
+ arcmsr_get_firmware_spec(acb);
arcmsr_start_adapter_bgrb(acb);
/* clear Qbuffer if door bell ringed */
outbound_doorbell = readl(&reg->outbound_doorbell);
@@ -2586,38 +2562,74 @@ sleep_again:
/* enable outbound Post Queue,outbound doorbell Interrupt */
arcmsr_enable_outbound_ints(acb, intmask_org);
atomic_set(&acb->rq_map_token, 16);
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
+ init_timer(&acb->eternal_timer);
+ acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
+ acb->eternal_timer.data = (unsigned long) acb;
+ acb->eternal_timer.function = &arcmsr_request_device_map;
+ add_timer(&acb->eternal_timer);
+ acb->acb_flags &= ~ACB_F_BUS_RESET;
+ rtn = SUCCESS;
+ printk(KERN_ERR "arcmsr: scsi eh bus reset succeeds\n");
+ } else {
+ acb->acb_flags &= ~ACB_F_BUS_RESET;
+ if (atomic_read(&acb->rq_map_token) == 0) {
+ atomic_set(&acb->rq_map_token, 16);
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
init_timer(&acb->eternal_timer);
- acb->eternal_timer.expires = jiffies + msecs_to_jiffies(20*HZ);
+ acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
acb->eternal_timer.data = (unsigned long) acb;
acb->eternal_timer.function = &arcmsr_request_device_map;
add_timer(&acb->eternal_timer);
- #endif
+ } else {
+ atomic_set(&acb->rq_map_token, 16);
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
+ mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
}
- break;
- case ACB_ADAPTER_TYPE_B: {
+ rtn = SUCCESS;
}
+ break;
}
+ case ACB_ADAPTER_TYPE_B:{
+ acb->acb_flags |= ACB_F_BUS_RESET;
+ if (arcmsr_iop_reset(acb)) {
+ acb->acb_flags &= ~ACB_F_BUS_RESET;
+ rtn = FAILED;
} else {
acb->acb_flags &= ~ACB_F_BUS_RESET;
+ if (atomic_read(&acb->rq_map_token) == 0) {
+ atomic_set(&acb->rq_map_token, 16);
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
+ init_timer(&acb->eternal_timer);
+ acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6*HZ);
+ acb->eternal_timer.data = (unsigned long) acb;
+ acb->eternal_timer.function = &arcmsr_request_device_map;
+ add_timer(&acb->eternal_timer);
+ } else {
+ atomic_set(&acb->rq_map_token, 16);
+ atomic_set(&acb->ante_token_value, 16);
+ acb->fw_flag = FW_NORMAL;
+ mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
+ }
+ rtn = SUCCESS;
}
- return SUCCESS;
+ }
+ }
+ return rtn;
}
-static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
+static int arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
struct CommandControlBlock *ccb)
{
- u32 intmask;
-
- ccb->startdone = ARCMSR_CCB_ABORTED;
-
- /*
- ** Wait for 3 sec for all command done.
- */
- ssleep(3);
-
- intmask = arcmsr_disable_outbound_ints(acb);
- arcmsr_polling_ccbdone(acb, ccb);
- arcmsr_enable_outbound_ints(acb, intmask);
+ int rtn;
+ spin_lock_irq(&acb->eh_lock);
+ rtn = arcmsr_polling_ccbdone(acb, ccb);
+ spin_unlock_irq(&acb->eh_lock);
+ return rtn;
}
static int arcmsr_abort(struct scsi_cmnd *cmd)
@@ -2625,10 +2637,12 @@ static int arcmsr_abort(struct scsi_cmnd *cmd)
struct AdapterControlBlock *acb =
(struct AdapterControlBlock *)cmd->device->host->hostdata;
int i = 0;
+ int rtn = FAILED;
printk(KERN_NOTICE
"arcmsr%d: abort device command of scsi id = %d lun = %d \n",
acb->host->host_no, cmd->device->id, cmd->device->lun);
+ acb->acb_flags |= ACB_F_ABORT;
acb->num_aborts++;
/*
************************************************
@@ -2637,17 +2651,18 @@ static int arcmsr_abort(struct scsi_cmnd *cmd)
************************************************
*/
if (!atomic_read(&acb->ccboutstandingcount))
- return SUCCESS;
+ return rtn;
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
struct CommandControlBlock *ccb = acb->pccb_pool[i];
if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) {
- arcmsr_abort_one_cmd(acb, ccb);
+ ccb->startdone = ARCMSR_CCB_ABORTED;
+ rtn = arcmsr_abort_one_cmd(acb, ccb);
break;
}
}
-
- return SUCCESS;
+ acb->acb_flags &= ~ACB_F_ABORT;
+ return rtn;
}
static const char *arcmsr_info(struct Scsi_Host *host)
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index c3928cb8b042..454027ccbf16 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -442,6 +442,31 @@ static int beiscsi_get_cid(struct beiscsi_hba *phba)
}
/**
+ * beiscsi_put_cid - Free the cid
+ * @phba: The phba for which the cid is being freed
+ * @cid: The cid to free
+ */
+static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid)
+{
+ phba->avlbl_cids++;
+ phba->cid_array[phba->cid_free++] = cid;
+ if (phba->cid_free == phba->params.cxns_per_ctrl)
+ phba->cid_free = 0;
+}
+
+/**
+ * beiscsi_free_ep - free endpoint
+ * @ep: pointer to iscsi endpoint structure
+ */
+static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep)
+{
+ struct beiscsi_hba *phba = beiscsi_ep->phba;
+
+ beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
+ beiscsi_ep->phba = NULL;
+}
+
+/**
* beiscsi_open_conn - Ask FW to open a TCP connection
* @ep: endpoint to be used
* @src_addr: The source IP address
@@ -475,7 +500,7 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start +
phba->params.cxns_per_ctrl * 2)) {
SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
- return ret;
+ goto free_ep;
}
beiscsi_ep->cid_vld = 0;
@@ -493,10 +518,10 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
if (status || extd_status) {
SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed"
- " status = %d extd_status = %d \n",
+ " status = %d extd_status = %d\n",
status, extd_status);
free_mcc_tag(&phba->ctrl, tag);
- return -1;
+ goto free_ep;
} else {
wrb = queue_get_wrb(mccq, wrb_num);
free_mcc_tag(&phba->ctrl, tag);
@@ -508,31 +533,10 @@ static int beiscsi_open_conn(struct iscsi_endpoint *ep,
SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n");
}
return 0;
-}
-
-/**
- * beiscsi_put_cid - Free the cid
- * @phba: The phba for which the cid is being freed
- * @cid: The cid to free
- */
-static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid)
-{
- phba->avlbl_cids++;
- phba->cid_array[phba->cid_free++] = cid;
- if (phba->cid_free == phba->params.cxns_per_ctrl)
- phba->cid_free = 0;
-}
-
-/**
- * beiscsi_free_ep - free endpoint
- * @ep: pointer to iscsi endpoint structure
- */
-static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep)
-{
- struct beiscsi_hba *phba = beiscsi_ep->phba;
- beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
- beiscsi_ep->phba = NULL;
+free_ep:
+ beiscsi_free_ep(beiscsi_ep);
+ return -1;
}
/**
@@ -585,7 +589,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
return ep;
free_ep:
- beiscsi_free_ep(beiscsi_ep);
+ iscsi_destroy_endpoint(ep);
return ERR_PTR(ret);
}
@@ -632,30 +636,6 @@ static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag)
}
/**
- * beiscsi_ep_disconnect - Tears down the TCP connection
- * @ep: endpoint to be used
- *
- * Tears down the TCP connection
- */
-void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
-{
- struct beiscsi_conn *beiscsi_conn;
- struct beiscsi_endpoint *beiscsi_ep;
- struct beiscsi_hba *phba;
-
- beiscsi_ep = ep->dd_data;
- phba = beiscsi_ep->phba;
- SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n",
- beiscsi_ep->ep_cid);
-
- if (beiscsi_ep->conn) {
- beiscsi_conn = beiscsi_ep->conn;
- iscsi_suspend_queue(beiscsi_conn->conn);
- }
-
-}
-
-/**
* beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table
* @phba: The phba instance
* @cid: The cid to free
@@ -673,28 +653,35 @@ static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba,
}
/**
- * beiscsi_conn_stop - Invalidate and stop the connection
- * @cls_conn: pointer to get iscsi_conn
- * @flag: The type of connection closure
+ * beiscsi_ep_disconnect - Tears down the TCP connection
+ * @ep: endpoint to be used
+ *
+ * Tears down the TCP connection
*/
-void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
+void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_conn *beiscsi_conn;
struct beiscsi_endpoint *beiscsi_ep;
- struct iscsi_session *session = conn->session;
- struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
- struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ struct beiscsi_hba *phba;
unsigned int tag;
unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH;
- beiscsi_ep = beiscsi_conn->ep;
- if (!beiscsi_ep) {
- SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n");
+ beiscsi_ep = ep->dd_data;
+ phba = beiscsi_ep->phba;
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n",
+ beiscsi_ep->ep_cid);
+
+ if (!beiscsi_ep->conn) {
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect, no "
+ "beiscsi_ep\n");
return;
}
- SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop ep_cid = %d\n",
- beiscsi_ep->ep_cid);
+ beiscsi_conn = beiscsi_ep->conn;
+ iscsi_suspend_queue(beiscsi_conn->conn);
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect ep_cid = %d\n",
+ beiscsi_ep->ep_cid);
+
tag = mgmt_invalidate_connection(phba, beiscsi_ep,
beiscsi_ep->ep_cid, 1,
savecfg_flag);
@@ -707,9 +694,9 @@ void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
phba->ctrl.mcc_numtag[tag]);
free_mcc_tag(&phba->ctrl, tag);
}
+
beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL);
beiscsi_free_ep(beiscsi_ep);
- iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
- iscsi_conn_stop(cls_conn, flag);
+ iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep);
}
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
index 1f512c28cbf9..870cdb2a73e4 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.h
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -59,8 +59,6 @@ int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn);
-void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag);
-
struct iscsi_endpoint *beiscsi_ep_connect(struct Scsi_Host *shost,
struct sockaddr *dst_addr,
int non_blocking);
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index dd5b105f8f47..0d35bf6c6acc 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -2750,6 +2750,7 @@ beiscsi_create_wrb_rings(struct beiscsi_hba *phba,
if (status != 0) {
shost_printk(KERN_ERR, phba->shost,
"wrbq create failed.");
+ kfree(pwrb_arr);
return status;
}
phwi_ctrlr->wrb_context[i * 2].cid = phwi_context->be_wrbq[i].
@@ -3773,8 +3774,8 @@ static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
ret = beiscsi_enable_pci(pcidev);
if (ret < 0) {
- shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
- "Failed to enable pci device \n");
+ dev_err(&pcidev->dev, "beiscsi_dev_probe-"
+ " Failed to enable pci device\n");
return ret;
}
@@ -3955,7 +3956,7 @@ struct iscsi_transport beiscsi_iscsi_transport = {
.get_session_param = iscsi_session_get_param,
.get_host_param = beiscsi_get_host_param,
.start_conn = beiscsi_conn_start,
- .stop_conn = beiscsi_conn_stop,
+ .stop_conn = iscsi_conn_stop,
.send_pdu = iscsi_conn_send_pdu,
.xmit_task = beiscsi_task_xmit,
.cleanup_task = beiscsi_cleanup_task,
diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.c b/drivers/scsi/cxgb3i/cxgb3i_ddp.c
index b58d9134ac1b..be0e23042c76 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_ddp.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.c
@@ -499,6 +499,7 @@ static int setup_conn_pgidx(struct t3cdev *tdev, unsigned int tid, int pg_idx,
/* set up ulp submode and page size */
req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ req->wr.wr_lo = 0;
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
req->reply = V_NO_REPLY(reply ? 0 : 1);
req->cpu_idx = 0;
@@ -564,6 +565,7 @@ int cxgb3i_setup_conn_digest(struct t3cdev *tdev, unsigned int tid,
/* set up ulp submode and page size */
req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ req->wr.wr_lo = 0;
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
req->reply = V_NO_REPLY(reply ? 0 : 1);
req->cpu_idx = 0;
diff --git a/drivers/scsi/cxgb3i/cxgb3i_offload.c b/drivers/scsi/cxgb3i/cxgb3i_offload.c
index a175be9c496f..246a6c246ed9 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_offload.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_offload.c
@@ -264,6 +264,7 @@ static void make_act_open_req(struct s3_conn *c3cn, struct sk_buff *skb,
skb->priority = CPL_PRIORITY_SETUP;
req = (struct cpl_act_open_req *)__skb_put(skb, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ req->wr.wr_lo = 0;
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, atid));
req->local_port = c3cn->saddr.sin_port;
req->peer_port = c3cn->daddr.sin_port;
@@ -273,6 +274,7 @@ static void make_act_open_req(struct s3_conn *c3cn, struct sk_buff *skb,
V_TX_CHANNEL(e->smt_idx));
req->opt0l = htonl(calc_opt0l(c3cn));
req->params = 0;
+ req->opt2 = 0;
}
static void fail_act_open(struct s3_conn *c3cn, int errno)
@@ -379,6 +381,7 @@ static void send_abort_req(struct s3_conn *c3cn)
c3cn->cpl_abort_req = NULL;
req = (struct cpl_abort_req *)skb->head;
+ memset(req, 0, sizeof(*req));
skb->priority = CPL_PRIORITY_DATA;
set_arp_failure_handler(skb, abort_arp_failure);
@@ -406,6 +409,7 @@ static void send_abort_rpl(struct s3_conn *c3cn, int rst_status)
c3cn->cpl_abort_rpl = NULL;
skb->priority = CPL_PRIORITY_DATA;
+ memset(rpl, 0, sizeof(*rpl));
rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));
rpl->wr.wr_lo = htonl(V_WR_TID(c3cn->tid));
OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, c3cn->tid));
@@ -430,6 +434,7 @@ static u32 send_rx_credits(struct s3_conn *c3cn, u32 credits, u32 dack)
req = (struct cpl_rx_data_ack *)__skb_put(skb, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ req->wr.wr_lo = 0;
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, c3cn->tid));
req->credit_dack = htonl(dack | V_RX_CREDITS(credits));
skb->priority = CPL_PRIORITY_ACK;
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index b0c576f84b28..f2d4df14c311 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -1290,7 +1290,7 @@ static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout)
ulong flags = 0;
struct adpt_i2o_post_wait_data *p1, *p2;
struct adpt_i2o_post_wait_data *wait_data =
- kmalloc(sizeof(struct adpt_i2o_post_wait_data),GFP_KERNEL);
+ kmalloc(sizeof(struct adpt_i2o_post_wait_data), GFP_ATOMIC);
DECLARE_WAITQUEUE(wait, current);
if (!wait_data)
@@ -2651,7 +2651,8 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
pDev = pDev->next_lun;
}
if(!pDev ) { // Something new add it
- d = kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
+ d = kmalloc(sizeof(struct i2o_device),
+ GFP_ATOMIC);
if(d==NULL)
{
printk(KERN_CRIT "Out of memory for I2O device data.\n");
@@ -2673,7 +2674,9 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
}
pDev = pHba->channel[bus_no].device[scsi_id];
if( pDev == NULL){
- pDev = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
+ pDev =
+ kzalloc(sizeof(struct adpt_device),
+ GFP_ATOMIC);
if(pDev == NULL) {
return -ENOMEM;
}
@@ -2682,7 +2685,9 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
while (pDev->next_lun) {
pDev = pDev->next_lun;
}
- pDev = pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
+ pDev = pDev->next_lun =
+ kzalloc(sizeof(struct adpt_device),
+ GFP_ATOMIC);
if(pDev == NULL) {
return -ENOMEM;
}
@@ -3127,7 +3132,7 @@ static int adpt_i2o_lct_get(adpt_hba* pHba)
if (pHba->lct == NULL) {
pHba->lct = dma_alloc_coherent(&pHba->pDev->dev,
pHba->lct_size, &pHba->lct_pa,
- GFP_KERNEL);
+ GFP_ATOMIC);
if(pHba->lct == NULL) {
printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
pHba->name);
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index 50aaa4bcfc50..f009191063f1 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -343,7 +343,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip,
fcf = fip->sel_fcf;
lp = fip->lp;
- if (!fcf || !lp->port_id)
+ if (!fcf || (ports && !lp->port_id))
return;
len = sizeof(*kal) + ports * sizeof(*vn);
@@ -557,38 +557,44 @@ EXPORT_SYMBOL(fcoe_ctlr_els_send);
*
* Called with lock held and preemption disabled.
*
- * An FCF is considered old if we have missed three advertisements.
- * That is, there have been no valid advertisement from it for three
- * times its keep-alive period including fuzz.
+ * An FCF is considered old if we have missed two advertisements.
+ * That is, there have been no valid advertisement from it for 2.5
+ * times its keep-alive period.
*
* In addition, determine the time when an FCF selection can occur.
*
* Also, increment the MissDiscAdvCount when no advertisement is received
* for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB).
+ *
+ * Returns the time in jiffies for the next call.
*/
-static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
+static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
{
struct fcoe_fcf *fcf;
struct fcoe_fcf *next;
+ unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
+ unsigned long deadline;
unsigned long sel_time = 0;
- unsigned long mda_time = 0;
struct fcoe_dev_stats *stats;
list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
- mda_time = fcf->fka_period + (fcf->fka_period >> 1);
- if ((fip->sel_fcf == fcf) &&
- (time_after(jiffies, fcf->time + mda_time))) {
- mod_timer(&fip->timer, jiffies + mda_time);
- stats = per_cpu_ptr(fip->lp->dev_stats,
- smp_processor_id());
- stats->MissDiscAdvCount++;
- printk(KERN_INFO "libfcoe: host%d: Missing Discovery "
- "Advertisement for fab %16.16llx count %lld\n",
- fip->lp->host->host_no, fcf->fabric_name,
- stats->MissDiscAdvCount);
+ deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2;
+ if (fip->sel_fcf == fcf) {
+ if (time_after(jiffies, deadline)) {
+ stats = per_cpu_ptr(fip->lp->dev_stats,
+ smp_processor_id());
+ stats->MissDiscAdvCount++;
+ printk(KERN_INFO "libfcoe: host%d: "
+ "Missing Discovery Advertisement "
+ "for fab %16.16llx count %lld\n",
+ fip->lp->host->host_no, fcf->fabric_name,
+ stats->MissDiscAdvCount);
+ } else if (time_after(next_timer, deadline))
+ next_timer = deadline;
}
- if (time_after(jiffies, fcf->time + fcf->fka_period * 3 +
- msecs_to_jiffies(FIP_FCF_FUZZ * 3))) {
+
+ deadline += fcf->fka_period;
+ if (time_after_eq(jiffies, deadline)) {
if (fip->sel_fcf == fcf)
fip->sel_fcf = NULL;
list_del(&fcf->list);
@@ -598,19 +604,20 @@ static void fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
stats = per_cpu_ptr(fip->lp->dev_stats,
smp_processor_id());
stats->VLinkFailureCount++;
- } else if (fcoe_ctlr_mtu_valid(fcf) &&
- (!sel_time || time_before(sel_time, fcf->time))) {
- sel_time = fcf->time;
+ } else {
+ if (time_after(next_timer, deadline))
+ next_timer = deadline;
+ if (fcoe_ctlr_mtu_valid(fcf) &&
+ (!sel_time || time_before(sel_time, fcf->time)))
+ sel_time = fcf->time;
}
}
- if (sel_time) {
+ if (sel_time && !fip->sel_fcf && !fip->sel_time) {
sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY);
fip->sel_time = sel_time;
- if (time_before(sel_time, fip->timer.expires))
- mod_timer(&fip->timer, sel_time);
- } else {
- fip->sel_time = 0;
}
+
+ return next_timer;
}
/**
@@ -633,6 +640,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
unsigned long t;
size_t rlen;
size_t dlen;
+ u32 desc_mask;
memset(fcf, 0, sizeof(*fcf));
fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA);
@@ -640,6 +648,12 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
fiph = (struct fip_header *)skb->data;
fcf->flags = ntohs(fiph->fip_flags);
+ /*
+ * mask of required descriptors. validating each one clears its bit.
+ */
+ desc_mask = BIT(FIP_DT_PRI) | BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
+ BIT(FIP_DT_FAB) | BIT(FIP_DT_FKA);
+
rlen = ntohs(fiph->fip_dl_len) * 4;
if (rlen + sizeof(*fiph) > skb->len)
return -EINVAL;
@@ -649,11 +663,19 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
dlen = desc->fip_dlen * FIP_BPW;
if (dlen < sizeof(*desc) || dlen > rlen)
return -EINVAL;
+ /* Drop Adv if there are duplicate critical descriptors */
+ if ((desc->fip_dtype < 32) &&
+ !(desc_mask & 1U << desc->fip_dtype)) {
+ LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
+ "Descriptors in FIP adv\n");
+ return -EINVAL;
+ }
switch (desc->fip_dtype) {
case FIP_DT_PRI:
if (dlen != sizeof(struct fip_pri_desc))
goto len_err;
fcf->pri = ((struct fip_pri_desc *)desc)->fd_pri;
+ desc_mask &= ~BIT(FIP_DT_PRI);
break;
case FIP_DT_MAC:
if (dlen != sizeof(struct fip_mac_desc))
@@ -666,12 +688,14 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
"in FIP adv\n");
return -EINVAL;
}
+ desc_mask &= ~BIT(FIP_DT_MAC);
break;
case FIP_DT_NAME:
if (dlen != sizeof(struct fip_wwn_desc))
goto len_err;
wwn = (struct fip_wwn_desc *)desc;
fcf->switch_name = get_unaligned_be64(&wwn->fd_wwn);
+ desc_mask &= ~BIT(FIP_DT_NAME);
break;
case FIP_DT_FAB:
if (dlen != sizeof(struct fip_fab_desc))
@@ -680,6 +704,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
fcf->fabric_name = get_unaligned_be64(&fab->fd_wwn);
fcf->vfid = ntohs(fab->fd_vfid);
fcf->fc_map = ntoh24(fab->fd_map);
+ desc_mask &= ~BIT(FIP_DT_FAB);
break;
case FIP_DT_FKA:
if (dlen != sizeof(struct fip_fka_desc))
@@ -690,6 +715,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
t = ntohl(fka->fd_fka_period);
if (t >= FCOE_CTLR_MIN_FKA)
fcf->fka_period = msecs_to_jiffies(t);
+ desc_mask &= ~BIT(FIP_DT_FKA);
break;
case FIP_DT_MAP_OUI:
case FIP_DT_FCOE_SIZE:
@@ -703,7 +729,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
/* standard says ignore unknown descriptors >= 128 */
if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
return -EINVAL;
- continue;
+ break;
}
desc = (struct fip_desc *)((char *)desc + dlen);
rlen -= dlen;
@@ -712,6 +738,11 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
return -EINVAL;
if (!fcf->switch_name || !fcf->fabric_name)
return -EINVAL;
+ if (desc_mask) {
+ LIBFCOE_FIP_DBG(fip, "adv missing descriptors mask %x\n",
+ desc_mask);
+ return -EINVAL;
+ }
return 0;
len_err:
@@ -762,18 +793,21 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
list_add(&fcf->list, &fip->fcfs);
} else {
/*
- * Flags in advertisements are ignored once the FCF is
- * selected. Flags in unsolicited advertisements are
- * ignored after a usable solicited advertisement
- * has been received.
+ * Update the FCF's keep-alive descriptor flags.
+ * Other flag changes from new advertisements are
+ * ignored after a solicited advertisement is
+ * received and the FCF is selectable (usable).
*/
- if (fcf == fip->sel_fcf) {
+ fcf->fd_flags = new.fd_flags;
+ if (!fcoe_ctlr_fcf_usable(fcf))
+ fcf->flags = new.flags;
+
+ if (fcf == fip->sel_fcf && !fcf->fd_flags) {
fip->ctlr_ka_time -= fcf->fka_period;
fip->ctlr_ka_time += new.fka_period;
if (time_before(fip->ctlr_ka_time, fip->timer.expires))
mod_timer(&fip->timer, fip->ctlr_ka_time);
- } else if (!fcoe_ctlr_fcf_usable(fcf))
- fcf->flags = new.flags;
+ }
fcf->fka_period = new.fka_period;
memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN);
}
@@ -805,7 +839,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
* If this is the first validated FCF, note the time and
* set a timer to trigger selection.
*/
- if (mtu_valid && !fip->sel_time && fcoe_ctlr_fcf_usable(fcf)) {
+ if (mtu_valid && !fip->sel_fcf && fcoe_ctlr_fcf_usable(fcf)) {
fip->sel_time = jiffies +
msecs_to_jiffies(FCOE_CTLR_START_DELAY);
if (!timer_pending(&fip->timer) ||
@@ -837,6 +871,8 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
size_t els_len = 0;
size_t rlen;
size_t dlen;
+ u32 desc_mask = 0;
+ u32 desc_cnt = 0;
fiph = (struct fip_header *)skb->data;
sub = fiph->fip_subcode;
@@ -849,11 +885,27 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
desc = (struct fip_desc *)(fiph + 1);
while (rlen > 0) {
+ desc_cnt++;
dlen = desc->fip_dlen * FIP_BPW;
if (dlen < sizeof(*desc) || dlen > rlen)
goto drop;
+ /* Drop ELS if there are duplicate critical descriptors */
+ if (desc->fip_dtype < 32) {
+ if (desc_mask & 1U << desc->fip_dtype) {
+ LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
+ "Descriptors in FIP ELS\n");
+ goto drop;
+ }
+ desc_mask |= (1 << desc->fip_dtype);
+ }
switch (desc->fip_dtype) {
case FIP_DT_MAC:
+ if (desc_cnt == 1) {
+ LIBFCOE_FIP_DBG(fip, "FIP descriptors "
+ "received out of order\n");
+ goto drop;
+ }
+
if (dlen != sizeof(struct fip_mac_desc))
goto len_err;
memcpy(granted_mac,
@@ -870,6 +922,11 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
case FIP_DT_FDISC:
case FIP_DT_LOGO:
case FIP_DT_ELP:
+ if (desc_cnt != 1) {
+ LIBFCOE_FIP_DBG(fip, "FIP descriptors "
+ "received out of order\n");
+ goto drop;
+ }
if (fh)
goto drop;
if (dlen < sizeof(*els) + sizeof(*fh) + 1)
@@ -885,7 +942,12 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
/* standard says ignore unknown descriptors >= 128 */
if (desc->fip_dtype < FIP_DT_VENDOR_BASE)
goto drop;
- continue;
+ if (desc_cnt <= 2) {
+ LIBFCOE_FIP_DBG(fip, "FIP descriptors "
+ "received out of order\n");
+ goto drop;
+ }
+ break;
}
desc = (struct fip_desc *)((char *)desc + dlen);
rlen -= dlen;
@@ -900,6 +962,13 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
els_op == ELS_LS_ACC && is_valid_ether_addr(granted_mac))
fip->flogi_oxid = FC_XID_UNKNOWN;
+ if ((desc_cnt == 0) || ((els_op != ELS_LS_RJT) &&
+ (!(1U << FIP_DT_MAC & desc_mask)))) {
+ LIBFCOE_FIP_DBG(fip, "Missing critical descriptors "
+ "in FIP ELS\n");
+ goto drop;
+ }
+
/*
* Convert skb into an fc_frame containing only the ELS.
*/
@@ -945,7 +1014,9 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
size_t dlen;
struct fcoe_fcf *fcf = fip->sel_fcf;
struct fc_lport *lport = fip->lp;
- u32 desc_mask;
+ struct fc_lport *vn_port = NULL;
+ u32 desc_mask;
+ int is_vn_port = 0;
LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
@@ -963,6 +1034,13 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
dlen = desc->fip_dlen * FIP_BPW;
if (dlen > rlen)
return;
+ /* Drop CVL if there are duplicate critical descriptors */
+ if ((desc->fip_dtype < 32) &&
+ !(desc_mask & 1U << desc->fip_dtype)) {
+ LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
+ "Descriptors in FIP CVL\n");
+ return;
+ }
switch (desc->fip_dtype) {
case FIP_DT_MAC:
mp = (struct fip_mac_desc *)desc;
@@ -987,8 +1065,26 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
if (compare_ether_addr(vp->fd_mac,
fip->get_src_addr(lport)) == 0 &&
get_unaligned_be64(&vp->fd_wwpn) == lport->wwpn &&
- ntoh24(vp->fd_fc_id) == lport->port_id)
+ ntoh24(vp->fd_fc_id) == lport->port_id) {
desc_mask &= ~BIT(FIP_DT_VN_ID);
+ break;
+ }
+ /* check if clr_vlink is for NPIV port */
+ mutex_lock(&lport->lp_mutex);
+ list_for_each_entry(vn_port, &lport->vports, list) {
+ if (compare_ether_addr(vp->fd_mac,
+ fip->get_src_addr(vn_port)) == 0 &&
+ (get_unaligned_be64(&vp->fd_wwpn)
+ == vn_port->wwpn) &&
+ (ntoh24(vp->fd_fc_id) ==
+ fc_host_port_id(vn_port->host))) {
+ desc_mask &= ~BIT(FIP_DT_VN_ID);
+ is_vn_port = 1;
+ break;
+ }
+ }
+ mutex_unlock(&lport->lp_mutex);
+
break;
default:
/* standard says ignore unknown descriptors >= 128 */
@@ -1009,14 +1105,18 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
} else {
LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n");
- spin_lock_bh(&fip->lock);
- per_cpu_ptr(lport->dev_stats,
- smp_processor_id())->VLinkFailureCount++;
- fcoe_ctlr_reset(fip);
- spin_unlock_bh(&fip->lock);
+ if (is_vn_port)
+ fc_lport_reset(vn_port);
+ else {
+ spin_lock_bh(&fip->lock);
+ per_cpu_ptr(lport->dev_stats,
+ smp_processor_id())->VLinkFailureCount++;
+ fcoe_ctlr_reset(fip);
+ spin_unlock_bh(&fip->lock);
- fc_lport_reset(fip->lp);
- fcoe_ctlr_solicit(fip, NULL);
+ fc_lport_reset(fip->lp);
+ fcoe_ctlr_solicit(fip, NULL);
+ }
}
}
@@ -1148,7 +1248,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)
struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg;
struct fcoe_fcf *sel;
struct fcoe_fcf *fcf;
- unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
+ unsigned long next_timer;
spin_lock_bh(&fip->lock);
if (fip->state == FIP_ST_DISABLED) {
@@ -1157,13 +1257,16 @@ static void fcoe_ctlr_timeout(unsigned long arg)
}
fcf = fip->sel_fcf;
- fcoe_ctlr_age_fcfs(fip);
+ next_timer = fcoe_ctlr_age_fcfs(fip);
sel = fip->sel_fcf;
- if (!sel && fip->sel_time && time_after_eq(jiffies, fip->sel_time)) {
- fcoe_ctlr_select(fip);
- sel = fip->sel_fcf;
- fip->sel_time = 0;
+ if (!sel && fip->sel_time) {
+ if (time_after_eq(jiffies, fip->sel_time)) {
+ fcoe_ctlr_select(fip);
+ sel = fip->sel_fcf;
+ fip->sel_time = 0;
+ } else if (time_after(next_timer, fip->sel_time))
+ next_timer = fip->sel_time;
}
if (sel != fcf) {
@@ -1176,6 +1279,8 @@ static void fcoe_ctlr_timeout(unsigned long arg)
fip->port_ka_time = jiffies +
msecs_to_jiffies(FIP_VN_KA_PERIOD);
fip->ctlr_ka_time = jiffies + sel->fka_period;
+ if (time_after(next_timer, fip->ctlr_ka_time))
+ next_timer = fip->ctlr_ka_time;
} else {
printk(KERN_NOTICE "libfcoe: host%d: "
"FIP Fibre-Channel Forwarder timed out. "
@@ -1201,12 +1306,9 @@ static void fcoe_ctlr_timeout(unsigned long arg)
}
if (time_after(next_timer, fip->port_ka_time))
next_timer = fip->port_ka_time;
- mod_timer(&fip->timer, next_timer);
- } else if (fip->sel_time) {
- next_timer = fip->sel_time +
- msecs_to_jiffies(FCOE_CTLR_START_DELAY);
- mod_timer(&fip->timer, next_timer);
}
+ if (!list_empty(&fip->fcfs))
+ mod_timer(&fip->timer, next_timer);
if (fip->send_ctlr_ka || fip->send_port_ka)
schedule_work(&fip->timer_work);
spin_unlock_bh(&fip->lock);
@@ -1232,8 +1334,11 @@ static void fcoe_ctlr_timer_work(struct work_struct *work)
fip->reset_req = 0;
spin_unlock_bh(&fip->lock);
- if (reset)
+ if (reset) {
fc_lport_reset(fip->lp);
+ /* restart things with a solicitation */
+ fcoe_ctlr_solicit(fip, NULL);
+ }
if (fip->send_ctlr_ka) {
fip->send_ctlr_ka = 0;
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
index 3cc47c6e1ada..198cbab3e894 100644
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -1246,11 +1246,10 @@ int fnic_abort_cmd(struct scsi_cmnd *sc)
lp = shost_priv(sc->device->host);
fnic = lport_priv(lp);
- FNIC_SCSI_DBG(KERN_DEBUG,
- fnic->lport->host,
- "Abort Cmd called FCID 0x%x, LUN 0x%x TAG %d\n",
- (starget_to_rport(scsi_target(sc->device)))->port_id,
- sc->device->lun, sc->request->tag);
+ rport = starget_to_rport(scsi_target(sc->device));
+ FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+ "Abort Cmd called FCID 0x%x, LUN 0x%x TAG %d\n",
+ rport->port_id, sc->device->lun, sc->request->tag);
if (lp->state != LPORT_ST_READY || !(lp->link_up)) {
ret = FAILED;
@@ -1299,7 +1298,6 @@ int fnic_abort_cmd(struct scsi_cmnd *sc)
* port is up, then send abts to the remote port to terminate
* the IO. Else, just locally terminate the IO in the firmware
*/
- rport = starget_to_rport(scsi_target(sc->device));
if (fc_remote_port_chkready(rport) == 0)
task_req = FCPIO_ITMF_ABT_TASK;
else
@@ -1418,7 +1416,6 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
unsigned long flags;
int ret = 0;
struct scsi_cmnd *sc;
- struct fc_rport *rport;
struct scsi_lun fc_lun;
struct scsi_device *lun_dev = lr_sc->device;
DECLARE_COMPLETION_ONSTACK(tm_done);
@@ -1458,7 +1455,6 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
/* Now queue the abort command to firmware */
int_to_scsilun(sc->device->lun, &fc_lun);
- rport = starget_to_rport(scsi_target(sc->device));
if (fnic_queue_abort_io_req(fnic, tag,
FCPIO_ITMF_ABT_TASK_TERM,
@@ -1528,18 +1524,16 @@ int fnic_device_reset(struct scsi_cmnd *sc)
lp = shost_priv(sc->device->host);
fnic = lport_priv(lp);
- FNIC_SCSI_DBG(KERN_DEBUG,
- fnic->lport->host,
- "Device reset called FCID 0x%x, LUN 0x%x\n",
- (starget_to_rport(scsi_target(sc->device)))->port_id,
- sc->device->lun);
+ rport = starget_to_rport(scsi_target(sc->device));
+ FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+ "Device reset called FCID 0x%x, LUN 0x%x\n",
+ rport->port_id, sc->device->lun);
if (lp->state != LPORT_ST_READY || !(lp->link_up))
goto fnic_device_reset_end;
/* Check if remote port up */
- rport = starget_to_rport(scsi_target(sc->device));
if (fc_remote_port_chkready(rport))
goto fnic_device_reset_end;
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index c016426b31b2..4f5551b5fe53 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -86,10 +86,17 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324a},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324b},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3233},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3250},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3251},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3252},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3253},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3254},
#define PCI_DEVICE_ID_HP_CISSF 0x333f
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x333F},
{PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
+ {PCI_VENDOR_ID_COMPAQ, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
{0,}
};
@@ -109,12 +116,18 @@ static struct board_type products[] = {
{0x324b103C, "Smart Array P711m", &SA5_access},
{0x3233103C, "StorageWorks P1210m", &SA5_access},
{0x333F103C, "StorageWorks P1210m", &SA5_access},
+ {0x3250103C, "Smart Array", &SA5_access},
+ {0x3250113C, "Smart Array", &SA5_access},
+ {0x3250123C, "Smart Array", &SA5_access},
+ {0x3250133C, "Smart Array", &SA5_access},
+ {0x3250143C, "Smart Array", &SA5_access},
{0xFFFF103C, "Unknown Smart Array", &SA5_access},
};
static int number_of_controllers;
-static irqreturn_t do_hpsa_intr(int irq, void *dev_id);
+static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id);
+static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id);
static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg);
static void start_io(struct ctlr_info *h);
@@ -148,6 +161,8 @@ static ssize_t lunid_show(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t unique_id_show(struct device *dev,
struct device_attribute *attr, char *buf);
+static ssize_t host_show_firmware_revision(struct device *dev,
+ struct device_attribute *attr, char *buf);
static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno);
static ssize_t host_store_rescan(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count);
@@ -158,13 +173,21 @@ static void check_ioctl_unit_attention(struct ctlr_info *h,
/* performant mode helper functions */
static void calc_bucket_map(int *bucket, int num_buckets,
int nsgs, int *bucket_map);
-static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
+static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
static inline u32 next_command(struct ctlr_info *h);
+static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
+ void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+ u64 *cfg_offset);
+static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
+ unsigned long *memory_bar);
+static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL);
static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL);
static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan);
+static DEVICE_ATTR(firmware_revision, S_IRUGO,
+ host_show_firmware_revision, NULL);
static struct device_attribute *hpsa_sdev_attrs[] = {
&dev_attr_raid_level,
@@ -175,6 +198,7 @@ static struct device_attribute *hpsa_sdev_attrs[] = {
static struct device_attribute *hpsa_shost_attrs[] = {
&dev_attr_rescan,
+ &dev_attr_firmware_revision,
NULL,
};
@@ -260,6 +284,21 @@ static ssize_t host_store_rescan(struct device *dev,
return count;
}
+static ssize_t host_show_firmware_revision(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ctlr_info *h;
+ struct Scsi_Host *shost = class_to_shost(dev);
+ unsigned char *fwrev;
+
+ h = shost_to_hba(shost);
+ if (!h->hba_inquiry_data)
+ return 0;
+ fwrev = &h->hba_inquiry_data[32];
+ return snprintf(buf, 20, "%c%c%c%c\n",
+ fwrev[0], fwrev[1], fwrev[2], fwrev[3]);
+}
+
/* Enqueuing and dequeuing functions for cmdlists. */
static inline void addQ(struct hlist_head *list, struct CommandList *c)
{
@@ -1440,12 +1479,6 @@ static int hpsa_update_device_info(struct ctlr_info *h,
goto bail_out;
}
- /* As a side effect, record the firmware version number
- * if we happen to be talking to the RAID controller.
- */
- if (is_hba_lunid(scsi3addr))
- memcpy(h->firm_ver, &inq_buff[32], 4);
-
this_device->devtype = (inq_buff[0] & 0x1f);
memcpy(this_device->scsi3addr, scsi3addr, 8);
memcpy(this_device->vendor, &inq_buff[8],
@@ -2826,9 +2859,8 @@ static inline bool interrupt_pending(struct ctlr_info *h)
static inline long interrupt_not_for_us(struct ctlr_info *h)
{
- return !(h->msi_vector || h->msix_vector) &&
- ((h->access.intr_pending(h) == 0) ||
- (h->interrupts_enabled == 0));
+ return (h->access.intr_pending(h) == 0) ||
+ (h->interrupts_enabled == 0);
}
static inline int bad_tag(struct ctlr_info *h, u32 tag_index,
@@ -2902,7 +2934,7 @@ static inline u32 process_nonindexed_cmd(struct ctlr_info *h,
return next_command(h);
}
-static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
+static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id)
{
struct ctlr_info *h = dev_id;
unsigned long flags;
@@ -2911,6 +2943,26 @@ static irqreturn_t do_hpsa_intr(int irq, void *dev_id)
if (interrupt_not_for_us(h))
return IRQ_NONE;
spin_lock_irqsave(&h->lock, flags);
+ while (interrupt_pending(h)) {
+ raw_tag = get_next_completion(h);
+ while (raw_tag != FIFO_EMPTY) {
+ if (hpsa_tag_contains_index(raw_tag))
+ raw_tag = process_indexed_cmd(h, raw_tag);
+ else
+ raw_tag = process_nonindexed_cmd(h, raw_tag);
+ }
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id)
+{
+ struct ctlr_info *h = dev_id;
+ unsigned long flags;
+ u32 raw_tag;
+
+ spin_lock_irqsave(&h->lock, flags);
raw_tag = get_next_completion(h);
while (raw_tag != FIFO_EMPTY) {
if (hpsa_tag_contains_index(raw_tag))
@@ -3052,17 +3104,75 @@ static __devinit int hpsa_reset_msi(struct pci_dev *pdev)
return 0;
}
-/* This does a hard reset of the controller using PCI power management
- * states.
- */
-static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
+static int hpsa_controller_hard_reset(struct pci_dev *pdev,
+ void * __iomem vaddr, bool use_doorbell)
{
- u16 pmcsr, saved_config_space[32];
- int i, pos;
+ u16 pmcsr;
+ int pos;
- dev_info(&pdev->dev, "using PCI PM to reset controller\n");
+ if (use_doorbell) {
+ /* For everything after the P600, the PCI power state method
+ * of resetting the controller doesn't work, so we have this
+ * other way using the doorbell register.
+ */
+ dev_info(&pdev->dev, "using doorbell to reset controller\n");
+ writel(DOORBELL_CTLR_RESET, vaddr + SA5_DOORBELL);
+ msleep(1000);
+ } else { /* Try to do it the PCI power state way */
+
+ /* Quoting from the Open CISS Specification: "The Power
+ * Management Control/Status Register (CSR) controls the power
+ * state of the device. The normal operating state is D0,
+ * CSR=00h. The software off state is D3, CSR=03h. To reset
+ * the controller, place the interface device in D3 then to D0,
+ * this causes a secondary PCI reset which will reset the
+ * controller." */
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
+ if (pos == 0) {
+ dev_err(&pdev->dev,
+ "hpsa_reset_controller: "
+ "PCI PM not supported\n");
+ return -ENODEV;
+ }
+ dev_info(&pdev->dev, "using PCI PM to reset controller\n");
+ /* enter the D3hot power management state */
+ pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
+ pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+ pmcsr |= PCI_D3hot;
+ pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
- /* This is very nearly the same thing as
+ msleep(500);
+
+ /* enter the D0 power management state */
+ pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+ pmcsr |= PCI_D0;
+ pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+ msleep(500);
+ }
+ return 0;
+}
+
+/* This does a hard reset of the controller using PCI power management
+ * states or the using the doorbell register.
+ */
+static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
+{
+ u16 saved_config_space[32];
+ u64 cfg_offset;
+ u32 cfg_base_addr;
+ u64 cfg_base_addr_index;
+ void __iomem *vaddr;
+ unsigned long paddr;
+ u32 misc_fw_support, active_transport;
+ int rc, i;
+ struct CfgTable __iomem *cfgtable;
+ bool use_doorbell;
+ u32 board_id;
+
+ /* For controllers as old as the P600, this is very nearly
+ * the same thing as
*
* pci_save_state(pci_dev);
* pci_set_power_state(pci_dev, PCI_D3hot);
@@ -3076,41 +3186,54 @@ static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
* violate the ordering requirements for restoring the
* configuration space from the CCISS document (see the
* comment below). So we roll our own ....
+ *
+ * For controllers newer than the P600, the pci power state
+ * method of resetting doesn't work so we have another way
+ * using the doorbell register.
*/
+ /* Exclude 640x boards. These are two pci devices in one slot
+ * which share a battery backed cache module. One controls the
+ * cache, the other accesses the cache through the one that controls
+ * it. If we reset the one controlling the cache, the other will
+ * likely not be happy. Just forbid resetting this conjoined mess.
+ * The 640x isn't really supported by hpsa anyway.
+ */
+ hpsa_lookup_board_id(pdev, &board_id);
+ if (board_id == 0x409C0E11 || board_id == 0x409D0E11)
+ return -ENOTSUPP;
+
for (i = 0; i < 32; i++)
pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
- pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
- if (pos == 0) {
- dev_err(&pdev->dev,
- "hpsa_reset_controller: PCI PM not supported\n");
- return -ENODEV;
- }
-
- /* Quoting from the Open CISS Specification: "The Power
- * Management Control/Status Register (CSR) controls the power
- * state of the device. The normal operating state is D0,
- * CSR=00h. The software off state is D3, CSR=03h. To reset
- * the controller, place the interface device in D3 then to
- * D0, this causes a secondary PCI reset which will reset the
- * controller."
- */
- /* enter the D3hot power management state */
- pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
- pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
- pmcsr |= PCI_D3hot;
- pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+ /* find the first memory BAR, so we can find the cfg table */
+ rc = hpsa_pci_find_memory_BAR(pdev, &paddr);
+ if (rc)
+ return rc;
+ vaddr = remap_pci_mem(paddr, 0x250);
+ if (!vaddr)
+ return -ENOMEM;
- msleep(500);
+ /* find cfgtable in order to check if reset via doorbell is supported */
+ rc = hpsa_find_cfg_addrs(pdev, vaddr, &cfg_base_addr,
+ &cfg_base_addr_index, &cfg_offset);
+ if (rc)
+ goto unmap_vaddr;
+ cfgtable = remap_pci_mem(pci_resource_start(pdev,
+ cfg_base_addr_index) + cfg_offset, sizeof(*cfgtable));
+ if (!cfgtable) {
+ rc = -ENOMEM;
+ goto unmap_vaddr;
+ }
- /* enter the D0 power management state */
- pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
- pmcsr |= PCI_D0;
- pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+ /* If reset via doorbell register is supported, use that. */
+ misc_fw_support = readl(&cfgtable->misc_fw_support);
+ use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
- msleep(500);
+ rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell);
+ if (rc)
+ goto unmap_cfgtable;
/* Restore the PCI configuration space. The Open CISS
* Specification says, "Restore the PCI Configuration
@@ -3127,7 +3250,29 @@ static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
wmb();
pci_write_config_word(pdev, 4, saved_config_space[2]);
- return 0;
+ /* Some devices (notably the HP Smart Array 5i Controller)
+ need a little pause here */
+ msleep(HPSA_POST_RESET_PAUSE_MSECS);
+
+ /* Controller should be in simple mode at this point. If it's not,
+ * It means we're on one of those controllers which doesn't support
+ * the doorbell reset method and on which the PCI power management reset
+ * method doesn't work (P800, for example.)
+ * In those cases, pretend the reset worked and hope for the best.
+ */
+ active_transport = readl(&cfgtable->TransportActive);
+ if (active_transport & PERFORMANT_MODE) {
+ dev_warn(&pdev->dev, "Unable to successfully reset controller,"
+ " proceeding anyway.\n");
+ rc = -ENOTSUPP;
+ }
+
+unmap_cfgtable:
+ iounmap(cfgtable);
+
+unmap_vaddr:
+ iounmap(vaddr);
+ return rc;
}
/*
@@ -3135,9 +3280,9 @@ static __devinit int hpsa_hard_reset_controller(struct pci_dev *pdev)
* the io functions.
* This is for debug only.
*/
-#ifdef HPSA_DEBUG
static void print_cfg_table(struct device *dev, struct CfgTable *tb)
{
+#ifdef HPSA_DEBUG
int i;
char temp_name[17];
@@ -3167,8 +3312,8 @@ static void print_cfg_table(struct device *dev, struct CfgTable *tb)
dev_info(dev, " Server Name = %s\n", temp_name);
dev_info(dev, " Heartbeat Counter = 0x%x\n\n\n",
readl(&(tb->HeartBeat)));
-}
#endif /* HPSA_DEBUG */
+}
static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
{
@@ -3209,8 +3354,7 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
* controllers that are capable. If not, we use IO-APIC mode.
*/
-static void __devinit hpsa_interrupt_mode(struct ctlr_info *h,
- struct pci_dev *pdev, u32 board_id)
+static void __devinit hpsa_interrupt_mode(struct ctlr_info *h)
{
#ifdef CONFIG_PCI_MSI
int err;
@@ -3219,13 +3363,12 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h,
};
/* Some boards advertise MSI but don't really support it */
- if ((board_id == 0x40700E11) ||
- (board_id == 0x40800E11) ||
- (board_id == 0x40820E11) || (board_id == 0x40830E11))
+ if ((h->board_id == 0x40700E11) || (h->board_id == 0x40800E11) ||
+ (h->board_id == 0x40820E11) || (h->board_id == 0x40830E11))
goto default_int_mode;
- if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
- dev_info(&pdev->dev, "MSIX\n");
- err = pci_enable_msix(pdev, hpsa_msix_entries, 4);
+ if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
+ dev_info(&h->pdev->dev, "MSIX\n");
+ err = pci_enable_msix(h->pdev, hpsa_msix_entries, 4);
if (!err) {
h->intr[0] = hpsa_msix_entries[0].vector;
h->intr[1] = hpsa_msix_entries[1].vector;
@@ -3235,144 +3378,158 @@ static void __devinit hpsa_interrupt_mode(struct ctlr_info *h,
return;
}
if (err > 0) {
- dev_warn(&pdev->dev, "only %d MSI-X vectors "
+ dev_warn(&h->pdev->dev, "only %d MSI-X vectors "
"available\n", err);
goto default_int_mode;
} else {
- dev_warn(&pdev->dev, "MSI-X init failed %d\n",
+ dev_warn(&h->pdev->dev, "MSI-X init failed %d\n",
err);
goto default_int_mode;
}
}
- if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
- dev_info(&pdev->dev, "MSI\n");
- if (!pci_enable_msi(pdev))
+ if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) {
+ dev_info(&h->pdev->dev, "MSI\n");
+ if (!pci_enable_msi(h->pdev))
h->msi_vector = 1;
else
- dev_warn(&pdev->dev, "MSI init failed\n");
+ dev_warn(&h->pdev->dev, "MSI init failed\n");
}
default_int_mode:
#endif /* CONFIG_PCI_MSI */
/* if we get here we're going to use the default interrupt mode */
- h->intr[PERF_MODE_INT] = pdev->irq;
+ h->intr[PERF_MODE_INT] = h->pdev->irq;
}
-static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
+static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id)
{
- ushort subsystem_vendor_id, subsystem_device_id, command;
- u32 board_id, scratchpad = 0;
- u64 cfg_offset;
- u32 cfg_base_addr;
- u64 cfg_base_addr_index;
- u32 trans_offset;
- int i, prod_index, err;
+ int i;
+ u32 subsystem_vendor_id, subsystem_device_id;
subsystem_vendor_id = pdev->subsystem_vendor;
subsystem_device_id = pdev->subsystem_device;
- board_id = (((u32) (subsystem_device_id << 16) & 0xffff0000) |
- subsystem_vendor_id);
+ *board_id = ((subsystem_device_id << 16) & 0xffff0000) |
+ subsystem_vendor_id;
for (i = 0; i < ARRAY_SIZE(products); i++)
- if (board_id == products[i].board_id)
- break;
-
- prod_index = i;
-
- if (prod_index == ARRAY_SIZE(products)) {
- prod_index--;
- if (subsystem_vendor_id != PCI_VENDOR_ID_HP ||
- !hpsa_allow_any) {
- dev_warn(&pdev->dev, "unrecognized board ID:"
- " 0x%08lx, ignoring.\n",
- (unsigned long) board_id);
+ if (*board_id == products[i].board_id)
+ return i;
+
+ if ((subsystem_vendor_id != PCI_VENDOR_ID_HP &&
+ subsystem_vendor_id != PCI_VENDOR_ID_COMPAQ) ||
+ !hpsa_allow_any) {
+ dev_warn(&pdev->dev, "unrecognized board ID: "
+ "0x%08x, ignoring.\n", *board_id);
return -ENODEV;
- }
- }
- /* check to see if controller has been disabled
- * BEFORE trying to enable it
- */
- (void)pci_read_config_word(pdev, PCI_COMMAND, &command);
- if (!(command & 0x02)) {
- dev_warn(&pdev->dev, "controller appears to be disabled\n");
- return -ENODEV;
- }
-
- err = pci_enable_device(pdev);
- if (err) {
- dev_warn(&pdev->dev, "unable to enable PCI device\n");
- return err;
}
+ return ARRAY_SIZE(products) - 1; /* generic unknown smart array */
+}
- err = pci_request_regions(pdev, "hpsa");
- if (err) {
- dev_err(&pdev->dev, "cannot obtain PCI resources, aborting\n");
- return err;
- }
+static inline bool hpsa_board_disabled(struct pci_dev *pdev)
+{
+ u16 command;
- /* If the kernel supports MSI/MSI-X we will try to enable that,
- * else we use the IO-APIC interrupt assigned to us by system ROM.
- */
- hpsa_interrupt_mode(h, pdev, board_id);
+ (void) pci_read_config_word(pdev, PCI_COMMAND, &command);
+ return ((command & PCI_COMMAND_MEMORY) == 0);
+}
- /* find the memory BAR */
- for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
- if (pci_resource_flags(pdev, i) & IORESOURCE_MEM)
- break;
- }
- if (i == DEVICE_COUNT_RESOURCE) {
- dev_warn(&pdev->dev, "no memory BAR found\n");
- err = -ENODEV;
- goto err_out_free_res;
- }
+static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev,
+ unsigned long *memory_bar)
+{
+ int i;
- h->paddr = pci_resource_start(pdev, i); /* addressing mode bits
- * already removed
- */
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
+ if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
+ /* addressing mode bits already removed */
+ *memory_bar = pci_resource_start(pdev, i);
+ dev_dbg(&pdev->dev, "memory BAR = %lx\n",
+ *memory_bar);
+ return 0;
+ }
+ dev_warn(&pdev->dev, "no memory BAR found\n");
+ return -ENODEV;
+}
- h->vaddr = remap_pci_mem(h->paddr, 0x250);
+static int __devinit hpsa_wait_for_board_ready(struct ctlr_info *h)
+{
+ int i;
+ u32 scratchpad;
- /* Wait for the board to become ready. */
for (i = 0; i < HPSA_BOARD_READY_ITERATIONS; i++) {
scratchpad = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET);
if (scratchpad == HPSA_FIRMWARE_READY)
- break;
+ return 0;
msleep(HPSA_BOARD_READY_POLL_INTERVAL_MSECS);
}
- if (scratchpad != HPSA_FIRMWARE_READY) {
- dev_warn(&pdev->dev, "board not ready, timed out.\n");
- err = -ENODEV;
- goto err_out_free_res;
- }
+ dev_warn(&h->pdev->dev, "board not ready, timed out.\n");
+ return -ENODEV;
+}
- /* get the address index number */
- cfg_base_addr = readl(h->vaddr + SA5_CTCFG_OFFSET);
- cfg_base_addr &= (u32) 0x0000ffff;
- cfg_base_addr_index = find_PCI_BAR_index(pdev, cfg_base_addr);
- if (cfg_base_addr_index == -1) {
+static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev,
+ void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index,
+ u64 *cfg_offset)
+{
+ *cfg_base_addr = readl(vaddr + SA5_CTCFG_OFFSET);
+ *cfg_offset = readl(vaddr + SA5_CTMEM_OFFSET);
+ *cfg_base_addr &= (u32) 0x0000ffff;
+ *cfg_base_addr_index = find_PCI_BAR_index(pdev, *cfg_base_addr);
+ if (*cfg_base_addr_index == -1) {
dev_warn(&pdev->dev, "cannot find cfg_base_addr_index\n");
- err = -ENODEV;
- goto err_out_free_res;
+ return -ENODEV;
}
+ return 0;
+}
- cfg_offset = readl(h->vaddr + SA5_CTMEM_OFFSET);
- h->cfgtable = remap_pci_mem(pci_resource_start(pdev,
- cfg_base_addr_index) + cfg_offset,
- sizeof(h->cfgtable));
+static int __devinit hpsa_find_cfgtables(struct ctlr_info *h)
+{
+ u64 cfg_offset;
+ u32 cfg_base_addr;
+ u64 cfg_base_addr_index;
+ u32 trans_offset;
+ int rc;
+
+ rc = hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr,
+ &cfg_base_addr_index, &cfg_offset);
+ if (rc)
+ return rc;
+ h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev,
+ cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable));
+ if (!h->cfgtable)
+ return -ENOMEM;
/* Find performant mode table. */
- trans_offset = readl(&(h->cfgtable->TransMethodOffset));
- h->transtable = remap_pci_mem(pci_resource_start(pdev,
+ trans_offset = readl(&h->cfgtable->TransMethodOffset);
+ h->transtable = remap_pci_mem(pci_resource_start(h->pdev,
cfg_base_addr_index)+cfg_offset+trans_offset,
sizeof(*h->transtable));
+ if (!h->transtable)
+ return -ENOMEM;
+ return 0;
+}
- h->board_id = board_id;
+static void __devinit hpsa_get_max_perf_mode_cmds(struct ctlr_info *h)
+{
h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
- h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
+ if (h->max_commands < 16) {
+ dev_warn(&h->pdev->dev, "Controller reports "
+ "max supported commands of %d, an obvious lie. "
+ "Using 16. Ensure that firmware is up to date.\n",
+ h->max_commands);
+ h->max_commands = 16;
+ }
+}
+/* Interrogate the hardware for some limits:
+ * max commands, max SG elements without chaining, and with chaining,
+ * SG chain block size, etc.
+ */
+static void __devinit hpsa_find_board_params(struct ctlr_info *h)
+{
+ hpsa_get_max_perf_mode_cmds(h);
+ h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
+ h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
/*
* Limit in-command s/g elements to 32 save dma'able memory.
* Howvever spec says if 0, use 31
*/
-
h->max_cmd_sg_entries = 31;
if (h->maxsgentries > 512) {
h->max_cmd_sg_entries = 32;
@@ -3382,45 +3539,49 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
h->maxsgentries = 31; /* default to traditional values */
h->chainsize = 0;
}
+}
- h->product_name = products[prod_index].product_name;
- h->access = *(products[prod_index].access);
- /* Allow room for some ioctls */
- h->nr_cmds = h->max_commands - 4;
-
+static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
+{
if ((readb(&h->cfgtable->Signature[0]) != 'C') ||
(readb(&h->cfgtable->Signature[1]) != 'I') ||
(readb(&h->cfgtable->Signature[2]) != 'S') ||
(readb(&h->cfgtable->Signature[3]) != 'S')) {
- dev_warn(&pdev->dev, "not a valid CISS config table\n");
- err = -ENODEV;
- goto err_out_free_res;
+ dev_warn(&h->pdev->dev, "not a valid CISS config table\n");
+ return false;
}
+ return true;
+}
+
+/* Need to enable prefetch in the SCSI core for 6400 in x86 */
+static inline void hpsa_enable_scsi_prefetch(struct ctlr_info *h)
+{
#ifdef CONFIG_X86
- {
- /* Need to enable prefetch in the SCSI core for 6400 in x86 */
- u32 prefetch;
- prefetch = readl(&(h->cfgtable->SCSI_Prefetch));
- prefetch |= 0x100;
- writel(prefetch, &(h->cfgtable->SCSI_Prefetch));
- }
+ u32 prefetch;
+
+ prefetch = readl(&(h->cfgtable->SCSI_Prefetch));
+ prefetch |= 0x100;
+ writel(prefetch, &(h->cfgtable->SCSI_Prefetch));
#endif
+}
- /* Disabling DMA prefetch for the P600
- * An ASIC bug may result in a prefetch beyond
- * physical memory.
- */
- if (board_id == 0x3225103C) {
- u32 dma_prefetch;
- dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG);
- dma_prefetch |= 0x8000;
- writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
- }
+/* Disable DMA prefetch for the P600. Otherwise an ASIC bug may result
+ * in a prefetch beyond physical memory.
+ */
+static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h)
+{
+ u32 dma_prefetch;
- h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
- /* Update the field, and then ring the doorbell */
- writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
- writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+ if (h->board_id != 0x3225103C)
+ return;
+ dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG);
+ dma_prefetch |= 0x8000;
+ writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
+}
+
+static void __devinit hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
+{
+ int i;
/* under certain very rare conditions, this can take awhile.
* (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
@@ -3432,24 +3593,96 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h, struct pci_dev *pdev)
/* delay and try again */
msleep(10);
}
+}
-#ifdef HPSA_DEBUG
- print_cfg_table(&pdev->dev, h->cfgtable);
-#endif /* HPSA_DEBUG */
+static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h)
+{
+ u32 trans_support;
+ trans_support = readl(&(h->cfgtable->TransportSupport));
+ if (!(trans_support & SIMPLE_MODE))
+ return -ENOTSUPP;
+
+ h->max_commands = readl(&(h->cfgtable->CmdsOutMax));
+ /* Update the field, and then ring the doorbell */
+ writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
+ writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
+ hpsa_wait_for_mode_change_ack(h);
+ print_cfg_table(&h->pdev->dev, h->cfgtable);
if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
- dev_warn(&pdev->dev, "unable to get board into simple mode\n");
+ dev_warn(&h->pdev->dev,
+ "unable to get board into simple mode\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int __devinit hpsa_pci_init(struct ctlr_info *h)
+{
+ int prod_index, err;
+
+ prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id);
+ if (prod_index < 0)
+ return -ENODEV;
+ h->product_name = products[prod_index].product_name;
+ h->access = *(products[prod_index].access);
+
+ if (hpsa_board_disabled(h->pdev)) {
+ dev_warn(&h->pdev->dev, "controller appears to be disabled\n");
+ return -ENODEV;
+ }
+ err = pci_enable_device(h->pdev);
+ if (err) {
+ dev_warn(&h->pdev->dev, "unable to enable PCI device\n");
+ return err;
+ }
+
+ err = pci_request_regions(h->pdev, "hpsa");
+ if (err) {
+ dev_err(&h->pdev->dev,
+ "cannot obtain PCI resources, aborting\n");
+ return err;
+ }
+ hpsa_interrupt_mode(h);
+ err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr);
+ if (err)
+ goto err_out_free_res;
+ h->vaddr = remap_pci_mem(h->paddr, 0x250);
+ if (!h->vaddr) {
+ err = -ENOMEM;
+ goto err_out_free_res;
+ }
+ err = hpsa_wait_for_board_ready(h);
+ if (err)
+ goto err_out_free_res;
+ err = hpsa_find_cfgtables(h);
+ if (err)
+ goto err_out_free_res;
+ hpsa_find_board_params(h);
+
+ if (!hpsa_CISS_signature_present(h)) {
err = -ENODEV;
goto err_out_free_res;
}
+ hpsa_enable_scsi_prefetch(h);
+ hpsa_p600_dma_prefetch_quirk(h);
+ err = hpsa_enter_simple_mode(h);
+ if (err)
+ goto err_out_free_res;
return 0;
err_out_free_res:
+ if (h->transtable)
+ iounmap(h->transtable);
+ if (h->cfgtable)
+ iounmap(h->cfgtable);
+ if (h->vaddr)
+ iounmap(h->vaddr);
/*
* Deliberately omit pci_disable_device(): it does something nasty to
* Smart Array controllers that pci_enable_device does not undo
*/
- pci_release_regions(pdev);
+ pci_release_regions(h->pdev);
return err;
}
@@ -3469,33 +3702,51 @@ static void __devinit hpsa_hba_inquiry(struct ctlr_info *h)
}
}
+static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev)
+{
+ int rc, i;
+
+ if (!reset_devices)
+ return 0;
+
+ /* Reset the controller with a PCI power-cycle or via doorbell */
+ rc = hpsa_kdump_hard_reset_controller(pdev);
+
+ /* -ENOTSUPP here means we cannot reset the controller
+ * but it's already (and still) up and running in
+ * "performant mode". Or, it might be 640x, which can't reset
+ * due to concerns about shared bbwc between 6402/6404 pair.
+ */
+ if (rc == -ENOTSUPP)
+ return 0; /* just try to do the kdump anyhow. */
+ if (rc)
+ return -ENODEV;
+ if (hpsa_reset_msi(pdev))
+ return -ENODEV;
+
+ /* Now try to get the controller to respond to a no-op */
+ for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
+ if (hpsa_noop(pdev) == 0)
+ break;
+ else
+ dev_warn(&pdev->dev, "no-op failed%s\n",
+ (i < 11 ? "; re-trying" : ""));
+ }
+ return 0;
+}
+
static int __devinit hpsa_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- int i, rc;
- int dac;
+ int dac, rc;
struct ctlr_info *h;
if (number_of_controllers == 0)
printk(KERN_INFO DRIVER_NAME "\n");
- if (reset_devices) {
- /* Reset the controller with a PCI power-cycle */
- if (hpsa_hard_reset_controller(pdev) || hpsa_reset_msi(pdev))
- return -ENODEV;
- /* Some devices (notably the HP Smart Array 5i Controller)
- need a little pause here */
- msleep(HPSA_POST_RESET_PAUSE_MSECS);
-
- /* Now try to get the controller to respond to a no-op */
- for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
- if (hpsa_noop(pdev) == 0)
- break;
- else
- dev_warn(&pdev->dev, "no-op failed%s\n",
- (i < 11 ? "; re-trying" : ""));
- }
- }
+ rc = hpsa_init_reset_devices(pdev);
+ if (rc)
+ return rc;
/* Command structures must be aligned on a 32-byte boundary because
* the 5 lower bits of the address are used by the hardware. and by
@@ -3507,17 +3758,17 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
if (!h)
return -ENOMEM;
+ h->pdev = pdev;
h->busy_initializing = 1;
INIT_HLIST_HEAD(&h->cmpQ);
INIT_HLIST_HEAD(&h->reqQ);
- rc = hpsa_pci_init(h, pdev);
+ rc = hpsa_pci_init(h);
if (rc != 0)
goto clean1;
sprintf(h->devname, "hpsa%d", number_of_controllers);
h->ctlr = number_of_controllers;
number_of_controllers++;
- h->pdev = pdev;
/* configure PCI DMA stuff */
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
@@ -3535,8 +3786,13 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
/* make sure the board interrupts are off */
h->access.set_intr_mask(h, HPSA_INTR_OFF);
- rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr,
- IRQF_DISABLED, h->devname, h);
+
+ if (h->msix_vector || h->msi_vector)
+ rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_msi,
+ IRQF_DISABLED, h->devname, h);
+ else
+ rc = request_irq(h->intr[PERF_MODE_INT], do_hpsa_intr_intx,
+ IRQF_DISABLED, h->devname, h);
if (rc) {
dev_err(&pdev->dev, "unable to get irq %d for %s\n",
h->intr[PERF_MODE_INT], h->devname);
@@ -3663,6 +3919,8 @@ static void __devexit hpsa_remove_one(struct pci_dev *pdev)
hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */
hpsa_shutdown(pdev);
iounmap(h->vaddr);
+ iounmap(h->transtable);
+ iounmap(h->cfgtable);
hpsa_free_sg_chain_blocks(h);
pci_free_consistent(h->pdev,
h->nr_cmds * sizeof(struct CommandList),
@@ -3742,38 +4000,35 @@ static void calc_bucket_map(int bucket[], int num_buckets,
}
}
-static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
+static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h)
{
- u32 trans_support;
- u64 trans_offset;
+ int i;
+ unsigned long register_value;
+
+ /* This is a bit complicated. There are 8 registers on
+ * the controller which we write to to tell it 8 different
+ * sizes of commands which there may be. It's a way of
+ * reducing the DMA done to fetch each command. Encoded into
+ * each command's tag are 3 bits which communicate to the controller
+ * which of the eight sizes that command fits within. The size of
+ * each command depends on how many scatter gather entries there are.
+ * Each SG entry requires 16 bytes. The eight registers are programmed
+ * with the number of 16-byte blocks a command of that size requires.
+ * The smallest command possible requires 5 such 16 byte blocks.
+ * the largest command possible requires MAXSGENTRIES + 4 16-byte
+ * blocks. Note, this only extends to the SG entries contained
+ * within the command block, and does not extend to chained blocks
+ * of SG elements. bft[] contains the eight values we write to
+ * the registers. They are not evenly distributed, but have more
+ * sizes for small commands, and fewer sizes for larger commands.
+ */
+ int bft[8] = {5, 6, 8, 10, 12, 20, 28, MAXSGENTRIES + 4};
+ BUILD_BUG_ON(28 > MAXSGENTRIES + 4);
/* 5 = 1 s/g entry or 4k
* 6 = 2 s/g entry or 8k
* 8 = 4 s/g entry or 16k
* 10 = 6 s/g entry or 24k
*/
- int bft[8] = {5, 6, 8, 10, 12, 20, 28, 35}; /* for scatter/gathers */
- int i = 0;
- int l = 0;
- unsigned long register_value;
-
- trans_support = readl(&(h->cfgtable->TransportSupport));
- if (!(trans_support & PERFORMANT_MODE))
- return;
-
- h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands));
- h->max_sg_entries = 32;
- /* Performant mode ring buffer and supporting data structures */
- h->reply_pool_size = h->max_commands * sizeof(u64);
- h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size,
- &(h->reply_pool_dhandle));
-
- /* Need a block fetch table for performant mode */
- h->blockFetchTable = kmalloc(((h->max_sg_entries+1) *
- sizeof(u32)), GFP_KERNEL);
-
- if ((h->reply_pool == NULL)
- || (h->blockFetchTable == NULL))
- goto clean_up;
h->reply_pool_wraparound = 1; /* spec: init to 1 */
@@ -3781,7 +4036,6 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
memset(h->reply_pool, 0, h->reply_pool_size);
h->reply_pool_head = h->reply_pool;
- trans_offset = readl(&(h->cfgtable->TransMethodOffset));
bft[7] = h->max_sg_entries + 4;
calc_bucket_map(bft, ARRAY_SIZE(bft), 32, h->blockFetchTable);
for (i = 0; i < 8; i++)
@@ -3797,23 +4051,39 @@ static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
writel(CFGTBL_Trans_Performant,
&(h->cfgtable->HostWrite.TransportRequest));
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
- /* under certain very rare conditions, this can take awhile.
- * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
- * as we enter this code.) */
- for (l = 0; l < MAX_CONFIG_WAIT; l++) {
- register_value = readl(h->vaddr + SA5_DOORBELL);
- if (!(register_value & CFGTBL_ChangeReq))
- break;
- /* delay and try again */
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(10);
- }
+ hpsa_wait_for_mode_change_ack(h);
register_value = readl(&(h->cfgtable->TransportActive));
if (!(register_value & CFGTBL_Trans_Performant)) {
dev_warn(&h->pdev->dev, "unable to get board into"
" performant mode\n");
return;
}
+}
+
+static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h)
+{
+ u32 trans_support;
+
+ trans_support = readl(&(h->cfgtable->TransportSupport));
+ if (!(trans_support & PERFORMANT_MODE))
+ return;
+
+ hpsa_get_max_perf_mode_cmds(h);
+ h->max_sg_entries = 32;
+ /* Performant mode ring buffer and supporting data structures */
+ h->reply_pool_size = h->max_commands * sizeof(u64);
+ h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size,
+ &(h->reply_pool_dhandle));
+
+ /* Need a block fetch table for performant mode */
+ h->blockFetchTable = kmalloc(((h->max_sg_entries+1) *
+ sizeof(u32)), GFP_KERNEL);
+
+ if ((h->reply_pool == NULL)
+ || (h->blockFetchTable == NULL))
+ goto clean_up;
+
+ hpsa_enter_performant_mode(h);
/* Change the access methods to the performant access methods */
h->access = SA5_performant_access;
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 1bb5233b09a0..a203ef65cb50 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -53,7 +53,6 @@ struct ctlr_info {
int ctlr;
char devname[8];
char *product_name;
- char firm_ver[4]; /* Firmware version */
struct pci_dev *pdev;
u32 board_id;
void __iomem *vaddr;
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 78de9b6d1e0b..f5c4c3cc0530 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -100,6 +100,7 @@
/* Configuration Table */
#define CFGTBL_ChangeReq 0x00000001l
#define CFGTBL_AccCmds 0x00000001l
+#define DOORBELL_CTLR_RESET 0x00000004l
#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
@@ -339,6 +340,9 @@ struct CfgTable {
u32 MaxPhysicalDevices;
u32 MaxPhysicalDrivesPerLogicalUnit;
u32 MaxPerformantModeCommands;
+ u8 reserved[0x78 - 0x58];
+ u32 misc_fw_support; /* offset 0x78 */
+#define MISC_FW_DOORBELL_RESET (0x02)
};
#define NUM_BLOCKFETCH_ENTRIES 8
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 645f7cdf21ab..0729f150b33a 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -1157,7 +1157,7 @@ free_pci_regions:
disable_pci_device:
pci_disable_device(pcidev);
- dprintk("scsi%d: hptiop_probe fail\n", host->host_no);
+ dprintk("scsi%d: hptiop_probe fail\n", host ? host->host_no : 0);
return -ENODEV;
}
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index fef49521cbc3..bd96cecaa619 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -504,12 +504,23 @@ static void ibmvfc_set_host_action(struct ibmvfc_host *vhost,
if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS)
vhost->action = action;
break;
- case IBMVFC_HOST_ACTION_LOGO:
case IBMVFC_HOST_ACTION_INIT:
case IBMVFC_HOST_ACTION_TGT_DEL:
+ switch (vhost->action) {
+ case IBMVFC_HOST_ACTION_RESET:
+ case IBMVFC_HOST_ACTION_REENABLE:
+ break;
+ default:
+ vhost->action = action;
+ break;
+ };
+ break;
+ case IBMVFC_HOST_ACTION_LOGO:
case IBMVFC_HOST_ACTION_QUERY_TGTS:
case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
case IBMVFC_HOST_ACTION_NONE:
+ case IBMVFC_HOST_ACTION_RESET:
+ case IBMVFC_HOST_ACTION_REENABLE:
default:
vhost->action = action;
break;
@@ -641,7 +652,7 @@ static int ibmvfc_send_crq_init_complete(struct ibmvfc_host *vhost)
**/
static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
{
- long rc;
+ long rc = 0;
struct vio_dev *vdev = to_vio_dev(vhost->dev);
struct ibmvfc_crq_queue *crq = &vhost->crq;
@@ -649,6 +660,8 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
free_irq(vdev->irq, vhost);
tasklet_kill(&vhost->tasklet);
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
@@ -667,11 +680,13 @@ static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost)
**/
static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)
{
- int rc;
+ int rc = 0;
struct vio_dev *vdev = to_vio_dev(vhost->dev);
/* Re-enable the CRQ */
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
} while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
@@ -690,15 +705,19 @@ static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost)
**/
static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
{
- int rc;
+ int rc = 0;
+ unsigned long flags;
struct vio_dev *vdev = to_vio_dev(vhost->dev);
struct ibmvfc_crq_queue *crq = &vhost->crq;
/* Close the CRQ */
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
+ spin_lock_irqsave(vhost->host->host_lock, flags);
vhost->state = IBMVFC_NO_CRQ;
vhost->logged_in = 0;
ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE);
@@ -716,6 +735,7 @@ static int ibmvfc_reset_crq(struct ibmvfc_host *vhost)
dev_warn(vhost->dev, "Partner adapter not ready\n");
else if (rc != 0)
dev_warn(vhost->dev, "Couldn't register crq (rc=%d)\n", rc);
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
return rc;
}
@@ -821,17 +841,9 @@ static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code)
**/
static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost)
{
- int rc;
-
- scsi_block_requests(vhost->host);
ibmvfc_purge_requests(vhost, DID_ERROR);
- if ((rc = ibmvfc_reset_crq(vhost)) ||
- (rc = ibmvfc_send_crq_init(vhost)) ||
- (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) {
- dev_err(vhost->dev, "Error after reset rc=%d\n", rc);
- ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
- } else
- ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET);
}
/**
@@ -2299,6 +2311,7 @@ static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd)
int rc = FAILED;
ENTER;
+ fc_block_scsi_eh(cmd);
ibmvfc_wait_while_resetting(vhost);
cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET);
abort_rc = ibmvfc_abort_task_set(sdev);
@@ -2325,6 +2338,7 @@ static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd)
int rc = FAILED;
ENTER;
+ fc_block_scsi_eh(cmd);
ibmvfc_wait_while_resetting(vhost);
cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_LUN_RESET);
reset_rc = ibmvfc_reset_device(sdev, IBMVFC_LUN_RESET, "LUN");
@@ -2389,6 +2403,7 @@ static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd)
unsigned long cancel_rc = 0;
ENTER;
+ fc_block_scsi_eh(cmd);
ibmvfc_wait_while_resetting(vhost);
starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all_reset);
reset_rc = ibmvfc_reset_device(sdev, IBMVFC_TARGET_RESET, "target");
@@ -2410,6 +2425,7 @@ static int ibmvfc_eh_host_reset_handler(struct scsi_cmnd *cmd)
int rc;
struct ibmvfc_host *vhost = shost_priv(cmd->device->host);
+ fc_block_scsi_eh(cmd);
dev_err(vhost->dev, "Resetting connection due to error recovery\n");
rc = ibmvfc_issue_fc_host_lip(vhost->host);
return rc ? FAILED : SUCCESS;
@@ -2606,22 +2622,13 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost)
dev_info(vhost->dev, "Re-enabling adapter\n");
vhost->client_migrated = 1;
ibmvfc_purge_requests(vhost, DID_REQUEUE);
- if ((rc = ibmvfc_reenable_crq_queue(vhost)) ||
- (rc = ibmvfc_send_crq_init(vhost))) {
- ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
- dev_err(vhost->dev, "Error after enable (rc=%ld)\n", rc);
- } else
- ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_REENABLE);
} else {
dev_err(vhost->dev, "Virtual adapter failed (rc=%d)\n", crq->format);
-
ibmvfc_purge_requests(vhost, DID_ERROR);
- if ((rc = ibmvfc_reset_crq(vhost)) ||
- (rc = ibmvfc_send_crq_init(vhost))) {
- ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
- dev_err(vhost->dev, "Error after reset (rc=%ld)\n", rc);
- } else
- ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+ ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET);
}
return;
case IBMVFC_CRQ_CMD_RSP:
@@ -4123,6 +4130,8 @@ static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost)
case IBMVFC_HOST_ACTION_TGT_DEL:
case IBMVFC_HOST_ACTION_TGT_DEL_FAILED:
case IBMVFC_HOST_ACTION_QUERY:
+ case IBMVFC_HOST_ACTION_RESET:
+ case IBMVFC_HOST_ACTION_REENABLE:
default:
break;
};
@@ -4220,6 +4229,7 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
struct ibmvfc_target *tgt;
unsigned long flags;
struct fc_rport *rport;
+ int rc;
ibmvfc_log_ae(vhost, vhost->events_to_log);
spin_lock_irqsave(vhost->host->host_lock, flags);
@@ -4229,6 +4239,27 @@ static void ibmvfc_do_work(struct ibmvfc_host *vhost)
case IBMVFC_HOST_ACTION_LOGO_WAIT:
case IBMVFC_HOST_ACTION_INIT_WAIT:
break;
+ case IBMVFC_HOST_ACTION_RESET:
+ vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+ rc = ibmvfc_reset_crq(vhost);
+ spin_lock_irqsave(vhost->host->host_lock, flags);
+ if (rc || (rc = ibmvfc_send_crq_init(vhost)) ||
+ (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) {
+ ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+ dev_err(vhost->dev, "Error after reset (rc=%d)\n", rc);
+ }
+ break;
+ case IBMVFC_HOST_ACTION_REENABLE:
+ vhost->action = IBMVFC_HOST_ACTION_TGT_DEL;
+ spin_unlock_irqrestore(vhost->host->host_lock, flags);
+ rc = ibmvfc_reenable_crq_queue(vhost);
+ spin_lock_irqsave(vhost->host->host_lock, flags);
+ if (rc || (rc = ibmvfc_send_crq_init(vhost))) {
+ ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+ dev_err(vhost->dev, "Error after enable (rc=%d)\n", rc);
+ }
+ break;
case IBMVFC_HOST_ACTION_LOGO:
vhost->job_step(vhost);
break;
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index 7e9742764e4b..d7e8dcd90650 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -29,8 +29,8 @@
#include "viosrp.h"
#define IBMVFC_NAME "ibmvfc"
-#define IBMVFC_DRIVER_VERSION "1.0.7"
-#define IBMVFC_DRIVER_DATE "(October 16, 2009)"
+#define IBMVFC_DRIVER_VERSION "1.0.8"
+#define IBMVFC_DRIVER_DATE "(June 17, 2010)"
#define IBMVFC_DEFAULT_TIMEOUT 60
#define IBMVFC_ADISC_CANCEL_TIMEOUT 45
@@ -649,6 +649,8 @@ struct ibmvfc_event_pool {
enum ibmvfc_host_action {
IBMVFC_HOST_ACTION_NONE = 0,
+ IBMVFC_HOST_ACTION_RESET,
+ IBMVFC_HOST_ACTION_REENABLE,
IBMVFC_HOST_ACTION_LOGO,
IBMVFC_HOST_ACTION_LOGO_WAIT,
IBMVFC_HOST_ACTION_INIT,
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index aad35cc41e49..67f78a470f5f 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -73,6 +73,7 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/pm.h>
+#include <linux/kthread.h>
#include <asm/firmware.h>
#include <asm/vio.h>
#include <scsi/scsi.h>
@@ -101,7 +102,7 @@ static int client_reserve = 1;
static struct scsi_transport_template *ibmvscsi_transport_template;
-#define IBMVSCSI_VERSION "1.5.8"
+#define IBMVSCSI_VERSION "1.5.9"
static struct ibmvscsi_ops *ibmvscsi_ops;
@@ -473,23 +474,26 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
*/
static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
{
- struct srp_event_struct *tmp_evt, *pos;
+ struct srp_event_struct *evt;
unsigned long flags;
spin_lock_irqsave(hostdata->host->host_lock, flags);
- list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
- list_del(&tmp_evt->list);
- del_timer(&tmp_evt->timer);
- if (tmp_evt->cmnd) {
- tmp_evt->cmnd->result = (error_code << 16);
- unmap_cmd_data(&tmp_evt->iu.srp.cmd,
- tmp_evt,
- tmp_evt->hostdata->dev);
- if (tmp_evt->cmnd_done)
- tmp_evt->cmnd_done(tmp_evt->cmnd);
- } else if (tmp_evt->done)
- tmp_evt->done(tmp_evt);
- free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
+ while (!list_empty(&hostdata->sent)) {
+ evt = list_first_entry(&hostdata->sent, struct srp_event_struct, list);
+ list_del(&evt->list);
+ del_timer(&evt->timer);
+
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+ if (evt->cmnd) {
+ evt->cmnd->result = (error_code << 16);
+ unmap_cmd_data(&evt->iu.srp.cmd, evt,
+ evt->hostdata->dev);
+ if (evt->cmnd_done)
+ evt->cmnd_done(evt->cmnd);
+ } else if (evt->done)
+ evt->done(evt);
+ free_event_struct(&evt->hostdata->pool, evt);
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
}
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
}
@@ -504,14 +508,8 @@ static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
atomic_set(&hostdata->request_limit, 0);
purge_requests(hostdata, DID_ERROR);
- if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata)) ||
- (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0)) ||
- (vio_enable_interrupts(to_vio_dev(hostdata->dev)))) {
- atomic_set(&hostdata->request_limit, -1);
- dev_err(hostdata->dev, "error after reset\n");
- }
-
- scsi_unblock_requests(hostdata->host);
+ hostdata->reset_crq = 1;
+ wake_up(&hostdata->work_wait_q);
}
/**
@@ -550,6 +548,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
int request_status = 0;
int rc;
+ int srp_req = 0;
/* If we have exhausted our request limit, just fail this request,
* unless it is for a reset or abort.
@@ -558,6 +557,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
* can handle more requests (can_queue) when we actually can't
*/
if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) {
+ srp_req = 1;
request_status =
atomic_dec_if_positive(&hostdata->request_limit);
/* If request limit was -1 when we started, it is now even
@@ -632,7 +632,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
goto send_busy;
}
dev_err(hostdata->dev, "send error %d\n", rc);
- atomic_inc(&hostdata->request_limit);
+ if (srp_req)
+ atomic_inc(&hostdata->request_limit);
goto send_error;
}
@@ -642,7 +643,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
free_event_struct(&hostdata->pool, evt_struct);
- if (request_status != -1)
+ if (srp_req && request_status != -1)
atomic_inc(&hostdata->request_limit);
return SCSI_MLQUEUE_HOST_BUSY;
@@ -1462,30 +1463,14 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
/* We need to re-setup the interpartition connection */
dev_info(hostdata->dev, "Re-enabling adapter!\n");
hostdata->client_migrated = 1;
+ hostdata->reenable_crq = 1;
purge_requests(hostdata, DID_REQUEUE);
- if ((ibmvscsi_ops->reenable_crq_queue(&hostdata->queue,
- hostdata)) ||
- (ibmvscsi_ops->send_crq(hostdata,
- 0xC001000000000000LL, 0))) {
- atomic_set(&hostdata->request_limit,
- -1);
- dev_err(hostdata->dev, "error after enable\n");
- }
+ wake_up(&hostdata->work_wait_q);
} else {
dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n",
crq->format);
-
- purge_requests(hostdata, DID_ERROR);
- if ((ibmvscsi_ops->reset_crq_queue(&hostdata->queue,
- hostdata)) ||
- (ibmvscsi_ops->send_crq(hostdata,
- 0xC001000000000000LL, 0))) {
- atomic_set(&hostdata->request_limit,
- -1);
- dev_err(hostdata->dev, "error after reset\n");
- }
+ ibmvscsi_reset_host(hostdata);
}
- scsi_unblock_requests(hostdata->host);
return;
case 0x80: /* real payload */
break;
@@ -1850,6 +1835,75 @@ static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev)
return desired_io;
}
+static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata)
+{
+ int rc;
+ char *action = "reset";
+
+ if (hostdata->reset_crq) {
+ smp_rmb();
+ hostdata->reset_crq = 0;
+
+ rc = ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata);
+ if (!rc)
+ rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0);
+ if (!rc)
+ rc = vio_enable_interrupts(to_vio_dev(hostdata->dev));
+ } else if (hostdata->reenable_crq) {
+ smp_rmb();
+ action = "enable";
+ rc = ibmvscsi_ops->reenable_crq_queue(&hostdata->queue, hostdata);
+ hostdata->reenable_crq = 0;
+ if (!rc)
+ rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0);
+ } else
+ return;
+
+ if (rc) {
+ atomic_set(&hostdata->request_limit, -1);
+ dev_err(hostdata->dev, "error after %s\n", action);
+ }
+
+ scsi_unblock_requests(hostdata->host);
+}
+
+static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata)
+{
+ if (kthread_should_stop())
+ return 1;
+ else if (hostdata->reset_crq) {
+ smp_rmb();
+ return 1;
+ } else if (hostdata->reenable_crq) {
+ smp_rmb();
+ return 1;
+ }
+
+ return 0;
+}
+
+static int ibmvscsi_work(void *data)
+{
+ struct ibmvscsi_host_data *hostdata = data;
+ int rc;
+
+ set_user_nice(current, -20);
+
+ while (1) {
+ rc = wait_event_interruptible(hostdata->work_wait_q,
+ ibmvscsi_work_to_do(hostdata));
+
+ BUG_ON(rc);
+
+ if (kthread_should_stop())
+ break;
+
+ ibmvscsi_do_work(hostdata);
+ }
+
+ return 0;
+}
+
/**
* Called by bus code for each adapter
*/
@@ -1875,6 +1929,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
hostdata = shost_priv(host);
memset(hostdata, 0x00, sizeof(*hostdata));
INIT_LIST_HEAD(&hostdata->sent);
+ init_waitqueue_head(&hostdata->work_wait_q);
hostdata->host = host;
hostdata->dev = dev;
atomic_set(&hostdata->request_limit, -1);
@@ -1885,10 +1940,19 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
goto persist_bufs_failed;
}
+ hostdata->work_thread = kthread_run(ibmvscsi_work, hostdata, "%s_%d",
+ "ibmvscsi", host->host_no);
+
+ if (IS_ERR(hostdata->work_thread)) {
+ dev_err(&vdev->dev, "couldn't initialize kthread. rc=%ld\n",
+ PTR_ERR(hostdata->work_thread));
+ goto init_crq_failed;
+ }
+
rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events);
if (rc != 0 && rc != H_RESOURCE) {
dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
- goto init_crq_failed;
+ goto kill_kthread;
}
if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) {
dev_err(&vdev->dev, "couldn't initialize event pool\n");
@@ -1944,6 +2008,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
release_event_pool(&hostdata->pool, hostdata);
init_pool_failed:
ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events);
+ kill_kthread:
+ kthread_stop(hostdata->work_thread);
init_crq_failed:
unmap_persist_bufs(hostdata);
persist_bufs_failed:
@@ -1960,6 +2026,7 @@ static int ibmvscsi_remove(struct vio_dev *vdev)
ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
max_events);
+ kthread_stop(hostdata->work_thread);
srp_remove_host(hostdata->host);
scsi_remove_host(hostdata->host);
scsi_host_put(hostdata->host);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 9cb7c6a773e1..02197a2b22b9 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -91,12 +91,16 @@ struct event_pool {
struct ibmvscsi_host_data {
atomic_t request_limit;
int client_migrated;
+ int reset_crq;
+ int reenable_crq;
struct device *dev;
struct event_pool pool;
struct crq_queue queue;
struct tasklet_struct srp_task;
struct list_head sent;
struct Scsi_Host *host;
+ struct task_struct *work_thread;
+ wait_queue_head_t work_wait_q;
struct mad_adapter_info_data madapter_info;
struct capabilities caps;
dma_addr_t caps_addr;
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index a864ccc0a342..53ce479a5db6 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -31,6 +31,7 @@
#include <asm/prom.h>
#include <asm/iommu.h>
#include <asm/hvcall.h>
+#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/gfp.h>
#include <linux/interrupt.h>
@@ -71,11 +72,13 @@ static void rpavscsi_release_crq_queue(struct crq_queue *queue,
struct ibmvscsi_host_data *hostdata,
int max_requests)
{
- long rc;
+ long rc = 0;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
free_irq(vdev->irq, (void *)hostdata);
tasklet_kill(&hostdata->srp_task);
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
dma_unmap_single(hostdata->dev,
@@ -200,11 +203,13 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
static int rpavscsi_reset_crq_queue(struct crq_queue *queue,
struct ibmvscsi_host_data *hostdata)
{
- int rc;
+ int rc = 0;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
/* Close the CRQ */
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
@@ -300,7 +305,10 @@ static int rpavscsi_init_crq_queue(struct crq_queue *queue,
return retrc;
req_irq_failed:
+ rc = 0;
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
} while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
reg_crq_failed:
@@ -322,11 +330,13 @@ static int rpavscsi_init_crq_queue(struct crq_queue *queue,
static int rpavscsi_reenable_crq_queue(struct crq_queue *queue,
struct ibmvscsi_host_data *hostdata)
{
- int rc;
+ int rc = 0;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
/* Re-enable the CRQ */
do {
+ if (rc)
+ msleep(100);
rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address);
} while ((rc == H_IN_PROGRESS) || (rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index c5564191732c..db205c9d42d1 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -167,7 +167,8 @@ static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
.clr_uproc_interrupt_reg32 = 0x0002C,
.init_feedback_reg = 0x0005C,
.dump_addr_reg = 0x00064,
- .dump_data_reg = 0x00068
+ .dump_data_reg = 0x00068,
+ .endian_swap_reg = 0x00084
}
},
};
@@ -1129,20 +1130,22 @@ static int ipr_is_same_device(struct ipr_resource_entry *res,
}
/**
- * ipr_format_resource_path - Format the resource path for printing.
+ * ipr_format_res_path - Format the resource path for printing.
* @res_path: resource path
* @buf: buffer
*
* Return value:
* pointer to buffer
**/
-static char *ipr_format_resource_path(u8 *res_path, char *buffer)
+static char *ipr_format_res_path(u8 *res_path, char *buffer, int len)
{
int i;
+ char *p = buffer;
- sprintf(buffer, "%02X", res_path[0]);
- for (i=1; res_path[i] != 0xff; i++)
- sprintf(buffer, "%s-%02X", buffer, res_path[i]);
+ res_path[0] = '\0';
+ p += snprintf(p, buffer + len - p, "%02X", res_path[0]);
+ for (i = 1; res_path[i] != 0xff && ((i * 3) < len); i++)
+ p += snprintf(p, buffer + len - p, "-%02X", res_path[i]);
return buffer;
}
@@ -1187,7 +1190,8 @@ static void ipr_update_res_entry(struct ipr_resource_entry *res,
if (res->sdev && new_path)
sdev_printk(KERN_INFO, res->sdev, "Resource path: %s\n",
- ipr_format_resource_path(&res->res_path[0], &buffer[0]));
+ ipr_format_res_path(res->res_path, buffer,
+ sizeof(buffer)));
} else {
res->flags = cfgtew->u.cfgte->flags;
if (res->flags & IPR_IS_IOA_RESOURCE)
@@ -1573,7 +1577,8 @@ static void ipr_log_sis64_config_error(struct ipr_ioa_cfg *ioa_cfg,
ipr_err_separator;
ipr_err("Device %d : %s", i + 1,
- ipr_format_resource_path(&dev_entry->res_path[0], &buffer[0]));
+ ipr_format_res_path(dev_entry->res_path, buffer,
+ sizeof(buffer)));
ipr_log_ext_vpd(&dev_entry->vpd);
ipr_err("-----New Device Information-----\n");
@@ -1919,13 +1924,14 @@ static void ipr_log64_fabric_path(struct ipr_hostrcb *hostrcb,
ipr_hcam_err(hostrcb, "%s %s: Resource Path=%s\n",
path_active_desc[i].desc, path_state_desc[j].desc,
- ipr_format_resource_path(&fabric->res_path[0], &buffer[0]));
+ ipr_format_res_path(fabric->res_path, buffer,
+ sizeof(buffer)));
return;
}
}
ipr_err("Path state=%02X Resource Path=%s\n", path_state,
- ipr_format_resource_path(&fabric->res_path[0], &buffer[0]));
+ ipr_format_res_path(fabric->res_path, buffer, sizeof(buffer)));
}
static const struct {
@@ -2066,7 +2072,8 @@ static void ipr_log64_path_elem(struct ipr_hostrcb *hostrcb,
ipr_hcam_err(hostrcb, "%s %s: Resource Path=%s, Link rate=%s, WWN=%08X%08X\n",
path_status_desc[j].desc, path_type_desc[i].desc,
- ipr_format_resource_path(&cfg->res_path[0], &buffer[0]),
+ ipr_format_res_path(cfg->res_path, buffer,
+ sizeof(buffer)),
link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
return;
@@ -2074,7 +2081,7 @@ static void ipr_log64_path_elem(struct ipr_hostrcb *hostrcb,
}
ipr_hcam_err(hostrcb, "Path element=%02X: Resource Path=%s, Link rate=%s "
"WWN=%08X%08X\n", cfg->type_status,
- ipr_format_resource_path(&cfg->res_path[0], &buffer[0]),
+ ipr_format_res_path(cfg->res_path, buffer, sizeof(buffer)),
link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK],
be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1]));
}
@@ -2139,7 +2146,7 @@ static void ipr_log_sis64_array_error(struct ipr_ioa_cfg *ioa_cfg,
ipr_err("RAID %s Array Configuration: %s\n",
error->protection_level,
- ipr_format_resource_path(&error->last_res_path[0], &buffer[0]));
+ ipr_format_res_path(error->last_res_path, buffer, sizeof(buffer)));
ipr_err_separator;
@@ -2160,9 +2167,11 @@ static void ipr_log_sis64_array_error(struct ipr_ioa_cfg *ioa_cfg,
ipr_err("Array Member %d:\n", i);
ipr_log_ext_vpd(&array_entry->vpd);
ipr_err("Current Location: %s",
- ipr_format_resource_path(&array_entry->res_path[0], &buffer[0]));
+ ipr_format_res_path(array_entry->res_path, buffer,
+ sizeof(buffer)));
ipr_err("Expected Location: %s",
- ipr_format_resource_path(&array_entry->expected_res_path[0], &buffer[0]));
+ ipr_format_res_path(array_entry->expected_res_path,
+ buffer, sizeof(buffer)));
ipr_err_separator;
}
@@ -4079,7 +4088,8 @@ static struct device_attribute ipr_adapter_handle_attr = {
};
/**
- * ipr_show_resource_path - Show the resource path for this device.
+ * ipr_show_resource_path - Show the resource path or the resource address for
+ * this device.
* @dev: device struct
* @buf: buffer
*
@@ -4097,9 +4107,14 @@ static ssize_t ipr_show_resource_path(struct device *dev, struct device_attribut
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
res = (struct ipr_resource_entry *)sdev->hostdata;
- if (res)
+ if (res && ioa_cfg->sis64)
len = snprintf(buf, PAGE_SIZE, "%s\n",
- ipr_format_resource_path(&res->res_path[0], &buffer[0]));
+ ipr_format_res_path(res->res_path, buffer,
+ sizeof(buffer)));
+ else if (res)
+ len = snprintf(buf, PAGE_SIZE, "%d:%d:%d:%d\n", ioa_cfg->host->host_no,
+ res->bus, res->target, res->lun);
+
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
return len;
}
@@ -4338,8 +4353,6 @@ static int ipr_slave_configure(struct scsi_device *sdev)
IPR_VSET_RW_TIMEOUT);
blk_queue_max_hw_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
}
- if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
- sdev->allow_restart = 1;
if (ipr_is_gata(res) && res->sata_port)
ap = res->sata_port->ap;
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
@@ -4351,7 +4364,8 @@ static int ipr_slave_configure(struct scsi_device *sdev)
scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
if (ioa_cfg->sis64)
sdev_printk(KERN_INFO, sdev, "Resource path: %s\n",
- ipr_format_resource_path(&res->res_path[0], &buffer[0]));
+ ipr_format_res_path(res->res_path, buffer,
+ sizeof(buffer)));
return 0;
}
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
@@ -6755,7 +6769,8 @@ static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd)
list_move_tail(&res->queue, &ioa_cfg->used_res_q);
ipr_init_res_entry(res, &cfgtew);
res->add_to_ml = 1;
- }
+ } else if (res->sdev && (ipr_is_vset_device(res) || ipr_is_scsi_disk(res)))
+ res->sdev->allow_restart = 1;
if (found)
ipr_update_res_entry(res, &cfgtew);
@@ -7193,6 +7208,12 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd)
ipr_init_ioa_mem(ioa_cfg);
ioa_cfg->allow_interrupts = 1;
+ if (ioa_cfg->sis64) {
+ /* Set the adapter to the correct endian mode. */
+ writel(IPR_ENDIAN_SWAP_KEY, ioa_cfg->regs.endian_swap_reg);
+ int_reg = readl(ioa_cfg->regs.endian_swap_reg);
+ }
+
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
@@ -7350,6 +7371,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+ volatile u32 int_reg;
int rc;
ENTER;
@@ -7368,6 +7390,12 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
ipr_fail_all_ops(ioa_cfg);
+ if (ioa_cfg->sis64) {
+ /* Set the adapter to the correct endian mode. */
+ writel(IPR_ENDIAN_SWAP_KEY, ioa_cfg->regs.endian_swap_reg);
+ int_reg = readl(ioa_cfg->regs.endian_swap_reg);
+ }
+
if (ioa_cfg->ioa_unit_checked) {
ioa_cfg->ioa_unit_checked = 0;
ipr_get_unit_check_buffer(ioa_cfg);
@@ -7537,7 +7565,7 @@ static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd)
}
/**
- * ipr_reset_alert_part2 - Alert the adapter of a pending reset
+ * ipr_reset_alert - Alert the adapter of a pending reset
* @ipr_cmd: ipr command struct
*
* Description: This function alerts the adapter that it will be reset.
@@ -8308,6 +8336,7 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
t->init_feedback_reg = base + p->init_feedback_reg;
t->dump_addr_reg = base + p->dump_addr_reg;
t->dump_data_reg = base + p->dump_data_reg;
+ t->endian_swap_reg = base + p->endian_swap_reg;
}
}
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 7e6ec7631bb8..ba63826dd905 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -997,7 +997,7 @@ struct ipr_hostrcb64_fabric_desc {
__be16 length;
u8 descriptor_id;
- u8 reserved;
+ u8 reserved[2];
u8 path_state;
u8 reserved2[2];
@@ -1055,7 +1055,7 @@ struct ipr_hostrcb64_error {
__be64 fd_lun;
u8 fd_res_path[8];
__be64 time_stamp;
- u8 reserved[2];
+ u8 reserved[16];
union {
struct ipr_hostrcb_type_ff_error type_ff_error;
struct ipr_hostrcb_type_12_error type_12_error;
@@ -1255,6 +1255,9 @@ struct ipr_interrupt_offsets {
unsigned long dump_addr_reg;
unsigned long dump_data_reg;
+
+#define IPR_ENDIAN_SWAP_KEY 0x000C0C00
+ unsigned long endian_swap_reg;
};
struct ipr_interrupts {
@@ -1280,6 +1283,8 @@ struct ipr_interrupts {
void __iomem *dump_addr_reg;
void __iomem *dump_data_reg;
+
+ void __iomem *endian_swap_reg;
};
struct ipr_chip_cfg_t {
@@ -1688,8 +1693,9 @@ struct ipr_ucode_image_header {
if (ipr_is_device(hostrcb)) { \
if ((hostrcb)->ioa_cfg->sis64) { \
printk(KERN_ERR IPR_NAME ": %s: " fmt, \
- ipr_format_resource_path(&hostrcb->hcam.u.error64.fd_res_path[0], \
- &hostrcb->rp_buffer[0]), \
+ ipr_format_res_path(hostrcb->hcam.u.error64.fd_res_path, \
+ hostrcb->rp_buffer, \
+ sizeof(hostrcb->rp_buffer)), \
__VA_ARGS__); \
} else { \
ipr_ra_err((hostrcb)->ioa_cfg, \
@@ -1858,4 +1864,12 @@ static inline int ipr_sdt_is_fmt2(u32 sdt_word)
return 0;
}
+#ifndef writeq
+static inline void writeq(u64 val, void __iomem *addr)
+{
+ writel(((u32) (val >> 32)), addr);
+ writel(((u32) (val)), (addr + 4));
+}
#endif
+
+#endif /* _IPR_H */
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index ec1f66c4a9d4..8914f1e95b72 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -745,7 +745,7 @@ static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg)
fh = fc_frame_header_get(fp);
r_ctl = fh->fh_r_ctl;
- if (!(lport->state & LPORT_ST_READY))
+ if (lport->state != LPORT_ST_READY)
goto out;
if (fc_fcp_lock_pkt(fsp))
goto out;
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 39e440f0f54a..363cde30c940 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -89,7 +89,6 @@ static const char *fc_rport_state_names[] = {
[RPORT_ST_LOGO] = "LOGO",
[RPORT_ST_ADISC] = "ADISC",
[RPORT_ST_DELETE] = "Delete",
- [RPORT_ST_RESTART] = "Restart",
};
/**
@@ -246,7 +245,6 @@ static void fc_rport_work(struct work_struct *work)
struct fc_rport_operations *rport_ops;
struct fc_rport_identifiers ids;
struct fc_rport *rport;
- int restart = 0;
mutex_lock(&rdata->rp_mutex);
event = rdata->event;
@@ -259,6 +257,7 @@ static void fc_rport_work(struct work_struct *work)
case RPORT_EV_READY:
ids = rdata->ids;
rdata->event = RPORT_EV_NONE;
+ rdata->major_retries = 0;
kref_get(&rdata->kref);
mutex_unlock(&rdata->rp_mutex);
@@ -298,24 +297,6 @@ static void fc_rport_work(struct work_struct *work)
port_id = rdata->ids.port_id;
mutex_unlock(&rdata->rp_mutex);
- if (port_id != FC_FID_DIR_SERV) {
- /*
- * We must drop rp_mutex before taking disc_mutex.
- * Re-evaluate state to allow for restart.
- * A transition to RESTART state must only happen
- * while disc_mutex is held and rdata is on the list.
- */
- mutex_lock(&lport->disc.disc_mutex);
- mutex_lock(&rdata->rp_mutex);
- if (rdata->rp_state == RPORT_ST_RESTART)
- restart = 1;
- else
- list_del(&rdata->peers);
- rdata->event = RPORT_EV_NONE;
- mutex_unlock(&rdata->rp_mutex);
- mutex_unlock(&lport->disc.disc_mutex);
- }
-
if (rport_ops && rport_ops->event_callback) {
FC_RPORT_DBG(rdata, "callback ev %d\n", event);
rport_ops->event_callback(lport, rdata, event);
@@ -336,13 +317,37 @@ static void fc_rport_work(struct work_struct *work)
mutex_unlock(&rdata->rp_mutex);
fc_remote_port_delete(rport);
}
- if (restart) {
- mutex_lock(&rdata->rp_mutex);
- FC_RPORT_DBG(rdata, "work restart\n");
- fc_rport_enter_plogi(rdata);
+
+ mutex_lock(&lport->disc.disc_mutex);
+ mutex_lock(&rdata->rp_mutex);
+ if (rdata->rp_state == RPORT_ST_DELETE) {
+ if (port_id == FC_FID_DIR_SERV) {
+ rdata->event = RPORT_EV_NONE;
+ mutex_unlock(&rdata->rp_mutex);
+ } else if ((rdata->flags & FC_RP_STARTED) &&
+ rdata->major_retries <
+ lport->max_rport_retry_count) {
+ rdata->major_retries++;
+ rdata->event = RPORT_EV_NONE;
+ FC_RPORT_DBG(rdata, "work restart\n");
+ fc_rport_enter_plogi(rdata);
+ mutex_unlock(&rdata->rp_mutex);
+ } else {
+ FC_RPORT_DBG(rdata, "work delete\n");
+ list_del(&rdata->peers);
+ mutex_unlock(&rdata->rp_mutex);
+ kref_put(&rdata->kref, lport->tt.rport_destroy);
+ }
+ } else {
+ /*
+ * Re-open for events. Reissue READY event if ready.
+ */
+ rdata->event = RPORT_EV_NONE;
+ if (rdata->rp_state == RPORT_ST_READY)
+ fc_rport_enter_ready(rdata);
mutex_unlock(&rdata->rp_mutex);
- } else
- kref_put(&rdata->kref, lport->tt.rport_destroy);
+ }
+ mutex_unlock(&lport->disc.disc_mutex);
break;
default:
@@ -367,16 +372,14 @@ int fc_rport_login(struct fc_rport_priv *rdata)
{
mutex_lock(&rdata->rp_mutex);
+ rdata->flags |= FC_RP_STARTED;
switch (rdata->rp_state) {
case RPORT_ST_READY:
FC_RPORT_DBG(rdata, "ADISC port\n");
fc_rport_enter_adisc(rdata);
break;
- case RPORT_ST_RESTART:
- break;
case RPORT_ST_DELETE:
FC_RPORT_DBG(rdata, "Restart deleted port\n");
- fc_rport_state_enter(rdata, RPORT_ST_RESTART);
break;
default:
FC_RPORT_DBG(rdata, "Login to port\n");
@@ -431,15 +434,12 @@ int fc_rport_logoff(struct fc_rport_priv *rdata)
FC_RPORT_DBG(rdata, "Remove port\n");
+ rdata->flags &= ~FC_RP_STARTED;
if (rdata->rp_state == RPORT_ST_DELETE) {
FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n");
goto out;
}
-
- if (rdata->rp_state == RPORT_ST_RESTART)
- FC_RPORT_DBG(rdata, "Port in Restart state, deleting\n");
- else
- fc_rport_enter_logo(rdata);
+ fc_rport_enter_logo(rdata);
/*
* Change the state to Delete so that we discard
@@ -503,7 +503,6 @@ static void fc_rport_timeout(struct work_struct *work)
case RPORT_ST_READY:
case RPORT_ST_INIT:
case RPORT_ST_DELETE:
- case RPORT_ST_RESTART:
break;
}
@@ -527,6 +526,7 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
switch (rdata->rp_state) {
case RPORT_ST_PLOGI:
case RPORT_ST_LOGO:
+ rdata->flags &= ~FC_RP_STARTED;
fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
break;
case RPORT_ST_RTV:
@@ -537,7 +537,6 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
fc_rport_enter_logo(rdata);
break;
case RPORT_ST_DELETE:
- case RPORT_ST_RESTART:
case RPORT_ST_READY:
case RPORT_ST_INIT:
break;
@@ -698,6 +697,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
u32 roles = FC_RPORT_ROLE_UNKNOWN;
u32 fcp_parm = 0;
u8 op;
+ u8 resp_code = 0;
mutex_lock(&rdata->rp_mutex);
@@ -722,11 +722,25 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
op = fc_frame_payload_op(fp);
if (op == ELS_LS_ACC) {
pp = fc_frame_payload_get(fp, sizeof(*pp));
- if (pp && pp->prli.prli_spp_len >= sizeof(pp->spp)) {
- fcp_parm = ntohl(pp->spp.spp_params);
- if (fcp_parm & FCP_SPPF_RETRY)
- rdata->flags |= FC_RP_FLAGS_RETRY;
+ if (!pp)
+ goto out;
+
+ resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK);
+ FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x\n",
+ pp->spp.spp_flags);
+ if (resp_code != FC_SPP_RESP_ACK) {
+ if (resp_code == FC_SPP_RESP_CONF)
+ fc_rport_error(rdata, fp);
+ else
+ fc_rport_error_retry(rdata, fp);
+ goto out;
}
+ if (pp->prli.prli_spp_len < sizeof(pp->spp))
+ goto out;
+
+ fcp_parm = ntohl(pp->spp.spp_params);
+ if (fcp_parm & FCP_SPPF_RETRY)
+ rdata->flags |= FC_RP_FLAGS_RETRY;
rdata->supported_classes = FC_COS_CLASS3;
if (fcp_parm & FCP_SPPF_INIT_FCN)
@@ -739,7 +753,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
} else {
FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n");
- fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
+ fc_rport_error_retry(rdata, fp);
}
out:
@@ -1377,7 +1391,6 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
break;
case RPORT_ST_DELETE:
case RPORT_ST_LOGO:
- case RPORT_ST_RESTART:
FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n",
fc_rport_state(rdata));
mutex_unlock(&rdata->rp_mutex);
@@ -1558,30 +1571,85 @@ drop:
* fc_rport_recv_prlo_req() - Handler for process logout (PRLO) requests
* @rdata: The remote port that sent the PRLO request
* @sp: The sequence that the PRLO was on
- * @fp: The PRLO request frame
+ * @rx_fp: The PRLO request frame
*
* Locking Note: The rport lock is exected to be held before calling
* this function.
*/
static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
struct fc_seq *sp,
- struct fc_frame *fp)
+ struct fc_frame *rx_fp)
{
struct fc_lport *lport = rdata->local_port;
-
struct fc_frame_header *fh;
+ struct fc_exch *ep;
+ struct fc_frame *fp;
+ struct {
+ struct fc_els_prlo prlo;
+ struct fc_els_spp spp;
+ } *pp;
+ struct fc_els_spp *rspp; /* request service param page */
+ struct fc_els_spp *spp; /* response spp */
+ unsigned int len;
+ unsigned int plen;
+ u32 f_ctl;
struct fc_seq_els_data rjt_data;
- fh = fc_frame_header_get(fp);
+ rjt_data.fp = NULL;
+ fh = fc_frame_header_get(rx_fp);
FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n",
fc_rport_state(rdata));
- rjt_data.fp = NULL;
- rjt_data.reason = ELS_RJT_UNAB;
- rjt_data.explan = ELS_EXPL_NONE;
+ len = fr_len(rx_fp) - sizeof(*fh);
+ pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
+ if (!pp)
+ goto reject_len;
+ plen = ntohs(pp->prlo.prlo_len);
+ if (plen != 20)
+ goto reject_len;
+ if (plen < len)
+ len = plen;
+
+ rspp = &pp->spp;
+
+ fp = fc_frame_alloc(lport, len);
+ if (!fp) {
+ rjt_data.reason = ELS_RJT_UNAB;
+ rjt_data.explan = ELS_EXPL_INSUF_RES;
+ goto reject;
+ }
+
+ sp = lport->tt.seq_start_next(sp);
+ WARN_ON(!sp);
+ pp = fc_frame_payload_get(fp, len);
+ WARN_ON(!pp);
+ memset(pp, 0, len);
+ pp->prlo.prlo_cmd = ELS_LS_ACC;
+ pp->prlo.prlo_obs = 0x10;
+ pp->prlo.prlo_len = htons(len);
+ spp = &pp->spp;
+ spp->spp_type = rspp->spp_type;
+ spp->spp_type_ext = rspp->spp_type_ext;
+ spp->spp_flags = FC_SPP_RESP_ACK;
+
+ fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
+
+ f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
+ f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
+ ep = fc_seq_exch(sp);
+ fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
+ FC_TYPE_ELS, f_ctl, 0);
+ lport->tt.seq_send(lport, sp, fp);
+ goto drop;
+
+reject_len:
+ rjt_data.reason = ELS_RJT_PROT;
+ rjt_data.explan = ELS_EXPL_INV_LEN;
+reject:
lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
- fc_frame_free(fp);
+drop:
+ fc_frame_free(rx_fp);
}
/**
@@ -1614,13 +1682,6 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport,
fc_rport_state(rdata));
fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
-
- /*
- * If the remote port was created due to discovery, set state
- * to log back in. It may have seen a stale RSCN about us.
- */
- if (rdata->disc_id)
- fc_rport_state_enter(rdata, RPORT_ST_RESTART);
mutex_unlock(&rdata->rp_mutex);
} else
FC_RPORT_ID_DBG(lport, sid,
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index e35a4c71eb9a..bb40fcbe17c5 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -20,7 +20,6 @@
*******************************************************************/
#include <scsi/scsi_host.h>
-
struct lpfc_sli2_slim;
#define LPFC_PCI_DEV_LP 0x1
@@ -376,6 +375,7 @@ struct lpfc_vport {
#define WORKER_FABRIC_BLOCK_TMO 0x400 /* hba: fabric block timeout */
#define WORKER_RAMP_DOWN_QUEUE 0x800 /* hba: Decrease Q depth */
#define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */
+#define WORKER_SERVICE_TXQ 0x2000 /* hba: IOCBs on the txq */
struct timer_list fc_fdmitmo;
struct timer_list els_tmofunc;
@@ -510,9 +510,9 @@ struct lpfc_hba {
void (*lpfc_stop_port)
(struct lpfc_hba *);
int (*lpfc_hba_init_link)
- (struct lpfc_hba *);
+ (struct lpfc_hba *, uint32_t);
int (*lpfc_hba_down_link)
- (struct lpfc_hba *);
+ (struct lpfc_hba *, uint32_t);
/* SLI4 specific HBA data structure */
struct lpfc_sli4_hba sli4_hba;
@@ -525,7 +525,6 @@ struct lpfc_hba {
#define LPFC_SLI3_NPIV_ENABLED 0x02
#define LPFC_SLI3_VPORT_TEARDOWN 0x04
#define LPFC_SLI3_CRP_ENABLED 0x08
-#define LPFC_SLI3_INB_ENABLED 0x10
#define LPFC_SLI3_BG_ENABLED 0x20
#define LPFC_SLI3_DSS_ENABLED 0x40
uint32_t iocb_cmd_size;
@@ -557,9 +556,6 @@ struct lpfc_hba {
MAILBOX_t *mbox;
uint32_t *mbox_ext;
- uint32_t *inb_ha_copy;
- uint32_t *inb_counter;
- uint32_t inb_last_counter;
uint32_t ha_copy;
struct _PCB *pcb;
struct _IOCB *IOCBs;
@@ -628,6 +624,7 @@ struct lpfc_hba {
uint32_t cfg_hostmem_hgp;
uint32_t cfg_log_verbose;
uint32_t cfg_aer_support;
+ uint32_t cfg_iocb_cnt;
uint32_t cfg_suppress_link_up;
#define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */
#define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */
@@ -816,6 +813,9 @@ struct lpfc_hba {
uint8_t menlo_flag; /* menlo generic flags */
#define HBA_MENLO_SUPPORT 0x1 /* HBA supports menlo commands */
+ uint32_t iocb_cnt;
+ uint32_t iocb_max;
+ atomic_t sdev_cnt;
};
static inline struct Scsi_Host *
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index bf33b315f93e..a7c6b7390554 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -506,10 +506,10 @@ lpfc_link_state_store(struct device *dev, struct device_attribute *attr,
if ((strncmp(buf, "up", sizeof("up") - 1) == 0) &&
(phba->link_state == LPFC_LINK_DOWN))
- status = phba->lpfc_hba_init_link(phba);
+ status = phba->lpfc_hba_init_link(phba, MBX_NOWAIT);
else if ((strncmp(buf, "down", sizeof("down") - 1) == 0) &&
(phba->link_state >= LPFC_LINK_UP))
- status = phba->lpfc_hba_down_link(phba);
+ status = phba->lpfc_hba_down_link(phba, MBX_NOWAIT);
if (status == 0)
return strlen(buf);
@@ -864,7 +864,6 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
uint32_t *mrpi, uint32_t *arpi,
uint32_t *mvpi, uint32_t *avpi)
{
- struct lpfc_sli *psli = &phba->sli;
struct lpfc_mbx_read_config *rd_config;
LPFC_MBOXQ_t *pmboxq;
MAILBOX_t *pmb;
@@ -893,8 +892,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba,
pmb->mbxOwner = OWN_HOST;
pmboxq->context1 = NULL;
- if ((phba->pport->fc_flag & FC_OFFLINE_MODE) ||
- (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
+ if (phba->pport->fc_flag & FC_OFFLINE_MODE)
rc = MBX_NOT_FINISHED;
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -1949,6 +1947,59 @@ static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL);
LPFC_ATTR_R(suppress_link_up, LPFC_INITIALIZE_LINK, LPFC_INITIALIZE_LINK,
LPFC_DELAY_INIT_LINK_INDEFINITELY,
"Suppress Link Up at initialization");
+/*
+# lpfc_cnt: Number of IOCBs allocated for ELS, CT, and ABTS
+# 1 - (1024)
+# 2 - (2048)
+# 3 - (3072)
+# 4 - (4096)
+# 5 - (5120)
+*/
+static ssize_t
+lpfc_iocb_hw_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", phba->iocb_max);
+}
+
+static DEVICE_ATTR(iocb_hw, S_IRUGO,
+ lpfc_iocb_hw_show, NULL);
+static ssize_t
+lpfc_txq_hw_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ phba->sli.ring[LPFC_ELS_RING].txq_max);
+}
+
+static DEVICE_ATTR(txq_hw, S_IRUGO,
+ lpfc_txq_hw_show, NULL);
+static ssize_t
+lpfc_txcmplq_hw_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ phba->sli.ring[LPFC_ELS_RING].txcmplq_max);
+}
+
+static DEVICE_ATTR(txcmplq_hw, S_IRUGO,
+ lpfc_txcmplq_hw_show, NULL);
+
+int lpfc_iocb_cnt = 2;
+module_param(lpfc_iocb_cnt, int, 1);
+MODULE_PARM_DESC(lpfc_iocb_cnt,
+ "Number of IOCBs alloc for ELS, CT, and ABTS: 1k to 5k IOCBs");
+lpfc_param_show(iocb_cnt);
+lpfc_param_init(iocb_cnt, 2, 1, 5);
+static DEVICE_ATTR(lpfc_iocb_cnt, S_IRUGO,
+ lpfc_iocb_cnt_show, NULL);
/*
# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
@@ -2890,9 +2941,6 @@ lpfc_aer_support_store(struct device *dev, struct device_attribute *attr,
struct lpfc_hba *phba = vport->phba;
int val = 0, rc = -EINVAL;
- /* AER not supported on OC devices yet */
- if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
- return -EPERM;
if (!isdigit(buf[0]))
return -EINVAL;
if (sscanf(buf, "%i", &val) != 1)
@@ -2965,12 +3013,6 @@ lpfc_param_show(aer_support)
static int
lpfc_aer_support_init(struct lpfc_hba *phba, int val)
{
- /* AER not supported on OC devices yet */
- if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) {
- phba->cfg_aer_support = 0;
- return -EPERM;
- }
-
if (val == 0 || val == 1) {
phba->cfg_aer_support = val;
return 0;
@@ -3015,9 +3057,6 @@ lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr,
struct lpfc_hba *phba = vport->phba;
int val, rc = -1;
- /* AER not supported on OC devices yet */
- if (phba->pci_dev_grp == LPFC_PCI_DEV_OC)
- return -EPERM;
if (!isdigit(buf[0]))
return -EINVAL;
if (sscanf(buf, "%i", &val) != 1)
@@ -3334,6 +3373,10 @@ struct device_attribute *lpfc_hba_attrs[] = {
&dev_attr_lpfc_aer_support,
&dev_attr_lpfc_aer_state_cleanup,
&dev_attr_lpfc_suppress_link_up,
+ &dev_attr_lpfc_iocb_cnt,
+ &dev_attr_iocb_hw,
+ &dev_attr_txq_hw,
+ &dev_attr_txcmplq_hw,
NULL,
};
@@ -4042,8 +4085,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
pmboxq->context1 = NULL;
pmboxq->vport = vport;
- if ((vport->fc_flag & FC_OFFLINE_MODE) ||
- (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
+ if (vport->fc_flag & FC_OFFLINE_MODE)
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -4067,8 +4109,7 @@ lpfc_get_stats(struct Scsi_Host *shost)
pmboxq->context1 = NULL;
pmboxq->vport = vport;
- if ((vport->fc_flag & FC_OFFLINE_MODE) ||
- (!(psli->sli_flag & LPFC_SLI_ACTIVE)))
+ if (vport->fc_flag & FC_OFFLINE_MODE)
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
@@ -4521,6 +4562,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
lpfc_aer_support_init(phba, lpfc_aer_support);
lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up);
+ lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c
index dcf088262b20..55f984166dbc 100644
--- a/drivers/scsi/lpfc/lpfc_bsg.c
+++ b/drivers/scsi/lpfc/lpfc_bsg.c
@@ -377,6 +377,11 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
if (rc == IOCB_SUCCESS)
return 0; /* done for now */
+ else if (rc == IOCB_BUSY)
+ rc = EAGAIN;
+ else
+ rc = EIO;
+
/* iocb failed so cleanup */
pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
@@ -625,6 +630,10 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
lpfc_nlp_put(ndlp);
if (rc == IOCB_SUCCESS)
return 0; /* done for now */
+ else if (rc == IOCB_BUSY)
+ rc = EAGAIN;
+ else
+ rc = EIO;
pci_unmap_sg(phba->pcidev, job->request_payload.sg_list,
job->request_payload.sg_cnt, DMA_TO_DEVICE);
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index fbc9baeb6048..03f4ddc18572 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -41,6 +41,7 @@ void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
LPFC_MBOXQ_t *, uint32_t);
+void lpfc_set_var(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *);
@@ -190,6 +191,7 @@ irqreturn_t lpfc_sli4_sp_intr_handler(int, void *);
irqreturn_t lpfc_sli4_fp_intr_handler(int, void *);
void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_sli4_swap_str(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -402,3 +404,12 @@ int lpfc_bsg_request(struct fc_bsg_job *);
int lpfc_bsg_timeout(struct fc_bsg_job *);
int lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
+void __lpfc_sli_ringtx_put(struct lpfc_hba *, struct lpfc_sli_ring *,
+ struct lpfc_iocbq *);
+struct lpfc_iocbq *lpfc_sli_ringtx_get(struct lpfc_hba *,
+ struct lpfc_sli_ring *);
+int __lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t,
+ struct lpfc_iocbq *, uint32_t);
+uint32_t lpfc_drain_txq(struct lpfc_hba *);
+
+
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 36257a685509..7cae69de36f7 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -114,6 +114,8 @@ struct lpfc_nodelist {
};
/* Defines for nlp_flag (uint32) */
+#define NLP_IGNR_REG_CMPL 0x00000001 /* Rcvd rscn before we cmpl reg login */
+#define NLP_REG_LOGIN_SEND 0x00000002 /* sent reglogin to adapter */
#define NLP_PLOGI_SND 0x00000020 /* sent PLOGI request for this entry */
#define NLP_PRLI_SND 0x00000040 /* sent PRLI request for this entry */
#define NLP_ADISC_SND 0x00000080 /* sent ADISC request for this entry */
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index c4c7f0ad7468..017c933d60ab 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -796,7 +796,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* due to new FCF discovery
*/
if ((phba->hba_flag & HBA_FIP_SUPPORT) &&
- (phba->fcf.fcf_flag & FCF_DISCOVERY)) {
+ (phba->fcf.fcf_flag & FCF_DISCOVERY) &&
+ (irsp->ulpStatus != IOSTAT_LOCAL_REJECT) &&
+ (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS,
"2611 FLOGI failed on registered "
"FCF record fcf_index:%d, trying "
@@ -890,9 +892,39 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
if (sp->cmn.fPort)
rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
- else
+ else if (!(phba->hba_flag & HBA_FCOE_SUPPORT))
rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
-
+ else {
+ lpfc_printf_vlog(vport, KERN_ERR,
+ LOG_FIP | LOG_ELS,
+ "2831 FLOGI response with cleared Fabric "
+ "bit fcf_index 0x%x "
+ "Switch Name %02x%02x%02x%02x%02x%02x%02x%02x "
+ "Fabric Name "
+ "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ phba->fcf.current_rec.fcf_indx,
+ phba->fcf.current_rec.switch_name[0],
+ phba->fcf.current_rec.switch_name[1],
+ phba->fcf.current_rec.switch_name[2],
+ phba->fcf.current_rec.switch_name[3],
+ phba->fcf.current_rec.switch_name[4],
+ phba->fcf.current_rec.switch_name[5],
+ phba->fcf.current_rec.switch_name[6],
+ phba->fcf.current_rec.switch_name[7],
+ phba->fcf.current_rec.fabric_name[0],
+ phba->fcf.current_rec.fabric_name[1],
+ phba->fcf.current_rec.fabric_name[2],
+ phba->fcf.current_rec.fabric_name[3],
+ phba->fcf.current_rec.fabric_name[4],
+ phba->fcf.current_rec.fabric_name[5],
+ phba->fcf.current_rec.fabric_name[6],
+ phba->fcf.current_rec.fabric_name[7]);
+ lpfc_nlp_put(ndlp);
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag &= ~FCF_DISCOVERY;
+ spin_unlock_irq(&phba->hbalock);
+ goto out;
+ }
if (!rc) {
/* Mark the FCF discovery process done */
if (phba->hba_flag & HBA_FIP_SUPPORT)
@@ -1472,8 +1504,12 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
goto out;
}
- /* PLOGI failed */
- lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+ /* PLOGI failed Don't print the vport to vport rjts */
+ if (irsp->ulpStatus != IOSTAT_LS_RJT ||
+ (((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) &&
+ ((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) ||
+ (phba)->pport->cfg_log_verbose & LOG_ELS)
+ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
"2753 PLOGI failure DID:%06X Status:x%x/x%x\n",
ndlp->nlp_DID, irsp->ulpStatus,
irsp->un.ulpWord[4]);
@@ -2740,6 +2776,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
retry = 1;
break;
}
+ if (stat.un.b.lsRjtRsnCodeExp ==
+ LSEXP_CANT_GIVE_DATA) {
+ if (cmd == ELS_CMD_PLOGI) {
+ delay = 1000;
+ maxretry = 48;
+ }
+ retry = 1;
+ break;
+ }
if (cmd == ELS_CMD_PLOGI) {
delay = 1000;
maxretry = lpfc_max_els_tries + 1;
@@ -5135,6 +5180,7 @@ lpfc_els_timeout(unsigned long ptr)
return;
}
+
/**
* lpfc_els_timeout_handler - Process an els timeout event
* @vport: pointer to a virtual N_Port data structure.
@@ -5155,13 +5201,19 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
uint32_t els_command = 0;
uint32_t timeout;
uint32_t remote_ID = 0xffffffff;
+ LIST_HEAD(txcmplq_completions);
+ LIST_HEAD(abort_list);
+
- spin_lock_irq(&phba->hbalock);
timeout = (uint32_t)(phba->fc_ratov << 1);
pring = &phba->sli.ring[LPFC_ELS_RING];
- list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
+ spin_lock_irq(&phba->hbalock);
+ list_splice_init(&pring->txcmplq, &txcmplq_completions);
+ spin_unlock_irq(&phba->hbalock);
+
+ list_for_each_entry_safe(piocb, tmp_iocb, &txcmplq_completions, list) {
cmd = &piocb->iocb;
if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
@@ -5198,13 +5250,22 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport)
if (ndlp && NLP_CHK_NODE_ACT(ndlp))
remote_ID = ndlp->nlp_DID;
}
+ list_add_tail(&piocb->dlist, &abort_list);
+ }
+ spin_lock_irq(&phba->hbalock);
+ list_splice(&txcmplq_completions, &pring->txcmplq);
+ spin_unlock_irq(&phba->hbalock);
+
+ list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) {
lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
- "0127 ELS timeout Data: x%x x%x x%x "
- "x%x\n", els_command,
- remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
+ "0127 ELS timeout Data: x%x x%x x%x "
+ "x%x\n", els_command,
+ remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&piocb->dlist);
lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+ spin_unlock_irq(&phba->hbalock);
}
- spin_unlock_irq(&phba->hbalock);
if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 1f87b4fb8b50..9fcad20491ef 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -275,7 +275,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
if (!(vport->load_flag & FC_UNLOADING) &&
!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
!(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
- (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
+ (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) &&
+ (ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE))
lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
lpfc_unregister_unused_fcf(phba);
@@ -586,6 +587,8 @@ lpfc_work_done(struct lpfc_hba *phba)
(status &
HA_RXMASK));
}
+ if (phba->pport->work_port_events & WORKER_SERVICE_TXQ)
+ lpfc_drain_txq(phba);
/*
* Turn on Ring interrupts
*/
@@ -1297,7 +1300,7 @@ lpfc_register_fcf(struct lpfc_hba *phba)
* used for this FCF when the function returns.
* If the FCF record need to be used with a particular vlan id, the vlan is
* set in the vlan_id on return of the function. If not VLAN tagging need to
- * be used with the FCF vlan_id will be set to 0xFFFF;
+ * be used with the FCF vlan_id will be set to LPFC_FCOE_NULL_VID;
**/
static int
lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
@@ -1333,7 +1336,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
if (phba->valid_vlan)
*vlan_id = phba->vlan_id;
else
- *vlan_id = 0xFFFF;
+ *vlan_id = LPFC_FCOE_NULL_VID;
return 1;
}
@@ -1357,7 +1360,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
if (fcf_vlan_id)
*vlan_id = fcf_vlan_id;
else
- *vlan_id = 0xFFFF;
+ *vlan_id = LPFC_FCOE_NULL_VID;
return 1;
}
@@ -1466,7 +1469,7 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba,
else if (fcf_vlan_id)
*vlan_id = fcf_vlan_id;
else
- *vlan_id = 0xFFFF;
+ *vlan_id = LPFC_FCOE_NULL_VID;
return 1;
}
@@ -1518,6 +1521,9 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf)
* Do not continue FCF discovery and clear FCF_DISC_INPROGRESS
* flag
*/
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY,
+ "2833 Stop FCF discovery process due to link "
+ "state change (x%x)\n", phba->link_state);
spin_lock_irq(&phba->hbalock);
phba->hba_flag &= ~FCF_DISC_INPROGRESS;
phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | FCF_DISCOVERY);
@@ -1693,6 +1699,37 @@ lpfc_sli4_log_fcf_record_info(struct lpfc_hba *phba,
}
/**
+ lpfc_sli4_fcf_record_match - testing new FCF record for matching existing FCF
+ * @phba: pointer to lpfc hba data structure.
+ * @fcf_rec: pointer to an existing FCF record.
+ * @new_fcf_record: pointer to a new FCF record.
+ * @new_vlan_id: vlan id from the new FCF record.
+ *
+ * This function performs matching test of a new FCF record against an existing
+ * FCF record. If the new_vlan_id passed in is LPFC_FCOE_IGNORE_VID, vlan id
+ * will not be used as part of the FCF record matching criteria.
+ *
+ * Returns true if all the fields matching, otherwise returns false.
+ */
+static bool
+lpfc_sli4_fcf_record_match(struct lpfc_hba *phba,
+ struct lpfc_fcf_rec *fcf_rec,
+ struct fcf_record *new_fcf_record,
+ uint16_t new_vlan_id)
+{
+ if (new_vlan_id != LPFC_FCOE_IGNORE_VID)
+ if (!lpfc_vlan_id_match(fcf_rec->vlan_id, new_vlan_id))
+ return false;
+ if (!lpfc_mac_addr_match(fcf_rec->mac_addr, new_fcf_record))
+ return false;
+ if (!lpfc_sw_name_match(fcf_rec->switch_name, new_fcf_record))
+ return false;
+ if (!lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record))
+ return false;
+ return true;
+}
+
+/**
* lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler.
* @phba: pointer to lpfc hba data structure.
* @mboxq: pointer to mailbox object.
@@ -1755,7 +1792,7 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
*/
if (!rc) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
- "2781 FCF record fcf_index:x%x failed FCF "
+ "2781 FCF record (x%x) failed FCF "
"connection list check, fcf_avail:x%x, "
"fcf_valid:x%x\n",
bf_get(lpfc_fcf_record_fcf_index,
@@ -1764,6 +1801,32 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
new_fcf_record),
bf_get(lpfc_fcf_record_fcf_valid,
new_fcf_record));
+ if ((phba->fcf.fcf_flag & FCF_IN_USE) &&
+ lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
+ new_fcf_record, LPFC_FCOE_IGNORE_VID)) {
+ /*
+ * In case the current in-use FCF record becomes
+ * invalid/unavailable during FCF discovery that
+ * was not triggered by fast FCF failover process,
+ * treat it as fast FCF failover.
+ */
+ if (!(phba->fcf.fcf_flag & FCF_REDISC_PEND) &&
+ !(phba->fcf.fcf_flag & FCF_REDISC_FOV)) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_FIP,
+ "2835 Invalid in-use FCF "
+ "record (x%x) reported, "
+ "entering fast FCF failover "
+ "mode scanning.\n",
+ phba->fcf.current_rec.fcf_indx);
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag |= FCF_REDISC_FOV;
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_sli4_mbox_cmd_free(phba, mboxq);
+ lpfc_sli4_fcf_scan_read_fcf_rec(phba,
+ LPFC_FCOE_FCF_GET_FIRST);
+ return;
+ }
+ }
goto read_next_fcf;
} else {
fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record);
@@ -1780,14 +1843,8 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
*/
spin_lock_irq(&phba->hbalock);
if (phba->fcf.fcf_flag & FCF_IN_USE) {
- if (lpfc_fab_name_match(phba->fcf.current_rec.fabric_name,
- new_fcf_record) &&
- lpfc_sw_name_match(phba->fcf.current_rec.switch_name,
- new_fcf_record) &&
- lpfc_mac_addr_match(phba->fcf.current_rec.mac_addr,
- new_fcf_record) &&
- lpfc_vlan_id_match(phba->fcf.current_rec.vlan_id,
- vlan_id)) {
+ if (lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec,
+ new_fcf_record, vlan_id)) {
phba->fcf.fcf_flag |= FCF_AVAILABLE;
if (phba->fcf.fcf_flag & FCF_REDISC_PEND)
/* Stop FCF redisc wait timer if pending */
@@ -1797,6 +1854,13 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV |
FCF_DISCOVERY);
spin_unlock_irq(&phba->hbalock);
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2836 The new FCF record (x%x) "
+ "matches the in-use FCF record "
+ "(x%x)\n",
+ phba->fcf.current_rec.fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
goto out;
}
/*
@@ -1828,6 +1892,12 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
*/
if (boot_flag && !(fcf_rec->flag & BOOT_ENABLE)) {
/* Choose this FCF record */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2837 Update current FCF record "
+ "(x%x) with new FCF record (x%x)\n",
+ fcf_rec->fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
addr_mode, vlan_id, BOOT_ENABLE);
spin_unlock_irq(&phba->hbalock);
@@ -1848,6 +1918,12 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
*/
if (new_fcf_record->fip_priority < fcf_rec->priority) {
/* Choose the new FCF record with lower priority */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2838 Update current FCF record "
+ "(x%x) with new FCF record (x%x)\n",
+ fcf_rec->fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
addr_mode, vlan_id, 0);
/* Reset running random FCF selection count */
@@ -1857,11 +1933,18 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
phba->fcf.eligible_fcf_cnt++;
select_new_fcf = lpfc_sli4_new_fcf_random_select(phba,
phba->fcf.eligible_fcf_cnt);
- if (select_new_fcf)
+ if (select_new_fcf) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2839 Update current FCF record "
+ "(x%x) with new FCF record (x%x)\n",
+ fcf_rec->fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
/* Choose the new FCF by random selection */
__lpfc_update_fcf_record(phba, fcf_rec,
new_fcf_record,
addr_mode, vlan_id, 0);
+ }
}
spin_unlock_irq(&phba->hbalock);
goto read_next_fcf;
@@ -1871,6 +1954,11 @@ lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
* initial best-fit FCF.
*/
if (fcf_rec) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2840 Update current FCF record "
+ "with initial FCF record (x%x)\n",
+ bf_get(lpfc_fcf_record_fcf_index,
+ new_fcf_record));
__lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record,
addr_mode, vlan_id, (boot_flag ?
BOOT_ENABLE : 0));
@@ -1928,6 +2016,12 @@ read_next_fcf:
lpfc_unregister_fcf(phba);
/* Replace in-use record with the new record */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2842 Replace the current in-use "
+ "FCF record (x%x) with failover FCF "
+ "record (x%x)\n",
+ phba->fcf.current_rec.fcf_indx,
+ phba->fcf.failover_rec.fcf_indx);
memcpy(&phba->fcf.current_rec,
&phba->fcf.failover_rec,
sizeof(struct lpfc_fcf_rec));
@@ -1951,6 +2045,28 @@ read_next_fcf:
if ((phba->fcf.fcf_flag & FCF_REDISC_EVT) ||
(phba->fcf.fcf_flag & FCF_REDISC_PEND))
return;
+
+ if (phba->fcf.fcf_flag & FCF_IN_USE) {
+ /*
+ * In case the current in-use FCF record no
+ * longer existed during FCF discovery that
+ * was not triggered by fast FCF failover
+ * process, treat it as fast FCF failover.
+ */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2841 In-use FCF record (x%x) "
+ "not reported, entering fast "
+ "FCF failover mode scanning.\n",
+ phba->fcf.current_rec.fcf_indx);
+ spin_lock_irq(&phba->hbalock);
+ phba->fcf.fcf_flag |= FCF_REDISC_FOV;
+ spin_unlock_irq(&phba->hbalock);
+ lpfc_sli4_mbox_cmd_free(phba, mboxq);
+ lpfc_sli4_fcf_scan_read_fcf_rec(phba,
+ LPFC_FCOE_FCF_GET_FIRST);
+ return;
+ }
+
/*
* Otherwise, initial scan or post linkdown rescan,
* register with the best FCF record found so far
@@ -2033,6 +2149,11 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
next_fcf_index);
/* Upload new FCF record to the failover FCF record */
+ lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
+ "2834 Update the current FCF record (x%x) "
+ "with the next FCF record (x%x)\n",
+ phba->fcf.failover_rec.fcf_indx,
+ bf_get(lpfc_fcf_record_fcf_index, new_fcf_record));
spin_lock_irq(&phba->hbalock);
__lpfc_update_fcf_record(phba, &phba->fcf.failover_rec,
new_fcf_record, addr_mode, vlan_id,
@@ -2050,7 +2171,7 @@ lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
lpfc_printf_log(phba, KERN_INFO, LOG_FIP,
"2783 FLOGI round robin FCF failover from FCF "
- "(index:x%x) to FCF (index:x%x).\n",
+ "(x%x) to FCF (x%x).\n",
current_fcf_index,
bf_get(lpfc_fcf_record_fcf_index, new_fcf_record));
@@ -2715,11 +2836,35 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
struct lpfc_vport *vport = pmb->vport;
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
pmb->context1 = NULL;
- /* Good status, call state machine */
- lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
+ if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
+ ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
+
+ if (ndlp->nlp_flag & NLP_IGNR_REG_CMPL ||
+ ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) {
+ /* We rcvd a rscn after issuing this
+ * mbox reg login, we may have cycled
+ * back through the state and be
+ * back at reg login state so this
+ * mbox needs to be ignored becase
+ * there is another reg login in
+ * proccess.
+ */
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL;
+ spin_unlock_irq(shost->host_lock);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba,
+ pmb->u.mb.un.varRegLogin.rpi);
+
+ } else
+ /* Good status, call state machine */
+ lpfc_disc_state_machine(vport, ndlp, pmb,
+ NLP_EVT_CMPL_REG_LOGIN);
+
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool);
@@ -3700,6 +3845,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
mempool_free(mbox, phba->mbox_mem_pool);
}
lpfc_no_rpi(phba, ndlp);
+
ndlp->nlp_rpi = 0;
ndlp->nlp_flag &= ~NLP_RPI_VALID;
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
@@ -3842,6 +3988,9 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
kfree(mp);
}
list_del(&mb->list);
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ lpfc_sli4_free_rpi(phba,
+ mb->u.mb.un.varRegLogin.rpi);
mempool_free(mb, phba->mbox_mem_pool);
/* We shall not invoke the lpfc_nlp_put to decrement
* the ndlp reference count as we are in the process
@@ -3883,6 +4032,7 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
lpfc_cancel_retry_delay_tmo(vport, ndlp);
if ((ndlp->nlp_flag & NLP_DEFER_RM) &&
+ !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) &&
!(ndlp->nlp_flag & NLP_RPI_VALID)) {
/* For this case we need to cleanup the default rpi
* allocated by the firmware.
@@ -5186,7 +5336,8 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba)
spin_lock_irq(&phba->hbalock);
if (!(phba->hba_flag & HBA_FCOE_SUPPORT) ||
!(phba->fcf.fcf_flag & FCF_REGISTERED) ||
- !(phba->hba_flag & HBA_FIP_SUPPORT)) {
+ !(phba->hba_flag & HBA_FIP_SUPPORT) ||
+ (phba->pport->port_state == LPFC_FLOGI)) {
spin_unlock_irq(&phba->hbalock);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index e654d01dad24..f5dbf2be3eab 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1170,6 +1170,7 @@ typedef struct {
#define PCI_DEVICE_ID_TIGERSHARK 0x0704
#define PCI_DEVICE_ID_TOMCAT 0x0714
#define PCI_DEVICE_ID_FALCON 0xf180
+#define PCI_DEVICE_ID_BALIUS 0xe131
#define JEDEC_ID_ADDRESS 0x0080001c
#define FIREFLY_JEDEC_ID 0x1ACC
@@ -3014,18 +3015,10 @@ struct sli3_pgp {
uint32_t hbq_get[16];
};
-struct sli3_inb_pgp {
- uint32_t ha_copy;
- uint32_t counter;
- struct lpfc_pgp port[MAX_RINGS];
- uint32_t hbq_get[16];
-};
-
union sli_var {
struct sli2_desc s2;
struct sli3_desc s3;
struct sli3_pgp s3_pgp;
- struct sli3_inb_pgp s3_inb_pgp;
};
typedef struct {
@@ -3132,6 +3125,14 @@ typedef struct {
#define IOERR_BUFFER_SHORTAGE 0x28
#define IOERR_DEFAULT 0x29
#define IOERR_CNT 0x2A
+#define IOERR_SLER_FAILURE 0x46
+#define IOERR_SLER_CMD_RCV_FAILURE 0x47
+#define IOERR_SLER_REC_RJT_ERR 0x48
+#define IOERR_SLER_REC_SRR_RETRY_ERR 0x49
+#define IOERR_SLER_SRR_RJT_ERR 0x4A
+#define IOERR_SLER_RRQ_RJT_ERR 0x4C
+#define IOERR_SLER_RRQ_RETRY_ERR 0x4D
+#define IOERR_SLER_ABTS_ERR 0x4E
#define IOERR_DRVR_MASK 0x100
#define IOERR_SLI_DOWN 0x101 /* ulpStatus - Driver defined */
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index cd9697edf860..fb06933f8e6c 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -621,6 +621,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
/**
* lpfc_hba_init_link - Initialize the FC link
* @phba: pointer to lpfc hba data structure.
+ * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT
*
* This routine will issue the INIT_LINK mailbox command call.
* It is available to other drivers through the lpfc_hba data
@@ -632,7 +633,7 @@ lpfc_config_port_post(struct lpfc_hba *phba)
* Any other value - error
**/
int
-lpfc_hba_init_link(struct lpfc_hba *phba)
+lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag)
{
struct lpfc_vport *vport = phba->pport;
LPFC_MBOXQ_t *pmb;
@@ -651,7 +652,7 @@ lpfc_hba_init_link(struct lpfc_hba *phba)
phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
lpfc_set_loopback_flag(phba);
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ rc = lpfc_sli_issue_mbox(phba, pmb, flag);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"0498 Adapter failed to init, mbxCmd x%x "
@@ -664,17 +665,21 @@ lpfc_hba_init_link(struct lpfc_hba *phba)
writel(0xffffffff, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
phba->link_state = LPFC_HBA_ERROR;
- if (rc != MBX_BUSY)
+ if (rc != MBX_BUSY || flag == MBX_POLL)
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
}
phba->cfg_suppress_link_up = LPFC_INITIALIZE_LINK;
+ if (flag == MBX_POLL)
+ mempool_free(pmb, phba->mbox_mem_pool);
return 0;
}
/**
* lpfc_hba_down_link - this routine downs the FC link
+ * @phba: pointer to lpfc hba data structure.
+ * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT
*
* This routine will issue the DOWN_LINK mailbox command call.
* It is available to other drivers through the lpfc_hba data
@@ -685,7 +690,7 @@ lpfc_hba_init_link(struct lpfc_hba *phba)
* Any other value - error
**/
int
-lpfc_hba_down_link(struct lpfc_hba *phba)
+lpfc_hba_down_link(struct lpfc_hba *phba, uint32_t flag)
{
LPFC_MBOXQ_t *pmb;
int rc;
@@ -701,7 +706,7 @@ lpfc_hba_down_link(struct lpfc_hba *phba)
"0491 Adapter Link is disabled.\n");
lpfc_down_link(phba, pmb);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ rc = lpfc_sli_issue_mbox(phba, pmb, flag);
if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
lpfc_printf_log(phba,
KERN_ERR, LOG_INIT,
@@ -711,6 +716,9 @@ lpfc_hba_down_link(struct lpfc_hba *phba)
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
}
+ if (flag == MBX_POLL)
+ mempool_free(pmb, phba->mbox_mem_pool);
+
return 0;
}
@@ -1818,6 +1826,10 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
m = (typeof(m)){"LPSe12002-ML1-E", "PCIe",
"EmulexSecure Fibre"};
break;
+ case PCI_DEVICE_ID_BALIUS:
+ m = (typeof(m)){"LPVe12002", "PCIe Shared I/O",
+ "Fibre Channel Adapter"};
+ break;
default:
m = (typeof(m)){"Unknown", "", ""};
break;
@@ -2279,10 +2291,32 @@ static void
lpfc_block_mgmt_io(struct lpfc_hba * phba)
{
unsigned long iflag;
+ uint8_t actcmd = MBX_HEARTBEAT;
+ unsigned long timeout;
+
spin_lock_irqsave(&phba->hbalock, iflag);
phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
+ if (phba->sli.mbox_active)
+ actcmd = phba->sli.mbox_active->u.mb.mbxCommand;
spin_unlock_irqrestore(&phba->hbalock, iflag);
+ /* Determine how long we might wait for the active mailbox
+ * command to be gracefully completed by firmware.
+ */
+ timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, actcmd) * 1000) +
+ jiffies;
+ /* Wait for the outstnading mailbox command to complete */
+ while (phba->sli.mbox_active) {
+ /* Check active mailbox complete status every 2ms */
+ msleep(2);
+ if (time_after(jiffies, timeout)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2813 Mgmt IO is Blocked %x "
+ "- mbox cmd %x still active\n",
+ phba->sli.sli_flag, actcmd);
+ break;
+ }
+ }
}
/**
@@ -4885,6 +4919,7 @@ lpfc_create_shost(struct lpfc_hba *phba)
phba->fc_altov = FF_DEF_ALTOV;
phba->fc_arbtov = FF_DEF_ARBTOV;
+ atomic_set(&phba->sdev_cnt, 0);
vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
if (!vport)
return -ENODEV;
@@ -5533,9 +5568,12 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
mempool_free(pmb, phba->mbox_mem_pool);
/* Reset the DFT_HBA_Q_DEPTH to the max xri */
- if (phba->cfg_hba_queue_depth > (phba->sli4_hba.max_cfg_param.max_xri))
+ if (phba->cfg_hba_queue_depth >
+ (phba->sli4_hba.max_cfg_param.max_xri -
+ lpfc_sli4_get_els_iocb_cnt(phba)))
phba->cfg_hba_queue_depth =
- phba->sli4_hba.max_cfg_param.max_xri;
+ phba->sli4_hba.max_cfg_param.max_xri -
+ lpfc_sli4_get_els_iocb_cnt(phba);
return rc;
}
@@ -6993,22 +7031,28 @@ lpfc_sli_disable_intr(struct lpfc_hba *phba)
static int
lpfc_sli4_enable_msix(struct lpfc_hba *phba)
{
- int rc, index;
+ int vectors, rc, index;
/* Set up MSI-X multi-message vectors */
for (index = 0; index < phba->sli4_hba.cfg_eqn; index++)
phba->sli4_hba.msix_entries[index].entry = index;
/* Configure MSI-X capability structure */
+ vectors = phba->sli4_hba.cfg_eqn;
+enable_msix_vectors:
rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries,
- phba->sli4_hba.cfg_eqn);
- if (rc) {
+ vectors);
+ if (rc > 1) {
+ vectors = rc;
+ goto enable_msix_vectors;
+ } else if (rc) {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"0484 PCI enable MSI-X failed (%d)\n", rc);
goto msi_fail_out;
}
+
/* Log MSI-X vector assignment */
- for (index = 0; index < phba->sli4_hba.cfg_eqn; index++)
+ for (index = 0; index < vectors; index++)
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"0489 MSI-X entry[%d]: vector=x%x "
"message=%d\n", index,
@@ -7030,7 +7074,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
}
/* The rest of the vector(s) are associated to fast-path handler(s) */
- for (index = 1; index < phba->sli4_hba.cfg_eqn; index++) {
+ for (index = 1; index < vectors; index++) {
phba->sli4_hba.fcp_eq_hdl[index - 1].idx = index - 1;
phba->sli4_hba.fcp_eq_hdl[index - 1].phba = phba;
rc = request_irq(phba->sli4_hba.msix_entries[index].vector,
@@ -7044,6 +7088,7 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba)
goto cfg_fail_out;
}
}
+ phba->sli4_hba.msix_vec_nr = vectors;
return rc;
@@ -7077,9 +7122,10 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba)
/* Free up MSI-X multi-message vectors */
free_irq(phba->sli4_hba.msix_entries[0].vector, phba);
- for (index = 1; index < phba->sli4_hba.cfg_eqn; index++)
+ for (index = 1; index < phba->sli4_hba.msix_vec_nr; index++)
free_irq(phba->sli4_hba.msix_entries[index].vector,
&phba->sli4_hba.fcp_eq_hdl[index - 1]);
+
/* Disable MSI-X */
pci_disable_msix(phba->pcidev);
@@ -7121,6 +7167,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba)
pci_disable_msi(phba->pcidev);
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
"0490 MSI request_irq failed (%d)\n", rc);
+ return rc;
}
for (index = 0; index < phba->cfg_fcp_eq_count; index++) {
@@ -7128,7 +7175,7 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba)
phba->sli4_hba.fcp_eq_hdl[index].phba = phba;
}
- return rc;
+ return 0;
}
/**
@@ -7839,6 +7886,9 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2710 PCI channel disable preparing for reset\n");
+ /* Block any management I/Os to the device */
+ lpfc_block_mgmt_io(phba);
+
/* Block all SCSI devices' I/Os on the host */
lpfc_scsi_dev_block(phba);
@@ -7848,6 +7898,7 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
/* Disable interrupt and pci device */
lpfc_sli_disable_intr(phba);
pci_disable_device(phba->pcidev);
+
/* Flush all driver's outstanding SCSI I/Os as we are to reset */
lpfc_sli_flush_fcp_rings(phba);
}
@@ -7861,7 +7912,7 @@ lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba)
* pending I/Os.
**/
static void
-lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba)
+lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba)
{
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"2711 PCI channel permanent disable for failure\n");
@@ -7910,7 +7961,7 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state)
return PCI_ERS_RESULT_NEED_RESET;
case pci_channel_io_perm_failure:
/* Permanent failure, prepare for device down */
- lpfc_prep_dev_for_perm_failure(phba);
+ lpfc_sli_prep_dev_for_perm_failure(phba);
return PCI_ERS_RESULT_DISCONNECT;
default:
/* Unknown state, prepare and request slot reset */
@@ -7979,7 +8030,8 @@ lpfc_io_slot_reset_s3(struct pci_dev *pdev)
} else
phba->intr_mode = intr_mode;
- /* Take device offline; this will perform cleanup */
+ /* Take device offline, it will perform cleanup */
+ lpfc_offline_prep(phba);
lpfc_offline(phba);
lpfc_sli_brdrestart(phba);
@@ -8110,8 +8162,12 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
}
/* Initialize and populate the iocb list per host */
- error = lpfc_init_iocb_list(phba,
- phba->sli4_hba.max_cfg_param.max_xri);
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2821 initialize iocb list %d.\n",
+ phba->cfg_iocb_cnt*1024);
+ error = lpfc_init_iocb_list(phba, phba->cfg_iocb_cnt*1024);
+
if (error) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"1413 Failed to initialize iocb list.\n");
@@ -8160,6 +8216,8 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid)
/* Default to single FCP EQ for non-MSI-X */
if (phba->intr_type != MSIX)
phba->cfg_fcp_eq_count = 1;
+ else if (phba->sli4_hba.msix_vec_nr < phba->cfg_fcp_eq_count)
+ phba->cfg_fcp_eq_count = phba->sli4_hba.msix_vec_nr - 1;
/* Set up SLI-4 HBA */
if (lpfc_sli4_hba_setup(phba)) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -8321,7 +8379,7 @@ lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg)
struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "0298 PCI device Power Management suspend.\n");
+ "2843 PCI device Power Management suspend.\n");
/* Bring down the device */
lpfc_offline_prep(phba);
@@ -8412,6 +8470,84 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev)
}
/**
+ * lpfc_sli4_prep_dev_for_recover - Prepare SLI4 device for pci slot recover
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI4 device for PCI slot recover. It
+ * aborts all the outstanding SCSI I/Os to the pci device.
+ **/
+static void
+lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba)
+{
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring;
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2828 PCI channel I/O abort preparing for recovery\n");
+ /*
+ * There may be errored I/Os through HBA, abort all I/Os on txcmplq
+ * and let the SCSI mid-layer to retry them to recover.
+ */
+ pring = &psli->ring[psli->fcp_ring];
+ lpfc_sli_abort_iocb_ring(phba, pring);
+}
+
+/**
+ * lpfc_sli4_prep_dev_for_reset - Prepare SLI4 device for pci slot reset
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI4 device for PCI slot reset. It
+ * disables the device interrupt and pci device, and aborts the internal FCP
+ * pending I/Os.
+ **/
+static void
+lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba)
+{
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2826 PCI channel disable preparing for reset\n");
+
+ /* Block any management I/Os to the device */
+ lpfc_block_mgmt_io(phba);
+
+ /* Block all SCSI devices' I/Os on the host */
+ lpfc_scsi_dev_block(phba);
+
+ /* stop all timers */
+ lpfc_stop_hba_timers(phba);
+
+ /* Disable interrupt and pci device */
+ lpfc_sli4_disable_intr(phba);
+ pci_disable_device(phba->pcidev);
+
+ /* Flush all driver's outstanding SCSI I/Os as we are to reset */
+ lpfc_sli_flush_fcp_rings(phba);
+}
+
+/**
+ * lpfc_sli4_prep_dev_for_perm_failure - Prepare SLI4 dev for pci slot disable
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is called to prepare the SLI4 device for PCI slot permanently
+ * disabling. It blocks the SCSI transport layer traffic and flushes the FCP
+ * pending I/Os.
+ **/
+static void
+lpfc_sli4_prep_dev_for_perm_failure(struct lpfc_hba *phba)
+{
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2827 PCI channel permanent disable for failure\n");
+
+ /* Block all SCSI devices' I/Os on the host */
+ lpfc_scsi_dev_block(phba);
+
+ /* stop all timers */
+ lpfc_stop_hba_timers(phba);
+
+ /* Clean up all driver's outstanding SCSI I/Os */
+ lpfc_sli_flush_fcp_rings(phba);
+}
+
+/**
* lpfc_io_error_detected_s4 - Method for handling PCI I/O error to SLI-4 device
* @pdev: pointer to PCI device.
* @state: the current PCI connection state.
@@ -8430,7 +8566,29 @@ lpfc_pci_resume_one_s4(struct pci_dev *pdev)
static pci_ers_result_t
lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state)
{
- return PCI_ERS_RESULT_NEED_RESET;
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ switch (state) {
+ case pci_channel_io_normal:
+ /* Non-fatal error, prepare for recovery */
+ lpfc_sli4_prep_dev_for_recover(phba);
+ return PCI_ERS_RESULT_CAN_RECOVER;
+ case pci_channel_io_frozen:
+ /* Fatal error, prepare for slot reset */
+ lpfc_sli4_prep_dev_for_reset(phba);
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ /* Permanent failure, prepare for device down */
+ lpfc_sli4_prep_dev_for_perm_failure(phba);
+ return PCI_ERS_RESULT_DISCONNECT;
+ default:
+ /* Unknown state, prepare and request slot reset */
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2825 Unknown PCI error state: x%x\n", state);
+ lpfc_sli4_prep_dev_for_reset(phba);
+ return PCI_ERS_RESULT_NEED_RESET;
+ }
}
/**
@@ -8454,6 +8612,39 @@ lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state)
static pci_ers_result_t
lpfc_io_slot_reset_s4(struct pci_dev *pdev)
{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+ struct lpfc_sli *psli = &phba->sli;
+ uint32_t intr_mode;
+
+ dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n");
+ if (pci_enable_device_mem(pdev)) {
+ printk(KERN_ERR "lpfc: Cannot re-enable "
+ "PCI device after reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ pci_restore_state(pdev);
+ if (pdev->is_busmaster)
+ pci_set_master(pdev);
+
+ spin_lock_irq(&phba->hbalock);
+ psli->sli_flag &= ~LPFC_SLI_ACTIVE;
+ spin_unlock_irq(&phba->hbalock);
+
+ /* Configure and enable interrupt */
+ intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode);
+ if (intr_mode == LPFC_INTR_ERROR) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "2824 Cannot re-enable interrupt after "
+ "slot reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ } else
+ phba->intr_mode = intr_mode;
+
+ /* Log the current active interrupt mode */
+ lpfc_log_intr_mode(phba, phba->intr_mode);
+
return PCI_ERS_RESULT_RECOVERED;
}
@@ -8470,7 +8661,27 @@ lpfc_io_slot_reset_s4(struct pci_dev *pdev)
static void
lpfc_io_resume_s4(struct pci_dev *pdev)
{
- return;
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
+
+ /*
+ * In case of slot reset, as function reset is performed through
+ * mailbox command which needs DMA to be enabled, this operation
+ * has to be moved to the io resume phase. Taking device offline
+ * will perform the necessary cleanup.
+ */
+ if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) {
+ /* Perform device reset */
+ lpfc_offline_prep(phba);
+ lpfc_offline(phba);
+ lpfc_sli_brdrestart(phba);
+ /* Bring the device back online */
+ lpfc_online(phba);
+ }
+
+ /* Clean up Advanced Error Reporting (AER) if needed */
+ if (phba->hba_flag & HBA_AER_ENABLED)
+ pci_cleanup_aer_uncorrect_error_status(pdev);
}
/**
@@ -8802,6 +9013,8 @@ static struct pci_device_id lpfc_id_table[] = {
PCI_ANY_ID, PCI_ANY_ID, },
{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON,
PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS,
+ PCI_ANY_ID, PCI_ANY_ID, },
{ 0 }
};
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index e84dc33ca201..cb5d93b41b50 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -955,6 +955,26 @@ lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
return;
}
+void
+lpfc_sli4_swap_str(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ MAILBOX_t *mb = &pmb->u.mb;
+ struct lpfc_mqe *mqe;
+
+ switch (mb->mbxCommand) {
+ case MBX_READ_REV:
+ mqe = &pmb->u.mqe;
+ lpfc_sli_pcimem_bcopy(mqe->un.read_rev.fw_name,
+ mqe->un.read_rev.fw_name, 16);
+ lpfc_sli_pcimem_bcopy(mqe->un.read_rev.ulp_fw_name,
+ mqe->un.read_rev.ulp_fw_name, 16);
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
/**
* lpfc_build_hbq_profile2 - Set up the HBQ Selection Profile 2
* @hbqmb: pointer to the HBQ configuration data structure in mailbox command.
@@ -1199,7 +1219,6 @@ lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
mb->un.varCfgPort.cdss = 1; /* Configure Security */
mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */
- mb->un.varCfgPort.cinb = 1; /* Interrupt Notification Block */
mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count();
if (phba->max_vpi && phba->cfg_enable_npiv &&
phba->vpd.sli3Feat.cmv) {
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index b90820a699fd..bccc9c66fa37 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -190,6 +190,7 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
+
/*
* Free resources / clean up outstanding I/Os
* associated with a LPFC_NODELIST entry. This
@@ -199,13 +200,15 @@ int
lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
LIST_HEAD(completions);
+ LIST_HEAD(txcmplq_completions);
+ LIST_HEAD(abort_list);
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
struct lpfc_iocbq *iocb, *next_iocb;
/* Abort outstanding I/O on NPort <nlp_DID> */
lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_DISCOVERY,
- "0205 Abort outstanding I/O on NPort x%x "
+ "2819 Abort outstanding I/O on NPort x%x "
"Data: x%x x%x x%x\n",
ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi);
@@ -224,14 +227,25 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
}
/* Next check the txcmplq */
- list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+ list_splice_init(&pring->txcmplq, &txcmplq_completions);
+ spin_unlock_irq(&phba->hbalock);
+
+ list_for_each_entry_safe(iocb, next_iocb, &txcmplq_completions, list) {
/* Check to see if iocb matches the nport we are looking for */
- if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
- lpfc_sli_issue_abort_iotag(phba, pring, iocb);
- }
+ if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
+ list_add_tail(&iocb->dlist, &abort_list);
}
+ spin_lock_irq(&phba->hbalock);
+ list_splice(&txcmplq_completions, &pring->txcmplq);
spin_unlock_irq(&phba->hbalock);
+ list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) {
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&iocb->dlist);
+ lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+ spin_unlock_irq(&phba->hbalock);
+ }
+
/* Cancel all the IOCBs from the completions list */
lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
IOERR_SLI_ABORTED);
@@ -626,7 +640,8 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
if (!(vport->fc_flag & FC_PT2PT)) {
/* Check config parameter use-adisc or FCP-2 */
if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
- ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
+ ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) &&
+ (ndlp->nlp_type & NLP_FCP_TARGET))) {
spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_ADISC;
spin_unlock_irq(shost->host_lock);
@@ -962,6 +977,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login;
break;
default:
+ ndlp->nlp_flag |= NLP_REG_LOGIN_SEND;
mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
}
mbox->context2 = lpfc_nlp_get(ndlp);
@@ -972,6 +988,8 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
NLP_STE_REG_LOGIN_ISSUE);
return ndlp->nlp_state;
}
+ if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
+ ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND;
/* decrement node reference count to the failed mbox
* command
*/
@@ -1458,6 +1476,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport,
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_IGNR_REG_CMPL;
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
spin_unlock_irq(shost->host_lock);
lpfc_disc_set_adisc(vport, ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index f4a3b2e79eea..7b66b71a14fe 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -747,7 +747,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
int status = 0, index;
int bcnt;
int non_sequential_xri = 0;
- int rc = 0;
LIST_HEAD(sblist);
for (bcnt = 0; bcnt < num_to_alloc; bcnt++) {
@@ -774,6 +773,8 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
/* Allocate iotag for psb->cur_iocbq. */
iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq);
if (iotag == 0) {
+ pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
+ psb->data, psb->dma_handle);
kfree(psb);
break;
}
@@ -858,7 +859,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
if (status) {
/* Put this back on the abort scsi list */
psb->exch_busy = 1;
- rc++;
} else {
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
@@ -877,7 +877,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
if (status) {
/* Put this back on the abort scsi list */
psb->exch_busy = 1;
- rc++;
} else {
psb->exch_busy = 0;
psb->status = IOSTAT_SUCCESS;
@@ -887,7 +886,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
}
}
- return bcnt + non_sequential_xri - rc;
+ return bcnt + non_sequential_xri;
}
/**
@@ -2293,15 +2292,21 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
struct lpfc_vport *vport = pIocbIn->vport;
struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
struct lpfc_nodelist *pnode = rdata->pnode;
- struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
+ struct scsi_cmnd *cmd;
int result;
struct scsi_device *tmp_sdev;
int depth;
unsigned long flags;
struct lpfc_fast_path_event *fast_path_evt;
- struct Scsi_Host *shost = cmd->device->host;
+ struct Scsi_Host *shost;
uint32_t queue_depth, scsi_id;
+ /* Sanity check on return of outstanding command */
+ if (!(lpfc_cmd->pCmd))
+ return;
+ cmd = lpfc_cmd->pCmd;
+ shost = cmd->device->host;
+
lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4];
lpfc_cmd->status = pIocbOut->iocb.ulpStatus;
/* pick up SLI4 exhange busy status from HBA */
@@ -2363,7 +2368,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
case IOSTAT_LOCAL_REJECT:
if (lpfc_cmd->result == IOERR_INVALID_RPI ||
lpfc_cmd->result == IOERR_NO_RESOURCES ||
- lpfc_cmd->result == IOERR_ABORT_REQUESTED) {
+ lpfc_cmd->result == IOERR_ABORT_REQUESTED ||
+ lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) {
cmd->result = ScsiResult(DID_REQUEUE, 0);
break;
}
@@ -3225,7 +3231,9 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
lpfc_taskmgmt_name(task_mgmt_cmd),
tgt_id, lun_id, iocbqrsp->iocb.ulpStatus,
iocbqrsp->iocb.un.ulpWord[4]);
- } else
+ } else if (status == IOCB_BUSY)
+ ret = FAILED;
+ else
ret = SUCCESS;
lpfc_sli_release_iocbq(phba, iocbqrsp);
@@ -3561,11 +3569,13 @@ lpfc_slave_alloc(struct scsi_device *sdev)
uint32_t total = 0;
uint32_t num_to_alloc = 0;
int num_allocated = 0;
+ uint32_t sdev_cnt;
if (!rport || fc_remote_port_chkready(rport))
return -ENXIO;
sdev->hostdata = rport->dd_data;
+ sdev_cnt = atomic_inc_return(&phba->sdev_cnt);
/*
* Populate the cmds_per_lun count scsi_bufs into this host's globally
@@ -3577,6 +3587,10 @@ lpfc_slave_alloc(struct scsi_device *sdev)
total = phba->total_scsi_bufs;
num_to_alloc = vport->cfg_lun_queue_depth + 2;
+ /* If allocated buffers are enough do nothing */
+ if ((sdev_cnt * (vport->cfg_lun_queue_depth + 2)) < total)
+ return 0;
+
/* Allow some exchanges to be available always to complete discovery */
if (total >= phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
@@ -3658,6 +3672,9 @@ lpfc_slave_configure(struct scsi_device *sdev)
static void
lpfc_slave_destroy(struct scsi_device *sdev)
{
+ struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ atomic_dec(&phba->sdev_cnt);
sdev->hostdata = NULL;
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 7a61455140b6..7ddf52682271 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -455,6 +455,11 @@ __lpfc_sli_get_iocbq(struct lpfc_hba *phba)
struct lpfc_iocbq * iocbq = NULL;
list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list);
+
+ if (iocbq)
+ phba->iocb_cnt++;
+ if (phba->iocb_cnt > phba->iocb_max)
+ phba->iocb_max = phba->iocb_cnt;
return iocbq;
}
@@ -575,7 +580,8 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
struct lpfc_sglq *sglq;
size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
- unsigned long iflag;
+ unsigned long iflag = 0;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
if (iocbq->sli4_xritag == NO_XRI)
sglq = NULL;
@@ -593,6 +599,17 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
} else {
sglq->state = SGL_FREED;
list_add(&sglq->list, &phba->sli4_hba.lpfc_sgl_list);
+
+ /* Check if TXQ queue needs to be serviced */
+ if (pring->txq_cnt) {
+ spin_lock_irqsave(
+ &phba->pport->work_port_lock, iflag);
+ phba->pport->work_port_events |=
+ WORKER_SERVICE_TXQ;
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(
+ &phba->pport->work_port_lock, iflag);
+ }
}
}
@@ -605,6 +622,7 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
}
+
/**
* __lpfc_sli_release_iocbq_s3 - Release iocb to the iocb pool
* @phba: Pointer to HBA context object.
@@ -642,6 +660,7 @@ static void
__lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
phba->__lpfc_sli_release_iocbq(phba, iocbq);
+ phba->iocb_cnt--;
}
/**
@@ -872,7 +891,11 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb)
{
list_add_tail(&piocb->list, &pring->txcmplq);
+ piocb->iocb_flag |= LPFC_IO_ON_Q;
pring->txcmplq_cnt++;
+ if (pring->txcmplq_cnt > pring->txcmplq_max)
+ pring->txcmplq_max = pring->txcmplq_cnt;
+
if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
(piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
(piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
@@ -897,7 +920,7 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
* the txq, the function returns first iocb in the list after
* removing the iocb from the list, else it returns NULL.
**/
-static struct lpfc_iocbq *
+struct lpfc_iocbq *
lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
struct lpfc_iocbq *cmd_iocb;
@@ -2150,7 +2173,10 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
list_del_init(&cmd_iocb->list);
- pring->txcmplq_cnt--;
+ if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) {
+ pring->txcmplq_cnt--;
+ cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+ }
return cmd_iocb;
}
@@ -2183,7 +2209,10 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba,
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
list_del_init(&cmd_iocb->list);
- pring->txcmplq_cnt--;
+ if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) {
+ cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+ pring->txcmplq_cnt--;
+ }
return cmd_iocb;
}
@@ -3564,13 +3593,16 @@ static int
lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
-
+ uint32_t hba_aer_enabled;
/* Restart HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"0296 Restart HBA Data: x%x x%x\n",
phba->pport->port_state, psli->sli_flag);
+ /* Take PCIe device Advanced Error Reporting (AER) state */
+ hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED;
+
lpfc_sli4_brdreset(phba);
spin_lock_irq(&phba->hbalock);
@@ -3582,6 +3614,10 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba)
memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
psli->stats_start = get_seconds();
+ /* Reset HBA AER if it was enabled, note hba_flag was reset above */
+ if (hba_aer_enabled)
+ pci_disable_pcie_error_reporting(phba->pcidev);
+
lpfc_hba_down_post(phba);
return 0;
@@ -3794,7 +3830,7 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba)
phba->link_state = LPFC_HBA_ERROR;
mempool_free(pmb, phba->mbox_mem_pool);
- return ENXIO;
+ return -ENXIO;
}
}
phba->hbq_count = hbq_count;
@@ -3885,7 +3921,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
phba->sli3_options &= ~(LPFC_SLI3_NPIV_ENABLED |
LPFC_SLI3_HBQ_ENABLED |
LPFC_SLI3_CRP_ENABLED |
- LPFC_SLI3_INB_ENABLED |
LPFC_SLI3_BG_ENABLED);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -3927,20 +3962,9 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
if (pmb->u.mb.un.varCfgPort.gcrp)
phba->sli3_options |= LPFC_SLI3_CRP_ENABLED;
- if (pmb->u.mb.un.varCfgPort.ginb) {
- phba->sli3_options |= LPFC_SLI3_INB_ENABLED;
- phba->hbq_get = phba->mbox->us.s3_inb_pgp.hbq_get;
- phba->port_gp = phba->mbox->us.s3_inb_pgp.port;
- phba->inb_ha_copy = &phba->mbox->us.s3_inb_pgp.ha_copy;
- phba->inb_counter = &phba->mbox->us.s3_inb_pgp.counter;
- phba->inb_last_counter =
- phba->mbox->us.s3_inb_pgp.counter;
- } else {
- phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
- phba->port_gp = phba->mbox->us.s3_pgp.port;
- phba->inb_ha_copy = NULL;
- phba->inb_counter = NULL;
- }
+
+ phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get;
+ phba->port_gp = phba->mbox->us.s3_pgp.port;
if (phba->cfg_enable_bg) {
if (pmb->u.mb.un.varCfgPort.gbg)
@@ -3953,8 +3977,6 @@ lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode)
} else {
phba->hbq_get = NULL;
phba->port_gp = phba->mbox->us.s2.port;
- phba->inb_ha_copy = NULL;
- phba->inb_counter = NULL;
phba->max_vpi = 0;
}
do_prep_failed:
@@ -4214,7 +4236,8 @@ lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq,
if (mqe->un.read_rev.avail_vpd_len < *vpd_size)
*vpd_size = mqe->un.read_rev.avail_vpd_len;
- lpfc_sli_pcimem_bcopy(dmabuf->virt, vpd, *vpd_size);
+ memcpy(vpd, dmabuf->virt, *vpd_size);
+
dma_free_coherent(&phba->pcidev->dev, dma_size,
dmabuf->virt, dmabuf->phys);
kfree(dmabuf);
@@ -4539,6 +4562,24 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba)
/* Start error attention (ERATT) polling timer */
mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL);
+ /* Enable PCIe device Advanced Error Reporting (AER) if configured */
+ if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) {
+ rc = pci_enable_pcie_error_reporting(phba->pcidev);
+ if (!rc) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2829 This device supports "
+ "Advanced Error Reporting (AER)\n");
+ spin_lock_irq(&phba->hbalock);
+ phba->hba_flag |= HBA_AER_ENABLED;
+ spin_unlock_irq(&phba->hbalock);
+ } else {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "2830 This device does not support "
+ "Advanced Error Reporting (AER)\n");
+ phba->cfg_aer_support = 0;
+ }
+ }
+
/*
* The port is ready, set the host's link state to LINK_DOWN
* in preparation for link interrupts.
@@ -5265,7 +5306,8 @@ lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
if (mcqe_status != MB_CQE_STATUS_SUCCESS) {
bf_set(lpfc_mqe_status, mb, LPFC_MBX_ERROR_RANGE | mcqe_status);
rc = MBXERR_ERROR;
- }
+ } else
+ lpfc_sli4_swap_str(phba, mboxq);
lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
"(%d):0356 Mailbox cmd x%x (x%x) Status x%x "
@@ -5592,7 +5634,7 @@ lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp)
* iocb to the txq when SLI layer cannot submit the command iocb
* to the ring.
**/
-static void
+void
__lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb)
{
@@ -6209,7 +6251,6 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
struct lpfc_iocbq *piocb, uint32_t flag)
{
struct lpfc_sglq *sglq;
- uint16_t xritag;
union lpfc_wqe wqe;
struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number];
@@ -6218,10 +6259,26 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
sglq = NULL;
else {
+ if (pring->txq_cnt) {
+ if (!(flag & SLI_IOCB_RET_IOCB)) {
+ __lpfc_sli_ringtx_put(phba,
+ pring, piocb);
+ return IOCB_SUCCESS;
+ } else {
+ return IOCB_BUSY;
+ }
+ } else {
sglq = __lpfc_sli_get_sglq(phba);
- if (!sglq)
- return IOCB_ERROR;
- piocb->sli4_xritag = sglq->sli4_xritag;
+ if (!sglq) {
+ if (!(flag & SLI_IOCB_RET_IOCB)) {
+ __lpfc_sli_ringtx_put(phba,
+ pring,
+ piocb);
+ return IOCB_SUCCESS;
+ } else
+ return IOCB_BUSY;
+ }
+ }
}
} else if (piocb->iocb_flag & LPFC_IO_FCP) {
sglq = NULL; /* These IO's already have an XRI and
@@ -6237,8 +6294,9 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
}
if (sglq) {
- xritag = lpfc_sli4_bpl2sgl(phba, piocb, sglq);
- if (xritag != sglq->sli4_xritag)
+ piocb->sli4_xritag = sglq->sli4_xritag;
+
+ if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocb, sglq))
return IOCB_ERROR;
}
@@ -6278,7 +6336,7 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number,
* IOCB_SUCCESS - Success
* IOCB_BUSY - Busy
**/
-static inline int
+int
__lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number,
struct lpfc_iocbq *piocb, uint32_t flag)
{
@@ -7095,13 +7153,6 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
abort_iocb = phba->sli.iocbq_lookup[abort_context];
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI,
- "0327 Cannot abort els iocb %p "
- "with tag %x context %x, abort status %x, "
- "abort code %x\n",
- abort_iocb, abort_iotag, abort_context,
- irsp->ulpStatus, irsp->un.ulpWord[4]);
-
/*
* If the iocb is not found in Firmware queue the iocb
* might have completed already. Do not free it again.
@@ -7120,6 +7171,13 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
if (abort_iocb && phba->sli_rev == LPFC_SLI_REV4)
abort_context = abort_iocb->iocb.ulpContext;
}
+
+ lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_SLI,
+ "0327 Cannot abort els iocb %p "
+ "with tag %x context %x, abort status %x, "
+ "abort code %x\n",
+ abort_iocb, abort_iotag, abort_context,
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
/*
* make sure we have the right iocbq before taking it
* off the txcmplq and try to call completion routine.
@@ -7137,7 +7195,10 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
* following abort XRI from the HBA.
*/
list_del_init(&abort_iocb->list);
- pring->txcmplq_cnt--;
+ if (abort_iocb->iocb_flag & LPFC_IO_ON_Q) {
+ abort_iocb->iocb_flag &= ~LPFC_IO_ON_Q;
+ pring->txcmplq_cnt--;
+ }
/* Firmware could still be in progress of DMAing
* payload, so don't free data buffer till after
@@ -7269,8 +7330,9 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
"0339 Abort xri x%x, original iotag x%x, "
"abort cmd iotag x%x\n",
+ iabt->un.acxri.abortIoTag,
iabt->un.acxri.abortContextTag,
- iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
+ abtsiocbp->iotag);
retval = __lpfc_sli_issue_iocb(phba, pring->ringno, abtsiocbp, 0);
if (retval)
@@ -7600,7 +7662,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
long timeleft, timeout_req = 0;
int retval = IOCB_SUCCESS;
uint32_t creg_val;
-
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
/*
* If the caller has provided a response iocbq buffer, then context2
* is NULL or its an error.
@@ -7622,7 +7684,8 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
readl(phba->HCregaddr); /* flush */
}
- retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, 0);
+ retval = lpfc_sli_issue_iocb(phba, ring_number, piocb,
+ SLI_IOCB_RET_IOCB);
if (retval == IOCB_SUCCESS) {
timeout_req = timeout * HZ;
timeleft = wait_event_timeout(done_q,
@@ -7644,6 +7707,11 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
timeout, (timeleft / jiffies));
retval = IOCB_TIMEDOUT;
}
+ } else if (retval == IOCB_BUSY) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "2818 Max IOCBs %d txq cnt %d txcmplq cnt %d\n",
+ phba->iocb_cnt, pring->txq_cnt, pring->txcmplq_cnt);
+ return retval;
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"0332 IOCB wait issue failed, Data x%x\n",
@@ -7724,9 +7792,10 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
* if LPFC_MBX_WAKE flag is set the mailbox is completed
* else do not free the resources.
*/
- if (pmboxq->mbox_flag & LPFC_MBX_WAKE)
+ if (pmboxq->mbox_flag & LPFC_MBX_WAKE) {
retval = MBX_SUCCESS;
- else {
+ lpfc_sli4_swap_str(phba, pmboxq);
+ } else {
retval = MBX_TIMEOUT;
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
}
@@ -8789,12 +8858,17 @@ lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba,
{
struct lpfc_iocbq *irspiocbq;
unsigned long iflags;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING];
/* Get an irspiocbq for later ELS response processing use */
irspiocbq = lpfc_sli_get_iocbq(phba);
if (!irspiocbq) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "0387 Failed to allocate an iocbq\n");
+ "0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d "
+ "fcp_txcmplq_cnt=%d, els_txcmplq_cnt=%d\n",
+ pring->txq_cnt, phba->iocb_cnt,
+ phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt,
+ phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt);
return false;
}
@@ -9043,9 +9117,10 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe)
}
}
if (unlikely(!cq)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "0365 Slow-path CQ identifier (%d) does "
- "not exist\n", cqid);
+ if (phba->sli.sli_flag & LPFC_SLI_ACTIVE)
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "0365 Slow-path CQ identifier "
+ "(%d) does not exist\n", cqid);
return;
}
@@ -9208,6 +9283,7 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
{
struct lpfc_wcqe_release wcqe;
bool workposted = false;
+ unsigned long iflag;
/* Copy the work queue CQE and convert endian order if needed */
lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe));
@@ -9216,6 +9292,9 @@ lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq,
switch (bf_get(lpfc_wcqe_c_code, &wcqe)) {
case CQE_CODE_COMPL_WQE:
/* Process the WQ complete event */
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ phba->last_completion_time = jiffies;
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
lpfc_sli4_fp_handle_fcp_wcqe(phba,
(struct lpfc_wcqe_complete *)&wcqe);
break;
@@ -9271,9 +9350,10 @@ lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe,
cq = phba->sli4_hba.fcp_cq[fcp_cqidx];
if (unlikely(!cq)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "0367 Fast-path completion queue does not "
- "exist\n");
+ if (phba->sli.sli_flag & LPFC_SLI_ACTIVE)
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "0367 Fast-path completion queue "
+ "does not exist\n");
return;
}
@@ -11898,12 +11978,26 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba)
* available rpis maintained by the driver.
**/
void
+__lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
+{
+ if (test_and_clear_bit(rpi, phba->sli4_hba.rpi_bmask)) {
+ phba->sli4_hba.rpi_count--;
+ phba->sli4_hba.max_cfg_param.rpi_used--;
+ }
+}
+
+/**
+ * lpfc_sli4_free_rpi - Release an rpi for reuse.
+ * @phba: pointer to lpfc hba data structure.
+ *
+ * This routine is invoked to release an rpi to the pool of
+ * available rpis maintained by the driver.
+ **/
+void
lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi)
{
spin_lock_irq(&phba->hbalock);
- clear_bit(rpi, phba->sli4_hba.rpi_bmask);
- phba->sli4_hba.rpi_count--;
- phba->sli4_hba.max_cfg_param.rpi_used--;
+ __lpfc_sli4_free_rpi(phba, rpi);
spin_unlock_irq(&phba->hbalock);
}
@@ -12327,7 +12421,8 @@ lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba)
next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask,
LPFC_SLI4_FCF_TBL_INDX_MAX, 0);
/* Round robin failover stop condition */
- if (next_fcf_index == phba->fcf.fcf_rr_init_indx)
+ if ((next_fcf_index == phba->fcf.fcf_rr_init_indx) ||
+ (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX))
return LPFC_FCOE_FCF_NEXT_NONE;
return next_fcf_index;
@@ -12673,6 +12768,9 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
continue;
if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
+ if (phba->sli_rev == LPFC_SLI_REV4)
+ __lpfc_sli4_free_rpi(phba,
+ mb->u.mb.un.varRegLogin.rpi);
mp = (struct lpfc_dmabuf *) (mb->context1);
if (mp) {
__lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -12705,3 +12803,89 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
spin_unlock_irq(&phba->hbalock);
}
+/**
+ * lpfc_drain_txq - Drain the txq
+ * @phba: Pointer to HBA context object.
+ *
+ * This function attempt to submit IOCBs on the txq
+ * to the adapter. For SLI4 adapters, the txq contains
+ * ELS IOCBs that have been deferred because the there
+ * are no SGLs. This congestion can occur with large
+ * vport counts during node discovery.
+ **/
+
+uint32_t
+lpfc_drain_txq(struct lpfc_hba *phba)
+{
+ LIST_HEAD(completions);
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ struct lpfc_iocbq *piocbq = 0;
+ unsigned long iflags = 0;
+ char *fail_msg = NULL;
+ struct lpfc_sglq *sglq;
+ union lpfc_wqe wqe;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ if (pring->txq_cnt > pring->txq_max)
+ pring->txq_max = pring->txq_cnt;
+
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+ while (pring->txq_cnt) {
+ spin_lock_irqsave(&phba->hbalock, iflags);
+
+ sglq = __lpfc_sli_get_sglq(phba);
+ if (!sglq) {
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ break;
+ } else {
+ piocbq = lpfc_sli_ringtx_get(phba, pring);
+ if (!piocbq) {
+ /* The txq_cnt out of sync. This should
+ * never happen
+ */
+ sglq = __lpfc_clear_active_sglq(phba,
+ sglq->sli4_xritag);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2823 txq empty and txq_cnt is %d\n ",
+ pring->txq_cnt);
+ break;
+ }
+ }
+
+ /* The xri and iocb resources secured,
+ * attempt to issue request
+ */
+ piocbq->sli4_xritag = sglq->sli4_xritag;
+ if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq))
+ fail_msg = "to convert bpl to sgl";
+ else if (lpfc_sli4_iocb2wqe(phba, piocbq, &wqe))
+ fail_msg = "to convert iocb to wqe";
+ else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe))
+ fail_msg = " - Wq is full";
+ else
+ lpfc_sli_ringtxcmpl_put(phba, pring, piocbq);
+
+ if (fail_msg) {
+ /* Failed means we can't issue and need to cancel */
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "2822 IOCB failed %s iotag 0x%x "
+ "xri 0x%x\n",
+ fail_msg,
+ piocbq->iotag, piocbq->sli4_xritag);
+ list_add_tail(&piocbq->list, &completions);
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ }
+
+ spin_lock_irqsave(&phba->pport->work_port_lock, iflags);
+ phba->pport->work_port_events &= ~WORKER_SERVICE_TXQ;
+ spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags);
+
+ /* Cancel all the IOCBs that cannot be issued */
+ lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT,
+ IOERR_SLI_ABORTED);
+
+ return pring->txq_cnt;
+}
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index e3792151ca06..cd56d6cce6c3 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -48,6 +48,7 @@ struct lpfc_iocbq {
/* lpfc_iocbqs are used in double linked lists */
struct list_head list;
struct list_head clist;
+ struct list_head dlist;
uint16_t iotag; /* pre-assigned IO tag */
uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */
struct lpfc_cq_event cq_event;
@@ -64,6 +65,7 @@ struct lpfc_iocbq {
#define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */
#define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */
#define DSS_SECURITY_OP 0x100 /* security IO */
+#define LPFC_IO_ON_Q 0x200 /* The IO is still on the TXCMPLQ */
#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */
#define LPFC_FIP_ELS_ID_SHIFT 14
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index 58bb4c81b54e..c916079fbb35 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -51,6 +51,9 @@
#define LPFC_FCOE_FCF_GET_FIRST 0xFFFF
#define LPFC_FCOE_FCF_NEXT_NONE 0xFFFF
+#define LPFC_FCOE_NULL_VID 0xFFF
+#define LPFC_FCOE_IGNORE_VID 0xFFFF
+
/* First 3 bytes of default FCF MAC is specified by FC_MAP */
#define LPFC_FCOE_FCF_MAC3 0xFF
#define LPFC_FCOE_FCF_MAC4 0xFF
@@ -58,7 +61,7 @@
#define LPFC_FCOE_FCF_MAP0 0x0E
#define LPFC_FCOE_FCF_MAP1 0xFC
#define LPFC_FCOE_FCF_MAP2 0x00
-#define LPFC_FCOE_MAX_RCV_SIZE 0x5AC
+#define LPFC_FCOE_MAX_RCV_SIZE 0x800
#define LPFC_FCOE_FKA_ADV_PER 0
#define LPFC_FCOE_FIP_PRIORITY 0x80
@@ -382,6 +385,7 @@ struct lpfc_sli4_hba {
struct lpfc_pc_sli4_params pc_sli4_params;
struct msix_entry *msix_entries;
uint32_t cfg_eqn;
+ uint32_t msix_vec_nr;
struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */
/* Pointers to the constructed SLI4 queues */
struct lpfc_queue **fp_eq; /* Fast-path event queue */
@@ -524,6 +528,7 @@ int lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *);
struct lpfc_rpi_hdr *lpfc_sli4_create_rpi_hdr(struct lpfc_hba *);
void lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *);
int lpfc_sli4_alloc_rpi(struct lpfc_hba *);
+void __lpfc_sli4_free_rpi(struct lpfc_hba *, int);
void lpfc_sli4_free_rpi(struct lpfc_hba *, int);
void lpfc_sli4_remove_rpis(struct lpfc_hba *);
void lpfc_sli4_async_event_proc(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 5294c3a515a1..33d9d8db4d35 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.3.12"
+#define LPFC_DRIVER_VERSION "8.3.14"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp"
#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index ab91359bde20..1655507a682c 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -782,7 +782,7 @@ lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports)
int i;
if (vports == NULL)
return;
- for (i = 0; vports[i] != NULL && i <= phba->max_vports; i++)
+ for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++)
scsi_host_put(lpfc_shost_from_vport(vports[i]));
kfree(vports);
}
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index dada0a13223f..4b1c2f0350f9 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.14
+ * mpi2.h Version: 02.00.15
*
* Version History
* ---------------
@@ -57,6 +57,10 @@
* 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.
* --------------------------------------------------------------------------
*/
@@ -82,7 +86,7 @@
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x0E)
+#define MPI2_HEADER_VERSION_UNIT (0x0F)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
@@ -473,8 +477,6 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
/*****************************************************************************
*
* Message Functions
-* 0x80 -> 0x8F reserved for private message use per product
-*
*
*****************************************************************************/
@@ -506,6 +508,13 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
#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)
+/* beginning of product-specific range */
+#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0)
+/* end of product-specific range */
+#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF)
+
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index d4e9d6f8452e..e3728d736d85 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.13
+ * mpi2_cnfg.h Version: 02.00.14
*
* Version History
* ---------------
@@ -109,6 +109,18 @@
* 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.
* --------------------------------------------------------------------------
*/
@@ -373,8 +385,9 @@ typedef struct _MPI2_CONFIG_REPLY
#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_SAS2208_7 (0x0086)
-#define MPI2_MFGPAGE_DEVID_SAS2208_8 (0x0087)
+#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086)
+#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087)
+#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E)
/* Manufacturing Page 0 */
@@ -540,7 +553,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_4
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhys at runtime.
+ * 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)
@@ -618,7 +631,7 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX
#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1)
@@ -731,7 +744,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
+ * 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)
@@ -760,7 +773,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3
/*
* Upper layer code (drivers, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumDmaEngines at runtime.
+ * one and check the value returned for NumDmaEngines at runtime.
*/
#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES
#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1)
@@ -823,7 +836,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {
U8 PCIeWidth; /* 0x06 */
U8 PCIeSpeed; /* 0x07 */
U32 ProcessorState; /* 0x08 */
- U32 Reserved2; /* 0x0C */
+ U32 PowerManagementCapabilities; /* 0x0C */
U16 IOCTemperature; /* 0x10 */
U8 IOCTemperatureUnits; /* 0x12 */
U8 IOCSpeed; /* 0x13 */
@@ -831,7 +844,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {
} 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 (0x00)
+#define MPI2_IOUNITPAGE7_PAGEVERSION (0x01)
/* defines for IO Unit Page 7 PCIeWidth field */
#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01)
@@ -852,6 +865,14 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {
#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)
+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004)
+
+
/* defines for IO Unit Page 7 IOCTemperatureUnits field */
#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00)
#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01)
@@ -1195,7 +1216,7 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_3
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhys at runtime.
+ * 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)
@@ -1269,7 +1290,7 @@ typedef struct _MPI2_RAIDVOL0_SETTINGS
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
+ * 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)
@@ -1471,7 +1492,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhysDiskPaths at runtime.
+ * 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)
@@ -1633,7 +1654,7 @@ typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_SAS_IOUNIT0_PHY_MAX
#define MPI2_SAS_IOUNIT0_PHY_MAX (1)
@@ -1704,7 +1725,7 @@ typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_SAS_IOUNIT1_PHY_MAX
#define MPI2_SAS_IOUNIT1_PHY_MAX (1)
@@ -1795,7 +1816,7 @@ typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * four and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_SAS_IOUNIT4_PHY_MAX
#define MPI2_SAS_IOUNIT4_PHY_MAX (4)
@@ -1833,7 +1854,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4
typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS {
U8 ControlFlags; /* 0x00 */
- U8 Reserved1; /* 0x01 */
+ U8 PortWidthModGroup; /* 0x01 */
U16 InactivityTimerExponent; /* 0x02 */
U8 SATAPartialTimeout; /* 0x04 */
U8 Reserved2; /* 0x05 */
@@ -1853,6 +1874,9 @@ typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS {
#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)
@@ -1874,7 +1898,7 @@ typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS {
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_SAS_IOUNIT5_PHY_MAX
#define MPI2_SAS_IOUNIT5_PHY_MAX (1)
@@ -1892,7 +1916,132 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 {
MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5,
Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t;
-#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x00)
+#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 (0x000001000)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x000000800)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x000000400)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x000000200)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x000000100)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x000000010)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x000000008)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x000000004)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x000000002)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x000000001)
@@ -2182,7 +2331,7 @@ typedef struct _MPI2_SASPHY2_PHY_EVENT {
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ * one and check the value returned for NumPhyEvents at runtime.
*/
#ifndef MPI2_SASPHY2_PHY_EVENT_MAX
#define MPI2_SASPHY2_PHY_EVENT_MAX (1)
@@ -2274,7 +2423,7 @@ typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG {
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ * one and check the value returned for NumPhyEvents at runtime.
*/
#ifndef MPI2_SASPHY3_PHY_EVENT_MAX
#define MPI2_SASPHY3_PHY_EVENT_MAX (1)
@@ -2385,7 +2534,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * 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)
@@ -2435,7 +2584,7 @@ typedef struct _MPI2_CONFIG_PAGE_LOG_0
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumElements at runtime.
*/
#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS
#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
index 220bf65a9216..c4c99dfcb820 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
@@ -6,7 +6,7 @@
* Title: MPI SCSI initiator mode messages and structures
* Creation Date: June 23, 2006
*
- * mpi2_init.h Version: 02.00.08
+ * mpi2_init.h Version: 02.00.09
*
* Version History
* ---------------
@@ -31,6 +31,7 @@
* 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.
* --------------------------------------------------------------------------
*/
@@ -57,20 +58,6 @@ typedef struct
} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32,
Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t;
-/* TBD: I don't think this is needed for MPI2/Gen2 */
-#if 0
-typedef struct
-{
- U8 CDB[16]; /* 0x00 */
- U32 DataLength; /* 0x10 */
- U32 PrimaryReferenceTag; /* 0x14 */
- U16 PrimaryApplicationTag; /* 0x18 */
- U16 PrimaryApplicationTagMask; /* 0x1A */
- U32 TransferLength; /* 0x1C */
-} MPI2_SCSI_IO32_CDB_EEDP16, MPI2_POINTER PTR_MPI2_SCSI_IO32_CDB_EEDP16,
- Mpi2ScsiIo32CdbEedp16_t, MPI2_POINTER pMpi2ScsiIo32CdbEedp16_t;
-#endif
-
typedef union
{
U8 CDB32[32];
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
index f18f114922ba..495bedc4d1f7 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
@@ -6,7 +6,7 @@
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.13
+ * mpi2_ioc.h Version: 02.00.14
*
* Version History
* ---------------
@@ -98,6 +98,9 @@
* (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.
* --------------------------------------------------------------------------
*/
@@ -469,6 +472,7 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
#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)
/* Log Entry Added Event data */
@@ -895,6 +899,22 @@ typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER {
* */
+/* 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 {
@@ -1006,6 +1026,7 @@ typedef struct _MPI2_FW_DOWNLOAD_REQUEST
#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)
/* FWDownload TransactionContext Element */
@@ -1183,7 +1204,6 @@ typedef struct _MPI2_FW_IMAGE_HEADER
#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00)
#define MPI2_FW_HEADER_PID_PROD_A (0x0000)
-#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00)
#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200)
#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700)
@@ -1407,5 +1427,100 @@ typedef struct _MPI2_INIT_IMAGE_FOOTER
#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14)
+/****************************************************************************
+* 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)
+#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)
+#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01)
+#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02)
+/* Parameter2 indicates desired PCIe link width using these defines */
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08)
+/* 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/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 0ec1ed389c20..1f22a764927a 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -95,6 +95,10 @@ 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 ");
+
/**
* _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
*
@@ -1238,7 +1242,7 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
u64 pio_chip = 0;
u64 chip_phys = 0;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n",
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n",
ioc->name, __func__));
ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
@@ -1861,7 +1865,7 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
static void
_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
{
- dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
if (ioc->request) {
@@ -1947,7 +1951,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
u32 retry_sz;
u16 max_request_credit;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
retry_sz = 0;
@@ -2374,7 +2378,7 @@ _base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
do {
int_status = readl(&ioc->chip->HostInterruptStatus);
if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
- dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"successfull count(%d), timeout(%d)\n", ioc->name,
__func__, count, timeout));
return 0;
@@ -2415,7 +2419,7 @@ _base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
do {
int_status = readl(&ioc->chip->HostInterruptStatus);
if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
- dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"successfull count(%d), timeout(%d)\n", ioc->name,
__func__, count, timeout));
return 0;
@@ -2463,7 +2467,7 @@ _base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout,
do {
doorbell_reg = readl(&ioc->chip->Doorbell);
if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
- dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"successfull count(%d), timeout(%d)\n", ioc->name,
__func__, count, timeout));
return 0;
@@ -2637,9 +2641,9 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
if (ioc->logging_level & MPT_DEBUG_INIT) {
mfp = (u32 *)reply;
- printk(KERN_DEBUG "\toffset:data\n");
+ printk(KERN_INFO "\toffset:data\n");
for (i = 0; i < reply_bytes/4; i++)
- printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4,
+ printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
le32_to_cpu(mfp[i]));
}
return 0;
@@ -2672,7 +2676,7 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
void *request;
u16 wait_state_count;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
mutex_lock(&ioc->base_cmds.mutex);
@@ -2777,7 +2781,7 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
void *request;
u16 wait_state_count;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
mutex_lock(&ioc->base_cmds.mutex);
@@ -2865,7 +2869,7 @@ _base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag)
Mpi2PortFactsReply_t mpi_reply, *pfacts;
int mpi_reply_sz, mpi_request_sz, r;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
mpi_reply_sz = sizeof(Mpi2PortFactsReply_t);
@@ -2907,7 +2911,7 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
Mpi2IOCFactsReply_t mpi_reply, *facts;
int mpi_reply_sz, mpi_request_sz, r;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
@@ -2979,7 +2983,7 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
struct timeval current_time;
u16 ioc_status;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t));
@@ -3040,9 +3044,9 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
int i;
mfp = (u32 *)&mpi_request;
- printk(KERN_DEBUG "\toffset:data\n");
+ printk(KERN_INFO "\toffset:data\n");
for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++)
- printk(KERN_DEBUG "\t[0x%02x]:%08x\n", i*4,
+ printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
le32_to_cpu(mfp[i]));
}
@@ -3121,7 +3125,7 @@ _base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
r = -ETIME;
goto out;
} else
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n",
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n",
ioc->name, __func__));
ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_OPERATIONAL,
@@ -3181,7 +3185,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
int r = 0;
int i;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
@@ -3219,7 +3223,7 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
else
r = -ETIME;
} else
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: complete\n",
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n",
ioc->name, __func__));
ioc->base_cmds.status = MPT2_CMD_NOT_USED;
return r;
@@ -3281,7 +3285,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
_base_save_msix_table(ioc);
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "clear interrupts\n",
+ drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n",
ioc->name));
count = 0;
@@ -3289,7 +3293,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
/* Write magic sequence to WriteSequence register
* Loop until in diagnostic mode
*/
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "write magic "
+ 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);
@@ -3309,7 +3313,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
goto out;
host_diagnostic = readl(&ioc->chip->HostDiagnostic);
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "wrote magic "
+ drsprintk(ioc, printk(MPT2SAS_INFO_FMT "wrote magic "
"sequence: count(%d), host_diagnostic(0x%08x)\n",
ioc->name, count, host_diagnostic));
@@ -3317,7 +3321,7 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
hcb_size = readl(&ioc->chip->HCBSize);
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "diag reset: issued\n",
+ drsprintk(ioc, printk(MPT2SAS_INFO_FMT "diag reset: issued\n",
ioc->name));
writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,
&ioc->chip->HostDiagnostic);
@@ -3344,29 +3348,29 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
- drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "restart the adapter "
+ 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_DEBUG_FMT
+ 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_DEBUG_FMT "restart the adapter\n",
+ 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_DEBUG_FMT "disable writes to the "
+ 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_DEBUG_FMT "Wait for FW to go to the "
+ 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);
@@ -3398,19 +3402,20 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
enum reset_type type)
{
u32 ioc_state;
+ int rc;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
- dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: ioc_state(0x%08x)\n",
+ 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_DEBUG_FMT "unexpected doorbell "
+ dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "
"active!\n", ioc->name));
goto issue_diag_reset;
}
@@ -3426,11 +3431,15 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
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)))
+ MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) {
+ ioc->ioc_reset_count++;
return 0;
+ }
issue_diag_reset:
- return _base_diag_reset(ioc, CAN_SLEEP);
+ rc = _base_diag_reset(ioc, CAN_SLEEP);
+ ioc->ioc_reset_count++;
+ return rc;
}
/**
@@ -3449,7 +3458,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
u16 smid;
struct _tr_list *delayed_tr, *delayed_tr_next;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
/* clean the delayed target reset list */
@@ -3459,6 +3468,12 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
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);
@@ -3520,6 +3535,13 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
if (sleep_flag == CAN_SLEEP)
_base_static_config_pages(ioc);
+ if (ioc->wait_for_port_enable_to_complete) {
+ if (diag_buffer_enable != 0)
+ mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
+ if (disable_discovery > 0)
+ return r;
+ }
+
r = _base_send_port_enable(ioc, sleep_flag);
if (r)
return r;
@@ -3538,7 +3560,7 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
{
struct pci_dev *pdev = ioc->pdev;
- dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
_base_mask_interrupts(ioc);
@@ -3571,7 +3593,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
{
int r, i;
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
r = mpt2sas_base_map_resources(ioc);
@@ -3606,6 +3628,17 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
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->fwfault_debug = mpt2sas_fwfault_debug;
/* base internal command bits */
@@ -3635,11 +3668,20 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
/* 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;
@@ -3667,8 +3709,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
goto out_free_resources;
mpt2sas_base_start_watchdog(ioc);
- if (diag_buffer_enable != 0)
- mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
return 0;
out_free_resources:
@@ -3677,12 +3717,14 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
mpt2sas_base_free_resources(ioc);
_base_release_memory_pools(ioc);
pci_set_drvdata(ioc->pdev, NULL);
+ kfree(ioc->pd_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->ctl_cmds.reply);
+ kfree(ioc->ctl_cmds.sense);
kfree(ioc->pfacts);
ioc->ctl_cmds.reply = NULL;
ioc->base_cmds.reply = NULL;
@@ -3705,15 +3747,17 @@ void
mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
{
- dexitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ 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->pd_handles);
kfree(ioc->pfacts);
kfree(ioc->ctl_cmds.reply);
+ kfree(ioc->ctl_cmds.sense);
kfree(ioc->base_cmds.reply);
kfree(ioc->tm_cmds.reply);
kfree(ioc->transport_cmds.reply);
@@ -3738,11 +3782,11 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
{
switch (reset_phase) {
case MPT2_IOC_PRE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ 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_DEBUG_FMT "%s: "
+ 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;
@@ -3762,7 +3806,7 @@ _base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
}
break;
case MPT2_IOC_DONE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
break;
}
@@ -3804,7 +3848,7 @@ _wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
return;
/* wait for pending commands to complete */
- wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 3 * HZ);
+ wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ);
}
/**
@@ -3822,19 +3866,30 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
int r;
unsigned long flags;
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
if (mpt2sas_fwfault_debug)
mpt2sas_halt_firmware(ioc);
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- if (ioc->shost_recovery) {
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
- printk(MPT2SAS_ERR_FMT "%s: busy\n",
- ioc->name, __func__);
- return -EBUSY;
+ /* 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);
@@ -3849,13 +3904,17 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
if (!r)
_base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
out:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: %s\n",
+ 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;
complete(&ioc->shost_recovery_done);
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
+ mutex_unlock(&ioc->reset_in_progress_mutex);
+ 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
index b4afe431ac1e..0b0ef5e7899a 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -69,11 +69,11 @@
#define MPT2SAS_DRIVER_NAME "mpt2sas"
#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "05.100.00.02"
-#define MPT2SAS_MAJOR_VERSION 05
+#define MPT2SAS_DRIVER_VERSION "06.100.00.00"
+#define MPT2SAS_MAJOR_VERSION 06
#define MPT2SAS_MINOR_VERSION 100
#define MPT2SAS_BUILD_VERSION 00
-#define MPT2SAS_RELEASE_VERSION 02
+#define MPT2SAS_RELEASE_VERSION 00
/*
* Set MPT2SAS_SG_DEPTH value based on user input.
@@ -124,7 +124,6 @@
* logging format
*/
#define MPT2SAS_FMT "%s: "
-#define MPT2SAS_DEBUG_FMT KERN_DEBUG MPT2SAS_FMT
#define MPT2SAS_INFO_FMT KERN_INFO MPT2SAS_FMT
#define MPT2SAS_NOTE_FMT KERN_NOTICE MPT2SAS_FMT
#define MPT2SAS_WARN_FMT KERN_WARNING MPT2SAS_FMT
@@ -248,6 +247,7 @@ struct MPT2SAS_DEVICE {
* @mutex: mutex
* @done: completion
* @reply: reply message pointer
+ * @sense: sense data
* @status: MPT2_CMD_XXX status
* @smid: system message id
*/
@@ -255,6 +255,7 @@ struct _internal_cmd {
struct mutex mutex;
struct completion done;
void *reply;
+ void *sense;
u16 status;
u16 smid;
};
@@ -276,7 +277,7 @@ struct _internal_cmd {
* @id: target id
* @channel: target channel
* @slot: number number
- * @hidden_raid_component: set to 1 when this is a raid member
+ * @phy: phy identifier provided in sas device page 0
* @responding: used in _scsih_sas_device_mark_responding
*/
struct _sas_device {
@@ -294,7 +295,7 @@ struct _sas_device {
int id;
int channel;
u16 slot;
- u8 hidden_raid_component;
+ u8 phy;
u8 responding;
};
@@ -488,6 +489,8 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @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:
@@ -516,6 +519,9 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @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
+ * @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:
@@ -568,6 +574,8 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @reply_post_free_dma:
* @reply_post_free_dma_pool:
* @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
*/
struct MPT2SAS_ADAPTER {
struct list_head list;
@@ -600,9 +608,13 @@ struct MPT2SAS_ADAPTER {
int aen_event_read_flag;
u8 broadcast_aen_busy;
u8 shost_recovery;
+
+ struct mutex reset_in_progress_mutex;
struct completion shost_recovery_done;
spinlock_t ioc_reset_in_progress_lock;
u8 ioc_link_reset_in_progress;
+ int ioc_reset_in_progress_status;
+
u8 ignore_loginfos;
u8 remove_host;
u8 wait_for_port_enable_to_complete;
@@ -611,6 +623,7 @@ struct MPT2SAS_ADAPTER {
u16 msix_vector_count;
u32 *msix_table;
u32 *msix_table_backup;
+ u32 ioc_reset_count;
/* internal commands, callback index */
u8 scsi_io_cb_idx;
@@ -621,6 +634,7 @@ struct MPT2SAS_ADAPTER {
u8 base_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 transport_cmds;
@@ -664,6 +678,9 @@ struct MPT2SAS_ADAPTER {
u16 device_missing_delay;
int sas_id;
+ void *pd_handles;
+ u16 pd_handles_sz;
+
/* config page */
u16 config_page_sz;
void *config_page;
@@ -735,6 +752,7 @@ struct MPT2SAS_ADAPTER {
u32 reply_post_host_index;
struct list_head delayed_tr_list;
+ struct list_head delayed_tr_volume_list;
/* diag buffer support */
u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];
@@ -745,6 +763,8 @@ struct MPT2SAS_ADAPTER {
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;
};
typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c
index c65442982d7b..e26f9206a521 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_config.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_config.c
@@ -159,7 +159,7 @@ _config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
if (!desc)
return;
- printk(MPT2SAS_DEBUG_FMT "%s: %s(%d), action(%d), form(0x%08x), "
+ 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);
@@ -168,7 +168,7 @@ _config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
return;
if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
- printk(MPT2SAS_DEBUG_FMT
+ 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));
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index d88e9756d8f5..55ac1cb34778 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -80,6 +80,32 @@ enum block_state {
BLOCKING,
};
+/**
+ * _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;
+}
+
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
/**
* _ctl_display_some_debug - debug routine
@@ -188,14 +214,14 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
if (!desc)
return;
- printk(MPT2SAS_DEBUG_FMT "%s: %s, smid(%d)\n",
+ 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_DEBUG_FMT
+ 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));
@@ -205,8 +231,24 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
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_DEBUG_FMT
+ printk(MPT2SAS_INFO_FMT
"\tscsi_state(0x%02x), scsi_status"
"(0x%02x)\n", ioc->name,
scsi_reply->SCSIState,
@@ -233,6 +275,9 @@ 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;
@@ -243,6 +288,20 @@ mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
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);
@@ -392,7 +451,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
switch (reset_phase) {
case MPT2_IOC_PRE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ 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] &
@@ -405,7 +464,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
}
break;
case MPT2_IOC_AFTER_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ 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;
@@ -414,7 +473,7 @@ mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
}
break;
case MPT2_IOC_DONE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ 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++) {
@@ -531,7 +590,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
if (!found) {
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ 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;
@@ -549,7 +608,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
return 1;
}
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ 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)));
@@ -567,7 +626,7 @@ static long
_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
struct mpt2_ioctl_command karg, void __user *mf, enum block_state state)
{
- MPI2RequestHeader_t *mpi_request;
+ MPI2RequestHeader_t *mpi_request = NULL, *request;
MPI2DefaultReply_t *mpi_reply;
u32 ioc_state;
u16 ioc_status;
@@ -576,7 +635,6 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
u8 issue_reset;
u32 sz;
void *psge;
- void *priv_sense = NULL;
void *data_out = NULL;
dma_addr_t data_out_dma;
size_t data_out_sz = 0;
@@ -621,31 +679,50 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
ioc->name, __func__);
- 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;
+ 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;
}
- ret = 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;
- data_out_sz = karg.data_out_size;
- data_in_sz = karg.data_in_size;
-
/* 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;
- mpt2sas_base_free_smid(ioc, smid);
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) ||
@@ -691,7 +768,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
}
/* add scatter gather elements */
- psge = (void *)mpi_request + (karg.data_sge_offset*4);
+ psge = (void *)request + (karg.data_sge_offset*4);
if (!data_out_sz && !data_in_sz) {
mpt2sas_base_build_zero_len_sge(ioc, psge);
@@ -739,11 +816,11 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
{
Mpi2SCSIIORequest_t *scsiio_request =
- (Mpi2SCSIIORequest_t *)mpi_request;
+ (Mpi2SCSIIORequest_t *)request;
+ scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
scsiio_request->SenseBufferLowAddress =
mpt2sas_base_get_sense_buffer_dma(ioc, smid);
- priv_sense = mpt2sas_base_get_sense_buffer(ioc, smid);
- memset(priv_sense, 0, SCSI_SENSE_BUFFERSIZE);
+ 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));
@@ -754,9 +831,9 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
case MPI2_FUNCTION_SCSI_TASK_MGMT:
{
Mpi2SCSITaskManagementRequest_t *tm_request =
- (Mpi2SCSITaskManagementRequest_t *)mpi_request;
+ (Mpi2SCSITaskManagementRequest_t *)request;
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: "
+ 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));
@@ -851,7 +928,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
Mpi2SCSITaskManagementReply_t *tm_reply =
(Mpi2SCSITaskManagementReply_t *)mpi_reply;
- printk(MPT2SAS_DEBUG_FMT "TASK_MGMT: "
+ printk(MPT2SAS_INFO_FMT "TASK_MGMT: "
"IOCStatus(0x%04x), IOCLogInfo(0x%08x), "
"TerminationCount(0x%08x)\n", ioc->name,
le16_to_cpu(tm_reply->IOCStatus),
@@ -887,7 +964,8 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
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, priv_sense, sz)) {
+ 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;
@@ -926,6 +1004,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
pci_free_consistent(ioc->pdev, data_out_sz, data_out,
data_out_dma);
+ kfree(mpi_request);
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
mutex_unlock(&ioc->ctl_cmds.mutex);
return ret;
@@ -950,7 +1029,7 @@ _ctl_getiocinfo(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
memset(&karg, 0 , sizeof(karg));
@@ -998,7 +1077,7 @@ _ctl_eventquery(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
karg.event_entries = MPT2SAS_CTL_EVENT_LOG_SIZE;
@@ -1031,7 +1110,7 @@ _ctl_eventenable(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
if (ioc->event_log)
@@ -1073,7 +1152,7 @@ _ctl_eventreport(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
number_bytes = karg.hdr.max_data_size -
@@ -1118,7 +1197,7 @@ _ctl_do_reset(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
@@ -1219,7 +1298,7 @@ _ctl_btdh_mapping(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
rc = _ctl_btdh_search_sas_device(ioc, &karg);
@@ -1288,7 +1367,7 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,
u16 ioc_status;
u8 issue_reset = 0;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
@@ -1376,7 +1455,7 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,
mpi_request->VF_ID = 0; /* TODO */
mpi_request->VP_ID = 0;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), "
+ 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)));
@@ -1414,10 +1493,10 @@ _ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,
if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
ioc->diag_buffer_status[buffer_type] |=
MPT2_DIAG_BUFFER_IS_REGISTERED;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
ioc->name, __func__));
} else {
- printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
+ 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;
@@ -1541,7 +1620,7 @@ _ctl_diag_unregister(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
buffer_type = karg.unique_id & 0x000000ff;
@@ -1611,7 +1690,7 @@ _ctl_diag_query(void __user *arg)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
karg.application_flags = 0;
@@ -1689,7 +1768,7 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
int rc;
unsigned long timeleft;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
rc = 0;
@@ -1697,7 +1776,7 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"skipping due to FAULT state\n", ioc->name,
__func__));
rc = -EAGAIN;
@@ -1759,10 +1838,10 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
ioc->diag_buffer_status[buffer_type] |=
MPT2_DIAG_BUFFER_IS_RELEASED;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
ioc->name, __func__));
} else {
- printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
+ 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;
@@ -1800,7 +1879,7 @@ _ctl_diag_release(void __user *arg, enum block_state state)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
buffer_type = karg.unique_id & 0x000000ff;
@@ -1896,7 +1975,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
__func__));
buffer_type = karg.unique_id & 0x000000ff;
@@ -1927,7 +2006,7 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
}
diag_data = (void *)(request_data + karg.starting_offset);
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(%p), "
+ 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));
@@ -1942,11 +2021,11 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0)
return 0;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: Reregister "
+ 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_DEBUG_FMT "%s: "
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
"buffer_type(0x%02x) is still registered\n", ioc->name,
__func__, buffer_type));
return 0;
@@ -2020,10 +2099,10 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
ioc->diag_buffer_status[buffer_type] |=
MPT2_DIAG_BUFFER_IS_REGISTERED;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: success\n",
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
ioc->name, __func__));
} else {
- printk(MPT2SAS_DEBUG_FMT "%s: ioc_status(0x%04x) "
+ 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;
@@ -2140,7 +2219,7 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg)
!ioc)
return -ENODEV;
- dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dctlprintk(ioc, printk(MPT2SAS_INFO_FMT
"unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd));
break;
}
@@ -2581,6 +2660,218 @@ _ctl_fwfault_debug_store(struct device *cdev,
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);
+
+struct DIAG_BUFFER_START {
+ u32 Size;
+ u32 DiagVersion;
+ u8 BufferType;
+ u8 Reserved[3];
+ u32 Reserved1;
+ u32 Reserved2;
+ u32 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, "%s", 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,
@@ -2597,6 +2888,10 @@ struct device_attribute *mpt2sas_host_attrs[] = {
&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,
NULL,
};
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index c5ff26a2a51d..854cc91e7aac 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -70,6 +70,8 @@ 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);
+
/* global parameters */
LIST_HEAD(mpt2sas_ioc_list);
@@ -84,6 +86,7 @@ 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 */
@@ -223,9 +226,12 @@ static struct pci_device_id scsih_pci_table[] = {
PCI_ANY_ID, PCI_ANY_ID },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_7,
+ /* 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_SAS2208_8,
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
PCI_ANY_ID, PCI_ANY_ID },
{0} /* Terminating entry */
};
@@ -432,7 +438,7 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
(ioc->bios_pg2.ReqBootDeviceForm &
MPI2_BIOSPAGE2_FORM_MASK),
&ioc->bios_pg2.RequestedBootDevice)) {
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s: req_boot_device(0x%016llx)\n",
ioc->name, __func__,
(unsigned long long)sas_address));
@@ -447,7 +453,7 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
(ioc->bios_pg2.ReqAltBootDeviceForm &
MPI2_BIOSPAGE2_FORM_MASK),
&ioc->bios_pg2.RequestedAltBootDevice)) {
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s: req_alt_boot_device(0x%016llx)\n",
ioc->name, __func__,
(unsigned long long)sas_address));
@@ -462,7 +468,7 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
(ioc->bios_pg2.CurrentBootDeviceForm &
MPI2_BIOSPAGE2_FORM_MASK),
&ioc->bios_pg2.CurrentBootDevice)) {
- dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s: current_boot_device(0x%016llx)\n",
ioc->name, __func__,
(unsigned long long)sas_address));
@@ -563,7 +569,7 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
{
unsigned long flags;
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
+ 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));
@@ -590,7 +596,7 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
{
unsigned long flags;
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
+ 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));
@@ -692,7 +698,7 @@ _scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
{
unsigned long flags;
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle"
+ 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));
@@ -1223,7 +1229,7 @@ _scsih_target_alloc(struct scsi_target *starget)
sas_device->starget = starget;
sas_device->id = starget->id;
sas_device->channel = starget->channel;
- if (sas_device->hidden_raid_component)
+ if (test_bit(sas_device->handle, ioc->pd_handles))
sas_target_priv_data->flags |=
MPT_TARGET_FLAGS_RAID_COMPONENT;
}
@@ -1746,9 +1752,10 @@ _scsih_slave_configure(struct scsi_device *sdev)
}
sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
- "sas_addr(0x%016llx), device_name(0x%016llx)\n",
+ "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,
@@ -1999,7 +2006,7 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,
ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
if (ioc_state & MPI2_DOORBELL_USED) {
- dhsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "unexpected doorbell "
+ dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "
"active!\n", ioc->name));
mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
@@ -2116,8 +2123,59 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,
}
/**
+ * _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;
+
+ if (!priv_target)
+ return;
+
+ scsi_print_command(scmd);
+ if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
+ starget_printk(KERN_INFO, starget, "volume handle(0x%04x), "
+ "volume wwid(0x%016llx)\n",
+ priv_target->handle,
+ (unsigned long long)priv_target->sas_address);
+ } else {
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+ priv_target->sas_address);
+ 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);
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ }
+}
+
+/**
* _scsih_abort - eh threads main abort routine
- * @sdev: scsi device struct
+ * @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
@@ -2130,14 +2188,14 @@ _scsih_abort(struct scsi_cmnd *scmd)
u16 handle;
int r;
- printk(MPT2SAS_INFO_FMT "attempting task abort! scmd(%p)\n",
- ioc->name, scmd);
- scsi_print_command(scmd);
+ 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) {
- printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
- ioc->name, scmd);
+ 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;
@@ -2169,14 +2227,14 @@ _scsih_abort(struct scsi_cmnd *scmd)
MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, scmd);
out:
- printk(MPT2SAS_INFO_FMT "task abort: %s scmd(%p)\n",
- ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+ 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
- * @sdev: scsi device struct
+ * @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
@@ -2190,14 +2248,16 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)
u16 handle;
int r;
- printk(MPT2SAS_INFO_FMT "attempting device reset! scmd(%p)\n",
- ioc->name, scmd);
- scsi_print_command(scmd);
+ struct scsi_target *starget = scmd->device->sdev_target;
+
+ 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) {
- printk(MPT2SAS_INFO_FMT "device been deleted! scmd(%p)\n",
- ioc->name, scmd);
+ starget_printk(KERN_INFO, starget, "target been deleted! "
+ "scmd(%p)\n", scmd);
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
r = SUCCESS;
@@ -2228,14 +2288,14 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)
MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, scmd);
out:
- printk(MPT2SAS_INFO_FMT "device reset: %s scmd(%p)\n",
- ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+ sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
+ ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
return r;
}
/**
* _scsih_target_reset - eh threads main target reset routine
- * @sdev: scsi device struct
+ * @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
@@ -2248,15 +2308,16 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
unsigned long flags;
u16 handle;
int r;
+ struct scsi_target *starget = scmd->device->sdev_target;
- printk(MPT2SAS_INFO_FMT "attempting target reset! scmd(%p)\n",
- ioc->name, scmd);
- scsi_print_command(scmd);
+ 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) {
- printk(MPT2SAS_INFO_FMT "target been deleted! scmd(%p)\n",
- ioc->name, scmd);
+ starget_printk(KERN_INFO, starget, "target been deleted! "
+ "scmd(%p)\n", scmd);
scmd->result = DID_NO_CONNECT << 16;
scmd->scsi_done(scmd);
r = SUCCESS;
@@ -2287,14 +2348,14 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
30, scmd);
out:
- printk(MPT2SAS_INFO_FMT "target reset: %s scmd(%p)\n",
- ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+ starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
+ ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
return r;
}
/**
* _scsih_host_reset - eh threads main host reset routine
- * @sdev: scsi device struct
+ * @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
@@ -2579,6 +2640,7 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
Mpi2SCSITaskManagementRequest_t *mpi_request;
u16 smid;
struct _sas_device *sas_device;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
unsigned long flags;
struct _tr_list *delayed_tr;
@@ -2588,11 +2650,20 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
return;
}
+ /* if PD, then return */
+ if (test_bit(handle, ioc->pd_handles))
+ return;
+
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (sas_device && sas_device->hidden_raid_component) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
+ if (sas_device && sas_device->starget &&
+ sas_device->starget->hostdata) {
+ sas_target_priv_data = sas_device->starget->hostdata;
+ sas_target_priv_data->deleted = 1;
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "setting delete flag: handle(0x%04x), "
+ "sas_addr(0x%016llx)\n", ioc->name, handle,
+ (unsigned long long) sas_device->sas_address));
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
@@ -2655,6 +2726,99 @@ _scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
}
/**
+ * _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) {
+ 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) {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
+ "progress!\n", __func__, ioc->name));
+ 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
@@ -2680,7 +2844,6 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
mpt2sas_base_get_reply_virt_addr(ioc, reply);
Mpi2SasIoUnitControlRequest_t *mpi_request;
u16 smid_sas_ctrl;
- struct _tr_list *delayed_tr;
if (ioc->shost_recovery || ioc->remove_host) {
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
@@ -2721,6 +2884,35 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
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);
@@ -2728,8 +2920,9 @@ _scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
_scsih_tm_tr_send(ioc, delayed_tr->handle);
list_del(&delayed_tr->list);
kfree(delayed_tr);
- return 0; /* tells base_interrupt not to free mf */
+ return 0;
}
+
return 1;
}
@@ -2803,7 +2996,7 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
expander_handle) {
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
"setting ignoring flag\n", ioc->name));
fw_event->ignore = 1;
}
@@ -2813,6 +3006,165 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
}
/**
+ * _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;
+
+ /* 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_flush_running_cmds - completing outstanding commands.
* @ioc: per adapter object
*
@@ -2858,9 +3210,7 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
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_type == SCSI_PROT_DIF_TYPE2 ||
- prot_op == SCSI_PROT_NORMAL)
+ if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL)
return;
if (prot_op == SCSI_PROT_READ_STRIP)
@@ -2882,7 +3232,13 @@ _scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
mpi_request->CDB.EEDP32.PrimaryReferenceTag =
cpu_to_be32(scsi_get_lba(scmd));
+ break;
+ case SCSI_PROT_DIF_TYPE2:
+
+ eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
+ MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
break;
case SCSI_PROT_DIF_TYPE3:
@@ -3013,7 +3369,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
/* Make sure Device is not raid volume */
if (!_scsih_is_raid(&scmd->device->sdev_gendev) &&
- sas_is_tlr_enabled(scmd->device))
+ 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);
@@ -3025,6 +3381,8 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
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)
@@ -3119,6 +3477,13 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
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;
+ unsigned long flags;
+ struct scsi_target *starget = scmd->device->sdev_target;
+ struct MPT2SAS_TARGET *priv_target = starget->hostdata;
+
+ if (!priv_target)
+ return;
if (log_info == 0x31170000)
return;
@@ -3234,10 +3599,29 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
strcat(desc_scsi_state, "autosense valid ");
scsi_print_command(scmd);
- printk(MPT2SAS_WARN_FMT "\tdev handle(0x%04x), "
- "ioc_status(%s)(0x%04x), smid(%d)\n", ioc->name,
- le16_to_cpu(mpi_reply->DevHandle), desc_ioc_state,
- ioc_status, smid);
+
+ if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
+ printk(MPT2SAS_WARN_FMT "\tvolume wwid(0x%016llx)\n", ioc->name,
+ (unsigned long long)priv_target->sas_address);
+ } else {
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
+ priv_target->sas_address);
+ 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);
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ }
+
+ 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));
@@ -4178,7 +4562,7 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
le16_to_cpu(sas_device_pg0.Slot);
sas_device->device_info = device_info;
sas_device->sas_address = sas_address;
- sas_device->hidden_raid_component = is_pd;
+ sas_device->phy = sas_device_pg0.PhyNum;
/* get enclosure_logical_id */
if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
@@ -4199,62 +4583,6 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
}
/**
- * _scsih_remove_pd_device - removing sas device pd object
- * @ioc: per adapter object
- * @sas_device_delete: the sas_device object
- *
- * For hidden raid components, we do driver-fw handshake from
- * hotplug work threads.
- * Return nothing.
- */
-static void
-_scsih_remove_pd_device(struct MPT2SAS_ADAPTER *ioc, struct _sas_device
- sas_device)
-{
- Mpi2SasIoUnitControlReply_t mpi_reply;
- Mpi2SasIoUnitControlRequest_t mpi_request;
- u16 vol_handle, handle;
-
- handle = sas_device.handle;
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: handle(0x%04x),"
- " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
- (unsigned long long) sas_device.sas_address));
-
- vol_handle = sas_device.volume_handle;
- if (!vol_handle)
- return;
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset: "
- "handle(0x%04x)\n", ioc->name, vol_handle));
- mpt2sas_scsih_issue_tm(ioc, vol_handle, 0, 0, 0,
- MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 30, NULL);
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "issue target reset "
- "done: handle(0x%04x)\n", ioc->name, vol_handle));
- if (ioc->shost_recovery)
- return;
-
- /* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
- "(0x%04x)\n", ioc->name, handle));
- 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 = cpu_to_le16(handle);
- if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
- &mpi_request)) != 0)
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: ioc_status"
- "(0x%04x), loginfo(0x%08x)\n", ioc->name,
- le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo)));
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: handle(0x%04x),"
- " sas_addr(0x%016llx)\n", ioc->name, __func__, handle,
- (unsigned long long) sas_device.sas_address));
-}
-
-/**
* _scsih_remove_device - removing sas device object
* @ioc: per adapter object
* @sas_device_delete: the sas_device object
@@ -4284,9 +4612,6 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
sas_target_priv_data->deleted = 1;
}
- if (sas_device_backup.hidden_raid_component)
- _scsih_remove_pd_device(ioc, sas_device_backup);
-
_scsih_ublock_io_device(ioc, sas_device_backup.handle);
mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address,
@@ -4338,9 +4663,9 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
status_str = "unknown status";
break;
}
- printk(MPT2SAS_DEBUG_FMT "sas topology change: (%s)\n",
+ printk(MPT2SAS_INFO_FMT "sas topology change: (%s)\n",
ioc->name, status_str);
- printk(KERN_DEBUG "\thandle(0x%04x), enclosure_handle(0x%04x) "
+ 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),
@@ -4374,7 +4699,7 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
}
link_rate = event_data->PHY[i].LinkRate >> 4;
prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
- printk(KERN_DEBUG "\tphy(%02d), attached_handle(0x%04x): %s:"
+ 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);
@@ -4418,7 +4743,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
_scsih_sas_host_refresh(ioc);
if (fw_event->ignore) {
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring expander "
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring expander "
"event\n", ioc->name));
return;
}
@@ -4444,7 +4769,7 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
/* handle siblings events */
for (i = 0; i < event_data->NumEntries; i++) {
if (fw_event->ignore) {
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "ignoring "
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring "
"expander event\n", ioc->name));
return;
}
@@ -4564,12 +4889,12 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
reason_str = "unknown reason";
break;
}
- printk(MPT2SAS_DEBUG_FMT "device status change: (%s)\n"
+ printk(MPT2SAS_INFO_FMT "device status change: (%s)\n"
"\thandle(0x%04x), sas address(0x%016llx)", ioc->name,
reason_str, le16_to_cpu(event_data->DevHandle),
(unsigned long long)le64_to_cpu(event_data->SASAddress));
if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
- printk(MPT2SAS_DEBUG_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
+ printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
event_data->ASC, event_data->ASCQ);
printk(KERN_INFO "\n");
}
@@ -4653,7 +4978,7 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
break;
}
- printk(MPT2SAS_DEBUG_FMT "enclosure status change: (%s)\n"
+ 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),
@@ -4704,10 +5029,10 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data;
#endif
u16 ioc_status;
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "broadcast primative: "
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "broadcast primative: "
"phy number(%d), width(%d)\n", ioc->name, event_data->PhyNum,
event_data->PortWidth));
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
__func__));
termination_count = 0;
@@ -4751,7 +5076,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
}
ioc->broadcast_aen_busy = 0;
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s - exit, query_count = %d termination_count = %d\n",
ioc->name, __func__, query_count, termination_count));
}
@@ -4772,7 +5097,7 @@ _scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
- printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
+ printk(MPT2SAS_INFO_FMT "discovery event: (%s)", ioc->name,
(event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
"start" : "stop");
if (event_data->DiscoveryStatus)
@@ -4883,17 +5208,15 @@ _scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
/**
* _scsih_sas_volume_delete - delete volume
* @ioc: per adapter object
- * @element: IR config element data
+ * @handle: volume device handle
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventIrConfigElement_t *element)
+_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle)
{
struct _raid_device *raid_device;
- u16 handle = le16_to_cpu(element->VolDevHandle);
unsigned long flags;
struct MPT2SAS_TARGET *sas_target_priv_data;
@@ -4907,6 +5230,9 @@ _scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc,
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);
}
@@ -4935,7 +5261,7 @@ _scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
/* exposing raid component */
sas_device->volume_handle = 0;
sas_device->volume_wwid = 0;
- sas_device->hidden_raid_component = 0;
+ clear_bit(handle, ioc->pd_handles);
_scsih_reprobe_target(sas_device->starget, 0);
}
@@ -4966,7 +5292,7 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
&sas_device->volume_handle);
mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle,
&sas_device->volume_wwid);
- sas_device->hidden_raid_component = 1;
+ set_bit(handle, ioc->pd_handles);
_scsih_reprobe_target(sas_device->starget, 1);
}
@@ -5015,13 +5341,13 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
u64 sas_address;
u16 parent_handle;
+ 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 (sas_device) {
- sas_device->hidden_raid_component = 1;
+ if (sas_device)
return;
- }
if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
@@ -5066,7 +5392,7 @@ _scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
- printk(MPT2SAS_DEBUG_FMT "raid config change: (%s), elements(%d)\n",
+ 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);
@@ -5119,7 +5445,7 @@ _scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
element_str = "unknown element";
break;
}
- printk(KERN_DEBUG "\t(%s:%s), vol handle(0x%04x), "
+ 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),
@@ -5165,7 +5491,8 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
if (!foreign_config)
- _scsih_sas_volume_delete(ioc, element);
+ _scsih_sas_volume_delete(ioc,
+ le16_to_cpu(element->VolDevHandle));
break;
case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
_scsih_sas_pd_hide(ioc, element);
@@ -5201,7 +5528,6 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
u16 handle;
u32 state;
int rc;
- struct MPT2SAS_TARGET *sas_target_priv_data;
Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
@@ -5209,30 +5535,24 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
handle = le16_to_cpu(event_data->VolDevHandle);
state = le32_to_cpu(event_data->NewValue);
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
+ 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));
- 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);
-
switch (state) {
case MPI2_RAID_VOL_STATE_MISSING:
case MPI2_RAID_VOL_STATE_FAILED:
- if (!raid_device)
- break;
- 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);
- }
- _scsih_raid_device_remove(ioc, raid_device);
+ _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;
@@ -5297,23 +5617,25 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
handle = le16_to_cpu(event_data->PhysDiskDevHandle);
state = le32_to_cpu(event_data->NewValue);
- dewtprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: handle(0x%04x), "
+ 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));
- 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);
-
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:
- if (sas_device) {
- sas_device->hidden_raid_component = 1;
+ 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 (sas_device)
return;
- }
if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
&sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
@@ -5343,7 +5665,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
case MPI2_RAID_PD_STATE_OFFLINE:
case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
- case MPI2_RAID_PD_STATE_HOT_SPARE:
default:
break;
}
@@ -5471,7 +5792,7 @@ _scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
sas_address = sas_device->sas_address;
/* if hidden raid component, then change to volume characteristics */
- if (sas_device->hidden_raid_component && sas_device->volume_handle) {
+ if (test_bit(handle, ioc->pd_handles) && sas_device->volume_handle) {
spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_handle(
ioc, sas_device->volume_handle);
@@ -5485,7 +5806,7 @@ _scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
}
if (ioc->logging_level & MPT_DEBUG_TASK_SET_FULL)
- starget_printk(KERN_DEBUG, sas_device->starget, "task set "
+ starget_printk(KERN_INFO, sas_device->starget, "task set "
"full: handle(0x%04x), sas_addr(0x%016llx), depth(%d)\n",
handle, (unsigned long long)sas_address, current_depth);
@@ -5696,9 +6017,12 @@ 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;
printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__);
@@ -5713,8 +6037,32 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
break;
handle = le16_to_cpu(volume_pg1.DevHandle);
- _scsih_mark_responding_raid_device(ioc,
- le64_to_cpu(volume_pg1.WWID), handle);
+
+ 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 */
+ 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_CONFIG_INVALID_PAGE)
+ break;
+ phys_disk_num = pd_pg0.PhysDiskNum;
+ handle = le16_to_cpu(pd_pg0.DevHandle);
+ set_bit(handle, ioc->pd_handles);
}
}
@@ -5876,11 +6224,11 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
{
switch (reset_phase) {
case MPT2_IOC_PRE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ 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_DEBUG_FMT "%s: "
+ 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;
@@ -5897,7 +6245,7 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
_scsih_queue_rescan(ioc);
break;
case MPT2_IOC_DONE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: "
+ 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);
@@ -6034,14 +6382,21 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
(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_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_VOLUME:
case MPI2_EVENT_IR_PHYSICAL_DISK:
- case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
case MPI2_EVENT_TASK_SET_FULL:
break;
@@ -6548,9 +6903,11 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
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;
/* misc semaphores and spin locks */
+ mutex_init(&ioc->reset_in_progress_mutex);
spin_lock_init(&ioc->ioc_reset_in_progress_lock);
spin_lock_init(&ioc->scsi_lookup_lock);
spin_lock_init(&ioc->sas_device_lock);
@@ -6565,9 +6922,10 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
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 shost parameters */
- shost->max_cmd_len = 16;
+ shost->max_cmd_len = 32;
shost->max_lun = max_lun;
shost->transportt = mpt2sas_transport_template;
shost->unique_id = ioc->id;
@@ -6580,7 +6938,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
- | SHOST_DIF_TYPE3_PROTECTION);
+ | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION);
scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
/* event thread */
@@ -6867,6 +7225,10 @@ _scsih_init(void)
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);
@@ -6906,6 +7268,7 @@ _scsih_exit(void)
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 */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index 2727c3b65104..f29ea5e78bb3 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -397,7 +397,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
sizeof(struct rep_manu_reply), data_out_dma +
sizeof(struct rep_manu_request));
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - "
"send to sas_addr(0x%016llx)\n", ioc->name,
(unsigned long long)sas_address));
mpt2sas_base_put_smid_default(ioc, smid);
@@ -415,7 +415,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
goto issue_host_reset;
}
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - "
"complete\n", ioc->name));
if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
@@ -423,7 +423,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
mpi_reply = ioc->transport_cmds.reply;
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
"report_manufacture - reply data transfer size(%d)\n",
ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
@@ -449,7 +449,7 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
manufacture_reply->component_revision_id;
}
} else
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
"report_manufacture - no reply\n", ioc->name));
issue_host_reset:
@@ -940,22 +940,230 @@ rphy_to_ioc(struct sas_rphy *rphy)
return shost_priv(shost);
}
-static struct _sas_phy *
-_transport_find_local_phy(struct MPT2SAS_ADAPTER *ioc, struct sas_phy *phy)
+
+/* 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;
+ u16 expander_change_count;
+ u8 reserved_1[3];
+ u8 phy_identifier;
+ u8 reserved_2[2];
+ u32 invalid_dword;
+ u32 running_disparity_error;
+ u32 loss_of_dword_sync;
+ u32 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)
{
- int i;
+ 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;
+ u64 *sas_address_le;
+ u16 wait_state_count;
- for (i = 0; i < ioc->sas_hba.num_phys; i++)
- if (ioc->sas_hba.phy[i].phy == phy)
- return(&ioc->sas_hba.phy[i]);
- return NULL;
+ 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_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;
+ sas_address_le = (u64 *)&mpi_request->SASAddress;
+ *sas_address_le = 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));
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->transport_cmds.done);
+ 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 -
+ * _transport_get_linkerrors - return phy counters for both hba and expanders
* @phy: The sas phy object
*
- * Only support sas_host direct attached phys.
* Returns 0 for success, non-zero for failure.
*
*/
@@ -963,17 +1171,24 @@ static int
_transport_get_linkerrors(struct sas_phy *phy)
{
struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- struct _sas_phy *mpt2sas_phy;
+ unsigned long flags;
Mpi2ConfigReply_t mpi_reply;
Mpi2SasPhyPage1_t phy_pg1;
- mpt2sas_phy = _transport_find_local_phy(ioc, phy);
-
- if (!mpt2sas_phy) /* this phy not on sas_host */
+ 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,
- mpt2sas_phy->phy_id))) {
+ phy->number))) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
return -ENXIO;
@@ -982,8 +1197,7 @@ _transport_get_linkerrors(struct sas_phy *phy)
if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
"(0x%04x), loginfo(0x%08x)\n", ioc->name,
- mpt2sas_phy->phy_id,
- le16_to_cpu(mpi_reply.IOCStatus),
+ phy->number, le16_to_cpu(mpi_reply.IOCStatus),
le32_to_cpu(mpi_reply.IOCLogInfo));
phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount);
@@ -1007,18 +1221,18 @@ static int
_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
{
struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
- struct _sas_node *sas_expander;
+ struct _sas_device *sas_device;
unsigned long flags;
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
rphy->identify.sas_address);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_expander)
+ if (!sas_device)
return -ENXIO;
- *identifier = sas_expander->enclosure_logical_id;
+ *identifier = sas_device->enclosure_logical_id;
return 0;
}
@@ -1046,32 +1260,260 @@ _transport_get_bay_identifier(struct sas_rphy *rphy)
return sas_device->slot;
}
+/* 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;
+ u64 *sas_address_le;
+ 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;
+ sas_address_le = (u64 *)&mpi_request->SASAddress;
+ *sas_address_le = 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));
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->transport_cmds.done);
+ 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:
*
- * Only support sas_host direct attached phys.
* 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);
- struct _sas_phy *mpt2sas_phy;
Mpi2SasIoUnitControlReply_t mpi_reply;
Mpi2SasIoUnitControlRequest_t mpi_request;
+ unsigned long flags;
- mpt2sas_phy = _transport_find_local_phy(ioc, phy);
-
- if (!mpt2sas_phy) /* this phy not on sas_host */
+ 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 = mpt2sas_phy->phy_id;
+ 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",
@@ -1082,8 +1524,7 @@ _transport_phy_reset(struct sas_phy *phy, int hard_reset)
if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
"(0x%04x), loginfo(0x%08x)\n", ioc->name,
- mpt2sas_phy->phy_id,
- le16_to_cpu(mpi_reply.IOCStatus),
+ phy->number, le16_to_cpu(mpi_reply.IOCStatus),
le32_to_cpu(mpi_reply.IOCLogInfo));
return 0;
@@ -1101,17 +1542,28 @@ static int
_transport_phy_enable(struct sas_phy *phy, int enable)
{
struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- struct _sas_phy *mpt2sas_phy;
Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
Mpi2ConfigReply_t mpi_reply;
u16 ioc_status;
u16 sz;
int rc = 0;
+ unsigned long flags;
- mpt2sas_phy = _transport_find_local_phy(ioc, phy);
-
- if (!mpt2sas_phy) /* this phy not on sas_host */
+ 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 */
/* sas_iounit page 1 */
sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
@@ -1140,14 +1592,18 @@ _transport_phy_enable(struct sas_phy *phy, int enable)
}
if (enable)
- sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
+ sas_iounit_pg1->PhyData[phy->number].PhyFlags
&= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
else
- sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
+ 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);
return rc;
@@ -1165,7 +1621,6 @@ static int
_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
{
struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- struct _sas_phy *mpt2sas_phy;
Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
Mpi2SasPhyPage0_t phy_pg0;
Mpi2ConfigReply_t mpi_reply;
@@ -1173,11 +1628,15 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
u16 sz;
int i;
int rc = 0;
+ unsigned long flags;
- mpt2sas_phy = _transport_find_local_phy(ioc, phy);
-
- if (!mpt2sas_phy) /* this phy not on sas_host */
+ 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;
@@ -1189,6 +1648,16 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
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));
@@ -1216,7 +1685,7 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
}
for (i = 0; i < ioc->sas_hba.num_phys; i++) {
- if (mpt2sas_phy->phy_id != 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));
@@ -1240,7 +1709,7 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
/* read phy page 0, then update the rates in the sas transport phy */
if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
- mpt2sas_phy->phy_id)) {
+ 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(
@@ -1392,7 +1861,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4),
dma_addr_in);
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
"sending smp request\n", ioc->name, __func__));
mpt2sas_base_put_smid_default(ioc, smid);
@@ -1410,14 +1879,14 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
goto issue_host_reset;
}
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
+ 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_DEBUG_FMT
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s - reply data transfer size(%d)\n",
ioc->name, __func__,
le16_to_cpu(mpi_reply->ResponseDataLength)));
@@ -1428,7 +1897,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
rsp->resid_len -=
le16_to_cpu(mpi_reply->ResponseDataLength);
} else {
- dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
+ dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
"%s - no reply\n", ioc->name, __func__));
rc = -ENXIO;
}
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index c44e4ab4e938..9ebcea3643b2 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -113,6 +113,7 @@ static struct pmcraid_chip_details pmcraid_chip_cfg[] = {
.global_intr_mask = 0x00034,
.ioa_host_intr = 0x0009C,
.ioa_host_intr_clr = 0x000A0,
+ .ioa_host_msix_intr = 0x7FC40,
.ioa_host_mask = 0x7FC28,
.ioa_host_mask_clr = 0x7FC28,
.host_ioa_intr = 0x00020,
@@ -154,8 +155,12 @@ static int pmcraid_slave_alloc(struct scsi_device *scsi_dev)
u8 target, bus, lun;
unsigned long lock_flags;
int rc = -ENXIO;
+ u16 fw_version;
+
pinstance = shost_priv(scsi_dev->host);
+ fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
+
/* Driver exposes VSET and GSCSI resources only; all other device types
* are not exposed. Resource list is synchronized using resource lock
* so any traversal or modifications to the list should be done inside
@@ -166,7 +171,11 @@ static int pmcraid_slave_alloc(struct scsi_device *scsi_dev)
/* do not expose VSETs with order-ids > MAX_VSET_TARGETS */
if (RES_IS_VSET(temp->cfg_entry)) {
- target = temp->cfg_entry.unique_flags1;
+ if (fw_version <= PMCRAID_FW_VERSION_1)
+ target = temp->cfg_entry.unique_flags1;
+ else
+ target = temp->cfg_entry.array_id & 0xFF;
+
if (target > PMCRAID_MAX_VSET_TARGETS)
continue;
bus = PMCRAID_VSET_BUS_ID;
@@ -283,7 +292,7 @@ static void pmcraid_slave_destroy(struct scsi_device *scsi_dev)
* @reason: calling context
*
* Return value
- * actual depth set
+ * actual depth set
*/
static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth,
int reason)
@@ -305,7 +314,7 @@ static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth,
* @tag: type of tags to use
*
* Return value:
- * actual queue type set
+ * actual queue type set
*/
static int pmcraid_change_queue_type(struct scsi_device *scsi_dev, int tag)
{
@@ -357,6 +366,7 @@ void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index)
* processed by IOA
*/
memset(&cmd->ioa_cb->ioarcb.cdb, 0, PMCRAID_MAX_CDB_LEN);
+ ioarcb->hrrq_id = 0;
ioarcb->request_flags0 = 0;
ioarcb->request_flags1 = 0;
ioarcb->cmd_timeout = 0;
@@ -368,13 +378,15 @@ void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index)
ioarcb->add_cmd_param_offset = 0;
cmd->ioa_cb->ioasa.ioasc = 0;
cmd->ioa_cb->ioasa.residual_data_length = 0;
- cmd->u.time_left = 0;
+ cmd->time_left = 0;
}
cmd->cmd_done = NULL;
cmd->scsi_cmd = NULL;
cmd->release = 0;
cmd->completion_req = 0;
+ cmd->sense_buffer = 0;
+ cmd->sense_buffer_dma = 0;
cmd->dma_handle = 0;
init_timer(&cmd->timer);
}
@@ -449,7 +461,9 @@ void pmcraid_return_cmd(struct pmcraid_cmd *cmd)
*/
static u32 pmcraid_read_interrupts(struct pmcraid_instance *pinstance)
{
- return ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
+ return (pinstance->interrupt_mode) ?
+ ioread32(pinstance->int_regs.ioa_host_msix_interrupt_reg) :
+ ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
}
/**
@@ -469,10 +483,15 @@ static void pmcraid_disable_interrupts(
u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg);
u32 nmask = gmask | GLOBAL_INTERRUPT_MASK;
- iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg);
iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_clr_reg);
- iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_mask_reg);
- ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg);
+ ioread32(pinstance->int_regs.global_interrupt_mask_reg);
+
+ if (!pinstance->interrupt_mode) {
+ iowrite32(intrs,
+ pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ }
}
/**
@@ -493,8 +512,12 @@ static void pmcraid_enable_interrupts(
u32 nmask = gmask & (~GLOBAL_INTERRUPT_MASK);
iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg);
- iowrite32(~intrs, pinstance->int_regs.ioa_host_interrupt_mask_reg);
- ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+
+ if (!pinstance->interrupt_mode) {
+ iowrite32(~intrs,
+ pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ }
pmcraid_info("enabled interrupts global mask = %x intr_mask = %x\n",
ioread32(pinstance->int_regs.global_interrupt_mask_reg),
@@ -502,6 +525,39 @@ static void pmcraid_enable_interrupts(
}
/**
+ * pmcraid_clr_trans_op - clear trans to op interrupt
+ *
+ * @pinstance: pointer to per adapter instance structure
+ *
+ * Return Value
+ * None
+ */
+static void pmcraid_clr_trans_op(
+ struct pmcraid_instance *pinstance
+)
+{
+ unsigned long lock_flags;
+
+ if (!pinstance->interrupt_mode) {
+ iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
+ pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg);
+ iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
+ pinstance->int_regs.ioa_host_interrupt_clr_reg);
+ ioread32(pinstance->int_regs.ioa_host_interrupt_clr_reg);
+ }
+
+ if (pinstance->reset_cmd != NULL) {
+ del_timer(&pinstance->reset_cmd->timer);
+ spin_lock_irqsave(
+ pinstance->host->host_lock, lock_flags);
+ pinstance->reset_cmd->cmd_done(pinstance->reset_cmd);
+ spin_unlock_irqrestore(
+ pinstance->host->host_lock, lock_flags);
+ }
+}
+
+/**
* pmcraid_reset_type - Determine the required reset type
* @pinstance: pointer to adapter instance structure
*
@@ -536,7 +592,7 @@ static void pmcraid_reset_type(struct pmcraid_instance *pinstance)
* pmcraid_bist_done - completion function for PCI BIST
* @cmd: pointer to reset command
* Return Value
- * none
+ * none
*/
static void pmcraid_ioa_reset(struct pmcraid_cmd *);
@@ -552,16 +608,16 @@ static void pmcraid_bist_done(struct pmcraid_cmd *cmd)
/* If PCI config space can't be accessed wait for another two secs */
if ((rc != PCIBIOS_SUCCESSFUL || (!(pci_reg & PCI_COMMAND_MEMORY))) &&
- cmd->u.time_left > 0) {
+ cmd->time_left > 0) {
pmcraid_info("BIST not complete, waiting another 2 secs\n");
- cmd->timer.expires = jiffies + cmd->u.time_left;
- cmd->u.time_left = 0;
+ cmd->timer.expires = jiffies + cmd->time_left;
+ cmd->time_left = 0;
cmd->timer.data = (unsigned long)cmd;
cmd->timer.function =
(void (*)(unsigned long))pmcraid_bist_done;
add_timer(&cmd->timer);
} else {
- cmd->u.time_left = 0;
+ cmd->time_left = 0;
pmcraid_info("BIST is complete, proceeding with reset\n");
spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
pmcraid_ioa_reset(cmd);
@@ -585,10 +641,10 @@ static void pmcraid_start_bist(struct pmcraid_cmd *cmd)
pinstance->int_regs.host_ioa_interrupt_reg);
doorbells = ioread32(pinstance->int_regs.host_ioa_interrupt_reg);
intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
- pmcraid_info("doorbells after start bist: %x intrs: %x \n",
+ pmcraid_info("doorbells after start bist: %x intrs: %x\n",
doorbells, intrs);
- cmd->u.time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT);
+ cmd->time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT);
cmd->timer.data = (unsigned long)cmd;
cmd->timer.expires = jiffies + msecs_to_jiffies(PMCRAID_BIST_TIMEOUT);
cmd->timer.function = (void (*)(unsigned long))pmcraid_bist_done;
@@ -612,7 +668,7 @@ static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd)
* some more time to wait, restart the timer
*/
if (((status & INTRS_CRITICAL_OP_IN_PROGRESS) == 0) ||
- cmd->u.time_left <= 0) {
+ cmd->time_left <= 0) {
pmcraid_info("critical op is reset proceeding with reset\n");
spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
pmcraid_ioa_reset(cmd);
@@ -620,7 +676,7 @@ static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd)
} else {
pmcraid_info("critical op is not yet reset waiting again\n");
/* restart timer if some more time is available to wait */
- cmd->u.time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT;
+ cmd->time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT;
cmd->timer.data = (unsigned long)cmd;
cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT;
cmd->timer.function =
@@ -638,6 +694,7 @@ static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd)
* successfully written to IOA. Returns non-zero in case pci_config_space
* is not accessible
*/
+static void pmcraid_notify_ioastate(struct pmcraid_instance *, u32);
static void pmcraid_reset_alert(struct pmcraid_cmd *cmd)
{
struct pmcraid_instance *pinstance = cmd->drv_inst;
@@ -658,7 +715,7 @@ static void pmcraid_reset_alert(struct pmcraid_cmd *cmd)
* OPERATION bit is reset. A timer is started to wait for this
* bit to be reset.
*/
- cmd->u.time_left = PMCRAID_RESET_TIMEOUT;
+ cmd->time_left = PMCRAID_RESET_TIMEOUT;
cmd->timer.data = (unsigned long)cmd;
cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT;
cmd->timer.function =
@@ -693,7 +750,8 @@ static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd)
unsigned long lock_flags;
dev_info(&pinstance->pdev->dev,
- "Adapter being reset due to command timeout.\n");
+ "Adapter being reset due to cmd(CDB[0] = %x) timeout\n",
+ cmd->ioa_cb->ioarcb.cdb[0]);
/* Command timeouts result in hard reset sequence. The command that got
* timed out may be the one used as part of reset sequence. In this
@@ -736,9 +794,14 @@ static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd)
*/
if (cmd == pinstance->reset_cmd)
cmd->cmd_done = pmcraid_ioa_reset;
-
}
+ /* Notify apps of important IOA bringup/bringdown sequences */
+ if (pinstance->scn.ioa_state != PMC_DEVICE_EVENT_RESET_START &&
+ pinstance->scn.ioa_state != PMC_DEVICE_EVENT_SHUTDOWN_START)
+ pmcraid_notify_ioastate(pinstance,
+ PMC_DEVICE_EVENT_RESET_START);
+
pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
scsi_block_requests(pinstance->host);
pmcraid_reset_alert(cmd);
@@ -866,7 +929,7 @@ static void _pmcraid_fire_command(struct pmcraid_cmd *cmd)
/* Add this command block to pending cmd pool. We do this prior to
* writting IOARCB to ioarrin because IOA might complete the command
* by the time we are about to add it to the list. Response handler
- * (isr/tasklet) looks for cmb block in the pending pending list.
+ * (isr/tasklet) looks for cmd block in the pending pending list.
*/
spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags);
list_add_tail(&cmd->free_list, &pinstance->pending_cmd_pool);
@@ -916,6 +979,23 @@ static void pmcraid_send_cmd(
}
/**
+ * pmcraid_ioa_shutdown_done - completion function for IOA shutdown command
+ * @cmd: pointer to the command block used for sending IOA shutdown command
+ *
+ * Return value
+ * None
+ */
+static void pmcraid_ioa_shutdown_done(struct pmcraid_cmd *cmd)
+{
+ struct pmcraid_instance *pinstance = cmd->drv_inst;
+ unsigned long lock_flags;
+
+ spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
+ pmcraid_ioa_reset(cmd);
+ spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+}
+
+/**
* pmcraid_ioa_shutdown - sends SHUTDOWN command to ioa
*
* @cmd: pointer to the command block used as part of reset sequence
@@ -943,30 +1023,112 @@ static void pmcraid_ioa_shutdown(struct pmcraid_cmd *cmd)
pmcraid_info("firing normal shutdown command (%d) to IOA\n",
le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle));
- pmcraid_send_cmd(cmd, pmcraid_ioa_reset,
+ pmcraid_notify_ioastate(cmd->drv_inst, PMC_DEVICE_EVENT_SHUTDOWN_START);
+
+ pmcraid_send_cmd(cmd, pmcraid_ioa_shutdown_done,
PMCRAID_SHUTDOWN_TIMEOUT,
pmcraid_timeout_handler);
}
/**
- * pmcraid_identify_hrrq - registers host rrq buffers with IOA
- * @cmd: pointer to command block to be used for identify hrrq
+ * pmcraid_get_fwversion_done - completion function for get_fwversion
+ *
+ * @cmd: pointer to command block used to send INQUIRY command
*
* Return Value
- * 0 in case of success, otherwise non-zero failure code
+ * none
*/
-
static void pmcraid_querycfg(struct pmcraid_cmd *);
+static void pmcraid_get_fwversion_done(struct pmcraid_cmd *cmd)
+{
+ struct pmcraid_instance *pinstance = cmd->drv_inst;
+ u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc);
+ unsigned long lock_flags;
+
+ /* configuration table entry size depends on firmware version. If fw
+ * version is not known, it is not possible to interpret IOA config
+ * table
+ */
+ if (ioasc) {
+ pmcraid_err("IOA Inquiry failed with %x\n", ioasc);
+ spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
+ pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
+ pmcraid_reset_alert(cmd);
+ spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+ } else {
+ pmcraid_querycfg(cmd);
+ }
+}
+
+/**
+ * pmcraid_get_fwversion - reads firmware version information
+ *
+ * @cmd: pointer to command block used to send INQUIRY command
+ *
+ * Return Value
+ * none
+ */
+static void pmcraid_get_fwversion(struct pmcraid_cmd *cmd)
+{
+ struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb;
+ struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl;
+ struct pmcraid_instance *pinstance = cmd->drv_inst;
+ u16 data_size = sizeof(struct pmcraid_inquiry_data);
+
+ pmcraid_reinit_cmdblk(cmd);
+ ioarcb->request_type = REQ_TYPE_SCSI;
+ ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE);
+ ioarcb->cdb[0] = INQUIRY;
+ ioarcb->cdb[1] = 1;
+ ioarcb->cdb[2] = 0xD0;
+ ioarcb->cdb[3] = (data_size >> 8) & 0xFF;
+ ioarcb->cdb[4] = data_size & 0xFF;
+
+ /* Since entire inquiry data it can be part of IOARCB itself
+ */
+ ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) +
+ offsetof(struct pmcraid_ioarcb,
+ add_data.u.ioadl[0]));
+ ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc));
+ ioarcb->ioarcb_bus_addr &= ~(0x1FULL);
+
+ ioarcb->request_flags0 |= NO_LINK_DESCS;
+ ioarcb->data_transfer_length = cpu_to_le32(data_size);
+ ioadl = &(ioarcb->add_data.u.ioadl[0]);
+ ioadl->flags = IOADL_FLAGS_LAST_DESC;
+ ioadl->address = cpu_to_le64(pinstance->inq_data_baddr);
+ ioadl->data_len = cpu_to_le32(data_size);
+
+ pmcraid_send_cmd(cmd, pmcraid_get_fwversion_done,
+ PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler);
+}
+
+/**
+ * pmcraid_identify_hrrq - registers host rrq buffers with IOA
+ * @cmd: pointer to command block to be used for identify hrrq
+ *
+ * Return Value
+ * none
+ */
static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd)
{
struct pmcraid_instance *pinstance = cmd->drv_inst;
struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb;
- int index = 0;
+ int index = cmd->hrrq_index;
__be64 hrrq_addr = cpu_to_be64(pinstance->hrrq_start_bus_addr[index]);
u32 hrrq_size = cpu_to_be32(sizeof(u32) * PMCRAID_MAX_CMD);
+ void (*done_function)(struct pmcraid_cmd *);
pmcraid_reinit_cmdblk(cmd);
+ cmd->hrrq_index = index + 1;
+
+ if (cmd->hrrq_index < pinstance->num_hrrq) {
+ done_function = pmcraid_identify_hrrq;
+ } else {
+ cmd->hrrq_index = 0;
+ done_function = pmcraid_get_fwversion;
+ }
/* Initialize ioarcb */
ioarcb->request_type = REQ_TYPE_IOACMD;
@@ -980,8 +1142,8 @@ static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd)
/* IOA expects 64-bit pci address to be written in B.E format
* (i.e cdb[2]=MSByte..cdb[9]=LSB.
*/
- pmcraid_info("HRRQ_IDENTIFY with hrrq:ioarcb => %llx:%llx\n",
- hrrq_addr, ioarcb->ioarcb_bus_addr);
+ pmcraid_info("HRRQ_IDENTIFY with hrrq:ioarcb:index => %llx:%llx:%x\n",
+ hrrq_addr, ioarcb->ioarcb_bus_addr, index);
memcpy(&(ioarcb->cdb[2]), &hrrq_addr, sizeof(hrrq_addr));
memcpy(&(ioarcb->cdb[10]), &hrrq_size, sizeof(hrrq_size));
@@ -990,7 +1152,7 @@ static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd)
* Note that this gets called even during reset from SCSI mid-layer
* or tasklet
*/
- pmcraid_send_cmd(cmd, pmcraid_querycfg,
+ pmcraid_send_cmd(cmd, done_function,
PMCRAID_INTERNAL_TIMEOUT,
pmcraid_timeout_handler);
}
@@ -1047,7 +1209,7 @@ static struct pmcraid_cmd *pmcraid_init_hcam
}
if (type == PMCRAID_HCAM_CODE_CONFIG_CHANGE) {
- rcb_size = sizeof(struct pmcraid_hcam_ccn);
+ rcb_size = sizeof(struct pmcraid_hcam_ccn_ext);
cmd_done = pmcraid_process_ccn;
dma = pinstance->ccn.baddr + PMCRAID_AEN_HDR_SIZE;
hcam = &pinstance->ccn;
@@ -1094,7 +1256,7 @@ static struct pmcraid_cmd *pmcraid_init_hcam
* This function will send a Host Controlled Async command to IOA.
*
* Return value:
- * none
+ * none
*/
static void pmcraid_send_hcam(struct pmcraid_instance *pinstance, u8 type)
{
@@ -1202,18 +1364,25 @@ static void pmcraid_cancel_ldn(struct pmcraid_cmd *cmd)
/**
* pmcraid_expose_resource - check if the resource can be exposed to OS
*
+ * @fw_version: firmware version code
* @cfgte: pointer to configuration table entry of the resource
*
* Return value:
- * true if resource can be added to midlayer, false(0) otherwise
+ * true if resource can be added to midlayer, false(0) otherwise
*/
-static int pmcraid_expose_resource(struct pmcraid_config_table_entry *cfgte)
+static int pmcraid_expose_resource(u16 fw_version,
+ struct pmcraid_config_table_entry *cfgte)
{
int retval = 0;
- if (cfgte->resource_type == RES_TYPE_VSET)
- retval = ((cfgte->unique_flags1 & 0x80) == 0);
- else if (cfgte->resource_type == RES_TYPE_GSCSI)
+ if (cfgte->resource_type == RES_TYPE_VSET) {
+ if (fw_version <= PMCRAID_FW_VERSION_1)
+ retval = ((cfgte->unique_flags1 & 0x80) == 0);
+ else
+ retval = ((cfgte->unique_flags0 & 0x80) == 0 &&
+ (cfgte->unique_flags1 & 0x80) == 0);
+
+ } else if (cfgte->resource_type == RES_TYPE_GSCSI)
retval = (RES_BUS(cfgte->resource_address) !=
PMCRAID_VIRTUAL_ENCL_BUS_ID);
return retval;
@@ -1246,8 +1415,8 @@ static struct genl_family pmcraid_event_family = {
* pmcraid_netlink_init - registers pmcraid_event_family
*
* Return value:
- * 0 if the pmcraid_event_family is successfully registered
- * with netlink generic, non-zero otherwise
+ * 0 if the pmcraid_event_family is successfully registered
+ * with netlink generic, non-zero otherwise
*/
static int pmcraid_netlink_init(void)
{
@@ -1268,7 +1437,7 @@ static int pmcraid_netlink_init(void)
* pmcraid_netlink_release - unregisters pmcraid_event_family
*
* Return value:
- * none
+ * none
*/
static void pmcraid_netlink_release(void)
{
@@ -1283,31 +1452,30 @@ static void pmcraid_netlink_release(void)
* Return value:
* 0 if success, error value in case of any failure.
*/
-static int pmcraid_notify_aen(struct pmcraid_instance *pinstance, u8 type)
+static int pmcraid_notify_aen(
+ struct pmcraid_instance *pinstance,
+ struct pmcraid_aen_msg *aen_msg,
+ u32 data_size
+)
{
struct sk_buff *skb;
- struct pmcraid_aen_msg *aen_msg;
void *msg_header;
- int data_size, total_size;
+ u32 total_size, nla_genl_hdr_total_size;
int result;
-
- if (type == PMCRAID_HCAM_CODE_LOG_DATA) {
- aen_msg = pinstance->ldn.msg;
- data_size = pinstance->ldn.hcam->data_len;
- } else {
- aen_msg = pinstance->ccn.msg;
- data_size = pinstance->ccn.hcam->data_len;
- }
-
- data_size += sizeof(struct pmcraid_hcam_hdr);
aen_msg->hostno = (pinstance->host->unique_id << 16 |
MINOR(pinstance->cdev.dev));
aen_msg->length = data_size;
+
data_size += sizeof(*aen_msg);
total_size = nla_total_size(data_size);
- skb = genlmsg_new(total_size, GFP_ATOMIC);
+ /* Add GENL_HDR to total_size */
+ nla_genl_hdr_total_size =
+ (total_size + (GENL_HDRLEN +
+ ((struct genl_family *)&pmcraid_event_family)->hdrsize)
+ + NLMSG_HDRLEN);
+ skb = genlmsg_new(nla_genl_hdr_total_size, GFP_ATOMIC);
if (!skb) {
@@ -1329,7 +1497,7 @@ static int pmcraid_notify_aen(struct pmcraid_instance *pinstance, u8 type)
result = nla_put(skb, PMCRAID_AEN_ATTR_EVENT, data_size, aen_msg);
if (result) {
- pmcraid_err("failed to copy AEN attribute data \n");
+ pmcraid_err("failed to copy AEN attribute data\n");
nlmsg_free(skb);
return -EINVAL;
}
@@ -1350,13 +1518,57 @@ static int pmcraid_notify_aen(struct pmcraid_instance *pinstance, u8 type)
* value.
*/
if (result)
- pmcraid_info("failed to send %s event message %x!\n",
- type == PMCRAID_HCAM_CODE_LOG_DATA ? "LDN" : "CCN",
- result);
+ pmcraid_info("error (%x) sending aen event message\n", result);
return result;
}
/**
+ * pmcraid_notify_ccn - notifies about CCN event msg to user space
+ * @pinstance: pointer adapter instance structure
+ *
+ * Return value:
+ * 0 if success, error value in case of any failure
+ */
+static int pmcraid_notify_ccn(struct pmcraid_instance *pinstance)
+{
+ return pmcraid_notify_aen(pinstance,
+ pinstance->ccn.msg,
+ pinstance->ccn.hcam->data_len +
+ sizeof(struct pmcraid_hcam_hdr));
+}
+
+/**
+ * pmcraid_notify_ldn - notifies about CCN event msg to user space
+ * @pinstance: pointer adapter instance structure
+ *
+ * Return value:
+ * 0 if success, error value in case of any failure
+ */
+static int pmcraid_notify_ldn(struct pmcraid_instance *pinstance)
+{
+ return pmcraid_notify_aen(pinstance,
+ pinstance->ldn.msg,
+ pinstance->ldn.hcam->data_len +
+ sizeof(struct pmcraid_hcam_hdr));
+}
+
+/**
+ * pmcraid_notify_ioastate - sends IOA state event msg to user space
+ * @pinstance: pointer adapter instance structure
+ * @evt: controller state event to be sent
+ *
+ * Return value:
+ * 0 if success, error value in case of any failure
+ */
+static void pmcraid_notify_ioastate(struct pmcraid_instance *pinstance, u32 evt)
+{
+ pinstance->scn.ioa_state = evt;
+ pmcraid_notify_aen(pinstance,
+ &pinstance->scn.msg,
+ sizeof(u32));
+}
+
+/**
* pmcraid_handle_config_change - Handle a config change from the adapter
* @pinstance: pointer to per adapter instance structure
*
@@ -1375,10 +1587,12 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
unsigned long host_lock_flags;
u32 new_entry = 1;
u32 hidden_entry = 0;
+ u16 fw_version;
int rc;
ccn_hcam = (struct pmcraid_hcam_ccn *)pinstance->ccn.hcam;
cfg_entry = &ccn_hcam->cfg_entry;
+ fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
pmcraid_info
("CCN(%x): %x type: %x lost: %x flags: %x res: %x:%x:%x:%x\n",
@@ -1391,7 +1605,10 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
RES_IS_VSET(*cfg_entry) ? PMCRAID_VSET_BUS_ID :
(RES_IS_GSCSI(*cfg_entry) ? PMCRAID_PHYS_BUS_ID :
RES_BUS(cfg_entry->resource_address)),
- RES_IS_VSET(*cfg_entry) ? cfg_entry->unique_flags1 :
+ RES_IS_VSET(*cfg_entry) ?
+ (fw_version <= PMCRAID_FW_VERSION_1 ?
+ cfg_entry->unique_flags1 :
+ cfg_entry->array_id & 0xFF) :
RES_TARGET(cfg_entry->resource_address),
RES_LUN(cfg_entry->resource_address));
@@ -1415,11 +1632,16 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
*/
if (pinstance->ccn.hcam->notification_type ==
NOTIFICATION_TYPE_ENTRY_CHANGED &&
- cfg_entry->resource_type == RES_TYPE_VSET &&
- cfg_entry->unique_flags1 & 0x80) {
- hidden_entry = 1;
- } else if (!pmcraid_expose_resource(cfg_entry))
+ cfg_entry->resource_type == RES_TYPE_VSET) {
+
+ if (fw_version <= PMCRAID_FW_VERSION_1)
+ hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0;
+ else
+ hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0;
+
+ } else if (!pmcraid_expose_resource(fw_version, cfg_entry)) {
goto out_notify_apps;
+ }
spin_lock_irqsave(&pinstance->resource_lock, lock_flags);
list_for_each_entry(res, &pinstance->used_res_q, queue) {
@@ -1466,13 +1688,15 @@ static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance)
list_add_tail(&res->queue, &pinstance->used_res_q);
}
- memcpy(&res->cfg_entry, cfg_entry,
- sizeof(struct pmcraid_config_table_entry));
+ memcpy(&res->cfg_entry, cfg_entry, pinstance->config_table_entry_size);
if (pinstance->ccn.hcam->notification_type ==
NOTIFICATION_TYPE_ENTRY_DELETED || hidden_entry) {
if (res->scsi_dev) {
- res->cfg_entry.unique_flags1 &= 0x7F;
+ if (fw_version <= PMCRAID_FW_VERSION_1)
+ res->cfg_entry.unique_flags1 &= 0x7F;
+ else
+ res->cfg_entry.array_id &= 0xFF;
res->change_detected = RES_CHANGE_DEL;
res->cfg_entry.resource_handle =
PMCRAID_INVALID_RES_HANDLE;
@@ -1491,7 +1715,7 @@ out_notify_apps:
/* Notify configuration changes to registered applications.*/
if (!pmcraid_disable_aen)
- pmcraid_notify_aen(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE);
+ pmcraid_notify_ccn(pinstance);
cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE);
if (cmd)
@@ -1528,7 +1752,7 @@ void pmcraid_ioasc_logger(u32 ioasc, struct pmcraid_cmd *cmd)
return;
/* log the error string */
- pmcraid_err("cmd [%d] for resource %x failed with %x(%s)\n",
+ pmcraid_err("cmd [%x] for resource %x failed with %x(%s)\n",
cmd->ioa_cb->ioarcb.cdb[0],
cmd->ioa_cb->ioarcb.resource_handle,
le32_to_cpu(ioasc), error_info->error_string);
@@ -1663,7 +1887,7 @@ static void pmcraid_process_ldn(struct pmcraid_cmd *cmd)
}
/* send netlink message for HCAM notification if enabled */
if (!pmcraid_disable_aen)
- pmcraid_notify_aen(pinstance, PMCRAID_HCAM_CODE_LOG_DATA);
+ pmcraid_notify_ldn(pinstance);
cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA);
if (cmd)
@@ -1701,10 +1925,13 @@ static void pmcraid_unregister_hcams(struct pmcraid_cmd *cmd)
atomic_set(&pinstance->ldn.ignore, 1);
/* If adapter reset was forced as part of runtime reset sequence,
- * start the reset sequence.
+ * start the reset sequence. Reset will be triggered even in case
+ * IOA unit_check.
*/
- if (pinstance->force_ioa_reset && !pinstance->ioa_bringdown) {
+ if ((pinstance->force_ioa_reset && !pinstance->ioa_bringdown) ||
+ pinstance->ioa_unit_check) {
pinstance->force_ioa_reset = 0;
+ pinstance->ioa_unit_check = 0;
pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
pmcraid_reset_alert(cmd);
return;
@@ -1735,10 +1962,13 @@ static int pmcraid_reset_enable_ioa(struct pmcraid_instance *pinstance)
pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS);
if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) {
- iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
- pinstance->int_regs.ioa_host_interrupt_mask_reg);
- iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
- pinstance->int_regs.ioa_host_interrupt_clr_reg);
+ if (!pinstance->interrupt_mode) {
+ iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
+ pinstance->int_regs.
+ ioa_host_interrupt_mask_reg);
+ iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
+ pinstance->int_regs.ioa_host_interrupt_clr_reg);
+ }
return 1;
} else {
return 0;
@@ -1777,8 +2007,19 @@ static void pmcraid_soft_reset(struct pmcraid_cmd *cmd)
doorbell = DOORBELL_RUNTIME_RESET |
DOORBELL_ENABLE_DESTRUCTIVE_DIAGS;
+ /* Since we do RESET_ALERT and Start BIST we have to again write
+ * MSIX Doorbell to indicate the interrupt mode
+ */
+ if (pinstance->interrupt_mode) {
+ iowrite32(DOORBELL_INTR_MODE_MSIX,
+ pinstance->int_regs.host_ioa_interrupt_reg);
+ ioread32(pinstance->int_regs.host_ioa_interrupt_reg);
+ }
+
iowrite32(doorbell, pinstance->int_regs.host_ioa_interrupt_reg);
+ ioread32(pinstance->int_regs.host_ioa_interrupt_reg),
int_reg = ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
+
pmcraid_info("Waiting for IOA to become operational %x:%x\n",
ioread32(pinstance->int_regs.host_ioa_interrupt_reg),
int_reg);
@@ -1854,7 +2095,8 @@ static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance)
} else if (cmd->cmd_done == pmcraid_internal_done ||
cmd->cmd_done == pmcraid_erp_done) {
cmd->cmd_done(cmd);
- } else if (cmd->cmd_done != pmcraid_ioa_reset) {
+ } else if (cmd->cmd_done != pmcraid_ioa_reset &&
+ cmd->cmd_done != pmcraid_ioa_shutdown_done) {
pmcraid_return_cmd(cmd);
}
@@ -1964,6 +2206,13 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
pinstance->ioa_reset_attempts = 0;
pmcraid_err("IOA didn't respond marking it as dead\n");
pinstance->ioa_state = IOA_STATE_DEAD;
+
+ if (pinstance->ioa_bringdown)
+ pmcraid_notify_ioastate(pinstance,
+ PMC_DEVICE_EVENT_SHUTDOWN_FAILED);
+ else
+ pmcraid_notify_ioastate(pinstance,
+ PMC_DEVICE_EVENT_RESET_FAILED);
reset_complete = 1;
break;
}
@@ -1971,7 +2220,6 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
/* Once either bist or pci reset is done, restore PCI config
* space. If this fails, proceed with hard reset again
*/
-
if (pci_restore_state(pinstance->pdev)) {
pmcraid_info("config-space error resetting again\n");
pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT;
@@ -2002,6 +2250,8 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
pinstance->ioa_shutdown_type = SHUTDOWN_NONE;
pinstance->ioa_bringdown = 0;
pinstance->ioa_state = IOA_STATE_UNKNOWN;
+ pmcraid_notify_ioastate(pinstance,
+ PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS);
reset_complete = 1;
} else {
/* bring-up IOA, so proceed with soft reset
@@ -2051,6 +2301,8 @@ static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd)
*/
if (pinstance->ioa_shutdown_type == SHUTDOWN_NONE &&
pinstance->force_ioa_reset == 0) {
+ pmcraid_notify_ioastate(pinstance,
+ PMC_DEVICE_EVENT_RESET_SUCCESS);
reset_complete = 1;
} else {
if (pinstance->ioa_shutdown_type != SHUTDOWN_NONE)
@@ -2116,6 +2368,8 @@ static void pmcraid_initiate_reset(struct pmcraid_instance *pinstance)
pinstance->ioa_shutdown_type = SHUTDOWN_NONE;
pinstance->reset_cmd = cmd;
pinstance->force_ioa_reset = 1;
+ pmcraid_notify_ioastate(pinstance,
+ PMC_DEVICE_EVENT_RESET_START);
pmcraid_ioa_reset(cmd);
}
}
@@ -2191,7 +2445,7 @@ static int pmcraid_reset_reload(
wait_event(pinstance->reset_wait_q,
!pinstance->ioa_reset_in_progress);
- pmcraid_info("reset_reload: reset is complete !! \n");
+ pmcraid_info("reset_reload: reset is complete !!\n");
scsi_unblock_requests(pinstance->host);
if (pinstance->ioa_state == target_state)
reset = 0;
@@ -2225,6 +2479,8 @@ static int pmcraid_reset_bringdown(struct pmcraid_instance *pinstance)
*/
static int pmcraid_reset_bringup(struct pmcraid_instance *pinstance)
{
+ pmcraid_notify_ioastate(pinstance, PMC_DEVICE_EVENT_RESET_START);
+
return pmcraid_reset_reload(pinstance,
SHUTDOWN_NONE,
IOA_STATE_OPERATIONAL);
@@ -2704,7 +2960,7 @@ static struct pmcraid_cmd *pmcraid_abort_cmd(struct pmcraid_cmd *cmd)
pmcraid_info("command (%d) CDB[0] = %x for %x\n",
le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.response_handle) >> 2,
- cmd->ioa_cb->ioarcb.cdb[0],
+ cancel_cmd->ioa_cb->ioarcb.cdb[0],
le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.resource_handle));
pmcraid_send_cmd(cancel_cmd,
@@ -2729,8 +2985,8 @@ static int pmcraid_abort_complete(struct pmcraid_cmd *cancel_cmd)
u32 ioasc;
wait_for_completion(&cancel_cmd->wait_for_completion);
- res = cancel_cmd->u.res;
- cancel_cmd->u.res = NULL;
+ res = cancel_cmd->res;
+ cancel_cmd->res = NULL;
ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc);
/* If the abort task is not timed out we will get a Good completion
@@ -2823,7 +3079,7 @@ static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd)
host_lock_flags);
if (cancel_cmd) {
- cancel_cmd->u.res = cmd->scsi_cmd->device->hostdata;
+ cancel_cmd->res = cmd->scsi_cmd->device->hostdata;
rc = pmcraid_abort_complete(cancel_cmd);
}
@@ -2842,7 +3098,7 @@ static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd)
* takes care by locking/unlocking host_lock.
*
* Return value
- * SUCCESS or FAILED
+ * SUCCESS or FAILED
*/
static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd)
{
@@ -2879,7 +3135,7 @@ static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd)
* Initiates adapter reset to bring it up to operational state
*
* Return value
- * SUCCESS or FAILED
+ * SUCCESS or FAILED
*/
static int pmcraid_eh_host_reset_handler(struct scsi_cmnd *scmd)
{
@@ -2991,7 +3247,7 @@ pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount)
* to firmware. This builds ioadl descriptors and sets up ioarcb fields.
*
* Return value:
- * 0 on success or -1 on failure
+ * 0 on success or -1 on failure
*/
static int pmcraid_build_ioadl(
struct pmcraid_instance *pinstance,
@@ -3049,7 +3305,7 @@ static int pmcraid_build_ioadl(
* Free a DMA'able memory previously allocated with pmcraid_alloc_sglist
*
* Return value:
- * none
+ * none
*/
static void pmcraid_free_sglist(struct pmcraid_sglist *sglist)
{
@@ -3070,7 +3326,7 @@ static void pmcraid_free_sglist(struct pmcraid_sglist *sglist)
* list.
*
* Return value
- * pointer to sglist / NULL on failure
+ * pointer to sglist / NULL on failure
*/
static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen)
{
@@ -3224,11 +3480,12 @@ static int pmcraid_queuecommand(
struct pmcraid_resource_entry *res;
struct pmcraid_ioarcb *ioarcb;
struct pmcraid_cmd *cmd;
+ u32 fw_version;
int rc = 0;
pinstance =
(struct pmcraid_instance *)scsi_cmd->device->host->hostdata;
-
+ fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
scsi_cmd->scsi_done = done;
res = scsi_cmd->device->hostdata;
scsi_cmd->result = (DID_OK << 16);
@@ -3247,6 +3504,15 @@ static int pmcraid_queuecommand(
if (pinstance->ioa_reset_in_progress)
return SCSI_MLQUEUE_HOST_BUSY;
+ /* Firmware doesn't support SYNCHRONIZE_CACHE command (0x35), complete
+ * the command here itself with success return
+ */
+ if (scsi_cmd->cmnd[0] == SYNCHRONIZE_CACHE) {
+ pmcraid_info("SYNC_CACHE(0x35), completing in driver itself\n");
+ scsi_cmd->scsi_done(scsi_cmd);
+ return 0;
+ }
+
/* initialize the command and IOARCB to be sent to IOA */
cmd = pmcraid_get_free_cmd(pinstance);
@@ -3261,6 +3527,13 @@ static int pmcraid_queuecommand(
ioarcb->resource_handle = res->cfg_entry.resource_handle;
ioarcb->request_type = REQ_TYPE_SCSI;
+ /* set hrrq number where the IOA should respond to. Note that all cmds
+ * generated internally uses hrrq_id 0, exception to this is the cmd
+ * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses
+ * hrrq_id assigned here in queuecommand
+ */
+ ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) %
+ pinstance->num_hrrq;
cmd->cmd_done = pmcraid_io_done;
if (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry)) {
@@ -3287,7 +3560,9 @@ static int pmcraid_queuecommand(
RES_IS_VSET(res->cfg_entry) ? PMCRAID_VSET_BUS_ID :
PMCRAID_PHYS_BUS_ID,
RES_IS_VSET(res->cfg_entry) ?
- res->cfg_entry.unique_flags1 :
+ (fw_version <= PMCRAID_FW_VERSION_1 ?
+ res->cfg_entry.unique_flags1 :
+ res->cfg_entry.array_id & 0xFF) :
RES_TARGET(res->cfg_entry.resource_address),
RES_LUN(res->cfg_entry.resource_address));
@@ -3465,6 +3740,7 @@ static long pmcraid_ioctl_passthrough(
unsigned long request_buffer;
unsigned long request_offset;
unsigned long lock_flags;
+ u32 ioasc;
int request_size;
int buffer_size;
u8 access, direction;
@@ -3566,6 +3842,14 @@ static long pmcraid_ioctl_passthrough(
buffer->ioarcb.add_cmd_param_length);
}
+ /* set hrrq number where the IOA should respond to. Note that all cmds
+ * generated internally uses hrrq_id 0, exception to this is the cmd
+ * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses
+ * hrrq_id assigned here in queuecommand
+ */
+ ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) %
+ pinstance->num_hrrq;
+
if (request_size) {
rc = pmcraid_build_passthrough_ioadls(cmd,
request_size,
@@ -3606,6 +3890,14 @@ static long pmcraid_ioctl_passthrough(
_pmcraid_fire_command(cmd);
spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+ /* NOTE ! Remove the below line once abort_task is implemented
+ * in firmware. This line disables ioctl command timeout handling logic
+ * similar to IO command timeout handling, making ioctl commands to wait
+ * until the command completion regardless of timeout value specified in
+ * ioarcb
+ */
+ buffer->ioarcb.cmd_timeout = 0;
+
/* If command timeout is specified put caller to wait till that time,
* otherwise it would be blocking wait. If command gets timed out, it
* will be aborted.
@@ -3620,25 +3912,47 @@ static long pmcraid_ioctl_passthrough(
le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle >> 2),
cmd->ioa_cb->ioarcb.cdb[0]);
- rc = -ETIMEDOUT;
spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
cancel_cmd = pmcraid_abort_cmd(cmd);
spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
if (cancel_cmd) {
wait_for_completion(&cancel_cmd->wait_for_completion);
+ ioasc = cancel_cmd->ioa_cb->ioasa.ioasc;
pmcraid_return_cmd(cancel_cmd);
+
+ /* if abort task couldn't find the command i.e it got
+ * completed prior to aborting, return good completion.
+ * if command got aborted succesfully or there was IOA
+ * reset due to abort task itself getting timedout then
+ * return -ETIMEDOUT
+ */
+ if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET ||
+ PMCRAID_IOASC_SENSE_KEY(ioasc) == 0x00) {
+ if (ioasc != PMCRAID_IOASC_GC_IOARCB_NOTFOUND)
+ rc = -ETIMEDOUT;
+ goto out_handle_response;
+ }
}
- goto out_free_sglist;
+ /* no command block for abort task or abort task failed to abort
+ * the IOARCB, then wait for 150 more seconds and initiate reset
+ * sequence after timeout
+ */
+ if (!wait_for_completion_timeout(
+ &cmd->wait_for_completion,
+ msecs_to_jiffies(150 * 1000))) {
+ pmcraid_reset_bringup(cmd->drv_inst);
+ rc = -ETIMEDOUT;
+ }
}
+out_handle_response:
/* If the command failed for any reason, copy entire IOASA buffer and
* return IOCTL success. If copying IOASA to user-buffer fails, return
* EFAULT
*/
- if (le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)) {
-
+ if (PMCRAID_IOASC_SENSE_KEY(le32_to_cpu(cmd->ioa_cb->ioasa.ioasc))) {
void *ioasa =
(void *)(arg +
offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa));
@@ -3651,6 +3965,7 @@ static long pmcraid_ioctl_passthrough(
rc = -EFAULT;
}
}
+
/* If the data transfer was from device, copy the data onto user
* buffers
*/
@@ -3699,7 +4014,7 @@ static long pmcraid_ioctl_driver(
int rc = -ENOSYS;
if (!access_ok(VERIFY_READ, user_buffer, _IOC_SIZE(cmd))) {
- pmcraid_err("ioctl_driver: access fault in request buffer \n");
+ pmcraid_err("ioctl_driver: access fault in request buffer\n");
return -EFAULT;
}
@@ -4011,36 +4326,77 @@ static struct scsi_host_template pmcraid_host_template = {
.proc_name = PMCRAID_DRIVER_NAME
};
-/**
- * pmcraid_isr_common - Common interrupt handler routine
- *
- * @pinstance: pointer to adapter instance
- * @intrs: active interrupts (contents of ioa_host_interrupt register)
- * @hrrq_id: Host RRQ index
+/*
+ * pmcraid_isr_msix - implements MSI-X interrupt handling routine
+ * @irq: interrupt vector number
+ * @dev_id: pointer hrrq_vector
*
* Return Value
- * none
+ * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored
*/
-static void pmcraid_isr_common(
- struct pmcraid_instance *pinstance,
- u32 intrs,
- int hrrq_id
-)
+
+static irqreturn_t pmcraid_isr_msix(int irq, void *dev_id)
{
- u32 intrs_clear =
- (intrs & INTRS_CRITICAL_OP_IN_PROGRESS) ? intrs
- : INTRS_HRRQ_VALID;
- iowrite32(intrs_clear,
- pinstance->int_regs.ioa_host_interrupt_clr_reg);
- intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
+ struct pmcraid_isr_param *hrrq_vector;
+ struct pmcraid_instance *pinstance;
+ unsigned long lock_flags;
+ u32 intrs_val;
+ int hrrq_id;
+
+ hrrq_vector = (struct pmcraid_isr_param *)dev_id;
+ hrrq_id = hrrq_vector->hrrq_id;
+ pinstance = hrrq_vector->drv_inst;
+
+ if (!hrrq_id) {
+ /* Read the interrupt */
+ intrs_val = pmcraid_read_interrupts(pinstance);
+ if (intrs_val &&
+ ((ioread32(pinstance->int_regs.host_ioa_interrupt_reg)
+ & DOORBELL_INTR_MSIX_CLR) == 0)) {
+ /* Any error interrupts including unit_check,
+ * initiate IOA reset.In case of unit check indicate
+ * to reset_sequence that IOA unit checked and prepare
+ * for a dump during reset sequence
+ */
+ if (intrs_val & PMCRAID_ERROR_INTERRUPTS) {
+ if (intrs_val & INTRS_IOA_UNIT_CHECK)
+ pinstance->ioa_unit_check = 1;
+
+ pmcraid_err("ISR: error interrupts: %x \
+ initiating reset\n", intrs_val);
+ spin_lock_irqsave(pinstance->host->host_lock,
+ lock_flags);
+ pmcraid_initiate_reset(pinstance);
+ spin_unlock_irqrestore(
+ pinstance->host->host_lock,
+ lock_flags);
+ }
+ /* If interrupt was as part of the ioa initialization,
+ * clear it. Delete the timer and wakeup the
+ * reset engine to proceed with reset sequence
+ */
+ if (intrs_val & INTRS_TRANSITION_TO_OPERATIONAL)
+ pmcraid_clr_trans_op(pinstance);
+
+ /* Clear the interrupt register by writing
+ * to host to ioa doorbell. Once done
+ * FW will clear the interrupt.
+ */
+ iowrite32(DOORBELL_INTR_MSIX_CLR,
+ pinstance->int_regs.host_ioa_interrupt_reg);
+ ioread32(pinstance->int_regs.host_ioa_interrupt_reg);
+
- /* hrrq valid bit was set, schedule tasklet to handle the response */
- if (intrs_clear == INTRS_HRRQ_VALID)
- tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id]));
+ }
+ }
+
+ tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id]));
+
+ return IRQ_HANDLED;
}
/**
- * pmcraid_isr - implements interrupt handling routine
+ * pmcraid_isr - implements legacy interrupt handling routine
*
* @irq: interrupt vector number
* @dev_id: pointer hrrq_vector
@@ -4052,8 +4408,9 @@ static irqreturn_t pmcraid_isr(int irq, void *dev_id)
{
struct pmcraid_isr_param *hrrq_vector;
struct pmcraid_instance *pinstance;
- unsigned long lock_flags;
u32 intrs;
+ unsigned long lock_flags;
+ int hrrq_id = 0;
/* In case of legacy interrupt mode where interrupts are shared across
* isrs, it may be possible that the current interrupt is not from IOA
@@ -4062,21 +4419,13 @@ static irqreturn_t pmcraid_isr(int irq, void *dev_id)
printk(KERN_INFO "%s(): NULL host pointer\n", __func__);
return IRQ_NONE;
}
-
hrrq_vector = (struct pmcraid_isr_param *)dev_id;
pinstance = hrrq_vector->drv_inst;
- /* Acquire the lock (currently host_lock) while processing interrupts.
- * This interval is small as most of the response processing is done by
- * tasklet without the lock.
- */
- spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
intrs = pmcraid_read_interrupts(pinstance);
- if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0)) {
- spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+ if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0))
return IRQ_NONE;
- }
/* Any error interrupts including unit_check, initiate IOA reset.
* In case of unit check indicate to reset_sequence that IOA unit
@@ -4091,13 +4440,28 @@ static irqreturn_t pmcraid_isr(int irq, void *dev_id)
pinstance->int_regs.ioa_host_interrupt_clr_reg);
pmcraid_err("ISR: error interrupts: %x initiating reset\n",
intrs);
- intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg);
+ intrs = ioread32(
+ pinstance->int_regs.ioa_host_interrupt_clr_reg);
+ spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
pmcraid_initiate_reset(pinstance);
+ spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
} else {
- pmcraid_isr_common(pinstance, intrs, hrrq_vector->hrrq_id);
- }
+ /* If interrupt was as part of the ioa initialization,
+ * clear. Delete the timer and wakeup the
+ * reset engine to proceed with reset sequence
+ */
+ if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) {
+ pmcraid_clr_trans_op(pinstance);
+ } else {
+ iowrite32(intrs,
+ pinstance->int_regs.ioa_host_interrupt_clr_reg);
+ ioread32(
+ pinstance->int_regs.ioa_host_interrupt_clr_reg);
- spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags);
+ tasklet_schedule(
+ &(pinstance->isr_tasklet[hrrq_id]));
+ }
+ }
return IRQ_HANDLED;
}
@@ -4120,6 +4484,7 @@ static void pmcraid_worker_function(struct work_struct *workp)
struct scsi_device *sdev;
unsigned long lock_flags;
unsigned long host_lock_flags;
+ u16 fw_version;
u8 bus, target, lun;
pinstance = container_of(workp, struct pmcraid_instance, worker_q);
@@ -4127,6 +4492,8 @@ static void pmcraid_worker_function(struct work_struct *workp)
if (!atomic_read(&pinstance->expose_resources))
return;
+ fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
+
spin_lock_irqsave(&pinstance->resource_lock, lock_flags);
list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) {
@@ -4166,12 +4533,16 @@ static void pmcraid_worker_function(struct work_struct *workp)
if (res->change_detected == RES_CHANGE_ADD) {
- if (!pmcraid_expose_resource(&res->cfg_entry))
+ if (!pmcraid_expose_resource(fw_version,
+ &res->cfg_entry))
continue;
if (RES_IS_VSET(res->cfg_entry)) {
bus = PMCRAID_VSET_BUS_ID;
- target = res->cfg_entry.unique_flags1;
+ if (fw_version <= PMCRAID_FW_VERSION_1)
+ target = res->cfg_entry.unique_flags1;
+ else
+ target = res->cfg_entry.array_id & 0xFF;
lun = PMCRAID_VSET_LUN_ID;
} else {
bus = PMCRAID_PHYS_BUS_ID;
@@ -4201,7 +4572,7 @@ static void pmcraid_worker_function(struct work_struct *workp)
* Return Value
* None
*/
-void pmcraid_tasklet_function(unsigned long instance)
+static void pmcraid_tasklet_function(unsigned long instance)
{
struct pmcraid_isr_param *hrrq_vector;
struct pmcraid_instance *pinstance;
@@ -4210,35 +4581,12 @@ void pmcraid_tasklet_function(unsigned long instance)
unsigned long host_lock_flags;
spinlock_t *lockp; /* hrrq buffer lock */
int id;
- u32 intrs;
__le32 resp;
hrrq_vector = (struct pmcraid_isr_param *)instance;
pinstance = hrrq_vector->drv_inst;
id = hrrq_vector->hrrq_id;
lockp = &(pinstance->hrrq_lock[id]);
- intrs = pmcraid_read_interrupts(pinstance);
-
- /* If interrupts was as part of the ioa initialization, clear and mask
- * it. Delete the timer and wakeup the reset engine to proceed with
- * reset sequence
- */
- if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) {
- iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
- pinstance->int_regs.ioa_host_interrupt_mask_reg);
- iowrite32(INTRS_TRANSITION_TO_OPERATIONAL,
- pinstance->int_regs.ioa_host_interrupt_clr_reg);
-
- if (pinstance->reset_cmd != NULL) {
- del_timer(&pinstance->reset_cmd->timer);
- spin_lock_irqsave(pinstance->host->host_lock,
- host_lock_flags);
- pinstance->reset_cmd->cmd_done(pinstance->reset_cmd);
- spin_unlock_irqrestore(pinstance->host->host_lock,
- host_lock_flags);
- }
- return;
- }
/* loop through each of the commands responded by IOA. Each HRRQ buf is
* protected by its own lock. Traversals must be done within this lock
@@ -4256,27 +4604,6 @@ void pmcraid_tasklet_function(unsigned long instance)
int cmd_index = resp >> 2;
struct pmcraid_cmd *cmd = NULL;
- if (cmd_index < PMCRAID_MAX_CMD) {
- cmd = pinstance->cmd_list[cmd_index];
- } else {
- /* In case of invalid response handle, initiate IOA
- * reset sequence.
- */
- spin_unlock_irqrestore(lockp, hrrq_lock_flags);
-
- pmcraid_err("Invalid response %d initiating reset\n",
- cmd_index);
-
- spin_lock_irqsave(pinstance->host->host_lock,
- host_lock_flags);
- pmcraid_initiate_reset(pinstance);
- spin_unlock_irqrestore(pinstance->host->host_lock,
- host_lock_flags);
-
- spin_lock_irqsave(lockp, hrrq_lock_flags);
- break;
- }
-
if (pinstance->hrrq_curr[id] < pinstance->hrrq_end[id]) {
pinstance->hrrq_curr[id]++;
} else {
@@ -4284,6 +4611,14 @@ void pmcraid_tasklet_function(unsigned long instance)
pinstance->host_toggle_bit[id] ^= 1u;
}
+ if (cmd_index >= PMCRAID_MAX_CMD) {
+ /* In case of invalid response handle, log message */
+ pmcraid_err("Invalid response handle %d\n", cmd_index);
+ resp = le32_to_cpu(*(pinstance->hrrq_curr[id]));
+ continue;
+ }
+
+ cmd = pinstance->cmd_list[cmd_index];
spin_unlock_irqrestore(lockp, hrrq_lock_flags);
spin_lock_irqsave(&pinstance->pending_pool_lock,
@@ -4324,7 +4659,16 @@ void pmcraid_tasklet_function(unsigned long instance)
static
void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance)
{
- free_irq(pinstance->pdev->irq, &(pinstance->hrrq_vector[0]));
+ int i;
+
+ for (i = 0; i < pinstance->num_hrrq; i++)
+ free_irq(pinstance->hrrq_vector[i].vector,
+ &(pinstance->hrrq_vector[i]));
+
+ if (pinstance->interrupt_mode) {
+ pci_disable_msix(pinstance->pdev);
+ pinstance->interrupt_mode = 0;
+ }
}
/**
@@ -4337,14 +4681,70 @@ void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance)
static int
pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance)
{
+ int rc;
struct pci_dev *pdev = pinstance->pdev;
+ if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+ int num_hrrq = PMCRAID_NUM_MSIX_VECTORS;
+ struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS];
+ int i;
+ for (i = 0; i < PMCRAID_NUM_MSIX_VECTORS; i++)
+ entries[i].entry = i;
+
+ rc = pci_enable_msix(pdev, entries, num_hrrq);
+ if (rc < 0)
+ goto pmcraid_isr_legacy;
+
+ /* Check how many MSIX vectors are allocated and register
+ * msi-x handlers for each of them giving appropriate buffer
+ */
+ if (rc > 0) {
+ num_hrrq = rc;
+ if (pci_enable_msix(pdev, entries, num_hrrq))
+ goto pmcraid_isr_legacy;
+ }
+
+ for (i = 0; i < num_hrrq; i++) {
+ pinstance->hrrq_vector[i].hrrq_id = i;
+ pinstance->hrrq_vector[i].drv_inst = pinstance;
+ pinstance->hrrq_vector[i].vector = entries[i].vector;
+ rc = request_irq(pinstance->hrrq_vector[i].vector,
+ pmcraid_isr_msix, 0,
+ PMCRAID_DRIVER_NAME,
+ &(pinstance->hrrq_vector[i]));
+
+ if (rc) {
+ int j;
+ for (j = 0; j < i; j++)
+ free_irq(entries[j].vector,
+ &(pinstance->hrrq_vector[j]));
+ pci_disable_msix(pdev);
+ goto pmcraid_isr_legacy;
+ }
+ }
+
+ pinstance->num_hrrq = num_hrrq;
+ pinstance->interrupt_mode = 1;
+ iowrite32(DOORBELL_INTR_MODE_MSIX,
+ pinstance->int_regs.host_ioa_interrupt_reg);
+ ioread32(pinstance->int_regs.host_ioa_interrupt_reg);
+ goto pmcraid_isr_out;
+ }
+
+pmcraid_isr_legacy:
+ /* If MSI-X registration failed fallback to legacy mode, where
+ * only one hrrq entry will be used
+ */
pinstance->hrrq_vector[0].hrrq_id = 0;
pinstance->hrrq_vector[0].drv_inst = pinstance;
- pinstance->hrrq_vector[0].vector = 0;
+ pinstance->hrrq_vector[0].vector = pdev->irq;
pinstance->num_hrrq = 1;
- return request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED,
- PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]);
+ rc = 0;
+
+ rc = request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED,
+ PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]);
+pmcraid_isr_out:
+ return rc;
}
/**
@@ -4516,12 +4916,11 @@ pmcraid_release_host_rrqs(struct pmcraid_instance *pinstance, int maxindex)
static int __devinit
pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance)
{
- int i;
- int buf_count = PMCRAID_MAX_CMD / pinstance->num_hrrq;
+ int i, buffer_size;
- for (i = 0; i < pinstance->num_hrrq; i++) {
- int buffer_size = HRRQ_ENTRY_SIZE * buf_count;
+ buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD;
+ for (i = 0; i < pinstance->num_hrrq; i++) {
pinstance->hrrq_start[i] =
pci_alloc_consistent(
pinstance->pdev,
@@ -4529,7 +4928,8 @@ pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance)
&(pinstance->hrrq_start_bus_addr[i]));
if (pinstance->hrrq_start[i] == 0) {
- pmcraid_err("could not allocate host rrq: %d\n", i);
+ pmcraid_err("pci_alloc failed for hrrq vector : %d\n",
+ i);
pmcraid_release_host_rrqs(pinstance, i);
return -ENOMEM;
}
@@ -4537,7 +4937,7 @@ pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance)
memset(pinstance->hrrq_start[i], 0, buffer_size);
pinstance->hrrq_curr[i] = pinstance->hrrq_start[i];
pinstance->hrrq_end[i] =
- pinstance->hrrq_start[i] + buf_count - 1;
+ pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1;
pinstance->host_toggle_bit[i] = 1;
spin_lock_init(&pinstance->hrrq_lock[i]);
}
@@ -4557,7 +4957,7 @@ static void pmcraid_release_hcams(struct pmcraid_instance *pinstance)
if (pinstance->ccn.msg != NULL) {
pci_free_consistent(pinstance->pdev,
PMCRAID_AEN_HDR_SIZE +
- sizeof(struct pmcraid_hcam_ccn),
+ sizeof(struct pmcraid_hcam_ccn_ext),
pinstance->ccn.msg,
pinstance->ccn.baddr);
@@ -4591,7 +4991,7 @@ static int pmcraid_allocate_hcams(struct pmcraid_instance *pinstance)
pinstance->ccn.msg = pci_alloc_consistent(
pinstance->pdev,
PMCRAID_AEN_HDR_SIZE +
- sizeof(struct pmcraid_hcam_ccn),
+ sizeof(struct pmcraid_hcam_ccn_ext),
&(pinstance->ccn.baddr));
pinstance->ldn.msg = pci_alloc_consistent(
@@ -4724,6 +5124,32 @@ static void pmcraid_kill_tasklets(struct pmcraid_instance *pinstance)
}
/**
+ * pmcraid_release_buffers - release per-adapter buffers allocated
+ *
+ * @pinstance: pointer to adapter soft state
+ *
+ * Return Value
+ * none
+ */
+static void pmcraid_release_buffers(struct pmcraid_instance *pinstance)
+{
+ pmcraid_release_config_buffers(pinstance);
+ pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD);
+ pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD);
+ pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq);
+
+ if (pinstance->inq_data != NULL) {
+ pci_free_consistent(pinstance->pdev,
+ sizeof(struct pmcraid_inquiry_data),
+ pinstance->inq_data,
+ pinstance->inq_data_baddr);
+
+ pinstance->inq_data = NULL;
+ pinstance->inq_data_baddr = 0;
+ }
+}
+
+/**
* pmcraid_init_buffers - allocates memory and initializes various structures
* @pinstance: pointer to per adapter instance structure
*
@@ -4753,20 +5179,32 @@ static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance)
}
if (pmcraid_allocate_cmd_blocks(pinstance)) {
- pmcraid_err("couldn't allocate memory for cmd blocks \n");
+ pmcraid_err("couldn't allocate memory for cmd blocks\n");
pmcraid_release_config_buffers(pinstance);
pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq);
return -ENOMEM;
}
if (pmcraid_allocate_control_blocks(pinstance)) {
- pmcraid_err("couldn't allocate memory control blocks \n");
+ pmcraid_err("couldn't allocate memory control blocks\n");
pmcraid_release_config_buffers(pinstance);
pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD);
pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq);
return -ENOMEM;
}
+ /* allocate DMAable memory for page D0 INQUIRY buffer */
+ pinstance->inq_data = pci_alloc_consistent(
+ pinstance->pdev,
+ sizeof(struct pmcraid_inquiry_data),
+ &pinstance->inq_data_baddr);
+
+ if (pinstance->inq_data == NULL) {
+ pmcraid_err("couldn't allocate DMA memory for INQUIRY\n");
+ pmcraid_release_buffers(pinstance);
+ return -ENOMEM;
+ }
+
/* Initialize all the command blocks and add them to free pool. No
* need to lock (free_pool_lock) as this is done in initialization
* itself
@@ -4785,7 +5223,7 @@ static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance)
* pmcraid_reinit_buffers - resets various buffer pointers
* @pinstance: pointer to adapter instance
* Return value
- * none
+ * none
*/
static void pmcraid_reinit_buffers(struct pmcraid_instance *pinstance)
{
@@ -4836,6 +5274,8 @@ static int __devinit pmcraid_init_instance(
mapped_pci_addr + chip_cfg->ioa_host_intr;
pint_regs->ioa_host_interrupt_clr_reg =
mapped_pci_addr + chip_cfg->ioa_host_intr_clr;
+ pint_regs->ioa_host_msix_interrupt_reg =
+ mapped_pci_addr + chip_cfg->ioa_host_msix_intr;
pint_regs->host_ioa_interrupt_reg =
mapped_pci_addr + chip_cfg->host_ioa_intr;
pint_regs->host_ioa_interrupt_clr_reg =
@@ -4858,6 +5298,7 @@ static int __devinit pmcraid_init_instance(
init_waitqueue_head(&pinstance->reset_wait_q);
atomic_set(&pinstance->outstanding_cmds, 0);
+ atomic_set(&pinstance->last_message_id, 0);
atomic_set(&pinstance->expose_resources, 0);
INIT_LIST_HEAD(&pinstance->free_res_q);
@@ -4883,23 +5324,6 @@ static int __devinit pmcraid_init_instance(
}
/**
- * pmcraid_release_buffers - release per-adapter buffers allocated
- *
- * @pinstance: pointer to adapter soft state
- *
- * Return Value
- * none
- */
-static void pmcraid_release_buffers(struct pmcraid_instance *pinstance)
-{
- pmcraid_release_config_buffers(pinstance);
- pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD);
- pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD);
- pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq);
-
-}
-
-/**
* pmcraid_shutdown - shutdown adapter controller.
* @pdev: pci device struct
*
@@ -4958,7 +5382,7 @@ static int pmcraid_setup_chrdev(struct pmcraid_instance *pinstance)
pmcraid_release_minor(minor);
else
device_create(pmcraid_class, NULL, MKDEV(pmcraid_major, minor),
- NULL, "pmcsas%u", minor);
+ NULL, "%s%u", PMCRAID_DEVFILE, minor);
return error;
}
@@ -5050,7 +5474,6 @@ static int pmcraid_resume(struct pci_dev *pdev)
struct pmcraid_instance *pinstance = pci_get_drvdata(pdev);
struct Scsi_Host *host = pinstance->host;
int rc;
- int hrrqs;
pci_set_power_state(pdev, PCI_D0);
pci_enable_wake(pdev, PCI_D0, 0);
@@ -5077,8 +5500,8 @@ static int pmcraid_resume(struct pci_dev *pdev)
goto disable_device;
}
+ pmcraid_disable_interrupts(pinstance, ~0);
atomic_set(&pinstance->outstanding_cmds, 0);
- hrrqs = pinstance->num_hrrq;
rc = pmcraid_register_interrupt_handler(pinstance);
if (rc) {
@@ -5100,7 +5523,7 @@ static int pmcraid_resume(struct pci_dev *pdev)
* state.
*/
if (pmcraid_reset_bringup(pinstance)) {
- dev_err(&pdev->dev, "couldn't initialize IOA \n");
+ dev_err(&pdev->dev, "couldn't initialize IOA\n");
rc = -ENODEV;
goto release_tasklets;
}
@@ -5108,6 +5531,7 @@ static int pmcraid_resume(struct pci_dev *pdev)
return 0;
release_tasklets:
+ pmcraid_disable_interrupts(pinstance, ~0);
pmcraid_kill_tasklets(pinstance);
pmcraid_unregister_interrupt_handler(pinstance);
@@ -5129,7 +5553,7 @@ disable_device:
/**
* pmcraid_complete_ioa_reset - Called by either timer or tasklet during
- * completion of the ioa reset
+ * completion of the ioa reset
* @cmd: pointer to reset command block
*/
static void pmcraid_complete_ioa_reset(struct pmcraid_cmd *cmd)
@@ -5204,11 +5628,14 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)
struct pmcraid_config_table_entry *cfgte;
unsigned long lock_flags;
int found, rc, i;
+ u16 fw_version;
LIST_HEAD(old_res);
if (pinstance->cfg_table->flags & MICROCODE_UPDATE_REQUIRED)
pmcraid_err("IOA requires microcode download\n");
+ fw_version = be16_to_cpu(pinstance->inq_data->fw_version);
+
/* resource list is protected by pinstance->resource_lock.
* init_res_table can be called from probe (user-thread) or runtime
* reset (timer/tasklet)
@@ -5219,9 +5646,14 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)
list_move_tail(&res->queue, &old_res);
for (i = 0; i < pinstance->cfg_table->num_entries; i++) {
- cfgte = &pinstance->cfg_table->entries[i];
+ if (be16_to_cpu(pinstance->inq_data->fw_version) <=
+ PMCRAID_FW_VERSION_1)
+ cfgte = &pinstance->cfg_table->entries[i];
+ else
+ cfgte = (struct pmcraid_config_table_entry *)
+ &pinstance->cfg_table->entries_ext[i];
- if (!pmcraid_expose_resource(cfgte))
+ if (!pmcraid_expose_resource(fw_version, cfgte))
continue;
found = 0;
@@ -5263,10 +5695,12 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)
*/
if (found) {
memcpy(&res->cfg_entry, cfgte,
- sizeof(struct pmcraid_config_table_entry));
+ pinstance->config_table_entry_size);
pmcraid_info("New res type:%x, vset:%x, addr:%x:\n",
res->cfg_entry.resource_type,
- res->cfg_entry.unique_flags1,
+ (fw_version <= PMCRAID_FW_VERSION_1 ?
+ res->cfg_entry.unique_flags1 :
+ res->cfg_entry.array_id & 0xFF),
le32_to_cpu(res->cfg_entry.resource_address));
}
}
@@ -5306,6 +5740,14 @@ static void pmcraid_querycfg(struct pmcraid_cmd *cmd)
struct pmcraid_instance *pinstance = cmd->drv_inst;
int cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table));
+ if (be16_to_cpu(pinstance->inq_data->fw_version) <=
+ PMCRAID_FW_VERSION_1)
+ pinstance->config_table_entry_size =
+ sizeof(struct pmcraid_config_table_entry);
+ else
+ pinstance->config_table_entry_size =
+ sizeof(struct pmcraid_config_table_entry_ext);
+
ioarcb->request_type = REQ_TYPE_IOACMD;
ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE);
@@ -5338,7 +5780,7 @@ static void pmcraid_querycfg(struct pmcraid_cmd *cmd)
/**
- * pmcraid_probe - PCI probe entry pointer for PMC MaxRaid controller driver
+ * pmcraid_probe - PCI probe entry pointer for PMC MaxRAID controller driver
* @pdev: pointer to pci device structure
* @dev_id: pointer to device ids structure
*
@@ -5485,7 +5927,7 @@ static int __devinit pmcraid_probe(
*/
pmcraid_info("starting IOA initialization sequence\n");
if (pmcraid_reset_bringup(pinstance)) {
- dev_err(&pdev->dev, "couldn't initialize IOA \n");
+ dev_err(&pdev->dev, "couldn't initialize IOA\n");
rc = 1;
goto out_release_bufs;
}
diff --git a/drivers/scsi/pmcraid.h b/drivers/scsi/pmcraid.h
index b8ad07c3449e..6cfa0145a1d7 100644
--- a/drivers/scsi/pmcraid.h
+++ b/drivers/scsi/pmcraid.h
@@ -40,10 +40,12 @@
* Driver version: version string in major_version.minor_version.patch format
* Driver date : date information in "Mon dd yyyy" format
*/
-#define PMCRAID_DRIVER_NAME "PMC MaxRAID"
+#define PMCRAID_DRIVER_NAME "PMC MaxRAID"
#define PMCRAID_DEVFILE "pmcsas"
-#define PMCRAID_DRIVER_VERSION "1.0.2"
-#define PMCRAID_DRIVER_DATE __DATE__
+#define PMCRAID_DRIVER_VERSION "2.0.2"
+#define PMCRAID_DRIVER_DATE __DATE__
+
+#define PMCRAID_FW_VERSION_1 0x002
/* Maximum number of adapters supported by current version of the driver */
#define PMCRAID_MAX_ADAPTERS 1024
@@ -85,17 +87,17 @@
#define PMCRAID_IOARCB_ALIGNMENT 32
#define PMCRAID_IOADL_ALIGNMENT 16
#define PMCRAID_IOASA_ALIGNMENT 4
-#define PMCRAID_NUM_MSIX_VECTORS 1
+#define PMCRAID_NUM_MSIX_VECTORS 16
/* various other limits */
-#define PMCRAID_VENDOR_ID_LEN 8
-#define PMCRAID_PRODUCT_ID_LEN 16
-#define PMCRAID_SERIAL_NUM_LEN 8
-#define PMCRAID_LUN_LEN 8
-#define PMCRAID_MAX_CDB_LEN 16
-#define PMCRAID_DEVICE_ID_LEN 8
-#define PMCRAID_SENSE_DATA_LEN 256
-#define PMCRAID_ADD_CMD_PARAM_LEN 48
+#define PMCRAID_VENDOR_ID_LEN 8
+#define PMCRAID_PRODUCT_ID_LEN 16
+#define PMCRAID_SERIAL_NUM_LEN 8
+#define PMCRAID_LUN_LEN 8
+#define PMCRAID_MAX_CDB_LEN 16
+#define PMCRAID_DEVICE_ID_LEN 8
+#define PMCRAID_SENSE_DATA_LEN 256
+#define PMCRAID_ADD_CMD_PARAM_LEN 48
#define PMCRAID_MAX_BUS_TO_SCAN 1
#define PMCRAID_MAX_NUM_TARGETS_PER_BUS 256
@@ -116,17 +118,10 @@
#define PMCRAID_VSET_MAX_SECTORS 512
#define PMCRAID_MAX_CMD_PER_LUN 254
-/* Number of configuration table entries (resources) */
-#define PMCRAID_MAX_NUM_OF_VSETS 240
-
-/* Todo : Check max limit for Phase 1 */
-#define PMCRAID_MAX_NUM_OF_PHY_DEVS 256
-
-/* MAX_NUM_OF_DEVS includes 1 FP, 1 Dummy Enclosure device */
-#define PMCRAID_MAX_NUM_OF_DEVS \
- (PMCRAID_MAX_NUM_OF_VSETS + PMCRAID_MAX_NUM_OF_PHY_DEVS + 2)
-
-#define PMCRAID_MAX_RESOURCES PMCRAID_MAX_NUM_OF_DEVS
+/* Number of configuration table entries (resources), includes 1 FP,
+ * 1 Enclosure device
+ */
+#define PMCRAID_MAX_RESOURCES 256
/* Adapter Commands used by driver */
#define PMCRAID_QUERY_RESOURCE_STATE 0xC2
@@ -177,6 +172,7 @@
#define PMCRAID_IOASC_SENSE_STATUS(ioasc) ((ioasc) & 0x000000ff)
#define PMCRAID_IOASC_GOOD_COMPLETION 0x00000000
+#define PMCRAID_IOASC_GC_IOARCB_NOTFOUND 0x005A0000
#define PMCRAID_IOASC_NR_INIT_CMD_REQUIRED 0x02040200
#define PMCRAID_IOASC_NR_IOA_RESET_REQUIRED 0x02048000
#define PMCRAID_IOASC_NR_SYNC_REQUIRED 0x023F0000
@@ -187,12 +183,12 @@
#define PMCRAID_IOASC_HW_IOA_RESET_REQUIRED 0x04448600
#define PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE 0x05250000
#define PMCRAID_IOASC_AC_TERMINATED_BY_HOST 0x0B5A0000
-#define PMCRAID_IOASC_UA_BUS_WAS_RESET 0x06290000
-#define PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER 0x06298000
+#define PMCRAID_IOASC_UA_BUS_WAS_RESET 0x06290000
+#define PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER 0x06298000
/* Driver defined IOASCs */
-#define PMCRAID_IOASC_IOA_WAS_RESET 0x10000001
-#define PMCRAID_IOASC_PCI_ACCESS_ERROR 0x10000002
+#define PMCRAID_IOASC_IOA_WAS_RESET 0x10000001
+#define PMCRAID_IOASC_PCI_ACCESS_ERROR 0x10000002
/* Various timeout values (in milliseconds) used. If any of these are chip
* specific, move them to pmcraid_chip_details structure.
@@ -336,6 +332,13 @@ struct pmcraid_config_table_entry {
__u8 lun[PMCRAID_LUN_LEN];
} __attribute__((packed, aligned(4)));
+/* extended configuration table sizes are of 64 bytes in size */
+#define PMCRAID_CFGTE_EXT_SIZE 32
+struct pmcraid_config_table_entry_ext {
+ struct pmcraid_config_table_entry cfgte;
+ __u8 cfgte_ext[PMCRAID_CFGTE_EXT_SIZE];
+};
+
/* resource types (config_table_entry.resource_type values) */
#define RES_TYPE_AF_DASD 0x00
#define RES_TYPE_GSCSI 0x01
@@ -376,7 +379,12 @@ struct pmcraid_config_table {
__u8 reserved1;
__u8 flags;
__u8 reserved2[11];
- struct pmcraid_config_table_entry entries[PMCRAID_MAX_RESOURCES];
+ union {
+ struct pmcraid_config_table_entry
+ entries[PMCRAID_MAX_RESOURCES];
+ struct pmcraid_config_table_entry_ext
+ entries_ext[PMCRAID_MAX_RESOURCES];
+ };
} __attribute__((packed, aligned(4)));
/* config_table.flags value */
@@ -385,7 +393,7 @@ struct pmcraid_config_table {
/*
* HCAM format
*/
-#define PMCRAID_HOSTRCB_LDNSIZE 4056
+#define PMCRAID_HOSTRCB_LDNSIZE 4056
/* Error log notification format */
struct pmcraid_hostrcb_error {
@@ -416,6 +424,15 @@ struct pmcraid_hcam_hdr {
struct pmcraid_hcam_ccn {
struct pmcraid_hcam_hdr header;
struct pmcraid_config_table_entry cfg_entry;
+ struct pmcraid_config_table_entry cfg_entry_old;
+} __attribute__((packed, aligned(4)));
+
+#define PMCRAID_CCN_EXT_SIZE 3944
+struct pmcraid_hcam_ccn_ext {
+ struct pmcraid_hcam_hdr header;
+ struct pmcraid_config_table_entry_ext cfg_entry;
+ struct pmcraid_config_table_entry_ext cfg_entry_old;
+ __u8 reserved[PMCRAID_CCN_EXT_SIZE];
} __attribute__((packed, aligned(4)));
struct pmcraid_hcam_ldn {
@@ -431,6 +448,8 @@ struct pmcraid_hcam_ldn {
#define NOTIFICATION_TYPE_ENTRY_CHANGED 0x0
#define NOTIFICATION_TYPE_ENTRY_NEW 0x1
#define NOTIFICATION_TYPE_ENTRY_DELETED 0x2
+#define NOTIFICATION_TYPE_STATE_CHANGE 0x3
+#define NOTIFICATION_TYPE_ENTRY_STATECHANGED 0x4
#define NOTIFICATION_TYPE_ERROR_LOG 0x10
#define NOTIFICATION_TYPE_INFORMATION_LOG 0x11
@@ -460,6 +479,7 @@ struct pmcraid_chip_details {
unsigned long mailbox;
unsigned long global_intr_mask;
unsigned long ioa_host_intr;
+ unsigned long ioa_host_msix_intr;
unsigned long ioa_host_intr_clr;
unsigned long ioa_host_mask;
unsigned long ioa_host_mask_clr;
@@ -482,6 +502,7 @@ struct pmcraid_chip_details {
#define INTRS_IOA_PROCESSOR_ERROR PMC_BIT32(29)
#define INTRS_HRRQ_VALID PMC_BIT32(30)
#define INTRS_OPERATIONAL_STATUS PMC_BIT32(0)
+#define INTRS_ALLOW_MSIX_VECTOR0 PMC_BIT32(31)
/* Host to IOA Doorbells */
#define DOORBELL_RUNTIME_RESET PMC_BIT32(1)
@@ -489,10 +510,12 @@ struct pmcraid_chip_details {
#define DOORBELL_IOA_DEBUG_ALERT PMC_BIT32(9)
#define DOORBELL_ENABLE_DESTRUCTIVE_DIAGS PMC_BIT32(8)
#define DOORBELL_IOA_START_BIST PMC_BIT32(23)
+#define DOORBELL_INTR_MODE_MSIX PMC_BIT32(25)
+#define DOORBELL_INTR_MSIX_CLR PMC_BIT32(26)
#define DOORBELL_RESET_IOA PMC_BIT32(31)
/* Global interrupt mask register value */
-#define GLOBAL_INTERRUPT_MASK 0x4ULL
+#define GLOBAL_INTERRUPT_MASK 0x5ULL
#define PMCRAID_ERROR_INTERRUPTS (INTRS_IOARCB_TRANSFER_FAILED | \
INTRS_IOA_UNIT_CHECK | \
@@ -503,8 +526,8 @@ struct pmcraid_chip_details {
#define PMCRAID_PCI_INTERRUPTS (PMCRAID_ERROR_INTERRUPTS | \
INTRS_HRRQ_VALID | \
- INTRS_CRITICAL_OP_IN_PROGRESS |\
- INTRS_TRANSITION_TO_OPERATIONAL)
+ INTRS_TRANSITION_TO_OPERATIONAL |\
+ INTRS_ALLOW_MSIX_VECTOR0)
/* control_block, associated with each of the commands contains IOARCB, IOADLs
* memory for IOASA. Additional 3 * 16 bytes are allocated in order to support
@@ -526,17 +549,24 @@ struct pmcraid_sglist {
struct scatterlist scatterlist[1];
};
+/* page D0 inquiry data of focal point resource */
+struct pmcraid_inquiry_data {
+ __u8 ph_dev_type;
+ __u8 page_code;
+ __u8 reserved1;
+ __u8 add_page_len;
+ __u8 length;
+ __u8 reserved2;
+ __le16 fw_version;
+ __u8 reserved3[16];
+};
+
/* pmcraid_cmd - LLD representation of SCSI command */
struct pmcraid_cmd {
/* Ptr and bus address of DMA.able control block for this command */
struct pmcraid_control_block *ioa_cb;
dma_addr_t ioa_cb_bus_addr;
-
- /* sense buffer for REQUEST SENSE command if firmware is not sending
- * auto sense data
- */
- dma_addr_t sense_buffer_dma;
dma_addr_t dma_handle;
u8 *sense_buffer;
@@ -556,11 +586,22 @@ struct pmcraid_cmd {
struct pmcraid_sglist *sglist; /* used for passthrough IOCTLs */
- /* scratch used during reset sequence */
+ /* scratch used */
union {
+ /* during reset sequence */
unsigned long time_left;
struct pmcraid_resource_entry *res;
- } u;
+ int hrrq_index;
+
+ /* used during IO command error handling. Sense buffer
+ * for REQUEST SENSE command if firmware is not sending
+ * auto sense data
+ */
+ struct {
+ u8 *sense_buffer;
+ dma_addr_t sense_buffer_dma;
+ };
+ };
};
/*
@@ -568,6 +609,7 @@ struct pmcraid_cmd {
*/
struct pmcraid_interrupts {
void __iomem *ioa_host_interrupt_reg;
+ void __iomem *ioa_host_msix_interrupt_reg;
void __iomem *ioa_host_interrupt_clr_reg;
void __iomem *ioa_host_interrupt_mask_reg;
void __iomem *ioa_host_interrupt_mask_clr_reg;
@@ -578,11 +620,12 @@ struct pmcraid_interrupts {
/* ISR parameters LLD allocates (one for each MSI-X if enabled) vectors */
struct pmcraid_isr_param {
- u8 hrrq_id; /* hrrq entry index */
- u16 vector; /* allocated msi-x vector */
struct pmcraid_instance *drv_inst;
+ u16 vector; /* allocated msi-x vector */
+ u8 hrrq_id; /* hrrq entry index */
};
+
/* AEN message header sent as part of event data to applications */
struct pmcraid_aen_msg {
u32 hostno;
@@ -591,6 +634,19 @@ struct pmcraid_aen_msg {
u8 data[0];
};
+/* Controller state event message type */
+struct pmcraid_state_msg {
+ struct pmcraid_aen_msg msg;
+ u32 ioa_state;
+};
+
+#define PMC_DEVICE_EVENT_RESET_START 0x11000000
+#define PMC_DEVICE_EVENT_RESET_SUCCESS 0x11000001
+#define PMC_DEVICE_EVENT_RESET_FAILED 0x11000002
+#define PMC_DEVICE_EVENT_SHUTDOWN_START 0x11000003
+#define PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS 0x11000004
+#define PMC_DEVICE_EVENT_SHUTDOWN_FAILED 0x11000005
+
struct pmcraid_hostrcb {
struct pmcraid_instance *drv_inst;
struct pmcraid_aen_msg *msg;
@@ -628,6 +684,7 @@ struct pmcraid_instance {
/* HostRCBs needed for HCAM */
struct pmcraid_hostrcb ldn;
struct pmcraid_hostrcb ccn;
+ struct pmcraid_state_msg scn; /* controller state change msg */
/* Bus address of start of HRRQ */
@@ -645,12 +702,15 @@ struct pmcraid_instance {
/* Lock for HRRQ access */
spinlock_t hrrq_lock[PMCRAID_NUM_MSIX_VECTORS];
+ struct pmcraid_inquiry_data *inq_data;
+ dma_addr_t inq_data_baddr;
+
+ /* size of configuration table entry, varies based on the firmware */
+ u32 config_table_entry_size;
+
/* Expected toggle bit at host */
u8 host_toggle_bit[PMCRAID_NUM_MSIX_VECTORS];
- /* No of Reset IOA retries . IOA marked dead if threshold exceeds */
- u8 ioa_reset_attempts;
-#define PMCRAID_RESET_ATTEMPTS 3
/* Wait Q for threads to wait for Reset IOA completion */
wait_queue_head_t reset_wait_q;
@@ -664,14 +724,22 @@ struct pmcraid_instance {
struct Scsi_Host *host; /* mid layer interface structure handle */
struct pci_dev *pdev; /* PCI device structure handle */
+ /* No of Reset IOA retries . IOA marked dead if threshold exceeds */
+ u8 ioa_reset_attempts;
+#define PMCRAID_RESET_ATTEMPTS 3
+
u8 current_log_level; /* default level for logging IOASC errors */
u8 num_hrrq; /* Number of interrupt vectors allocated */
+ u8 interrupt_mode; /* current interrupt mode legacy or msix */
dev_t dev; /* Major-Minor numbers for Char device */
/* Used as ISR handler argument */
struct pmcraid_isr_param hrrq_vector[PMCRAID_NUM_MSIX_VECTORS];
+ /* Message id as filled in last fired IOARCB, used to identify HRRQ */
+ atomic_t last_message_id;
+
/* configuration table */
struct pmcraid_config_table *cfg_table;
dma_addr_t cfg_table_bus_addr;
@@ -686,8 +754,14 @@ struct pmcraid_instance {
struct list_head free_cmd_pool;
struct list_head pending_cmd_pool;
- spinlock_t free_pool_lock; /* free pool lock */
- spinlock_t pending_pool_lock; /* pending pool lock */
+ spinlock_t free_pool_lock; /* free pool lock */
+ spinlock_t pending_pool_lock; /* pending pool lock */
+
+ /* Tasklet to handle deferred processing */
+ struct tasklet_struct isr_tasklet[PMCRAID_NUM_MSIX_VECTORS];
+
+ /* Work-queue (Shared) for deferred reset processing */
+ struct work_struct worker_q;
/* No of IO commands pending with FW */
atomic_t outstanding_cmds;
@@ -695,11 +769,6 @@ struct pmcraid_instance {
/* should add/delete resources to mid-layer now ?*/
atomic_t expose_resources;
- /* Tasklet to handle deferred processing */
- struct tasklet_struct isr_tasklet[PMCRAID_NUM_MSIX_VECTORS];
-
- /* Work-queue (Shared) for deferred reset processing */
- struct work_struct worker_q;
u32 ioa_state:4; /* For IOA Reset sequence FSM */
@@ -728,7 +797,10 @@ struct pmcraid_instance {
/* LLD maintained resource entry structure */
struct pmcraid_resource_entry {
struct list_head queue; /* link to "to be exposed" resources */
- struct pmcraid_config_table_entry cfg_entry;
+ union {
+ struct pmcraid_config_table_entry cfg_entry;
+ struct pmcraid_config_table_entry_ext cfg_entry_ext;
+ };
struct scsi_device *scsi_dev; /* Link scsi_device structure */
atomic_t read_failures; /* count of failed READ commands */
atomic_t write_failures; /* count of failed WRITE commands */
@@ -771,73 +843,75 @@ struct pmcraid_ioasc_error {
* statically.
*/
static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = {
- {0x01180600, IOASC_LOG_LEVEL_MUST,
+ {0x01180600, IOASC_LOG_LEVEL_HARD,
"Recovered Error, soft media error, sector reassignment suggested"},
- {0x015D0000, IOASC_LOG_LEVEL_MUST,
- "Recovered Error, failure prediction threshold exceeded"},
- {0x015D9200, IOASC_LOG_LEVEL_MUST,
- "Recovered Error, soft Cache Card Battery error threshold"},
- {0x015D9200, IOASC_LOG_LEVEL_MUST,
- "Recovered Error, soft Cache Card Battery error threshold"},
- {0x02048000, IOASC_LOG_LEVEL_MUST,
+ {0x015D0000, IOASC_LOG_LEVEL_HARD,
+ "Recovered Error, failure prediction thresold exceeded"},
+ {0x015D9200, IOASC_LOG_LEVEL_HARD,
+ "Recovered Error, soft Cache Card Battery error thresold"},
+ {0x015D9200, IOASC_LOG_LEVEL_HARD,
+ "Recovered Error, soft Cache Card Battery error thresold"},
+ {0x02048000, IOASC_LOG_LEVEL_HARD,
"Not Ready, IOA Reset Required"},
- {0x02408500, IOASC_LOG_LEVEL_MUST,
+ {0x02408500, IOASC_LOG_LEVEL_HARD,
"Not Ready, IOA microcode download required"},
- {0x03110B00, IOASC_LOG_LEVEL_MUST,
+ {0x03110B00, IOASC_LOG_LEVEL_HARD,
"Medium Error, data unreadable, reassignment suggested"},
{0x03110C00, IOASC_LOG_LEVEL_MUST,
"Medium Error, data unreadable do not reassign"},
- {0x03310000, IOASC_LOG_LEVEL_MUST,
+ {0x03310000, IOASC_LOG_LEVEL_HARD,
"Medium Error, media corrupted"},
- {0x04050000, IOASC_LOG_LEVEL_MUST,
+ {0x04050000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, IOA can't communicate with device"},
{0x04080000, IOASC_LOG_LEVEL_MUST,
"Hardware Error, device bus error"},
- {0x04080000, IOASC_LOG_LEVEL_MUST,
+ {0x04088000, IOASC_LOG_LEVEL_MUST,
"Hardware Error, device bus is not functioning"},
- {0x04118000, IOASC_LOG_LEVEL_MUST,
+ {0x04118000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, IOA reserved area data check"},
- {0x04118100, IOASC_LOG_LEVEL_MUST,
+ {0x04118100, IOASC_LOG_LEVEL_HARD,
"Hardware Error, IOA reserved area invalid data pattern"},
- {0x04118200, IOASC_LOG_LEVEL_MUST,
+ {0x04118200, IOASC_LOG_LEVEL_HARD,
"Hardware Error, IOA reserved area LRC error"},
- {0x04320000, IOASC_LOG_LEVEL_MUST,
+ {0x04320000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, reassignment space exhausted"},
- {0x04330000, IOASC_LOG_LEVEL_MUST,
+ {0x04330000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, data transfer underlength error"},
- {0x04330000, IOASC_LOG_LEVEL_MUST,
+ {0x04330000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, data transfer overlength error"},
{0x04418000, IOASC_LOG_LEVEL_MUST,
"Hardware Error, PCI bus error"},
- {0x04440000, IOASC_LOG_LEVEL_MUST,
+ {0x04440000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, device error"},
- {0x04448300, IOASC_LOG_LEVEL_MUST,
+ {0x04448200, IOASC_LOG_LEVEL_MUST,
+ "Hardware Error, IOA error"},
+ {0x04448300, IOASC_LOG_LEVEL_HARD,
"Hardware Error, undefined device response"},
- {0x04448400, IOASC_LOG_LEVEL_MUST,
+ {0x04448400, IOASC_LOG_LEVEL_HARD,
"Hardware Error, IOA microcode error"},
- {0x04448600, IOASC_LOG_LEVEL_MUST,
+ {0x04448600, IOASC_LOG_LEVEL_HARD,
"Hardware Error, IOA reset required"},
- {0x04449200, IOASC_LOG_LEVEL_MUST,
+ {0x04449200, IOASC_LOG_LEVEL_HARD,
"Hardware Error, hard Cache Fearuee Card Battery error"},
- {0x0444A000, IOASC_LOG_LEVEL_MUST,
+ {0x0444A000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, failed device altered"},
- {0x0444A200, IOASC_LOG_LEVEL_MUST,
+ {0x0444A200, IOASC_LOG_LEVEL_HARD,
"Hardware Error, data check after reassignment"},
- {0x0444A300, IOASC_LOG_LEVEL_MUST,
+ {0x0444A300, IOASC_LOG_LEVEL_HARD,
"Hardware Error, LRC error after reassignment"},
- {0x044A0000, IOASC_LOG_LEVEL_MUST,
+ {0x044A0000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, device bus error (msg/cmd phase)"},
- {0x04670400, IOASC_LOG_LEVEL_MUST,
+ {0x04670400, IOASC_LOG_LEVEL_HARD,
"Hardware Error, new device can't be used"},
- {0x04678000, IOASC_LOG_LEVEL_MUST,
+ {0x04678000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, invalid multiadapter configuration"},
- {0x04678100, IOASC_LOG_LEVEL_MUST,
+ {0x04678100, IOASC_LOG_LEVEL_HARD,
"Hardware Error, incorrect connection between enclosures"},
- {0x04678200, IOASC_LOG_LEVEL_MUST,
+ {0x04678200, IOASC_LOG_LEVEL_HARD,
"Hardware Error, connections exceed IOA design limits"},
- {0x04678300, IOASC_LOG_LEVEL_MUST,
+ {0x04678300, IOASC_LOG_LEVEL_HARD,
"Hardware Error, incorrect multipath connection"},
- {0x04679000, IOASC_LOG_LEVEL_MUST,
+ {0x04679000, IOASC_LOG_LEVEL_HARD,
"Hardware Error, command to LUN failed"},
{0x064C8000, IOASC_LOG_LEVEL_HARD,
"Unit Attention, cache exists for missing/failed device"},
@@ -845,15 +919,15 @@ static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = {
"Unit Attention, incompatible exposed mode device"},
{0x06670600, IOASC_LOG_LEVEL_HARD,
"Unit Attention, attachment of logical unit failed"},
- {0x06678000, IOASC_LOG_LEVEL_MUST,
+ {0x06678000, IOASC_LOG_LEVEL_HARD,
"Unit Attention, cables exceed connective design limit"},
- {0x06678300, IOASC_LOG_LEVEL_MUST,
+ {0x06678300, IOASC_LOG_LEVEL_HARD,
"Unit Attention, incomplete multipath connection between" \
"IOA and enclosure"},
- {0x06678400, IOASC_LOG_LEVEL_MUST,
+ {0x06678400, IOASC_LOG_LEVEL_HARD,
"Unit Attention, incomplete multipath connection between" \
"device and enclosure"},
- {0x06678500, IOASC_LOG_LEVEL_MUST,
+ {0x06678500, IOASC_LOG_LEVEL_HARD,
"Unit Attention, incomplete multipath connection between" \
"IOA and remote IOA"},
{0x06678600, IOASC_LOG_LEVEL_HARD,
@@ -863,11 +937,11 @@ static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = {
"function"},
{0x06698200, IOASC_LOG_LEVEL_HARD,
"Unit Attention, corrupt array parity detected on device"},
- {0x066B0200, IOASC_LOG_LEVEL_MUST,
+ {0x066B0200, IOASC_LOG_LEVEL_HARD,
"Unit Attention, array exposed"},
{0x066B8200, IOASC_LOG_LEVEL_HARD,
"Unit Attention, exposed array is still protected"},
- {0x066B9200, IOASC_LOG_LEVEL_MUST,
+ {0x066B9200, IOASC_LOG_LEVEL_HARD,
"Unit Attention, Multipath redundancy level got worse"},
{0x07270000, IOASC_LOG_LEVEL_HARD,
"Data Protect, device is read/write protected by IOA"},
@@ -875,37 +949,37 @@ static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = {
"Data Protect, IOA doesn't support device attribute"},
{0x07278100, IOASC_LOG_LEVEL_HARD,
"Data Protect, NVRAM mirroring prohibited"},
- {0x07278400, IOASC_LOG_LEVEL_MUST,
+ {0x07278400, IOASC_LOG_LEVEL_HARD,
"Data Protect, array is short 2 or more devices"},
- {0x07278600, IOASC_LOG_LEVEL_MUST,
+ {0x07278600, IOASC_LOG_LEVEL_HARD,
"Data Protect, exposed array is short a required device"},
- {0x07278700, IOASC_LOG_LEVEL_MUST,
+ {0x07278700, IOASC_LOG_LEVEL_HARD,
"Data Protect, array members not at required addresses"},
- {0x07278800, IOASC_LOG_LEVEL_MUST,
+ {0x07278800, IOASC_LOG_LEVEL_HARD,
"Data Protect, exposed mode device resource address conflict"},
- {0x07278900, IOASC_LOG_LEVEL_MUST,
+ {0x07278900, IOASC_LOG_LEVEL_HARD,
"Data Protect, incorrect resource address of exposed mode device"},
- {0x07278A00, IOASC_LOG_LEVEL_MUST,
+ {0x07278A00, IOASC_LOG_LEVEL_HARD,
"Data Protect, Array is missing a device and parity is out of sync"},
- {0x07278B00, IOASC_LOG_LEVEL_MUST,
+ {0x07278B00, IOASC_LOG_LEVEL_HARD,
"Data Protect, maximum number of arrays already exist"},
{0x07278C00, IOASC_LOG_LEVEL_HARD,
"Data Protect, cannot locate cache data for device"},
{0x07278D00, IOASC_LOG_LEVEL_HARD,
"Data Protect, cache data exits for a changed device"},
- {0x07279100, IOASC_LOG_LEVEL_MUST,
+ {0x07279100, IOASC_LOG_LEVEL_HARD,
"Data Protect, detection of a device requiring format"},
- {0x07279200, IOASC_LOG_LEVEL_MUST,
+ {0x07279200, IOASC_LOG_LEVEL_HARD,
"Data Protect, IOA exceeds maximum number of devices"},
- {0x07279600, IOASC_LOG_LEVEL_MUST,
+ {0x07279600, IOASC_LOG_LEVEL_HARD,
"Data Protect, missing array, volume set is not functional"},
- {0x07279700, IOASC_LOG_LEVEL_MUST,
+ {0x07279700, IOASC_LOG_LEVEL_HARD,
"Data Protect, single device for a volume set"},
- {0x07279800, IOASC_LOG_LEVEL_MUST,
+ {0x07279800, IOASC_LOG_LEVEL_HARD,
"Data Protect, missing multiple devices for a volume set"},
{0x07279900, IOASC_LOG_LEVEL_HARD,
"Data Protect, maximum number of volument sets already exists"},
- {0x07279A00, IOASC_LOG_LEVEL_MUST,
+ {0x07279A00, IOASC_LOG_LEVEL_HARD,
"Data Protect, other volume set problem"},
};
@@ -952,27 +1026,6 @@ struct pmcraid_ioctl_header {
#define PMCRAID_IOCTL_SIGNATURE "PMCRAID"
-
-/*
- * pmcraid_event_details - defines AEN details that apps can retrieve from LLD
- *
- * .rcb_ccn - complete RCB of CCN
- * .rcb_ldn - complete RCB of CCN
- */
-struct pmcraid_event_details {
- struct pmcraid_hcam_ccn rcb_ccn;
- struct pmcraid_hcam_ldn rcb_ldn;
-};
-
-/*
- * pmcraid_driver_ioctl_buffer - structure passed as argument to most of the
- * PMC driver handled ioctls.
- */
-struct pmcraid_driver_ioctl_buffer {
- struct pmcraid_ioctl_header ioctl_header;
- struct pmcraid_event_details event_details;
-};
-
/*
* pmcraid_passthrough_ioctl_buffer - structure given as argument to
* passthrough(or firmware handled) IOCTL commands. Note that ioarcb requires
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 1e4cafabba15..fd6f7b100547 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -1208,7 +1208,7 @@ qla24xx_84xx_fw_version_show(struct device *dev,
if (!IS_QLA84XX(ha))
return snprintf(buf, PAGE_SIZE, "\n");
- if (ha->cs84xx && ha->cs84xx->op_fw_version == 0)
+ if (ha->cs84xx->op_fw_version == 0)
rval = qla84xx_verify_chip(vha, status);
if ((rval == QLA_SUCCESS) && (status[0] == 0))
@@ -1732,7 +1732,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
}
- if (IS_QLA25XX(ha) && ql2xenabledif) {
+ if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
if (ha->fw_attributes & BIT_4) {
vha->flags.difdix_supported = 1;
DEBUG18(qla_printk(KERN_INFO, ha,
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index b905dfe5ea61..3a0248388505 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -483,6 +483,98 @@ done:
return rval;
}
+/* Set the port configuration to enable the
+ * internal loopback on ISP81XX
+ */
+static inline int
+qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
+ uint16_t *new_config)
+{
+ int ret = 0;
+ int rval = 0;
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!IS_QLA81XX(ha))
+ goto done_set_internal;
+
+ new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1);
+ memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
+
+ ha->notify_dcbx_comp = 1;
+ ret = qla81xx_set_port_config(vha, new_config);
+ if (ret != QLA_SUCCESS) {
+ DEBUG2(printk(KERN_ERR
+ "%s(%lu): Set port config failed\n",
+ __func__, vha->host_no));
+ ha->notify_dcbx_comp = 0;
+ rval = -EINVAL;
+ goto done_set_internal;
+ }
+
+ /* Wait for DCBX complete event */
+ if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "State change notificaition not received.\n"));
+ } else
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "State change RECEIVED\n"));
+
+ ha->notify_dcbx_comp = 0;
+
+done_set_internal:
+ return rval;
+}
+
+/* Set the port configuration to disable the
+ * internal loopback on ISP81XX
+ */
+static inline int
+qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
+ int wait)
+{
+ int ret = 0;
+ int rval = 0;
+ uint16_t new_config[4];
+ struct qla_hw_data *ha = vha->hw;
+
+ if (!IS_QLA81XX(ha))
+ goto done_reset_internal;
+
+ memset(new_config, 0 , sizeof(new_config));
+ if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==
+ ENABLE_INTERNAL_LOOPBACK) {
+ new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK;
+ memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
+
+ ha->notify_dcbx_comp = wait;
+ ret = qla81xx_set_port_config(vha, new_config);
+ if (ret != QLA_SUCCESS) {
+ DEBUG2(printk(KERN_ERR
+ "%s(%lu): Set port config failed\n",
+ __func__, vha->host_no));
+ ha->notify_dcbx_comp = 0;
+ rval = -EINVAL;
+ goto done_reset_internal;
+ }
+
+ /* Wait for DCBX complete event */
+ if (wait && !wait_for_completion_timeout(&ha->dcbx_comp,
+ (20 * HZ))) {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "State change notificaition not received.\n"));
+ ha->notify_dcbx_comp = 0;
+ rval = -EINVAL;
+ goto done_reset_internal;
+ } else
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "State change RECEIVED\n"));
+
+ ha->notify_dcbx_comp = 0;
+ }
+done_reset_internal:
+ return rval;
+}
+
static int
qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
{
@@ -494,6 +586,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
char *type;
struct msg_echo_lb elreq;
uint16_t response[MAILBOX_REGISTER_COUNT];
+ uint16_t config[4], new_config[4];
uint8_t *fw_sts_ptr;
uint8_t *req_data = NULL;
dma_addr_t req_data_dma;
@@ -568,29 +661,102 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
- if (ha->current_topology != ISP_CFG_F) {
- type = "FC_BSG_HST_VENDOR_LOOPBACK";
+ if ((ha->current_topology == ISP_CFG_F ||
+ (IS_QLA81XX(ha) &&
+ le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
+ && req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
+ elreq.options == EXTERNAL_LOOPBACK) {
+ type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
DEBUG2(qla_printk(KERN_INFO, ha,
- "scsi(%ld) bsg rqst type: %s\n",
- vha->host_no, type));
-
- command_sent = INT_DEF_LB_LOOPBACK_CMD;
- rval = qla2x00_loopback_test(vha, &elreq, response);
+ "scsi(%ld) bsg rqst type: %s\n", vha->host_no, type));
+ command_sent = INT_DEF_LB_ECHO_CMD;
+ rval = qla2x00_echo_test(vha, &elreq, response);
+ } else {
if (IS_QLA81XX(ha)) {
+ memset(config, 0, sizeof(config));
+ memset(new_config, 0, sizeof(new_config));
+ if (qla81xx_get_port_config(vha, config)) {
+ DEBUG2(printk(KERN_ERR
+ "%s(%lu): Get port config failed\n",
+ __func__, vha->host_no));
+ bsg_job->reply->reply_payload_rcv_len = 0;
+ bsg_job->reply->result = (DID_ERROR << 16);
+ rval = -EPERM;
+ goto done_free_dma_req;
+ }
+
+ if (elreq.options != EXTERNAL_LOOPBACK) {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "Internal: current port config = %x\n",
+ config[0]));
+ if (qla81xx_set_internal_loopback(vha, config,
+ new_config)) {
+ bsg_job->reply->reply_payload_rcv_len =
+ 0;
+ bsg_job->reply->result =
+ (DID_ERROR << 16);
+ rval = -EPERM;
+ goto done_free_dma_req;
+ }
+ } else {
+ /* For external loopback to work
+ * ensure internal loopback is disabled
+ */
+ if (qla81xx_reset_internal_loopback(vha,
+ config, 1)) {
+ bsg_job->reply->reply_payload_rcv_len =
+ 0;
+ bsg_job->reply->result =
+ (DID_ERROR << 16);
+ rval = -EPERM;
+ goto done_free_dma_req;
+ }
+ }
+
+ type = "FC_BSG_HST_VENDOR_LOOPBACK";
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld) bsg rqst type: %s\n",
+ vha->host_no, type));
+
+ command_sent = INT_DEF_LB_LOOPBACK_CMD;
+ rval = qla2x00_loopback_test(vha, &elreq, response);
+
+ if (new_config[1]) {
+ /* Revert back to original port config
+ * Also clear internal loopback
+ */
+ qla81xx_reset_internal_loopback(vha,
+ new_config, 0);
+ }
+
if (response[0] == MBS_COMMAND_ERROR &&
- response[1] == MBS_LB_RESET) {
+ response[1] == MBS_LB_RESET) {
DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing "
- "ISP\n", __func__, vha->host_no));
+ "ISP\n", __func__, vha->host_no));
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
qla2xxx_wake_dpc(vha);
+ qla2x00_wait_for_chip_reset(vha);
+ /* Also reset the MPI */
+ if (qla81xx_restart_mpi_firmware(vha) !=
+ QLA_SUCCESS) {
+ qla_printk(KERN_INFO, ha,
+ "MPI reset failed for host%ld.\n",
+ vha->host_no);
+ }
+
+ bsg_job->reply->reply_payload_rcv_len = 0;
+ bsg_job->reply->result = (DID_ERROR << 16);
+ rval = -EIO;
+ goto done_free_dma_req;
}
+ } else {
+ type = "FC_BSG_HST_VENDOR_LOOPBACK";
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld) bsg rqst type: %s\n",
+ vha->host_no, type));
+ command_sent = INT_DEF_LB_LOOPBACK_CMD;
+ rval = qla2x00_loopback_test(vha, &elreq, response);
}
- } else {
- type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
- DEBUG2(qla_printk(KERN_INFO, ha,
- "scsi(%ld) bsg rqst type: %s\n", vha->host_no, type));
- command_sent = INT_DEF_LB_ECHO_CMD;
- rval = qla2x00_echo_test(vha, &elreq, response);
}
if (rval) {
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index 76ed92dd2ef2..1f096dabc015 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -19,6 +19,13 @@
#define INT_DEF_LB_LOOPBACK_CMD 0
#define INT_DEF_LB_ECHO_CMD 1
+/* Loopback related definations */
+#define EXTERNAL_LOOPBACK 0xF2
+#define ENABLE_INTERNAL_LOOPBACK 0x02
+#define INTERNAL_LOOPBACK_MASK 0x000E
+#define MAX_ELS_FRAME_PAYLOAD 252
+#define ELS_OPCODE_BYTE 0x10
+
/* BSG Vendor specific definations */
#define A84_ISSUE_WRITE_TYPE_CMD 0
#define A84_ISSUE_READ_TYPE_CMD 1
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 839610909018..2bb187e23db0 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -202,6 +202,7 @@ struct sd_dif_tuple {
* SCSI Request Block
*/
typedef struct srb {
+ atomic_t ref_count;
struct fc_port *fcport;
uint32_t handle;
@@ -713,6 +714,8 @@ typedef struct {
#define MBC_SEND_RNFT_ELS 0x5e /* Send RNFT ELS request */
#define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */
#define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */
+#define MBC_SET_PORT_CONFIG 0x122 /* Set port configuration */
+#define MBC_GET_PORT_CONFIG 0x123 /* Get port configuration */
/* Firmware return data sizes */
#define FCAL_MAP_SIZE 128
@@ -2410,6 +2413,7 @@ struct qla_hw_data {
uint32_t cpu_affinity_enabled :1;
uint32_t disable_msix_handshake :1;
uint32_t fcp_prio_enabled :1;
+ uint32_t fw_hung :1;
} flags;
/* This spinlock is used to protect "io transactions", you must
@@ -2630,6 +2634,8 @@ struct qla_hw_data {
struct mutex vport_lock; /* Virtual port synchronization */
struct completion mbx_cmd_comp; /* Serialize mbx access */
struct completion mbx_intr_comp; /* Used for completion notification */
+ struct completion dcbx_comp; /* For set port config notification */
+ int notify_dcbx_comp;
/* Basic firmware related information. */
uint16_t fw_major_version;
@@ -2783,6 +2789,9 @@ struct qla_hw_data {
uint16_t gbl_dsd_avail;
struct list_head gbl_dsd_list;
#define NUM_DSD_CHAIN 4096
+
+ uint8_t fw_type;
+ __le32 file_prd_off; /* File firmware product offset */
};
/*
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 8217c3bcbc2e..7ae2ee42564e 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -357,6 +357,11 @@ qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t);
extern int qla2x00_get_data_rate(scsi_qla_host_t *);
extern int qla24xx_set_fcp_prio(scsi_qla_host_t *, uint16_t, uint16_t,
uint16_t *);
+extern int
+qla81xx_get_port_config(scsi_qla_host_t *, uint16_t *);
+
+extern int
+qla81xx_set_port_config(scsi_qla_host_t *, uint16_t *);
/*
* Global Function Prototypes in qla_isr.c source file.
@@ -513,7 +518,6 @@ extern int qla82xx_nvram_config(struct scsi_qla_host *);
extern int qla82xx_pinit_from_rom(scsi_qla_host_t *);
extern int qla82xx_load_firmware(scsi_qla_host_t *);
extern int qla82xx_reset_hw(scsi_qla_host_t *);
-extern int qla82xx_load_risc_blob(scsi_qla_host_t *, uint32_t *);
extern void qla82xx_watchdog(scsi_qla_host_t *);
/* Firmware and flash related functions */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index ab2cc71994c2..d0b993c8a189 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -60,9 +60,8 @@ qla2x00_ctx_sp_timeout(unsigned long __data)
ctx = sp->ctx;
iocb = ctx->u.iocb_cmd;
iocb->timeout(sp);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
iocb->free(sp);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
void
@@ -122,7 +121,23 @@ done:
/* Asynchronous Login/Logout Routines -------------------------------------- */
-#define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2)
+static inline unsigned long
+qla2x00_get_async_timeout(struct scsi_qla_host *vha)
+{
+ unsigned long tmo;
+ struct qla_hw_data *ha = vha->hw;
+
+ /* Firmware should use switch negotiated r_a_tov for timeout. */
+ tmo = ha->r_a_tov / 10 * 2;
+ if (!IS_FWI2_CAPABLE(ha)) {
+ /*
+ * Except for earlier ISPs where the timeout is seeded from the
+ * initialization control block.
+ */
+ tmo = ha->login_timeout;
+ }
+ return tmo;
+}
static void
qla2x00_async_iocb_timeout(srb_t *sp)
@@ -131,12 +146,22 @@ qla2x00_async_iocb_timeout(srb_t *sp)
struct srb_ctx *ctx = sp->ctx;
DEBUG2(printk(KERN_WARNING
- "scsi(%ld:%x): Async-%s timeout.\n",
- fcport->vha->host_no, sp->handle, ctx->name));
+ "scsi(%ld:%x): Async-%s timeout - portid=%02x%02x%02x.\n",
+ fcport->vha->host_no, sp->handle,
+ ctx->name, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa));
fcport->flags &= ~FCF_ASYNC_SENT;
- if (ctx->type == SRB_LOGIN_CMD)
+ if (ctx->type == SRB_LOGIN_CMD) {
+ struct srb_iocb *lio = ctx->u.iocb_cmd;
qla2x00_post_async_logout_work(fcport->vha, fcport, NULL);
+ /* Retry as needed. */
+ lio->u.logio.data[0] = MBS_COMMAND_ERROR;
+ lio->u.logio.data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
+ QLA_LOGIO_LOGIN_RETRIED : 0;
+ qla2x00_post_async_login_done_work(fcport->vha, fcport,
+ lio->u.logio.data);
+ }
}
static void
@@ -154,7 +179,6 @@ int
qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
{
- struct qla_hw_data *ha = vha->hw;
srb_t *sp;
struct srb_ctx *ctx;
struct srb_iocb *lio;
@@ -162,7 +186,7 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
- ELS_TMO_2_RATOV(ha) + 2);
+ qla2x00_get_async_timeout(vha) + 2);
if (!sp)
goto done;
@@ -206,7 +230,6 @@ qla2x00_async_logout_ctx_done(srb_t *sp)
int
qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
{
- struct qla_hw_data *ha = vha->hw;
srb_t *sp;
struct srb_ctx *ctx;
struct srb_iocb *lio;
@@ -214,7 +237,7 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
- ELS_TMO_2_RATOV(ha) + 2);
+ qla2x00_get_async_timeout(vha) + 2);
if (!sp)
goto done;
@@ -255,7 +278,6 @@ int
qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
{
- struct qla_hw_data *ha = vha->hw;
srb_t *sp;
struct srb_ctx *ctx;
struct srb_iocb *lio;
@@ -263,7 +285,7 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
- ELS_TMO_2_RATOV(ha) + 2);
+ qla2x00_get_async_timeout(vha) + 2);
if (!sp)
goto done;
@@ -307,7 +329,6 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
uint32_t tag)
{
struct scsi_qla_host *vha = fcport->vha;
- struct qla_hw_data *ha = vha->hw;
srb_t *sp;
struct srb_ctx *ctx;
struct srb_iocb *tcf;
@@ -315,7 +336,7 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
- ELS_TMO_2_RATOV(ha) + 2);
+ qla2x00_get_async_timeout(vha) + 2);
if (!sp)
goto done;
@@ -418,10 +439,11 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
else
- qla2x00_mark_device_lost(vha, fcport, 1, 0);
+ qla2x00_mark_device_lost(vha, fcport, 1, 1);
break;
case MBS_PORT_ID_USED:
fcport->loop_id = data[1];
+ qla2x00_post_async_logout_work(vha, fcport, NULL);
qla2x00_post_async_login_work(vha, fcport, NULL);
break;
case MBS_LOOP_ID_USED:
@@ -429,7 +451,7 @@ qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
rval = qla2x00_find_new_loop_id(vha, fcport);
if (rval != QLA_SUCCESS) {
fcport->flags &= ~FCF_ASYNC_SENT;
- qla2x00_mark_device_lost(vha, fcport, 1, 0);
+ qla2x00_mark_device_lost(vha, fcport, 1, 1);
break;
}
qla2x00_post_async_login_work(vha, fcport, NULL);
@@ -461,7 +483,7 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport,
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
else
- qla2x00_mark_device_lost(vha, fcport, 1, 0);
+ qla2x00_mark_device_lost(vha, fcport, 1, 1);
return;
}
@@ -1454,6 +1476,8 @@ qla2x00_setup_chip(scsi_qla_host_t *vha)
rval = ha->isp_ops->load_risc(vha, &srisc_address);
if (rval == QLA_SUCCESS)
goto enable_82xx_npiv;
+ else
+ goto failed;
}
if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
@@ -1960,7 +1984,8 @@ qla2x00_fw_ready(scsi_qla_host_t *vha)
}
} else {
/* Mailbox cmd failed. Timeout on min_wait. */
- if (time_after_eq(jiffies, mtime))
+ if (time_after_eq(jiffies, mtime) ||
+ (IS_QLA82XX(ha) && ha->flags.fw_hung))
break;
}
@@ -2396,7 +2421,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
ha->retry_count = nv->retry_count;
/* Set minimum login_timeout to 4 seconds. */
- if (nv->login_timeout < ql2xlogintimeout)
+ if (nv->login_timeout != ql2xlogintimeout)
nv->login_timeout = ql2xlogintimeout;
if (nv->login_timeout < 4)
nv->login_timeout = 4;
@@ -2639,7 +2664,8 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
if (test_bit(RSCN_UPDATE, &save_flags)) {
set_bit(RSCN_UPDATE, &vha->dpc_flags);
- vha->flags.rscn_queue_overflow = 1;
+ if (!IS_ALOGIO_CAPABLE(ha))
+ vha->flags.rscn_queue_overflow = 1;
}
}
@@ -3197,8 +3223,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
if (qla2x00_is_reserved_id(vha, loop_id))
continue;
- if (atomic_read(&vha->loop_down_timer) ||
- LOOP_TRANSITION(vha)) {
+ if (ha->current_topology == ISP_CFG_FL &&
+ (atomic_read(&vha->loop_down_timer) ||
+ LOOP_TRANSITION(vha))) {
atomic_set(&vha->loop_down_timer, 0);
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 8ef945365412..5d0e99c2b522 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -1683,7 +1683,7 @@ qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx)
struct srb_iocb *lio = ctx->u.iocb_cmd;
uint16_t opts;
- mbx->entry_type = MBX_IOCB_TYPE;;
+ mbx->entry_type = MBX_IOCB_TYPE;
SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT);
opts = lio->u.logio.flags & SRB_LOGIN_COND_PLOGI ? BIT_0 : 0;
@@ -1718,7 +1718,7 @@ qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx)
{
struct qla_hw_data *ha = sp->fcport->vha->hw;
- mbx->entry_type = MBX_IOCB_TYPE;;
+ mbx->entry_type = MBX_IOCB_TYPE;
SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT);
mbx->mb1 = HAS_EXTENDED_IDS(ha) ?
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index be3d8bed2ecf..8a608725eb76 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -545,10 +545,13 @@ skip_rio:
if (IS_QLA2100(ha))
break;
- if (IS_QLA8XXX_TYPE(ha))
+ if (IS_QLA8XXX_TYPE(ha)) {
DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x "
"%04x\n", vha->host_no, mb[1], mb[2], mb[3]));
- else
+ if (ha->notify_dcbx_comp)
+ complete(&ha->dcbx_comp);
+
+ } else
DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE "
"received.\n", vha->host_no));
@@ -918,12 +921,15 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
QLA_LOGIO_LOGIN_RETRIED : 0;
if (mbx->entry_status) {
DEBUG2(printk(KERN_WARNING
- "scsi(%ld:%x): Async-%s error entry - entry-status=%x "
- "status=%x state-flag=%x status-flags=%x.\n",
+ "scsi(%ld:%x): Async-%s error entry - portid=%02x%02x%02x "
+ "entry-status=%x status=%x state-flag=%x "
+ "status-flags=%x.\n",
fcport->vha->host_no, sp->handle, type,
- mbx->entry_status, le16_to_cpu(mbx->status),
- le16_to_cpu(mbx->state_flags),
+ fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa, mbx->entry_status,
+ le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags),
le16_to_cpu(mbx->status_flags)));
+
DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx)));
goto logio_done;
@@ -935,16 +941,18 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
status = 0;
if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
DEBUG2(printk(KERN_DEBUG
- "scsi(%ld:%x): Async-%s complete - mbx1=%x.\n",
+ "scsi(%ld:%x): Async-%s complete - portid=%02x%02x%02x "
+ "mbx1=%x.\n",
fcport->vha->host_no, sp->handle, type,
- le16_to_cpu(mbx->mb1)));
+ fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa, le16_to_cpu(mbx->mb1)));
data[0] = MBS_COMMAND_COMPLETE;
if (ctx->type == SRB_LOGIN_CMD) {
fcport->port_type = FCT_TARGET;
if (le16_to_cpu(mbx->mb1) & BIT_0)
fcport->port_type = FCT_INITIATOR;
- if (le16_to_cpu(mbx->mb1) & BIT_1)
+ else if (le16_to_cpu(mbx->mb1) & BIT_1)
fcport->flags |= FCF_FCP2_DEVICE;
}
goto logio_done;
@@ -963,9 +971,10 @@ qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
}
DEBUG2(printk(KERN_WARNING
- "scsi(%ld:%x): Async-%s failed - status=%x mb0=%x mb1=%x mb2=%x "
- "mb6=%x mb7=%x.\n",
- fcport->vha->host_no, sp->handle, type, status,
+ "scsi(%ld:%x): Async-%s failed - portid=%02x%02x%02x status=%x "
+ "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n",
+ fcport->vha->host_no, sp->handle, type, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa, status,
le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
le16_to_cpu(mbx->mb7)));
@@ -1096,9 +1105,11 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
QLA_LOGIO_LOGIN_RETRIED : 0;
if (logio->entry_status) {
DEBUG2(printk(KERN_WARNING
- "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n",
+ "scsi(%ld:%x): Async-%s error entry - "
+ "portid=%02x%02x%02x entry-status=%x.\n",
fcport->vha->host_no, sp->handle, type,
- logio->entry_status));
+ fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa, logio->entry_status));
DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio)));
goto logio_done;
@@ -1106,8 +1117,11 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
DEBUG2(printk(KERN_DEBUG
- "scsi(%ld:%x): Async-%s complete - iop0=%x.\n",
+ "scsi(%ld:%x): Async-%s complete - portid=%02x%02x%02x "
+ "iop0=%x.\n",
fcport->vha->host_no, sp->handle, type,
+ fcport->d_id.b.domain, fcport->d_id.b.area,
+ fcport->d_id.b.al_pa,
le32_to_cpu(logio->io_parameter[0])));
data[0] = MBS_COMMAND_COMPLETE;
@@ -1119,9 +1133,9 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
fcport->port_type = FCT_TARGET;
if (iop[0] & BIT_8)
fcport->flags |= FCF_FCP2_DEVICE;
- }
- if (iop[0] & BIT_5)
+ } else if (iop[0] & BIT_5)
fcport->port_type = FCT_INITIATOR;
+
if (logio->io_parameter[7] || logio->io_parameter[8])
fcport->supported_classes |= FC_COS_CLASS2;
if (logio->io_parameter[9] || logio->io_parameter[10])
@@ -1152,8 +1166,10 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
}
DEBUG2(printk(KERN_WARNING
- "scsi(%ld:%x): Async-%s failed - comp=%x iop0=%x iop1=%x.\n",
- fcport->vha->host_no, sp->handle, type,
+ "scsi(%ld:%x): Async-%s failed - portid=%02x%02x%02x comp=%x "
+ "iop0=%x iop1=%x.\n",
+ fcport->vha->host_no, sp->handle, type, fcport->d_id.b.domain,
+ fcport->d_id.b.area, fcport->d_id.b.al_pa,
le16_to_cpu(logio->comp_status),
le32_to_cpu(logio->io_parameter[0]),
le32_to_cpu(logio->io_parameter[1])));
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index f3650d0434ca..2f39e3093939 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -37,7 +37,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
device_reg_t __iomem *reg;
uint8_t abort_active;
uint8_t io_lock_on;
- uint16_t command;
+ uint16_t command = 0;
uint16_t *iptr;
uint16_t __iomem *optr;
uint32_t cnt;
@@ -83,6 +83,13 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
return QLA_FUNCTION_TIMEOUT;
}
+ if (IS_QLA82XX(ha) && ha->flags.fw_hung) {
+ /* Setting Link-Down error */
+ mcp->mb[0] = MBS_LINK_DOWN_ERROR;
+ rval = QLA_FUNCTION_FAILED;
+ goto premature_exit;
+ }
+
ha->flags.mbox_busy = 1;
/* Save mailbox command for debug */
ha->mcp = mcp;
@@ -151,7 +158,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
DEBUG2_3_11(printk(KERN_INFO
"%s(%ld): Pending Mailbox timeout. "
"Exiting.\n", __func__, base_vha->host_no));
- return QLA_FUNCTION_TIMEOUT;
+ rval = QLA_FUNCTION_TIMEOUT;
+ goto premature_exit;
}
WRT_REG_DWORD(&reg->isp82.hint, HINT_MBX_INT_PENDING);
} else if (IS_FWI2_CAPABLE(ha))
@@ -176,7 +184,8 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
DEBUG2_3_11(printk(KERN_INFO
"%s(%ld): Pending Mailbox timeout. "
"Exiting.\n", __func__, base_vha->host_no));
- return QLA_FUNCTION_TIMEOUT;
+ rval = QLA_FUNCTION_TIMEOUT;
+ goto premature_exit;
}
WRT_REG_DWORD(&reg->isp82.hint, HINT_MBX_INT_PENDING);
} else if (IS_FWI2_CAPABLE(ha))
@@ -214,6 +223,15 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
ha->flags.mbox_int = 0;
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+ if (IS_QLA82XX(ha) && ha->flags.fw_hung) {
+ ha->flags.mbox_busy = 0;
+ /* Setting Link-Down error */
+ mcp->mb[0] = MBS_LINK_DOWN_ERROR;
+ ha->mcp = NULL;
+ rval = QLA_FUNCTION_FAILED;
+ goto premature_exit;
+ }
+
if (ha->mailbox_out[0] != MBS_COMMAND_COMPLETE)
rval = QLA_FUNCTION_FAILED;
@@ -279,35 +297,51 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
DEBUG2_3_11(printk("%s(%ld): timeout schedule "
"isp_abort_needed.\n", __func__,
base_vha->host_no));
- qla_printk(KERN_WARNING, ha,
- "Mailbox command timeout occurred. Scheduling ISP "
- "abort. eeh_busy: 0x%x\n", ha->flags.eeh_busy);
- set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
- qla2xxx_wake_dpc(vha);
+
+ if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
+ !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
+ !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+
+ qla_printk(KERN_WARNING, ha,
+ "Mailbox command timeout occured. "
+ "Scheduling ISP " "abort. eeh_busy: 0x%x\n",
+ ha->flags.eeh_busy);
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+ }
} else if (!abort_active) {
/* call abort directly since we are in the DPC thread */
DEBUG(printk("%s(%ld): timeout calling abort_isp\n",
__func__, base_vha->host_no));
DEBUG2_3_11(printk("%s(%ld): timeout calling "
"abort_isp\n", __func__, base_vha->host_no));
- qla_printk(KERN_WARNING, ha,
- "Mailbox command timeout occurred. Issuing ISP "
- "abort.\n");
-
- set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
- clear_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
- if (ha->isp_ops->abort_isp(base_vha)) {
- /* Failed. retry later. */
- set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
+
+ if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) &&
+ !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) &&
+ !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
+
+ qla_printk(KERN_WARNING, ha,
+ "Mailbox command timeout occured. "
+ "Issuing ISP abort.\n");
+
+ set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
+ clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ if (ha->isp_ops->abort_isp(vha)) {
+ /* Failed. retry later. */
+ set_bit(ISP_ABORT_NEEDED,
+ &vha->dpc_flags);
+ }
+ clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags);
+ DEBUG(printk("%s(%ld): finished abort_isp\n",
+ __func__, vha->host_no));
+ DEBUG2_3_11(printk(
+ "%s(%ld): finished abort_isp\n",
+ __func__, vha->host_no));
}
- clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags);
- DEBUG(printk("%s(%ld): finished abort_isp\n", __func__,
- base_vha->host_no));
- DEBUG2_3_11(printk("%s(%ld): finished abort_isp\n",
- __func__, base_vha->host_no));
}
}
+premature_exit:
/* Allow next mbx cmd to come in. */
complete(&ha->mbx_cmd_comp);
@@ -866,8 +900,8 @@ qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag)
l = l;
vha = fcport->vha;
- req = vha->hw->req_q_map[tag];
- rsp = vha->hw->rsp_q_map[tag];
+ req = vha->hw->req_q_map[0];
+ rsp = req->rsp;
mcp->mb[0] = MBC_ABORT_TARGET;
mcp->out_mb = MBX_9|MBX_2|MBX_1|MBX_0;
if (HAS_EXTENDED_IDS(vha->hw)) {
@@ -915,8 +949,8 @@ qla2x00_lun_reset(struct fc_port *fcport, unsigned int l, int tag)
DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->vha->host_no));
vha = fcport->vha;
- req = vha->hw->req_q_map[tag];
- rsp = vha->hw->rsp_q_map[tag];
+ req = vha->hw->req_q_map[0];
+ rsp = req->rsp;
mcp->mb[0] = MBC_LUN_RESET;
mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0;
if (HAS_EXTENDED_IDS(vha->hw))
@@ -3950,6 +3984,72 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
}
int
+qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ struct qla_hw_data *ha = vha->hw;
+
+ DEBUG11(printk(KERN_INFO
+ "%s(%ld): entered.\n", __func__, vha->host_no));
+
+ if (!IS_QLA81XX(ha))
+ return QLA_FUNCTION_FAILED;
+ mcp->mb[0] = MBC_GET_PORT_CONFIG;
+ mcp->out_mb = MBX_0;
+ mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk(KERN_WARNING
+ "%s(%ld): failed=%x (%x).\n", __func__,
+ vha->host_no, rval, mcp->mb[0]));
+ } else {
+ /* Copy all bits to preserve original value */
+ memcpy(mb, &mcp->mb[1], sizeof(uint16_t) * 4);
+
+ DEBUG11(printk(KERN_INFO
+ "%s(%ld): done.\n", __func__, vha->host_no));
+ }
+ return rval;
+}
+
+int
+qla81xx_set_port_config(scsi_qla_host_t *vha, uint16_t *mb)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ DEBUG11(printk(KERN_INFO
+ "%s(%ld): entered.\n", __func__, vha->host_no));
+
+ mcp->mb[0] = MBC_SET_PORT_CONFIG;
+ /* Copy all bits to preserve original setting */
+ memcpy(&mcp->mb[1], mb, sizeof(uint16_t) * 4);
+ mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_0;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(vha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk(KERN_WARNING
+ "%s(%ld): failed=%x (%x).\n", __func__,
+ vha->host_no, rval, mcp->mb[0]));
+ } else
+ DEBUG11(printk(KERN_INFO
+ "%s(%ld): done.\n", __func__, vha->host_no));
+
+ return rval;
+}
+
+
+int
qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority,
uint16_t *mb)
{
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 8220e7b9799b..d1618b4a5e50 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -136,7 +136,8 @@ qla24xx_enable_vp(scsi_qla_host_t *vha)
/* Check if physical ha port is Up */
if (atomic_read(&base_vha->loop_state) == LOOP_DOWN ||
- atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
+ atomic_read(&base_vha->loop_state) == LOOP_DEAD ||
+ !(ha->current_topology & ISP_CFG_F)) {
vha->vp_err_state = VP_ERR_PORTDWN;
fc_vport_set_state(vha->fc_vport, FC_VPORT_LINKDOWN);
goto enable_failed;
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index ff562de0e8e7..e3e3ebdfe5d9 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -19,6 +19,7 @@
#define QLA82XX_PCI_OCM0_2M (0xc0000)
#define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800)
#define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
+#define BLOCK_PROTECT_BITS 0x0F
/* CRB window related */
#define CRB_BLK(off) ((off >> 20) & 0x3f)
@@ -1407,7 +1408,8 @@ qla82xx_fw_load_from_flash(struct qla_hw_data *ha)
{
int i;
long size = 0;
- long flashaddr = BOOTLD_START, memaddr = BOOTLD_START;
+ long flashaddr = ha->flt_region_bootload << 2;
+ long memaddr = BOOTLD_START;
u64 data;
u32 high, low;
size = (IMAGE_START - BOOTLD_START) / 8;
@@ -1677,6 +1679,94 @@ qla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
return ret;
}
+static struct qla82xx_uri_table_desc *
+qla82xx_get_table_desc(const u8 *unirom, int section)
+{
+ uint32_t i;
+ struct qla82xx_uri_table_desc *directory =
+ (struct qla82xx_uri_table_desc *)&unirom[0];
+ __le32 offset;
+ __le32 tab_type;
+ __le32 entries = cpu_to_le32(directory->num_entries);
+
+ for (i = 0; i < entries; i++) {
+ offset = cpu_to_le32(directory->findex) +
+ (i * cpu_to_le32(directory->entry_size));
+ tab_type = cpu_to_le32(*((u32 *)&unirom[offset] + 8));
+
+ if (tab_type == section)
+ return (struct qla82xx_uri_table_desc *)&unirom[offset];
+ }
+
+ return NULL;
+}
+
+static struct qla82xx_uri_data_desc *
+qla82xx_get_data_desc(struct qla_hw_data *ha,
+ u32 section, u32 idx_offset)
+{
+ const u8 *unirom = ha->hablob->fw->data;
+ int idx = cpu_to_le32(*((int *)&unirom[ha->file_prd_off] + idx_offset));
+ struct qla82xx_uri_table_desc *tab_desc = NULL;
+ __le32 offset;
+
+ tab_desc = qla82xx_get_table_desc(unirom, section);
+ if (!tab_desc)
+ return NULL;
+
+ offset = cpu_to_le32(tab_desc->findex) +
+ (cpu_to_le32(tab_desc->entry_size) * idx);
+
+ return (struct qla82xx_uri_data_desc *)&unirom[offset];
+}
+
+static u8 *
+qla82xx_get_bootld_offset(struct qla_hw_data *ha)
+{
+ u32 offset = BOOTLD_START;
+ struct qla82xx_uri_data_desc *uri_desc = NULL;
+
+ if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
+ uri_desc = qla82xx_get_data_desc(ha,
+ QLA82XX_URI_DIR_SECT_BOOTLD, QLA82XX_URI_BOOTLD_IDX_OFF);
+ if (uri_desc)
+ offset = cpu_to_le32(uri_desc->findex);
+ }
+
+ return (u8 *)&ha->hablob->fw->data[offset];
+}
+
+static __le32
+qla82xx_get_fw_size(struct qla_hw_data *ha)
+{
+ struct qla82xx_uri_data_desc *uri_desc = NULL;
+
+ if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
+ uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW,
+ QLA82XX_URI_FIRMWARE_IDX_OFF);
+ if (uri_desc)
+ return cpu_to_le32(uri_desc->size);
+ }
+
+ return cpu_to_le32(*(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]);
+}
+
+static u8 *
+qla82xx_get_fw_offs(struct qla_hw_data *ha)
+{
+ u32 offset = IMAGE_START;
+ struct qla82xx_uri_data_desc *uri_desc = NULL;
+
+ if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
+ uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW,
+ QLA82XX_URI_FIRMWARE_IDX_OFF);
+ if (uri_desc)
+ offset = cpu_to_le32(uri_desc->findex);
+ }
+
+ return (u8 *)&ha->hablob->fw->data[offset];
+}
+
/* PCI related functions */
char *
qla82xx_pci_info_str(struct scsi_qla_host *vha, char *str)
@@ -1878,19 +1968,19 @@ int qla82xx_fw_load_from_blob(struct qla_hw_data *ha)
size = (IMAGE_START - BOOTLD_START) / 8;
- ptr64 = (u64 *)&ha->hablob->fw->data[BOOTLD_START];
+ ptr64 = (u64 *)qla82xx_get_bootld_offset(ha);
flashaddr = BOOTLD_START;
for (i = 0; i < size; i++) {
data = cpu_to_le64(ptr64[i]);
- qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8);
+ if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8))
+ return -EIO;
flashaddr += 8;
}
- size = *(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET];
- size = (__force u32)cpu_to_le32(size) / 8;
- ptr64 = (u64 *)&ha->hablob->fw->data[IMAGE_START];
flashaddr = FLASH_ADDR_START;
+ size = (__force u32)qla82xx_get_fw_size(ha) / 8;
+ ptr64 = (u64 *)qla82xx_get_fw_offs(ha);
for (i = 0; i < size; i++) {
data = cpu_to_le64(ptr64[i]);
@@ -1899,19 +1989,88 @@ int qla82xx_fw_load_from_blob(struct qla_hw_data *ha)
return -EIO;
flashaddr += 8;
}
+ udelay(100);
/* Write a magic value to CAMRAM register
* at a specified offset to indicate
* that all data is written and
* ready for firmware to initialize.
*/
- qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), 0x12345678);
+ qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), QLA82XX_BDINFO_MAGIC);
+ read_lock(&ha->hw_lock);
if (QLA82XX_IS_REVISION_P3PLUS(ha->chip_revision)) {
qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
} else
qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001d);
+ read_unlock(&ha->hw_lock);
+ return 0;
+}
+
+static int
+qla82xx_set_product_offset(struct qla_hw_data *ha)
+{
+ struct qla82xx_uri_table_desc *ptab_desc = NULL;
+ const uint8_t *unirom = ha->hablob->fw->data;
+ uint32_t i;
+ __le32 entries;
+ __le32 flags, file_chiprev, offset;
+ uint8_t chiprev = ha->chip_revision;
+ /* Hardcoding mn_present flag for P3P */
+ int mn_present = 0;
+ uint32_t flagbit;
+
+ ptab_desc = qla82xx_get_table_desc(unirom,
+ QLA82XX_URI_DIR_SECT_PRODUCT_TBL);
+ if (!ptab_desc)
+ return -1;
+
+ entries = cpu_to_le32(ptab_desc->num_entries);
+
+ for (i = 0; i < entries; i++) {
+ offset = cpu_to_le32(ptab_desc->findex) +
+ (i * cpu_to_le32(ptab_desc->entry_size));
+ flags = cpu_to_le32(*((int *)&unirom[offset] +
+ QLA82XX_URI_FLAGS_OFF));
+ file_chiprev = cpu_to_le32(*((int *)&unirom[offset] +
+ QLA82XX_URI_CHIP_REV_OFF));
+
+ flagbit = mn_present ? 1 : 2;
+
+ if ((chiprev == file_chiprev) && ((1ULL << flagbit) & flags)) {
+ ha->file_prd_off = offset;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+int
+qla82xx_validate_firmware_blob(scsi_qla_host_t *vha, uint8_t fw_type)
+{
+ __le32 val;
+ uint32_t min_size;
+ struct qla_hw_data *ha = vha->hw;
+ const struct firmware *fw = ha->hablob->fw;
+
+ ha->fw_type = fw_type;
+
+ if (fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
+ if (qla82xx_set_product_offset(ha))
+ return -EINVAL;
+
+ min_size = QLA82XX_URI_FW_MIN_SIZE;
+ } else {
+ val = cpu_to_le32(*(u32 *)&fw->data[QLA82XX_FW_MAGIC_OFFSET]);
+ if ((__force u32)val != QLA82XX_BDINFO_MAGIC)
+ return -EINVAL;
+
+ min_size = QLA82XX_FW_MIN_SIZE;
+ }
+
+ if (fw->size < min_size)
+ return -EINVAL;
return 0;
}
@@ -2470,6 +2629,18 @@ try_blob_fw:
goto fw_load_failed;
}
+ /* Validating firmware blob */
+ if (qla82xx_validate_firmware_blob(vha,
+ QLA82XX_FLASH_ROMIMAGE)) {
+ /* Fallback to URI format */
+ if (qla82xx_validate_firmware_blob(vha,
+ QLA82XX_UNIFIED_ROMIMAGE)) {
+ qla_printk(KERN_ERR, ha,
+ "No valid firmware image found!!!");
+ return QLA_FUNCTION_FAILED;
+ }
+ }
+
if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) {
qla_printk(KERN_ERR, ha,
"%s: Firmware loaded successfully "
@@ -2977,10 +3148,10 @@ qla82xx_unprotect_flash(struct qla_hw_data *ha)
if (ret < 0)
goto done_unprotect;
- val &= ~(0x7 << 2);
+ val &= ~(BLOCK_PROTECT_BITS << 2);
ret = qla82xx_write_status_reg(ha, val);
if (ret < 0) {
- val |= (0x7 << 2);
+ val |= (BLOCK_PROTECT_BITS << 2);
qla82xx_write_status_reg(ha, val);
}
@@ -3008,7 +3179,7 @@ qla82xx_protect_flash(struct qla_hw_data *ha)
if (ret < 0)
goto done_protect;
- val |= (0x7 << 2);
+ val |= (BLOCK_PROTECT_BITS << 2);
/* LOCK all sectors */
ret = qla82xx_write_status_reg(ha, val);
if (ret < 0)
@@ -3201,11 +3372,16 @@ qla82xx_start_iocbs(srb_t *sp)
dbval = 0x04 | (ha->portnum << 5);
dbval = dbval | (req->id << 8) | (req->ring_index << 16);
- WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval);
- wmb();
- while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) {
- WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval);
+ if (ql2xdbwr)
+ qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval);
+ else {
+ WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval);
wmb();
+ while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) {
+ WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr,
+ dbval);
+ wmb();
+ }
}
}
@@ -3279,6 +3455,10 @@ qla82xx_dev_failed_handler(scsi_qla_host_t *vha)
/* Disable the board */
qla_printk(KERN_INFO, ha, "Disabling the board\n");
+ qla82xx_idc_lock(ha);
+ qla82xx_clear_drv_active(ha);
+ qla82xx_idc_unlock(ha);
+
/* Set DEV_FAILED flag to disable timer */
vha->device_flags |= DFLG_DEV_FAILED;
qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
@@ -3369,6 +3549,14 @@ qla82xx_check_fw_alive(scsi_qla_host_t *vha)
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
}
qla2xxx_wake_dpc(vha);
+ if (ha->flags.mbox_busy) {
+ ha->flags.fw_hung = 1;
+ ha->flags.mbox_int = 1;
+ DEBUG2(qla_printk(KERN_ERR, ha,
+ "Due to fw hung, doing premature "
+ "completion of mbx command\n"));
+ complete(&ha->mbx_intr_comp);
+ }
}
}
vha->fw_heartbeat_counter = fw_heartbeat_counter;
@@ -3472,6 +3660,14 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
"%s(): Adapter reset needed!\n", __func__);
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
qla2xxx_wake_dpc(vha);
+ if (ha->flags.mbox_busy) {
+ ha->flags.fw_hung = 1;
+ ha->flags.mbox_int = 1;
+ DEBUG2(qla_printk(KERN_ERR, ha,
+ "Need reset, doing premature "
+ "completion of mbx command\n"));
+ complete(&ha->mbx_intr_comp);
+ }
} else {
qla82xx_check_fw_alive(vha);
}
@@ -3527,8 +3723,10 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
qla82xx_clear_rst_ready(ha);
qla82xx_idc_unlock(ha);
- if (rval == QLA_SUCCESS)
+ if (rval == QLA_SUCCESS) {
+ ha->flags.fw_hung = 0;
qla82xx_restart_isp(vha);
+ }
if (rval) {
vha->flags.online = 1;
diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h
index f8f99a5ea532..9a9127efadaf 100644
--- a/drivers/scsi/qla2xxx/qla_nx.h
+++ b/drivers/scsi/qla2xxx/qla_nx.h
@@ -538,11 +538,10 @@
/* Driver Coexistence Defines */
#define QLA82XX_CRB_DRV_ACTIVE (QLA82XX_CAM_RAM(0x138))
#define QLA82XX_CRB_DEV_STATE (QLA82XX_CAM_RAM(0x140))
-#define QLA82XX_CRB_DEV_PART_INFO (QLA82XX_CAM_RAM(0x14c))
-#define QLA82XX_CRB_DRV_IDC_VERSION (QLA82XX_CAM_RAM(0x174))
#define QLA82XX_CRB_DRV_STATE (QLA82XX_CAM_RAM(0x144))
#define QLA82XX_CRB_DRV_SCRATCH (QLA82XX_CAM_RAM(0x148))
#define QLA82XX_CRB_DEV_PART_INFO (QLA82XX_CAM_RAM(0x14c))
+#define QLA82XX_CRB_DRV_IDC_VERSION (QLA82XX_CAM_RAM(0x174))
/* Every driver should use these Device State */
#define QLA82XX_DEV_COLD 1
@@ -774,13 +773,48 @@ struct qla82xx_legacy_intr_set {
.pci_int_reg = ISR_MSI_INT_TRIGGER(7) }, \
}
+#define BRDCFG_START 0x4000
#define BOOTLD_START 0x10000
#define IMAGE_START 0x100000
#define FLASH_ADDR_START 0x43000
/* Magic number to let user know flash is programmed */
#define QLA82XX_BDINFO_MAGIC 0x12345678
+#define QLA82XX_FW_MAGIC_OFFSET (BRDCFG_START + 0x128)
#define FW_SIZE_OFFSET (0x3e840c)
+#define QLA82XX_FW_MIN_SIZE 0x3fffff
+
+/* UNIFIED ROMIMAGE START */
+#define QLA82XX_URI_FW_MIN_SIZE 0xc8000
+#define QLA82XX_URI_DIR_SECT_PRODUCT_TBL 0x0
+#define QLA82XX_URI_DIR_SECT_BOOTLD 0x6
+#define QLA82XX_URI_DIR_SECT_FW 0x7
+
+/* Offsets */
+#define QLA82XX_URI_CHIP_REV_OFF 10
+#define QLA82XX_URI_FLAGS_OFF 11
+#define QLA82XX_URI_BIOS_VERSION_OFF 12
+#define QLA82XX_URI_BOOTLD_IDX_OFF 27
+#define QLA82XX_URI_FIRMWARE_IDX_OFF 29
+
+struct qla82xx_uri_table_desc{
+ uint32_t findex;
+ uint32_t num_entries;
+ uint32_t entry_size;
+ uint32_t reserved[5];
+};
+
+struct qla82xx_uri_data_desc{
+ uint32_t findex;
+ uint32_t size;
+ uint32_t reserved[5];
+};
+
+/* UNIFIED ROMIMAGE END */
+
+#define QLA82XX_UNIFIED_ROMIMAGE 3
+#define QLA82XX_FLASH_ROMIMAGE 4
+#define QLA82XX_UNKNOWN_ROMIMAGE 0xff
#define QLA82XX_IS_REVISION_P3PLUS(_rev_) ((_rev_) >= 0x50)
#define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0)
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index be1a8fcbb1fb..5be8db748964 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -140,7 +140,7 @@ MODULE_PARM_DESC(ql2xetsenable,
"Enables firmware ETS burst."
"Default is 0 - skip ETS enablement.");
-int ql2xdbwr;
+int ql2xdbwr = 1;
module_param(ql2xdbwr, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xdbwr,
"Option to specify scheme for request queue posting\n"
@@ -517,6 +517,7 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport,
if (!sp)
return sp;
+ atomic_set(&sp->ref_count, 1);
sp->fcport = fcport;
sp->cmd = cmd;
sp->flags = 0;
@@ -797,6 +798,12 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha)
return (return_status);
}
+static void
+sp_get(struct srb *sp)
+{
+ atomic_inc(&sp->ref_count);
+}
+
/**************************************************************************
* qla2xxx_eh_abort
*
@@ -825,6 +832,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = vha->req;
srb_t *spt;
+ int got_ref = 0;
fc_block_scsi_eh(cmd);
@@ -856,6 +864,10 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
DEBUG2(printk("%s(%ld): aborting sp %p from RISC."
" pid=%ld.\n", __func__, vha->host_no, sp, serial));
+ /* Get a reference to the sp and drop the lock.*/
+ sp_get(sp);
+ got_ref++;
+
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (ha->isp_ops->abort_command(sp)) {
DEBUG2(printk("%s(%ld): abort_command "
@@ -881,6 +893,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
}
}
+ if (got_ref)
+ qla2x00_sp_compl(ha, sp);
+
qla_printk(KERN_INFO, ha,
"scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n",
vha->host_no, id, lun, wait, serial, ret);
@@ -1662,7 +1677,7 @@ static struct isp_operations qla81xx_isp_ops = {
.read_optrom = qla25xx_read_optrom_data,
.write_optrom = qla24xx_write_optrom_data,
.get_flash_version = qla24xx_get_flash_version,
- .start_scsi = qla24xx_start_scsi,
+ .start_scsi = qla24xx_dif_start_scsi,
.abort_isp = qla2x00_abort_isp,
};
@@ -2113,6 +2128,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
init_completion(&ha->mbx_cmd_comp);
complete(&ha->mbx_cmd_comp);
init_completion(&ha->mbx_intr_comp);
+ init_completion(&ha->dcbx_comp);
set_bit(0, (unsigned long *) ha->vp_idx_map);
@@ -2258,7 +2274,7 @@ skip_dpc:
DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
base_vha->host_no, ha));
- if (IS_QLA25XX(ha) && ql2xenabledif) {
+ if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && ql2xenabledif) {
if (ha->fw_attributes & BIT_4) {
base_vha->flags.difdix_supported = 1;
DEBUG18(qla_printk(KERN_INFO, ha,
@@ -2402,6 +2418,10 @@ qla2x00_remove_one(struct pci_dev *pdev)
scsi_host_put(base_vha->host);
if (IS_QLA82XX(ha)) {
+ qla82xx_idc_lock(ha);
+ qla82xx_clear_drv_active(ha);
+ qla82xx_idc_unlock(ha);
+
iounmap((device_reg_t __iomem *)ha->nx_pcibase);
if (!ql2xdbwr)
iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr);
@@ -3464,7 +3484,7 @@ qla2x00_sp_free_dma(srb_t *sp)
}
void
-qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
+qla2x00_sp_final_compl(struct qla_hw_data *ha, srb_t *sp)
{
struct scsi_cmnd *cmd = sp->cmd;
@@ -3485,6 +3505,20 @@ qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
cmd->scsi_done(cmd);
}
+void
+qla2x00_sp_compl(struct qla_hw_data *ha, srb_t *sp)
+{
+ if (atomic_read(&sp->ref_count) == 0) {
+ DEBUG2(qla_printk(KERN_WARNING, ha,
+ "SP reference-count to ZERO -- sp=%p\n", sp));
+ DEBUG2(BUG());
+ return;
+ }
+ if (!atomic_dec_and_test(&sp->ref_count))
+ return;
+ qla2x00_sp_final_compl(ha, sp);
+}
+
/**************************************************************************
* qla2x00_timer
*
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 109068df933f..9b49b0862747 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.03.02-k2"
+#define QLA2XXX_VERSION "8.03.03-k0"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 3
-#define QLA_DRIVER_PATCH_VER 2
-#define QLA_DRIVER_BETA_VER 2
+#define QLA_DRIVER_PATCH_VER 3
+#define QLA_DRIVER_BETA_VER 0