提交 35116db9 编写于 作者: N nagalakshmi.nandigama@lsi.com 提交者: James Bottomley

[SCSI] mpt2sas: Fix for Panic when inactive volume is tried deleting

The driver was setting the action to MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
which only returns active volumes. In order to get info on inactive volumes,
the driver needs to change the action to
MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM, and traverse each config till the
iocstatus is MPI2_IOCSTATUS_CONFIG_INVALID_PAGE returned.
Added a change in the driver to remove the instance of
sas_device object when the driver returns "1" from the slave_configure callback.
Also fixed code to report the hot spares to the operating system with a /dev/sg
assigned.
Signed-off-by: NNagalakshmi Nandigama <nagalakshmi.nandigama@lsi.com>
Cc: stable@kernel.org
Signed-off-by: NJames Bottomley <JBottomley@Parallels.com>
上级 6faace2a
...@@ -1356,6 +1356,9 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, ...@@ -1356,6 +1356,9 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
Mpi2ConfigReply_t mpi_reply; Mpi2ConfigReply_t mpi_reply;
int r, i, config_page_sz; int r, i, config_page_sz;
u16 ioc_status; u16 ioc_status;
int config_num;
u16 element_type;
u16 phys_disk_dev_handle;
*volume_handle = 0; *volume_handle = 0;
memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
...@@ -1371,35 +1374,53 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, ...@@ -1371,35 +1374,53 @@ mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
if (r) if (r)
goto out; goto out;
mpi_request.PageAddress =
cpu_to_le32(MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG);
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4); config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4);
config_page = kmalloc(config_page_sz, GFP_KERNEL); config_page = kmalloc(config_page_sz, GFP_KERNEL);
if (!config_page) if (!config_page) {
goto out; r = -1;
r = _config_request(ioc, &mpi_request, &mpi_reply,
MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
config_page_sz);
if (r)
goto out; goto out;
}
r = -1; config_num = 0xff;
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; while (1) {
if (ioc_status != MPI2_IOCSTATUS_SUCCESS) mpi_request.PageAddress = cpu_to_le32(config_num +
goto out; MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM);
for (i = 0; i < config_page->NumElements; i++) { r = _config_request(ioc, &mpi_request, &mpi_reply,
if ((le16_to_cpu(config_page->ConfigElement[i].ElementFlags) & MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE) != config_page_sz);
MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT) if (r)
continue; goto out;
if (le16_to_cpu(config_page->ConfigElement[i]. r = -1;
PhysDiskDevHandle) == pd_handle) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
*volume_handle = le16_to_cpu(config_page-> MPI2_IOCSTATUS_MASK;
ConfigElement[i].VolDevHandle); if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
r = 0;
goto out; goto out;
for (i = 0; i < config_page->NumElements; i++) {
element_type = le16_to_cpu(config_page->
ConfigElement[i].ElementFlags) &
MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE;
if (element_type ==
MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT ||
element_type ==
MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT) {
phys_disk_dev_handle =
le16_to_cpu(config_page->ConfigElement[i].
PhysDiskDevHandle);
if (phys_disk_dev_handle == pd_handle) {
*volume_handle =
le16_to_cpu(config_page->
ConfigElement[i].VolDevHandle);
r = 0;
goto out;
}
} else if (element_type ==
MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT) {
*volume_handle = 0;
r = 0;
goto out;
}
} }
config_num = config_page->ConfigNum;
} }
out: out:
kfree(config_page); kfree(config_page);
......
...@@ -610,8 +610,15 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc, ...@@ -610,8 +610,15 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
spin_unlock_irqrestore(&ioc->sas_device_lock, flags); spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!mpt2sas_transport_port_add(ioc, sas_device->handle, if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
sas_device->sas_address_parent)) sas_device->sas_address_parent)) {
_scsih_sas_device_remove(ioc, sas_device); _scsih_sas_device_remove(ioc, sas_device);
} else if (!sas_device->starget) {
if (!ioc->is_driver_loading)
mpt2sas_transport_port_remove(ioc,
sas_device->sas_address,
sas_device->sas_address_parent);
_scsih_sas_device_remove(ioc, sas_device);
}
} }
/** /**
...@@ -1423,6 +1430,10 @@ _scsih_slave_destroy(struct scsi_device *sdev) ...@@ -1423,6 +1430,10 @@ _scsih_slave_destroy(struct scsi_device *sdev)
{ {
struct MPT2SAS_TARGET *sas_target_priv_data; struct MPT2SAS_TARGET *sas_target_priv_data;
struct scsi_target *starget; struct scsi_target *starget;
struct Scsi_Host *shost;
struct MPT2SAS_ADAPTER *ioc;
struct _sas_device *sas_device;
unsigned long flags;
if (!sdev->hostdata) if (!sdev->hostdata)
return; return;
...@@ -1430,6 +1441,19 @@ _scsih_slave_destroy(struct scsi_device *sdev) ...@@ -1430,6 +1441,19 @@ _scsih_slave_destroy(struct scsi_device *sdev)
starget = scsi_target(sdev); starget = scsi_target(sdev);
sas_target_priv_data = starget->hostdata; sas_target_priv_data = starget->hostdata;
sas_target_priv_data->num_luns--; sas_target_priv_data->num_luns--;
shost = dev_to_shost(&starget->dev);
ioc = shost_priv(shost);
if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
sas_target_priv_data->sas_address);
if (sas_device)
sas_device->starget = NULL;
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
kfree(sdev->hostdata); kfree(sdev->hostdata);
sdev->hostdata = NULL; sdev->hostdata = NULL;
} }
...@@ -2045,7 +2069,8 @@ _scsih_slave_configure(struct scsi_device *sdev) ...@@ -2045,7 +2069,8 @@ _scsih_slave_configure(struct scsi_device *sdev)
__FILE__, __LINE__, __func__)); __FILE__, __LINE__, __func__));
return 1; return 1;
} }
if (mpt2sas_config_get_volume_wwid(ioc, if (sas_device->volume_handle &&
mpt2sas_config_get_volume_wwid(ioc,
sas_device->volume_handle, sas_device->volume_handle,
&sas_device->volume_wwid)) { &sas_device->volume_wwid)) {
dfailprintk(ioc, printk(MPT2SAS_WARN_FMT dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
...@@ -5893,8 +5918,11 @@ _scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach) ...@@ -5893,8 +5918,11 @@ _scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
static void static void
_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach) _scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach)
{ {
struct MPT2SAS_TARGET *sas_target_priv_data = starget->hostdata; struct MPT2SAS_TARGET *sas_target_priv_data;
if (starget == NULL)
return;
sas_target_priv_data = starget->hostdata;
if (no_uld_attach) if (no_uld_attach)
sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT; sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
else else
...@@ -7676,8 +7704,9 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc) ...@@ -7676,8 +7704,9 @@ _scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
sas_device->sas_address_parent)) { sas_device->sas_address_parent)) {
_scsih_sas_device_remove(ioc, sas_device); _scsih_sas_device_remove(ioc, sas_device);
} else if (!sas_device->starget) { } else if (!sas_device->starget) {
mpt2sas_transport_port_remove(ioc, sas_address, if (!ioc->is_driver_loading)
sas_address_parent); mpt2sas_transport_port_remove(ioc, sas_address,
sas_address_parent);
_scsih_sas_device_remove(ioc, sas_device); _scsih_sas_device_remove(ioc, sas_device);
} }
} }
...@@ -7731,9 +7760,10 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) ...@@ -7731,9 +7760,10 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
kfree(sas_device); kfree(sas_device);
continue; continue;
} else if (!sas_device->starget) { } else if (!sas_device->starget) {
mpt2sas_transport_port_remove(ioc, if (!ioc->is_driver_loading)
sas_device->sas_address, mpt2sas_transport_port_remove(ioc,
sas_device->sas_address_parent); sas_device->sas_address,
sas_device->sas_address_parent);
list_del(&sas_device->list); list_del(&sas_device->list);
kfree(sas_device); kfree(sas_device);
continue; continue;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册