mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 13:14:07 +08:00
[SCSI] mpt fusion: RAID device handling and Dual port Raid support is added
1. Handle integrated Raid device(Add/Delete) and error condition and check related to Raid device. is_logical_volume will represent logical volume device. 2. Raid device dual port support is added. Main functions to support this feature are mpt_raid_phys_disk_get_num_paths and mpt_raid_phys_disk_pg1. Signed-off-by: Kashyap Desai <kadesai@lsi.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
parent
71278192a8
commit
a7938b0bb3
@ -5762,6 +5762,161 @@ mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpt_raid_phys_disk_get_num_paths - returns number paths associated to this phys_num
|
||||||
|
* @ioc: Pointer to a Adapter Structure
|
||||||
|
* @phys_disk_num: io unit unique phys disk num generated by the ioc
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* returns number paths
|
||||||
|
**/
|
||||||
|
int
|
||||||
|
mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc, u8 phys_disk_num)
|
||||||
|
{
|
||||||
|
CONFIGPARMS cfg;
|
||||||
|
ConfigPageHeader_t hdr;
|
||||||
|
dma_addr_t dma_handle;
|
||||||
|
pRaidPhysDiskPage1_t buffer = NULL;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
memset(&cfg, 0 , sizeof(CONFIGPARMS));
|
||||||
|
memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
|
||||||
|
|
||||||
|
hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
|
||||||
|
hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
|
||||||
|
hdr.PageNumber = 1;
|
||||||
|
cfg.cfghdr.hdr = &hdr;
|
||||||
|
cfg.physAddr = -1;
|
||||||
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
||||||
|
|
||||||
|
if (mpt_config(ioc, &cfg) != 0) {
|
||||||
|
rc = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hdr.PageLength) {
|
||||||
|
rc = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
|
||||||
|
&dma_handle);
|
||||||
|
|
||||||
|
if (!buffer) {
|
||||||
|
rc = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.physAddr = dma_handle;
|
||||||
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
||||||
|
cfg.pageAddr = phys_disk_num;
|
||||||
|
|
||||||
|
if (mpt_config(ioc, &cfg) != 0) {
|
||||||
|
rc = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = buffer->NumPhysDiskPaths;
|
||||||
|
out:
|
||||||
|
|
||||||
|
if (buffer)
|
||||||
|
pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
|
||||||
|
dma_handle);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(mpt_raid_phys_disk_get_num_paths);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpt_raid_phys_disk_pg1 - returns phys disk page 1
|
||||||
|
* @ioc: Pointer to a Adapter Structure
|
||||||
|
* @phys_disk_num: io unit unique phys disk num generated by the ioc
|
||||||
|
* @phys_disk: requested payload data returned
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* 0 on success
|
||||||
|
* -EFAULT if read of config page header fails or data pointer not NULL
|
||||||
|
* -ENOMEM if pci_alloc failed
|
||||||
|
**/
|
||||||
|
int
|
||||||
|
mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
|
||||||
|
RaidPhysDiskPage1_t *phys_disk)
|
||||||
|
{
|
||||||
|
CONFIGPARMS cfg;
|
||||||
|
ConfigPageHeader_t hdr;
|
||||||
|
dma_addr_t dma_handle;
|
||||||
|
pRaidPhysDiskPage1_t buffer = NULL;
|
||||||
|
int rc;
|
||||||
|
int i;
|
||||||
|
__le64 sas_address;
|
||||||
|
|
||||||
|
memset(&cfg, 0 , sizeof(CONFIGPARMS));
|
||||||
|
memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
|
hdr.PageVersion = MPI_RAIDPHYSDISKPAGE1_PAGEVERSION;
|
||||||
|
hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_PHYSDISK;
|
||||||
|
hdr.PageNumber = 1;
|
||||||
|
cfg.cfghdr.hdr = &hdr;
|
||||||
|
cfg.physAddr = -1;
|
||||||
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
||||||
|
|
||||||
|
if (mpt_config(ioc, &cfg) != 0) {
|
||||||
|
rc = -EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hdr.PageLength) {
|
||||||
|
rc = -EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
|
||||||
|
&dma_handle);
|
||||||
|
|
||||||
|
if (!buffer) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.physAddr = dma_handle;
|
||||||
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
||||||
|
cfg.pageAddr = phys_disk_num;
|
||||||
|
|
||||||
|
if (mpt_config(ioc, &cfg) != 0) {
|
||||||
|
rc = -EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
phys_disk->NumPhysDiskPaths = buffer->NumPhysDiskPaths;
|
||||||
|
phys_disk->PhysDiskNum = phys_disk_num;
|
||||||
|
for (i = 0; i < phys_disk->NumPhysDiskPaths; i++) {
|
||||||
|
phys_disk->Path[i].PhysDiskID = buffer->Path[i].PhysDiskID;
|
||||||
|
phys_disk->Path[i].PhysDiskBus = buffer->Path[i].PhysDiskBus;
|
||||||
|
phys_disk->Path[i].OwnerIdentifier =
|
||||||
|
buffer->Path[i].OwnerIdentifier;
|
||||||
|
phys_disk->Path[i].Flags = le16_to_cpu(buffer->Path[i].Flags);
|
||||||
|
memcpy(&sas_address, &buffer->Path[i].WWID, sizeof(__le64));
|
||||||
|
sas_address = le64_to_cpu(sas_address);
|
||||||
|
memcpy(&phys_disk->Path[i].WWID, &sas_address, sizeof(__le64));
|
||||||
|
memcpy(&sas_address,
|
||||||
|
&buffer->Path[i].OwnerWWID, sizeof(__le64));
|
||||||
|
sas_address = le64_to_cpu(sas_address);
|
||||||
|
memcpy(&phys_disk->Path[i].OwnerWWID,
|
||||||
|
&sas_address, sizeof(__le64));
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
|
||||||
|
if (buffer)
|
||||||
|
pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
|
||||||
|
dma_handle);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(mpt_raid_phys_disk_pg1);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
|
* mpt_findImVolumes - Identify IDs of hidden disks and RAID Volumes
|
||||||
* @ioc: Pointer to a Adapter Strucutre
|
* @ioc: Pointer to a Adapter Strucutre
|
||||||
@ -7170,6 +7325,18 @@ mpt_display_event_info(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply)
|
|||||||
"id=%d channel=%d phys_num=%d",
|
"id=%d channel=%d phys_num=%d",
|
||||||
id, channel, phys_num);
|
id, channel, phys_num);
|
||||||
break;
|
break;
|
||||||
|
case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
|
||||||
|
snprintf(evStr, EVENT_DESCR_STR_SZ,
|
||||||
|
"IR2: Dual Port Added: "
|
||||||
|
"id=%d channel=%d phys_num=%d",
|
||||||
|
id, channel, phys_num);
|
||||||
|
break;
|
||||||
|
case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
|
||||||
|
snprintf(evStr, EVENT_DESCR_STR_SZ,
|
||||||
|
"IR2: Dual Port Removed: "
|
||||||
|
"id=%d channel=%d phys_num=%d",
|
||||||
|
id, channel, phys_num);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ds = "IR2";
|
ds = "IR2";
|
||||||
break;
|
break;
|
||||||
|
@ -958,6 +958,10 @@ extern void mpt_free_fw_memory(MPT_ADAPTER *ioc);
|
|||||||
extern int mpt_findImVolumes(MPT_ADAPTER *ioc);
|
extern int mpt_findImVolumes(MPT_ADAPTER *ioc);
|
||||||
extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
|
extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode);
|
||||||
extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk);
|
extern int mpt_raid_phys_disk_pg0(MPT_ADAPTER *ioc, u8 phys_disk_num, pRaidPhysDiskPage0_t phys_disk);
|
||||||
|
extern int mpt_raid_phys_disk_pg1(MPT_ADAPTER *ioc, u8 phys_disk_num,
|
||||||
|
pRaidPhysDiskPage1_t phys_disk);
|
||||||
|
extern int mpt_raid_phys_disk_get_num_paths(MPT_ADAPTER *ioc,
|
||||||
|
u8 phys_disk_num);
|
||||||
extern int mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
|
extern int mpt_set_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
|
||||||
extern void mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
|
extern void mpt_clear_taskmgmt_in_progress_flag(MPT_ADAPTER *ioc);
|
||||||
extern void mpt_halt_firmware(MPT_ADAPTER *ioc);
|
extern void mpt_halt_firmware(MPT_ADAPTER *ioc);
|
||||||
|
@ -121,6 +121,7 @@ static void mptsas_expander_delete(MPT_ADAPTER *ioc,
|
|||||||
static void mptsas_send_expander_event(struct fw_event_work *fw_event);
|
static void mptsas_send_expander_event(struct fw_event_work *fw_event);
|
||||||
static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
|
static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
|
||||||
static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
|
static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
|
||||||
|
static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
|
||||||
|
|
||||||
static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
|
static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
|
||||||
MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
|
MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
|
||||||
@ -542,9 +543,10 @@ mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
|
|||||||
mutex_lock(&ioc->sas_device_info_mutex);
|
mutex_lock(&ioc->sas_device_info_mutex);
|
||||||
list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
|
list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
|
||||||
list) {
|
list) {
|
||||||
if ((sas_info->sas_address == sas_address ||
|
if (!sas_info->is_logical_volume &&
|
||||||
(sas_info->fw.channel == channel &&
|
(sas_info->sas_address == sas_address ||
|
||||||
sas_info->fw.id == id))) {
|
(sas_info->fw.channel == channel &&
|
||||||
|
sas_info->fw.id == id))) {
|
||||||
list_del(&sas_info->list);
|
list_del(&sas_info->list);
|
||||||
kfree(sas_info);
|
kfree(sas_info);
|
||||||
}
|
}
|
||||||
@ -616,6 +618,100 @@ mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
|
|||||||
sas_device.slot, enclosure_info.enclosure_logical_id);
|
sas_device.slot, enclosure_info.enclosure_logical_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding
|
||||||
|
* each individual device to list
|
||||||
|
* @ioc: Pointer to MPT_ADAPTER structure
|
||||||
|
* @channel: fw mapped id's
|
||||||
|
* @id:
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
static void
|
||||||
|
mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
|
||||||
|
struct scsi_target *starget)
|
||||||
|
{
|
||||||
|
CONFIGPARMS cfg;
|
||||||
|
ConfigPageHeader_t hdr;
|
||||||
|
dma_addr_t dma_handle;
|
||||||
|
pRaidVolumePage0_t buffer = NULL;
|
||||||
|
int i;
|
||||||
|
RaidPhysDiskPage0_t phys_disk;
|
||||||
|
struct mptsas_device_info *sas_info, *next;
|
||||||
|
|
||||||
|
memset(&cfg, 0 , sizeof(CONFIGPARMS));
|
||||||
|
memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
|
||||||
|
hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
|
||||||
|
/* assumption that all volumes on channel = 0 */
|
||||||
|
cfg.pageAddr = starget->id;
|
||||||
|
cfg.cfghdr.hdr = &hdr;
|
||||||
|
cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
|
||||||
|
cfg.timeout = 10;
|
||||||
|
|
||||||
|
if (mpt_config(ioc, &cfg) != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!hdr.PageLength)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
|
||||||
|
&dma_handle);
|
||||||
|
|
||||||
|
if (!buffer)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
cfg.physAddr = dma_handle;
|
||||||
|
cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
|
||||||
|
|
||||||
|
if (mpt_config(ioc, &cfg) != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!buffer->NumPhysDisks)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adding entry for hidden components
|
||||||
|
*/
|
||||||
|
for (i = 0; i < buffer->NumPhysDisks; i++) {
|
||||||
|
|
||||||
|
if (mpt_raid_phys_disk_pg0(ioc,
|
||||||
|
buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
|
||||||
|
phys_disk.PhysDiskID);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete all matching devices out of the list
|
||||||
|
*/
|
||||||
|
mutex_lock(&ioc->sas_device_info_mutex);
|
||||||
|
list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
|
||||||
|
list) {
|
||||||
|
if (sas_info->is_logical_volume && sas_info->fw.id ==
|
||||||
|
starget->id) {
|
||||||
|
list_del(&sas_info->list);
|
||||||
|
kfree(sas_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
|
||||||
|
if (sas_info) {
|
||||||
|
sas_info->fw.id = starget->id;
|
||||||
|
sas_info->os.id = starget->id;
|
||||||
|
sas_info->os.channel = starget->channel;
|
||||||
|
sas_info->is_logical_volume = 1;
|
||||||
|
INIT_LIST_HEAD(&sas_info->list);
|
||||||
|
list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
|
||||||
|
}
|
||||||
|
mutex_unlock(&ioc->sas_device_info_mutex);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (buffer)
|
||||||
|
pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
|
||||||
|
dma_handle);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mptsas_add_device_component_starget -
|
* mptsas_add_device_component_starget -
|
||||||
* @ioc: Pointer to MPT_ADAPTER structure
|
* @ioc: Pointer to MPT_ADAPTER structure
|
||||||
@ -817,6 +913,10 @@ mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
|
|||||||
if ((vdevice == NULL) ||
|
if ((vdevice == NULL) ||
|
||||||
(vdevice->vtarget == NULL))
|
(vdevice->vtarget == NULL))
|
||||||
continue;
|
continue;
|
||||||
|
if ((vdevice->vtarget->tflags &
|
||||||
|
MPT_TARGET_FLAGS_RAID_COMPONENT ||
|
||||||
|
vdevice->vtarget->raidVolume))
|
||||||
|
continue;
|
||||||
if (vdevice->vtarget->id == id &&
|
if (vdevice->vtarget->id == id &&
|
||||||
vdevice->vtarget->channel == channel)
|
vdevice->vtarget->channel == channel)
|
||||||
vtarget = vdevice->vtarget;
|
vtarget = vdevice->vtarget;
|
||||||
@ -1487,9 +1587,21 @@ mptsas_slave_configure(struct scsi_device *sdev)
|
|||||||
struct Scsi_Host *host = sdev->host;
|
struct Scsi_Host *host = sdev->host;
|
||||||
MPT_SCSI_HOST *hd = shost_priv(host);
|
MPT_SCSI_HOST *hd = shost_priv(host);
|
||||||
MPT_ADAPTER *ioc = hd->ioc;
|
MPT_ADAPTER *ioc = hd->ioc;
|
||||||
|
VirtDevice *vdevice = sdev->hostdata;
|
||||||
|
|
||||||
if (sdev->channel == MPTSAS_RAID_CHANNEL)
|
if (vdevice->vtarget->deleted) {
|
||||||
|
sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
|
||||||
|
vdevice->vtarget->deleted = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RAID volumes placed beyond the last expected port.
|
||||||
|
* Ignore sending sas mode pages in that case..
|
||||||
|
*/
|
||||||
|
if (sdev->channel == MPTSAS_RAID_CHANNEL) {
|
||||||
|
mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
sas_read_port_mode_page(sdev);
|
sas_read_port_mode_page(sdev);
|
||||||
|
|
||||||
@ -1525,9 +1637,18 @@ mptsas_target_alloc(struct scsi_target *starget)
|
|||||||
* RAID volumes placed beyond the last expected port.
|
* RAID volumes placed beyond the last expected port.
|
||||||
*/
|
*/
|
||||||
if (starget->channel == MPTSAS_RAID_CHANNEL) {
|
if (starget->channel == MPTSAS_RAID_CHANNEL) {
|
||||||
for (i=0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
|
if (!ioc->raid_data.pIocPg2) {
|
||||||
if (id == ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID)
|
kfree(vtarget);
|
||||||
channel = ioc->raid_data.pIocPg2->RaidVolume[i].VolumeBus;
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
|
||||||
|
if (id == ioc->raid_data.pIocPg2->
|
||||||
|
RaidVolume[i].VolumeID) {
|
||||||
|
channel = ioc->raid_data.pIocPg2->
|
||||||
|
RaidVolume[i].VolumeBus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vtarget->raidVolume = 1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3277,59 +3398,66 @@ mptsas_not_responding_devices(MPT_ADAPTER *ioc)
|
|||||||
mutex_lock(&ioc->sas_device_info_mutex);
|
mutex_lock(&ioc->sas_device_info_mutex);
|
||||||
redo_device_scan:
|
redo_device_scan:
|
||||||
list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
|
list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
|
||||||
sas_device.handle = 0;
|
if (!sas_info->is_logical_volume) {
|
||||||
retry_count = 0;
|
sas_device.handle = 0;
|
||||||
|
retry_count = 0;
|
||||||
retry_page:
|
retry_page:
|
||||||
retval = mptsas_sas_device_pg0(ioc, &sas_device,
|
retval = mptsas_sas_device_pg0(ioc, &sas_device,
|
||||||
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
|
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
|
||||||
<< MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
|
<< MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
|
||||||
(sas_info->fw.channel << 8) +
|
(sas_info->fw.channel << 8) +
|
||||||
sas_info->fw.id);
|
sas_info->fw.id);
|
||||||
|
|
||||||
if (sas_device.handle)
|
if (sas_device.handle)
|
||||||
continue;
|
continue;
|
||||||
if (retval == -EBUSY) {
|
if (retval == -EBUSY) {
|
||||||
spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
|
spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
|
||||||
if (ioc->ioc_reset_in_progress) {
|
if (ioc->ioc_reset_in_progress) {
|
||||||
dfailprintk(ioc,
|
dfailprintk(ioc,
|
||||||
printk(MYIOC_s_DEBUG_FMT
|
printk(MYIOC_s_DEBUG_FMT
|
||||||
"%s: exiting due to reset\n",
|
"%s: exiting due to reset\n",
|
||||||
ioc->name, __func__));
|
ioc->name, __func__));
|
||||||
spin_unlock_irqrestore
|
spin_unlock_irqrestore
|
||||||
(&ioc->taskmgmt_lock, flags);
|
(&ioc->taskmgmt_lock, flags);
|
||||||
mutex_unlock(&ioc->sas_device_info_mutex);
|
mutex_unlock(&ioc->
|
||||||
return;
|
sas_device_info_mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&ioc->taskmgmt_lock,
|
||||||
|
flags);
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&ioc->taskmgmt_lock,
|
|
||||||
flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (retval && (retval != -ENODEV)) {
|
if (retval && (retval != -ENODEV)) {
|
||||||
if (retry_count < 10) {
|
if (retry_count < 10) {
|
||||||
retry_count++;
|
retry_count++;
|
||||||
goto retry_page;
|
goto retry_page;
|
||||||
} else {
|
} else {
|
||||||
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
|
||||||
"%s: Config page retry exceeded retry "
|
"%s: Config page retry exceeded retry "
|
||||||
"count deleting device 0x%llx\n",
|
"count deleting device 0x%llx\n",
|
||||||
ioc->name, __func__,
|
ioc->name, __func__,
|
||||||
sas_info->sas_address));
|
sas_info->sas_address));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* delete device */
|
/* delete device */
|
||||||
vtarget = mptsas_find_vtarget(ioc,
|
vtarget = mptsas_find_vtarget(ioc,
|
||||||
sas_info->fw.channel, sas_info->fw.id);
|
sas_info->fw.channel, sas_info->fw.id);
|
||||||
if (vtarget)
|
|
||||||
vtarget->deleted = 1;
|
if (vtarget)
|
||||||
phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
|
vtarget->deleted = 1;
|
||||||
sas_info->sas_address);
|
|
||||||
if (phy_info) {
|
phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
|
||||||
mptsas_del_end_device(ioc, phy_info);
|
sas_info->sas_address);
|
||||||
goto redo_device_scan;
|
|
||||||
}
|
if (phy_info) {
|
||||||
|
mptsas_del_end_device(ioc, phy_info);
|
||||||
|
goto redo_device_scan;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
mptsas_volume_delete(ioc, sas_info->fw.id);
|
||||||
}
|
}
|
||||||
mutex_unlock(&ioc->sas_device_info_mutex);
|
mutex_lock(&ioc->sas_device_info_mutex);
|
||||||
|
|
||||||
/* expanders */
|
/* expanders */
|
||||||
mutex_lock(&ioc->sas_topology_mutex);
|
mutex_lock(&ioc->sas_topology_mutex);
|
||||||
@ -3508,28 +3636,74 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
|
|||||||
return phy_info;
|
return phy_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mptsas_find_phyinfo_by_phys_disk_num -
|
||||||
|
* @ioc: Pointer to MPT_ADAPTER structure
|
||||||
|
* @phys_disk_num:
|
||||||
|
* @channel:
|
||||||
|
* @id:
|
||||||
|
*
|
||||||
|
**/
|
||||||
static struct mptsas_phyinfo *
|
static struct mptsas_phyinfo *
|
||||||
mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
|
mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
|
||||||
|
u8 channel, u8 id)
|
||||||
{
|
{
|
||||||
struct mptsas_portinfo *port_info;
|
|
||||||
struct mptsas_phyinfo *phy_info = NULL;
|
struct mptsas_phyinfo *phy_info = NULL;
|
||||||
|
struct mptsas_portinfo *port_info;
|
||||||
|
RaidPhysDiskPage1_t *phys_disk = NULL;
|
||||||
|
int num_paths;
|
||||||
|
u64 sas_address = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
phy_info = NULL;
|
||||||
|
if (!ioc->raid_data.pIocPg3)
|
||||||
|
return NULL;
|
||||||
|
/* dual port support */
|
||||||
|
num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
|
||||||
|
if (!num_paths)
|
||||||
|
goto out;
|
||||||
|
phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
|
||||||
|
(num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
|
||||||
|
if (!phys_disk)
|
||||||
|
goto out;
|
||||||
|
mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
|
||||||
|
for (i = 0; i < num_paths; i++) {
|
||||||
|
if ((phys_disk->Path[i].Flags & 1) != 0)
|
||||||
|
/* entry no longer valid */
|
||||||
|
continue;
|
||||||
|
if ((id == phys_disk->Path[i].PhysDiskID) &&
|
||||||
|
(channel == phys_disk->Path[i].PhysDiskBus)) {
|
||||||
|
memcpy(&sas_address, &phys_disk->Path[i].WWID,
|
||||||
|
sizeof(u64));
|
||||||
|
phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
|
||||||
|
sas_address);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
kfree(phys_disk);
|
||||||
|
if (phy_info)
|
||||||
|
return phy_info;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extra code to handle RAID0 case, where the sas_address is not updated
|
||||||
|
* in phys_disk_page_1 when hotswapped
|
||||||
|
*/
|
||||||
mutex_lock(&ioc->sas_topology_mutex);
|
mutex_lock(&ioc->sas_topology_mutex);
|
||||||
list_for_each_entry(port_info, &ioc->sas_topology, list) {
|
list_for_each_entry(port_info, &ioc->sas_topology, list) {
|
||||||
for (i = 0; i < port_info->num_phys; i++) {
|
for (i = 0; i < port_info->num_phys && !phy_info; i++) {
|
||||||
if (!mptsas_is_end_device(
|
if (!mptsas_is_end_device(
|
||||||
&port_info->phy_info[i].attached))
|
&port_info->phy_info[i].attached))
|
||||||
continue;
|
continue;
|
||||||
if (port_info->phy_info[i].attached.phys_disk_num == ~0)
|
if (port_info->phy_info[i].attached.phys_disk_num == ~0)
|
||||||
continue;
|
continue;
|
||||||
if (port_info->phy_info[i].attached.phys_disk_num != id)
|
if ((port_info->phy_info[i].attached.phys_disk_num ==
|
||||||
continue;
|
phys_disk_num) &&
|
||||||
if (port_info->phy_info[i].attached.channel != channel)
|
(port_info->phy_info[i].attached.id == id) &&
|
||||||
continue;
|
(port_info->phy_info[i].attached.channel ==
|
||||||
phy_info = &port_info->phy_info[i];
|
channel))
|
||||||
break;
|
phy_info = &port_info->phy_info[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&ioc->sas_topology_mutex);
|
mutex_unlock(&ioc->sas_topology_mutex);
|
||||||
@ -3683,8 +3857,9 @@ mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
|
|||||||
mpt_findImVolumes(ioc);
|
mpt_findImVolumes(ioc);
|
||||||
|
|
||||||
phy_info = mptsas_find_phyinfo_by_phys_disk_num(
|
phy_info = mptsas_find_phyinfo_by_phys_disk_num(
|
||||||
ioc, hot_plug_info->channel,
|
ioc, hot_plug_info->phys_disk_num,
|
||||||
hot_plug_info->phys_disk_num);
|
hot_plug_info->channel,
|
||||||
|
hot_plug_info->id);
|
||||||
mptsas_del_end_device(ioc, phy_info);
|
mptsas_del_end_device(ioc, phy_info);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -4032,6 +4207,7 @@ mptsas_send_ir2_event(struct fw_event_work *fw_event)
|
|||||||
struct mptsas_hotplug_event hot_plug_info;
|
struct mptsas_hotplug_event hot_plug_info;
|
||||||
MPI_EVENT_DATA_IR2 *ir2_data;
|
MPI_EVENT_DATA_IR2 *ir2_data;
|
||||||
u8 reasonCode;
|
u8 reasonCode;
|
||||||
|
RaidPhysDiskPage0_t phys_disk;
|
||||||
|
|
||||||
ioc = fw_event->ioc;
|
ioc = fw_event->ioc;
|
||||||
ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
|
ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
|
||||||
@ -4047,6 +4223,17 @@ mptsas_send_ir2_event(struct fw_event_work *fw_event)
|
|||||||
case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
|
case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
|
||||||
hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
|
hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
|
||||||
break;
|
break;
|
||||||
|
case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
|
||||||
|
hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
|
||||||
|
hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
|
||||||
|
break;
|
||||||
|
case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
|
||||||
|
hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
|
||||||
|
mpt_raid_phys_disk_pg0(ioc,
|
||||||
|
ir2_data->PhysDiskNum, &phys_disk);
|
||||||
|
hot_plug_info.id = phys_disk.PhysDiskID;
|
||||||
|
hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
mptsas_free_fw_event(ioc, fw_event);
|
mptsas_free_fw_event(ioc, fw_event);
|
||||||
return;
|
return;
|
||||||
@ -4132,6 +4319,31 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Delete a volume when no longer listed in ioc pg2
|
||||||
|
*/
|
||||||
|
static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
|
||||||
|
{
|
||||||
|
struct scsi_device *sdev;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
|
||||||
|
if (!sdev)
|
||||||
|
return;
|
||||||
|
if (!ioc->raid_data.pIocPg2)
|
||||||
|
goto out;
|
||||||
|
if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
|
||||||
|
goto out;
|
||||||
|
for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
|
||||||
|
if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
|
||||||
|
goto release_sdev;
|
||||||
|
out:
|
||||||
|
printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
|
||||||
|
"id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
|
||||||
|
scsi_remove_device(sdev);
|
||||||
|
release_sdev:
|
||||||
|
scsi_device_put(sdev);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
{
|
{
|
||||||
|
@ -82,6 +82,7 @@ struct mptsas_device_info {
|
|||||||
u32 device_info; /* specific bits for devices */
|
u32 device_info; /* specific bits for devices */
|
||||||
u16 slot; /* enclosure slot id */
|
u16 slot; /* enclosure slot id */
|
||||||
u64 enclosure_logical_id; /*enclosure address */
|
u64 enclosure_logical_id; /*enclosure address */
|
||||||
|
u8 is_logical_volume; /* is this logical volume */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mptsas_hotplug_event {
|
struct mptsas_hotplug_event {
|
||||||
|
@ -2087,8 +2087,10 @@ int
|
|||||||
mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
|
mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
|
||||||
{
|
{
|
||||||
struct inactive_raid_component_info *component_info;
|
struct inactive_raid_component_info *component_info;
|
||||||
int i;
|
int i, j;
|
||||||
|
RaidPhysDiskPage1_t *phys_disk;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
int num_paths;
|
||||||
|
|
||||||
if (!ioc->raid_data.pIocPg3)
|
if (!ioc->raid_data.pIocPg3)
|
||||||
goto out;
|
goto out;
|
||||||
@ -2100,6 +2102,45 @@ mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ioc->bus_type != SAS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if dual path
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
|
||||||
|
num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
|
||||||
|
ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
|
||||||
|
if (num_paths < 2)
|
||||||
|
continue;
|
||||||
|
phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
|
||||||
|
(num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
|
||||||
|
if (!phys_disk)
|
||||||
|
continue;
|
||||||
|
if ((mpt_raid_phys_disk_pg1(ioc,
|
||||||
|
ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
|
||||||
|
phys_disk))) {
|
||||||
|
kfree(phys_disk);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (j = 0; j < num_paths; j++) {
|
||||||
|
if ((phys_disk->Path[j].Flags &
|
||||||
|
MPI_RAID_PHYSDISK1_FLAG_INVALID))
|
||||||
|
continue;
|
||||||
|
if ((phys_disk->Path[j].Flags &
|
||||||
|
MPI_RAID_PHYSDISK1_FLAG_BROKEN))
|
||||||
|
continue;
|
||||||
|
if ((id == phys_disk->Path[j].PhysDiskID) &&
|
||||||
|
(channel == phys_disk->Path[j].PhysDiskBus)) {
|
||||||
|
rc = 1;
|
||||||
|
kfree(phys_disk);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kfree(phys_disk);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check inactive list for matching phys disks
|
* Check inactive list for matching phys disks
|
||||||
*/
|
*/
|
||||||
@ -2124,8 +2165,10 @@ u8
|
|||||||
mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
|
mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
|
||||||
{
|
{
|
||||||
struct inactive_raid_component_info *component_info;
|
struct inactive_raid_component_info *component_info;
|
||||||
int i;
|
int i, j;
|
||||||
|
RaidPhysDiskPage1_t *phys_disk;
|
||||||
int rc = -ENXIO;
|
int rc = -ENXIO;
|
||||||
|
int num_paths;
|
||||||
|
|
||||||
if (!ioc->raid_data.pIocPg3)
|
if (!ioc->raid_data.pIocPg3)
|
||||||
goto out;
|
goto out;
|
||||||
@ -2137,6 +2180,44 @@ mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ioc->bus_type != SAS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if dual path
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) {
|
||||||
|
num_paths = mpt_raid_phys_disk_get_num_paths(ioc,
|
||||||
|
ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum);
|
||||||
|
if (num_paths < 2)
|
||||||
|
continue;
|
||||||
|
phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
|
||||||
|
(num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
|
||||||
|
if (!phys_disk)
|
||||||
|
continue;
|
||||||
|
if ((mpt_raid_phys_disk_pg1(ioc,
|
||||||
|
ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskNum,
|
||||||
|
phys_disk))) {
|
||||||
|
kfree(phys_disk);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (j = 0; j < num_paths; j++) {
|
||||||
|
if ((phys_disk->Path[j].Flags &
|
||||||
|
MPI_RAID_PHYSDISK1_FLAG_INVALID))
|
||||||
|
continue;
|
||||||
|
if ((phys_disk->Path[j].Flags &
|
||||||
|
MPI_RAID_PHYSDISK1_FLAG_BROKEN))
|
||||||
|
continue;
|
||||||
|
if ((id == phys_disk->Path[j].PhysDiskID) &&
|
||||||
|
(channel == phys_disk->Path[j].PhysDiskBus)) {
|
||||||
|
rc = phys_disk->PhysDiskNum;
|
||||||
|
kfree(phys_disk);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kfree(phys_disk);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check inactive list for matching phys disks
|
* Check inactive list for matching phys disks
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user