aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/mpt2sas/mpt2sas_scsih.c
diff options
context:
space:
mode:
authorKashyap, Desai <kashyap.desai@lsi.com>2011-04-07 12:32:49 +0530
committerJames Bottomley <James.Bottomley@suse.de>2011-05-01 10:36:54 -0500
commit0bdccdb0a090ad8dc5f851cad5e843244c410ee8 (patch)
tree9380059a38551f6b4e208f897a6f04760e6f101f /drivers/scsi/mpt2sas/mpt2sas_scsih.c
parentaeaeb5cec5a5477b392e627883fdb46d8a5dcc1f (diff)
downloadkernel_samsung_smdk4412-0bdccdb0a090ad8dc5f851cad5e843244c410ee8.zip
kernel_samsung_smdk4412-0bdccdb0a090ad8dc5f851cad5e843244c410ee8.tar.gz
kernel_samsung_smdk4412-0bdccdb0a090ad8dc5f851cad5e843244c410ee8.tar.bz2
[SCSI] mpt2sas : WarpDrive New product SSS6200 support added
This patch has Support for the new solid state device product SSS6200 from LSI and relavent features w.r.t SSS6200. The major feature added in this driver is supporting Direct-I/O to the SSS6200 storage.There are some additional changes done to avoid exposing the RAID member disks to the OS and hiding/exposing drives based on the OEM Specific Flag in Manufacturing Page10 (this is required to handle specific changes in the SSS6200 firmware). Each and every changes are listed below. 1. Hiding IR related messages. For SSS6200, the driver is modified not to print IR related events. Even if the debugging is enabled the IR related messages will not be displayed. In some places if there is a need to display a message related to IR the string "IR" is replaced with string "DD" and the string "volume" is replaced with "direct drive". But the function names are not changed hence there are some places where the reference to volume can be seen if debug level is set. 2. Removed RAID transport support In Linux the user can retrieve RAID volume information from the sysfs directory. This support is removed for SSS6200. 3. Direct I/O support. The driver tries to enable direct I/O when a volume is reported to the driver by the firmware through IRCC events and the driver does this just before reporting to the OS, hence all the OS issued I/O can go through direct path if they can, The first validation is to see whether the manufacturing page10 flag is set to expose all drives always. If that is set, the driver will not enable direct I/O and displays the message "DDIO" is disabled globally as drives are exposed. The driver checks whether there is more than one volume in the controller, if so the direct I/O will be disabled globally for all volumes in the controller and the message displayed will be "DDIO is disabled globally as number of drives > 1. If retrieving number of PD is failed the driver will not enable direct I/O and displays the message Failure in computing number of drives DDIO disabled. If memory allocation for RAIDVolumePage0 is failed, the driver will not enable direct I/O and displays the message Memory allocation failure for RVPG0 DDIO disabled. If retrieving RAIDVolumePage0 is failed the driver will not enable direct I/O and displays the message Failure in retrieving RVPG0 DDIO disabled If the number of PD in a volume is greater than 8, then the direct I/O will be disabled. If any of individual drives handle retrieval is failed then the DD-IO will be disabled. If the volume is not RAID0 or if the block size is not 512 then the DD-IO will be disabled. If the volume size is greater than 2TB then the DD-IO will be disabled. If the driver is not able to find a valid stripe exponent using the configured stripe size then the DD-IO will be disabled When the DD-IO is enabled the driver will check every I/O request issued to the storage and checks whether the request is either READ6/WRITE6/READ10/WRITE10, if it is and if the complete I/O transfer is within a stripe size then the I/O is redirected to the drive directly instead of the volume. On completion of every I/O, if the completion is failure means if the reply is address reply with a reply frame associated with it, then the type of I/O will be checked, if the I/O is direct then the I/O will be retried to the volume once. Signed-off-by: Kashyap Desai <kashyap.desai@lsi.com> Reviewed-by: Eric Moore <eric.moore@lsi.com> Reviewed-by: Sathya Prakash <sathya.prakash@lsi.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/mpt2sas/mpt2sas_scsih.c')
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c614
1 files changed, 556 insertions, 58 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 33723ed..f12e023 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -233,6 +233,9 @@ static struct pci_device_id scsih_pci_table[] = {
PCI_ANY_ID, PCI_ANY_ID },
{ MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
PCI_ANY_ID, PCI_ANY_ID },
+ /* SSS6200 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200,
+ PCI_ANY_ID, PCI_ANY_ID },
{0} /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, scsih_pci_table);
@@ -1256,6 +1259,7 @@ _scsih_target_alloc(struct scsi_target *starget)
sas_target_priv_data->handle = raid_device->handle;
sas_target_priv_data->sas_address = raid_device->wwid;
sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
+ sas_target_priv_data->raid_device = raid_device;
raid_device->starget = starget;
}
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
@@ -1455,7 +1459,10 @@ static int
_scsih_is_raid(struct device *dev)
{
struct scsi_device *sdev = to_scsi_device(dev);
+ struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
+ if (ioc->is_warpdrive)
+ return 0;
return (sdev->channel == RAID_CHANNEL) ? 1 : 0;
}
@@ -1480,7 +1487,7 @@ _scsih_get_resync(struct device *dev)
sdev->channel);
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- if (!raid_device)
+ if (!raid_device || ioc->is_warpdrive)
goto out;
if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
@@ -1640,6 +1647,212 @@ _scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
kfree(vol_pg0);
}
+/**
+ * _scsih_disable_ddio - Disable direct I/O for all the volumes
+ * @ioc: per adapter object
+ */
+static void
+_scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc)
+{
+ Mpi2RaidVolPage1_t vol_pg1;
+ Mpi2ConfigReply_t mpi_reply;
+ struct _raid_device *raid_device;
+ u16 handle;
+ u16 ioc_status;
+
+ handle = 0xFFFF;
+ while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
+ &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ handle = le16_to_cpu(vol_pg1.DevHandle);
+ raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ if (raid_device)
+ raid_device->direct_io_enabled = 0;
+ }
+ return;
+}
+
+
+/**
+ * _scsih_get_num_volumes - Get number of volumes in the ioc
+ * @ioc: per adapter object
+ */
+static u8
+_scsih_get_num_volumes(struct MPT2SAS_ADAPTER *ioc)
+{
+ Mpi2RaidVolPage1_t vol_pg1;
+ Mpi2ConfigReply_t mpi_reply;
+ u16 handle;
+ u8 vol_cnt = 0;
+ u16 ioc_status;
+
+ handle = 0xFFFF;
+ while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
+ &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ vol_cnt++;
+ handle = le16_to_cpu(vol_pg1.DevHandle);
+ }
+ return vol_cnt;
+}
+
+
+/**
+ * _scsih_init_warpdrive_properties - Set properties for warpdrive direct I/O.
+ * @ioc: per adapter object
+ * @raid_device: the raid_device object
+ */
+static void
+_scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc,
+ struct _raid_device *raid_device)
+{
+ Mpi2RaidVolPage0_t *vol_pg0;
+ Mpi2RaidPhysDiskPage0_t pd_pg0;
+ Mpi2ConfigReply_t mpi_reply;
+ u16 sz;
+ u8 num_pds, count;
+ u64 mb = 1024 * 1024;
+ u64 tb_2 = 2 * mb * mb;
+ u64 capacity;
+ u32 stripe_sz;
+ u8 i, stripe_exp;
+
+ if (!ioc->is_warpdrive)
+ return;
+
+ if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) {
+ printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
+ "globally as drives are exposed\n", ioc->name);
+ return;
+ }
+ if (_scsih_get_num_volumes(ioc) > 1) {
+ _scsih_disable_ddio(ioc);
+ printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
+ "globally as number of drives > 1\n", ioc->name);
+ return;
+ }
+ if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
+ &num_pds)) || !num_pds) {
+ printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
+ "Failure in computing number of drives\n", ioc->name);
+ return;
+ }
+
+ sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
+ sizeof(Mpi2RaidVol0PhysDisk_t));
+ vol_pg0 = kzalloc(sz, GFP_KERNEL);
+ if (!vol_pg0) {
+ printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
+ "Memory allocation failure for RVPG0\n", ioc->name);
+ return;
+ }
+
+ if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
+ printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
+ "Failure in retrieving RVPG0\n", ioc->name);
+ kfree(vol_pg0);
+ return;
+ }
+
+ /*
+ * WARPDRIVE:If number of physical disks in a volume exceeds the max pds
+ * assumed for WARPDRIVE, disable direct I/O
+ */
+ if (num_pds > MPT_MAX_WARPDRIVE_PDS) {
+ printk(MPT2SAS_WARN_FMT "WarpDrive : Direct IO is disabled "
+ "for the drive with handle(0x%04x): num_mem=%d, "
+ "max_mem_allowed=%d\n", ioc->name, raid_device->handle,
+ num_pds, MPT_MAX_WARPDRIVE_PDS);
+ kfree(vol_pg0);
+ return;
+ }
+ for (count = 0; count < num_pds; count++) {
+ if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
+ &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
+ vol_pg0->PhysDisk[count].PhysDiskNum) ||
+ pd_pg0.DevHandle == MPT2SAS_INVALID_DEVICE_HANDLE) {
+ printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is "
+ "disabled for the drive with handle(0x%04x) member"
+ "handle retrieval failed for member number=%d\n",
+ ioc->name, raid_device->handle,
+ vol_pg0->PhysDisk[count].PhysDiskNum);
+ goto out_error;
+ }
+ raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle);
+ }
+
+ /*
+ * Assumption for WD: Direct I/O is not supported if the volume is
+ * not RAID0, if the stripe size is not 64KB, if the block size is
+ * not 512 and if the volume size is >2TB
+ */
+ if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0 ||
+ le16_to_cpu(vol_pg0->BlockSize) != 512) {
+ printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
+ "for the drive with handle(0x%04x): type=%d, "
+ "s_sz=%uK, blk_size=%u\n", ioc->name,
+ raid_device->handle, raid_device->volume_type,
+ le32_to_cpu(vol_pg0->StripeSize)/2,
+ le16_to_cpu(vol_pg0->BlockSize));
+ goto out_error;
+ }
+
+ capacity = (u64) le16_to_cpu(vol_pg0->BlockSize) *
+ (le64_to_cpu(vol_pg0->MaxLBA) + 1);
+
+ if (capacity > tb_2) {
+ printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
+ "for the drive with handle(0x%04x) since drive sz > 2TB\n",
+ ioc->name, raid_device->handle);
+ goto out_error;
+ }
+
+ stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
+ stripe_exp = 0;
+ for (i = 0; i < 32; i++) {
+ if (stripe_sz & 1)
+ break;
+ stripe_exp++;
+ stripe_sz >>= 1;
+ }
+ if (i == 32) {
+ printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
+ "for the drive with handle(0x%04x) invalid stripe sz %uK\n",
+ ioc->name, raid_device->handle,
+ le32_to_cpu(vol_pg0->StripeSize)/2);
+ goto out_error;
+ }
+ raid_device->stripe_exponent = stripe_exp;
+ raid_device->direct_io_enabled = 1;
+
+ printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is Enabled for the drive"
+ " with handle(0x%04x)\n", ioc->name, raid_device->handle);
+ /*
+ * WARPDRIVE: Though the following fields are not used for direct IO,
+ * stored for future purpose:
+ */
+ raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA);
+ raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
+ raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize);
+
+
+ kfree(vol_pg0);
+ return;
+
+out_error:
+ raid_device->direct_io_enabled = 0;
+ for (count = 0; count < num_pds; count++)
+ raid_device->pd_handle[count] = 0;
+ kfree(vol_pg0);
+ return;
+}
/**
* _scsih_enable_tlr - setting TLR flags
@@ -1710,6 +1923,11 @@ _scsih_slave_configure(struct scsi_device *sdev)
_scsih_get_volume_capabilities(ioc, raid_device);
+ /*
+ * WARPDRIVE: Initialize the required data for Direct IO
+ */
+ _scsih_init_warpdrive_properties(ioc, raid_device);
+
/* RAID Queue Depth Support
* IS volume = underlying qdepth of drive type, either
* MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
@@ -1757,14 +1975,16 @@ _scsih_slave_configure(struct scsi_device *sdev)
break;
}
- sdev_printk(KERN_INFO, sdev, "%s: "
- "handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n",
- r_level, raid_device->handle,
- (unsigned long long)raid_device->wwid,
- raid_device->num_pds, ds);
+ if (!ioc->hide_ir_msg)
+ sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
+ "wwid(0x%016llx), pd_count(%d), type(%s)\n",
+ r_level, raid_device->handle,
+ (unsigned long long)raid_device->wwid,
+ raid_device->num_pds, ds);
_scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
/* raid transport support */
- _scsih_set_level(sdev, raid_device);
+ if (!ioc->is_warpdrive)
+ _scsih_set_level(sdev, raid_device);
return 0;
}
@@ -2181,16 +2401,20 @@ _scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
struct MPT2SAS_TARGET *priv_target = starget->hostdata;
struct _sas_device *sas_device = NULL;
unsigned long flags;
+ char *device_str = NULL;
if (!priv_target)
return;
+ if (ioc->hide_ir_msg)
+ device_str = "WarpDrive";
+ else
+ device_str = "volume";
scsi_print_command(scmd);
if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
- starget_printk(KERN_INFO, starget, "volume handle(0x%04x), "
- "volume wwid(0x%016llx)\n",
- priv_target->handle,
- (unsigned long long)priv_target->sas_address);
+ starget_printk(KERN_INFO, starget, "%s handle(0x%04x), "
+ "%s wwid(0x%016llx)\n", device_str, priv_target->handle,
+ device_str, (unsigned long long)priv_target->sas_address);
} else {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
@@ -3129,6 +3353,9 @@ _scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc,
a = 0;
b = 0;
+ if (ioc->is_warpdrive)
+ return;
+
/* Volume Resets for Deleted or Removed */
element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
for (i = 0; i < event_data->NumElements; i++, element++) {
@@ -3346,6 +3573,105 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
}
/**
+ * _scsih_scsi_direct_io_get - returns direct io flag
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns the smid stored scmd pointer.
+ */
+static inline u8
+_scsih_scsi_direct_io_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+ return ioc->scsi_lookup[smid - 1].direct_io;
+}
+
+/**
+ * _scsih_scsi_direct_io_set - sets direct io flag
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @direct_io: Zero or non-zero value to set in the direct_io flag
+ *
+ * Returns Nothing.
+ */
+static inline void
+_scsih_scsi_direct_io_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 direct_io)
+{
+ ioc->scsi_lookup[smid - 1].direct_io = direct_io;
+}
+
+
+/**
+ * _scsih_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O
+ * @ioc: per adapter object
+ * @scmd: pointer to scsi command object
+ * @raid_device: pointer to raid device data structure
+ * @mpi_request: pointer to the SCSI_IO reqest message frame
+ * @smid: system request message index
+ *
+ * Returns nothing
+ */
+static void
+_scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
+ struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
+ u16 smid)
+{
+ u32 v_lba, p_lba, stripe_off, stripe_unit, column, io_size;
+ u32 stripe_sz, stripe_exp;
+ u8 num_pds, *cdb_ptr, *tmp_ptr, *lba_ptr1, *lba_ptr2;
+ u8 cdb0 = scmd->cmnd[0];
+
+ /*
+ * Try Direct I/O to RAID memeber disks
+ */
+ if (cdb0 == READ_16 || cdb0 == READ_10 ||
+ cdb0 == WRITE_16 || cdb0 == WRITE_10) {
+ cdb_ptr = mpi_request->CDB.CDB32;
+
+ if ((cdb0 < READ_16) || !(cdb_ptr[2] | cdb_ptr[3] | cdb_ptr[4]
+ | cdb_ptr[5])) {
+ io_size = scsi_bufflen(scmd) >> 9;
+ /* get virtual lba */
+ lba_ptr1 = lba_ptr2 = (cdb0 < READ_16) ? &cdb_ptr[2] :
+ &cdb_ptr[6];
+ tmp_ptr = (u8 *)&v_lba + 3;
+ *tmp_ptr-- = *lba_ptr1++;
+ *tmp_ptr-- = *lba_ptr1++;
+ *tmp_ptr-- = *lba_ptr1++;
+ *tmp_ptr = *lba_ptr1;
+
+ if (((u64)v_lba + (u64)io_size - 1) <=
+ (u32)raid_device->max_lba) {
+ stripe_sz = raid_device->stripe_sz;
+ stripe_exp = raid_device->stripe_exponent;
+ stripe_off = v_lba & (stripe_sz - 1);
+
+ /* Check whether IO falls within a stripe */
+ if ((stripe_off + io_size) <= stripe_sz) {
+ num_pds = raid_device->num_pds;
+ p_lba = v_lba >> stripe_exp;
+ stripe_unit = p_lba / num_pds;
+ column = p_lba % num_pds;
+ p_lba = (stripe_unit << stripe_exp) +
+ stripe_off;
+ mpi_request->DevHandle =
+ cpu_to_le16(raid_device->
+ pd_handle[column]);
+ tmp_ptr = (u8 *)&p_lba + 3;
+ *lba_ptr2++ = *tmp_ptr--;
+ *lba_ptr2++ = *tmp_ptr--;
+ *lba_ptr2++ = *tmp_ptr--;
+ *lba_ptr2 = *tmp_ptr;
+ /*
+ * WD: To indicate this I/O is directI/O
+ */
+ _scsih_scsi_direct_io_set(ioc, smid, 1);
+ }
+ }
+ }
+ }
+}
+
+/**
* _scsih_qcmd - main scsi request entry point
* @scmd: pointer to scsi command object
* @done: function pointer to be invoked on completion
@@ -3362,6 +3688,7 @@ _scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
struct MPT2SAS_DEVICE *sas_device_priv_data;
struct MPT2SAS_TARGET *sas_target_priv_data;
+ struct _raid_device *raid_device;
Mpi2SCSIIORequest_t *mpi_request;
u32 mpi_control;
u16 smid;
@@ -3423,8 +3750,10 @@ _scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
} else
mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
- /* Make sure Device is not raid volume */
- if (!_scsih_is_raid(&scmd->device->sdev_gendev) &&
+ /* Make sure Device is not raid volume.
+ * We do not expose raid functionality to upper layer for warpdrive.
+ */
+ if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&
sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32)
mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
@@ -3472,9 +3801,14 @@ _scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
}
}
+ raid_device = sas_target_priv_data->raid_device;
+ if (raid_device && raid_device->direct_io_enabled)
+ _scsih_setup_direct_io(ioc, scmd, raid_device, mpi_request,
+ smid);
+
if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST))
mpt2sas_base_put_smid_scsi_io(ioc, smid,
- sas_device_priv_data->sas_target->handle);
+ le16_to_cpu(mpi_request->DevHandle));
else
mpt2sas_base_put_smid_default(ioc, smid);
return 0;
@@ -3539,10 +3873,16 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
unsigned long flags;
struct scsi_target *starget = scmd->device->sdev_target;
struct MPT2SAS_TARGET *priv_target = starget->hostdata;
+ char *device_str = NULL;
if (!priv_target)
return;
+ if (ioc->hide_ir_msg)
+ device_str = "WarpDrive";
+ else
+ device_str = "volume";
+
if (log_info == 0x31170000)
return;
@@ -3659,8 +3999,8 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
scsi_print_command(scmd);
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);
+ printk(MPT2SAS_WARN_FMT "\t%s wwid(0x%016llx)\n", ioc->name,
+ device_str, (unsigned long long)priv_target->sas_address);
} else {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
@@ -3839,6 +4179,20 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
scmd->result = DID_NO_CONNECT << 16;
goto out;
}
+ /*
+ * WARPDRIVE: If direct_io is set then it is directIO,
+ * the failed direct I/O should be redirected to volume
+ */
+ if (_scsih_scsi_direct_io_get(ioc, smid)) {
+ _scsih_scsi_direct_io_set(ioc, smid, 0);
+ memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
+ mpi_request->DevHandle =
+ cpu_to_le16(sas_device_priv_data->sas_target->handle);
+ mpt2sas_base_put_smid_scsi_io(ioc, smid,
+ sas_device_priv_data->sas_target->handle);
+ return 0;
+ }
+
/* turning off TLR */
scsi_state = mpi_reply->SCSIState;
@@ -3847,7 +4201,10 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
if (!sas_device_priv_data->tlr_snoop_check) {
sas_device_priv_data->tlr_snoop_check++;
- if (!_scsih_is_raid(&scmd->device->sdev_gendev) &&
+ /* Make sure Device is not raid volume.
+ * We do not expose raid functionality to upper layer for warpdrive.
+ */
+ if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&
sas_is_tlr_enabled(scmd->device) &&
response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {
sas_disable_tlr(scmd->device);
@@ -4680,8 +5037,10 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
_scsih_ublock_io_device(ioc, sas_device_backup.handle);
- mpt2sas_transport_port_remove(ioc, sas_device_backup.sas_address,
- sas_device_backup.sas_address_parent);
+ if (!ioc->hide_drives)
+ mpt2sas_transport_port_remove(ioc,
+ sas_device_backup.sas_address,
+ sas_device_backup.sas_address_parent);
printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
"(0x%016llx)\n", ioc->name, sas_device_backup.handle,
@@ -5412,6 +5771,7 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
&sas_device->volume_wwid);
set_bit(handle, ioc->pd_handles);
_scsih_reprobe_target(sas_device->starget, 1);
+
}
/**
@@ -5590,7 +5950,8 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
+ if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
+ && !ioc->hide_ir_msg)
_scsih_sas_ir_config_change_event_debug(ioc, event_data);
#endif
@@ -5613,16 +5974,20 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
le16_to_cpu(element->VolDevHandle));
break;
case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
- _scsih_sas_pd_hide(ioc, element);
+ if (!ioc->is_warpdrive)
+ _scsih_sas_pd_hide(ioc, element);
break;
case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
- _scsih_sas_pd_expose(ioc, element);
+ if (!ioc->is_warpdrive)
+ _scsih_sas_pd_expose(ioc, element);
break;
case MPI2_EVENT_IR_CHANGE_RC_HIDE:
- _scsih_sas_pd_add(ioc, element);
+ if (!ioc->is_warpdrive)
+ _scsih_sas_pd_add(ioc, element);
break;
case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
- _scsih_sas_pd_delete(ioc, element);
+ if (!ioc->is_warpdrive)
+ _scsih_sas_pd_delete(ioc, element);
break;
}
}
@@ -5653,9 +6018,10 @@ _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_INFO_FMT "%s: handle(0x%04x), "
- "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
- le32_to_cpu(event_data->PreviousValue), state));
+ if (!ioc->hide_ir_msg)
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
+ "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
+ le32_to_cpu(event_data->PreviousValue), state));
switch (state) {
case MPI2_RAID_VOL_STATE_MISSING:
@@ -5735,9 +6101,10 @@ _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_INFO_FMT "%s: handle(0x%04x), "
- "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
- le32_to_cpu(event_data->PreviousValue), state));
+ if (!ioc->hide_ir_msg)
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
+ "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
+ le32_to_cpu(event_data->PreviousValue), state));
switch (state) {
case MPI2_RAID_PD_STATE_ONLINE:
@@ -5746,7 +6113,8 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
case MPI2_RAID_PD_STATE_OPTIMAL:
case MPI2_RAID_PD_STATE_HOT_SPARE:
- set_bit(handle, ioc->pd_handles);
+ if (!ioc->is_warpdrive)
+ set_bit(handle, ioc->pd_handles);
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
@@ -5850,7 +6218,8 @@ _scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
u16 handle;
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
+ if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
+ && !ioc->hide_ir_msg)
_scsih_sas_ir_operation_status_event_debug(ioc,
event_data);
#endif
@@ -5909,7 +6278,7 @@ static void
_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
u16 slot, u16 handle)
{
- struct MPT2SAS_TARGET *sas_target_priv_data;
+ struct MPT2SAS_TARGET *sas_target_priv_data = NULL;
struct scsi_target *starget;
struct _sas_device *sas_device;
unsigned long flags;
@@ -5917,7 +6286,7 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
spin_lock_irqsave(&ioc->sas_device_lock, flags);
list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
if (sas_device->sas_address == sas_address &&
- sas_device->slot == slot && sas_device->starget) {
+ sas_device->slot == slot) {
sas_device->responding = 1;
starget = sas_device->starget;
if (starget && starget->hostdata) {
@@ -5926,13 +6295,15 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
sas_target_priv_data->deleted = 0;
} else
sas_target_priv_data = NULL;
- starget_printk(KERN_INFO, sas_device->starget,
- "handle(0x%04x), sas_addr(0x%016llx), enclosure "
- "logical id(0x%016llx), slot(%d)\n", handle,
- (unsigned long long)sas_device->sas_address,
- (unsigned long long)
- sas_device->enclosure_logical_id,
- sas_device->slot);
+ if (starget)
+ starget_printk(KERN_INFO, starget,
+ "handle(0x%04x), sas_addr(0x%016llx), "
+ "enclosure logical id(0x%016llx), "
+ "slot(%d)\n", handle,
+ (unsigned long long)sas_device->sas_address,
+ (unsigned long long)
+ sas_device->enclosure_logical_id,
+ sas_device->slot);
if (sas_device->handle == handle)
goto out;
printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
@@ -6024,6 +6395,12 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
starget_printk(KERN_INFO, raid_device->starget,
"handle(0x%04x), wwid(0x%016llx)\n", handle,
(unsigned long long)raid_device->wwid);
+ /*
+ * WARPDRIVE: The handles of the PDs might have changed
+ * across the host reset so re-initialize the
+ * required data for Direct IO
+ */
+ _scsih_init_warpdrive_properties(ioc, raid_device);
if (raid_device->handle == handle)
goto out;
printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
@@ -6085,18 +6462,20 @@ _scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
}
/* 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);
+ if (!ioc->is_warpdrive) {
+ phys_disk_num = 0xFF;
+ memset(ioc->pd_handles, 0, ioc->pd_handles_sz);
+ while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
+ &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM,
+ phys_disk_num))) {
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ phys_disk_num = pd_pg0.PhysDiskNum;
+ handle = le16_to_cpu(pd_pg0.DevHandle);
+ set_bit(handle, ioc->pd_handles);
+ }
}
}
@@ -6242,6 +6621,50 @@ _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
}
/**
+ * _scsih_hide_unhide_sas_devices - add/remove device to/from OS
+ * @ioc: per adapter object
+ *
+ * Return nothing.
+ */
+static void
+_scsih_hide_unhide_sas_devices(struct MPT2SAS_ADAPTER *ioc)
+{
+ struct _sas_device *sas_device, *sas_device_next;
+
+ if (!ioc->is_warpdrive || ioc->mfg_pg10_hide_flag !=
+ MFG_PAGE10_HIDE_IF_VOL_PRESENT)
+ return;
+
+ if (ioc->hide_drives) {
+ if (_scsih_get_num_volumes(ioc))
+ return;
+ ioc->hide_drives = 0;
+ list_for_each_entry_safe(sas_device, sas_device_next,
+ &ioc->sas_device_list, list) {
+ if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
+ sas_device->sas_address_parent)) {
+ _scsih_sas_device_remove(ioc, sas_device);
+ } else if (!sas_device->starget) {
+ mpt2sas_transport_port_remove(ioc,
+ sas_device->sas_address,
+ sas_device->sas_address_parent);
+ _scsih_sas_device_remove(ioc, sas_device);
+ }
+ }
+ } else {
+ if (!_scsih_get_num_volumes(ioc))
+ return;
+ ioc->hide_drives = 1;
+ list_for_each_entry_safe(sas_device, sas_device_next,
+ &ioc->sas_device_list, list) {
+ mpt2sas_transport_port_remove(ioc,
+ sas_device->sas_address,
+ sas_device->sas_address_parent);
+ }
+ }
+}
+
+/**
* mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
* @ioc: per adapter object
* @reset_phase: phase
@@ -6325,6 +6748,7 @@ _firmware_event_work(struct work_struct *work)
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock,
flags);
_scsih_remove_unresponding_sas_devices(ioc);
+ _scsih_hide_unhide_sas_devices(ioc);
return;
}
@@ -6424,6 +6848,53 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
(Mpi2EventDataIrVolume_t *)
mpi_reply->EventData);
break;
+ case MPI2_EVENT_LOG_ENTRY_ADDED:
+ {
+ Mpi2EventDataLogEntryAdded_t *log_entry;
+ u32 *log_code;
+
+ if (!ioc->is_warpdrive)
+ break;
+
+ log_entry = (Mpi2EventDataLogEntryAdded_t *)
+ mpi_reply->EventData;
+ log_code = (u32 *)log_entry->LogData;
+
+ if (le16_to_cpu(log_entry->LogEntryQualifier)
+ != MPT2_WARPDRIVE_LOGENTRY)
+ break;
+
+ switch (le32_to_cpu(*log_code)) {
+ case MPT2_WARPDRIVE_LC_SSDT:
+ printk(MPT2SAS_WARN_FMT "WarpDrive Warning: "
+ "IO Throttling has occurred in the WarpDrive "
+ "subsystem. Check WarpDrive documentation for "
+ "additional details.\n", ioc->name);
+ break;
+ case MPT2_WARPDRIVE_LC_SSDLW:
+ printk(MPT2SAS_WARN_FMT "WarpDrive Warning: "
+ "Program/Erase Cycles for the WarpDrive subsystem "
+ "in degraded range. Check WarpDrive documentation "
+ "for additional details.\n", ioc->name);
+ break;
+ case MPT2_WARPDRIVE_LC_SSDLF:
+ printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: "
+ "There are no Program/Erase Cycles for the "
+ "WarpDrive subsystem. The storage device will be "
+ "in read-only mode. Check WarpDrive documentation "
+ "for additional details.\n", ioc->name);
+ break;
+ case MPT2_WARPDRIVE_LC_BRMF:
+ printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: "
+ "The Backup Rail Monitor has failed on the "
+ "WarpDrive subsystem. Check WarpDrive "
+ "documentation for additional details.\n",
+ ioc->name);
+ break;
+ }
+
+ break;
+ }
case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
case MPI2_EVENT_IR_OPERATION_STATUS:
case MPI2_EVENT_SAS_DISCOVERY:
@@ -6582,7 +7053,8 @@ _scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
- printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
+ if (!ioc->hide_ir_msg)
+ printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
init_completion(&ioc->scsih_cmds.done);
mpt2sas_base_put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
@@ -6596,10 +7068,11 @@ _scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) {
mpi_reply = ioc->scsih_cmds.reply;
- printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo));
+ if (!ioc->hide_ir_msg)
+ printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
+ "ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo));
}
out:
@@ -6758,6 +7231,9 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
spin_lock_irqsave(&ioc->sas_device_lock, flags);
list_move_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ if (ioc->hide_drives)
+ return;
if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
sas_device->sas_address_parent)) {
_scsih_sas_device_remove(ioc, sas_device);
@@ -6811,6 +7287,9 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
list_move_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (ioc->hide_drives)
+ continue;
+
if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
sas_device->sas_address_parent)) {
_scsih_sas_device_remove(ioc, sas_device);
@@ -6881,6 +7360,11 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->id = mpt_ids++;
sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
ioc->pdev = pdev;
+ if (id->device == MPI2_MFGPAGE_DEVID_SSS6200) {
+ ioc->is_warpdrive = 1;
+ ioc->hide_ir_msg = 1;
+ } else
+ ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
ioc->scsi_io_cb_idx = scsi_io_cb_idx;
ioc->tm_cb_idx = tm_cb_idx;
ioc->ctl_cb_idx = ctl_cb_idx;
@@ -6946,6 +7430,20 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
ioc->wait_for_port_enable_to_complete = 0;
+ if (ioc->is_warpdrive) {
+ if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS)
+ ioc->hide_drives = 0;
+ else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS)
+ ioc->hide_drives = 1;
+ else {
+ if (_scsih_get_num_volumes(ioc))
+ ioc->hide_drives = 1;
+ else
+ ioc->hide_drives = 0;
+ }
+ } else
+ ioc->hide_drives = 0;
+
_scsih_probe_devices(ioc);
return 0;