Commit 3eb0822c authored by Kashyap, Desai's avatar Kashyap, Desai Committed by James Bottomley

[SCSI] mpt fusion: Firmware event implementation using seperate WorkQueue

Now Firmware events are handled by firmware event queue.
Previously it was handled in interrupt context/WorkQueue of Linux.
Firmware Event handling is restructured and optimized.
Signed-off-by: default avatarKashyap Desai <kadesai@lsi.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent ea2a788d
...@@ -1931,6 +1931,11 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -1931,6 +1931,11 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
*/ */
mpt_detect_bound_ports(ioc, pdev); mpt_detect_bound_ports(ioc, pdev);
INIT_LIST_HEAD(&ioc->fw_event_list);
spin_lock_init(&ioc->fw_event_lock);
snprintf(ioc->fw_event_q_name, 20, "mpt/%d", ioc->id);
ioc->fw_event_q = create_singlethread_workqueue(ioc->fw_event_q_name);
if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP,
CAN_SLEEP)) != 0){ CAN_SLEEP)) != 0){
printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n", printk(MYIOC_s_ERR_FMT "didn't initialize properly! (%d)\n",
...@@ -2010,6 +2015,11 @@ mpt_detach(struct pci_dev *pdev) ...@@ -2010,6 +2015,11 @@ mpt_detach(struct pci_dev *pdev)
cancel_delayed_work(&ioc->fault_reset_work); cancel_delayed_work(&ioc->fault_reset_work);
destroy_workqueue(wq); destroy_workqueue(wq);
spin_lock_irqsave(&ioc->fw_event_lock, flags);
wq = ioc->fw_event_q;
ioc->fw_event_q = NULL;
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
destroy_workqueue(wq);
sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name); sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s/summary", ioc->name);
remove_proc_entry(pname, NULL); remove_proc_entry(pname, NULL);
......
...@@ -694,9 +694,18 @@ typedef struct _MPT_ADAPTER ...@@ -694,9 +694,18 @@ typedef struct _MPT_ADAPTER
struct net_device *netdev; struct net_device *netdev;
struct list_head sas_topology; struct list_head sas_topology;
struct mutex sas_topology_mutex; struct mutex sas_topology_mutex;
struct workqueue_struct *fw_event_q;
struct list_head fw_event_list;
spinlock_t fw_event_lock;
u8 fw_events_off; /* if '1', then ignore events */
char fw_event_q_name[20];
struct mutex sas_discovery_mutex; struct mutex sas_discovery_mutex;
u8 sas_discovery_runtime; u8 sas_discovery_runtime;
u8 sas_discovery_ignore_events; u8 sas_discovery_ignore_events;
struct list_head sas_device_info_list;
struct mutex sas_device_info_mutex;
u8 sas_discovery_quiesce_io; u8 sas_discovery_quiesce_io;
int sas_index; /* index refrencing */ int sas_index; /* index refrencing */
MPT_MGMT sas_mgmt; MPT_MGMT sas_mgmt;
......
...@@ -95,7 +95,24 @@ static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for interna ...@@ -95,7 +95,24 @@ static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for interna
static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS; static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS; static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
static void mptsas_hotplug_work(struct work_struct *work); static void mptsas_firmware_event_work(struct work_struct *work);
static void mptsas_send_sas_event(struct fw_event_work *fw_event);
static void mptsas_send_raid_event(struct fw_event_work *fw_event);
static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
static void mptsas_parse_device_info(struct sas_identify *identify,
struct mptsas_devinfo *device_info);
static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
(MPT_ADAPTER *ioc, u64 sas_address);
static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
static int mptsas_add_end_device(MPT_ADAPTER *ioc,
struct mptsas_phyinfo *phy_info);
static void mptsas_del_end_device(MPT_ADAPTER *ioc,
struct mptsas_phyinfo *phy_info);
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)
...@@ -219,6 +236,100 @@ static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1) ...@@ -219,6 +236,100 @@ static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
le16_to_cpu(pg1->AttachedDevHandle))); le16_to_cpu(pg1->AttachedDevHandle)));
} }
/* inhibit sas firmware event handling */
static void
mptsas_fw_event_off(MPT_ADAPTER *ioc)
{
unsigned long flags;
spin_lock_irqsave(&ioc->fw_event_lock, flags);
ioc->fw_events_off = 1;
ioc->sas_discovery_quiesce_io = 0;
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
}
/* enable sas firmware event handling */
static void
mptsas_fw_event_on(MPT_ADAPTER *ioc)
{
unsigned long flags;
spin_lock_irqsave(&ioc->fw_event_lock, flags);
ioc->fw_events_off = 0;
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
}
/* queue a sas firmware event */
static void
mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
unsigned long delay)
{
unsigned long flags;
spin_lock_irqsave(&ioc->fw_event_lock, flags);
list_add_tail(&fw_event->list, &ioc->fw_event_list);
INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
ioc->name, __func__, fw_event));
queue_delayed_work(ioc->fw_event_q, &fw_event->work,
delay);
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
}
/* free memory assoicated to a sas firmware event */
static void
mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
{
unsigned long flags;
spin_lock_irqsave(&ioc->fw_event_lock, flags);
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
ioc->name, __func__, fw_event));
list_del(&fw_event->list);
kfree(fw_event);
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
}
/* walk the firmware event queue, and either stop or wait for
* outstanding events to complete */
static void
mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
{
struct fw_event_work *fw_event, *next;
struct mptsas_target_reset_event *target_reset_list, *n;
u8 flush_q;
MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
/* flush the target_reset_list */
if (!list_empty(&hd->target_reset_list)) {
list_for_each_entry_safe(target_reset_list, n,
&hd->target_reset_list, list) {
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"%s: removing target reset for id=%d\n",
ioc->name, __func__,
target_reset_list->sas_event_data.TargetID));
list_del(&target_reset_list->list);
kfree(target_reset_list);
}
}
if (list_empty(&ioc->fw_event_list) ||
!ioc->fw_event_q || in_interrupt())
return;
flush_q = 0;
list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
if (cancel_delayed_work(&fw_event->work))
mptsas_free_fw_event(ioc, fw_event);
else
flush_q = 1;
}
if (flush_q)
flush_workqueue(ioc->fw_event_q);
}
static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
{ {
struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
...@@ -309,6 +420,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai ...@@ -309,6 +420,7 @@ mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_detai
if(phy_info->port_details != port_details) if(phy_info->port_details != port_details)
continue; continue;
memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
mptsas_set_rphy(ioc, phy_info, NULL);
phy_info->port_details = NULL; phy_info->port_details = NULL;
} }
kfree(port_details); kfree(port_details);
...@@ -380,6 +492,157 @@ starget) ...@@ -380,6 +492,157 @@ starget)
phy_info->port_details->starget = starget; phy_info->port_details->starget = starget;
} }
/**
* mptsas_add_device_component -
* @ioc: Pointer to MPT_ADAPTER structure
* @channel: fw mapped id's
* @id:
* @sas_address:
* @device_info:
*
**/
static void
mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
{
struct mptsas_device_info *sas_info, *next;
struct scsi_device *sdev;
struct scsi_target *starget;
struct sas_rphy *rphy;
/*
* 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->sas_address == sas_address ||
(sas_info->fw.channel == channel &&
sas_info->fw.id == id))) {
list_del(&sas_info->list);
kfree(sas_info);
}
}
sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
if (!sas_info)
goto out;
/*
* Set Firmware mapping
*/
sas_info->fw.id = id;
sas_info->fw.channel = channel;
sas_info->sas_address = sas_address;
sas_info->device_info = device_info;
sas_info->slot = slot;
sas_info->enclosure_logical_id = enclosure_logical_id;
INIT_LIST_HEAD(&sas_info->list);
list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
/*
* Set OS mapping
*/
shost_for_each_device(sdev, ioc->sh) {
starget = scsi_target(sdev);
rphy = dev_to_rphy(starget->dev.parent);
if (rphy->identify.sas_address == sas_address) {
sas_info->os.id = starget->id;
sas_info->os.channel = starget->channel;
}
}
out:
mutex_unlock(&ioc->sas_device_info_mutex);
return;
}
/**
* mptsas_add_device_component_by_fw -
* @ioc: Pointer to MPT_ADAPTER structure
* @channel: fw mapped id's
* @id:
*
**/
static void
mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
{
struct mptsas_devinfo sas_device;
struct mptsas_enclosure enclosure_info;
int rc;
rc = mptsas_sas_device_pg0(ioc, &sas_device,
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
(channel << 8) + id);
if (rc)
return;
memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
(MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
sas_device.handle_enclosure);
mptsas_add_device_component(ioc, sas_device.channel,
sas_device.id, sas_device.sas_address, sas_device.device_info,
sas_device.slot, enclosure_info.enclosure_logical_id);
}
/**
* mptsas_add_device_component_starget -
* @ioc: Pointer to MPT_ADAPTER structure
* @starget:
*
**/
static void
mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
struct scsi_target *starget)
{
VirtTarget *vtarget;
struct sas_rphy *rphy;
struct mptsas_phyinfo *phy_info = NULL;
struct mptsas_enclosure enclosure_info;
rphy = dev_to_rphy(starget->dev.parent);
vtarget = starget->hostdata;
phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
rphy->identify.sas_address);
if (!phy_info)
return;
memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
(MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
phy_info->attached.handle_enclosure);
mptsas_add_device_component(ioc, phy_info->attached.channel,
phy_info->attached.id, phy_info->attached.sas_address,
phy_info->attached.device_info,
phy_info->attached.slot, enclosure_info.enclosure_logical_id);
}
/**
* mptsas_del_device_components - Cleaning the list
* @ioc: Pointer to MPT_ADAPTER structure
*
**/
static void
mptsas_del_device_components(MPT_ADAPTER *ioc)
{
struct mptsas_device_info *sas_info, *next;
mutex_lock(&ioc->sas_device_info_mutex);
list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
list) {
list_del(&sas_info->list);
kfree(sas_info);
}
mutex_unlock(&ioc->sas_device_info_mutex);
}
/* /*
* mptsas_setup_wide_ports * mptsas_setup_wide_ports
...@@ -535,6 +798,29 @@ mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id) ...@@ -535,6 +798,29 @@ mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
return vtarget; return vtarget;
} }
static void
mptsas_queue_device_delete(MPT_ADAPTER *ioc,
MpiEventDataSasDeviceStatusChange_t *sas_event_data)
{
struct fw_event_work *fw_event;
int sz;
sz = offsetof(struct fw_event_work, event_data) +
sizeof(MpiEventDataSasDeviceStatusChange_t);
fw_event = kzalloc(sz, GFP_ATOMIC);
if (!fw_event) {
printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
ioc->name, __func__, __LINE__);
return;
}
memcpy(fw_event->event_data, sas_event_data,
sizeof(MpiEventDataSasDeviceStatusChange_t));
fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
fw_event->ioc = ioc;
mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
}
/** /**
* mptsas_target_reset * mptsas_target_reset
* *
...@@ -654,10 +940,8 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ...@@ -654,10 +940,8 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
{ {
MPT_SCSI_HOST *hd = shost_priv(ioc->sh); MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
struct list_head *head = &hd->target_reset_list; struct list_head *head = &hd->target_reset_list;
struct mptsas_hotplug_event *ev;
EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data; EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
u8 id, channel; u8 id, channel;
__le64 sas_address;
struct mptsas_target_reset_event *target_reset_list; struct mptsas_target_reset_event *target_reset_list;
SCSITaskMgmtReply_t *pScsiTmReply; SCSITaskMgmtReply_t *pScsiTmReply;
...@@ -729,41 +1013,9 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ...@@ -729,41 +1013,9 @@ mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
* enable work queue to remove device from upper layers * enable work queue to remove device from upper layers
*/ */
list_del(&target_reset_list->list); list_del(&target_reset_list->list);
if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
ev = kzalloc(sizeof(*ev), GFP_ATOMIC); mptsas_queue_device_delete(ioc,
if (!ev) { &target_reset_list->sas_event_data);
dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
ioc->name,__func__, __LINE__));
goto out_fail;
}
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
ioc->name, mf));
INIT_WORK(&ev->work, mptsas_hotplug_work);
ev->ioc = ioc;
ev->handle = le16_to_cpu(sas_event_data->DevHandle);
ev->parent_handle =
le16_to_cpu(sas_event_data->ParentDevHandle);
ev->channel = channel;
ev->id =id;
ev->phy_id = sas_event_data->PhyNum;
memcpy(&sas_address, &sas_event_data->SASAddress,
sizeof(__le64));
ev->sas_address = le64_to_cpu(sas_address);
ev->device_info = le32_to_cpu(sas_event_data->DeviceInfo);
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
ev->event_type = MPTSAS_DEL_DEVICE;
schedule_work(&ev->work);
kfree(target_reset_list);
out_fail:
mpt_clear_taskmgmt_in_progress_flag(ioc);
return 0;
/* /*
...@@ -798,37 +1050,58 @@ static int ...@@ -798,37 +1050,58 @@ static int
mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
{ {
MPT_SCSI_HOST *hd; MPT_SCSI_HOST *hd;
struct mptsas_target_reset_event *target_reset_list, *n;
int rc; int rc;
rc = mptscsih_ioc_reset(ioc, reset_phase); rc = mptscsih_ioc_reset(ioc, reset_phase);
if ((ioc->bus_type != SAS) || (!rc))
return rc;
if (ioc->bus_type != SAS)
goto out;
if (reset_phase != MPT_IOC_POST_RESET)
goto out;
if (!ioc->sh || !ioc->sh->hostdata)
goto out;
hd = shost_priv(ioc->sh); hd = shost_priv(ioc->sh);
if (!hd->ioc) if (!hd->ioc)
goto out; goto out;
if (list_empty(&hd->target_reset_list)) switch (reset_phase) {
goto out; case MPT_IOC_SETUP_RESET:
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
/* flush the target_reset_list */ "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
list_for_each_entry_safe(target_reset_list, n, mptsas_fw_event_off(ioc);
&hd->target_reset_list, list) { break;
list_del(&target_reset_list->list); case MPT_IOC_PRE_RESET:
kfree(target_reset_list); dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
break;
case MPT_IOC_POST_RESET:
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
complete(&ioc->sas_mgmt.done);
}
mptsas_cleanup_fw_event_q(ioc);
mptsas_fw_event_on(ioc);
break;
default:
break;
} }
out: out:
return rc; return rc;
} }
/**
* enum device_state -
* @DEVICE_RETRY: need to retry the TUR
* @DEVICE_ERROR: TUR return error, don't add device
* @DEVICE_READY: device can be added
*
*/
enum device_state{
DEVICE_RETRY,
DEVICE_ERROR,
DEVICE_READY,
};
static int static int
mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
u32 form, u32 form_specific) u32 form, u32 form_specific)
...@@ -894,15 +1167,268 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, ...@@ -894,15 +1167,268 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
return error; return error;
} }
/**
* mptsas_add_end_device - report a new end device to sas transport layer
* @ioc: Pointer to MPT_ADAPTER structure
* @phy_info: decribes attached device
*
* return (0) success (1) failure
*
**/
static int
mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
{
struct sas_rphy *rphy;
struct sas_port *port;
struct sas_identify identify;
char *ds = NULL;
u8 fw_id;
if (!phy_info) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__func__, __LINE__));
return 1;
}
fw_id = phy_info->attached.id;
if (mptsas_get_rphy(phy_info)) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, fw_id, __LINE__));
return 2;
}
port = mptsas_get_port(phy_info);
if (!port) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, fw_id, __LINE__));
return 3;
}
if (phy_info->attached.device_info &
MPI_SAS_DEVICE_INFO_SSP_TARGET)
ds = "ssp";
if (phy_info->attached.device_info &
MPI_SAS_DEVICE_INFO_STP_TARGET)
ds = "stp";
if (phy_info->attached.device_info &
MPI_SAS_DEVICE_INFO_SATA_DEVICE)
ds = "sata";
printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
" phy %d, sas_addr 0x%llx\n", ioc->name, ds,
phy_info->attached.channel, phy_info->attached.id,
phy_info->attached.phy_id, (unsigned long long)
phy_info->attached.sas_address);
mptsas_parse_device_info(&identify, &phy_info->attached);
rphy = sas_end_device_alloc(port);
if (!rphy) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, fw_id, __LINE__));
return 5; /* non-fatal: an rphy can be added later */
}
rphy->identify = identify;
if (sas_rphy_add(rphy)) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, fw_id, __LINE__));
sas_rphy_free(rphy);
return 6;
}
mptsas_set_rphy(ioc, phy_info, rphy);
return 0;
}
/**
* mptsas_del_end_device - report a deleted end device to sas transport
* layer
* @ioc: Pointer to MPT_ADAPTER structure
* @phy_info: decribes attached device
*
**/
static void
mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
{
struct sas_rphy *rphy;
struct sas_port *port;
struct mptsas_portinfo *port_info;
struct mptsas_phyinfo *phy_info_parent;
int i;
char *ds = NULL;
u8 fw_id;
u64 sas_address;
if (!phy_info)
return;
fw_id = phy_info->attached.id;
sas_address = phy_info->attached.sas_address;
if (!phy_info->port_details) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, fw_id, __LINE__));
return;
}
rphy = mptsas_get_rphy(phy_info);
if (!rphy) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, fw_id, __LINE__));
return;
}
if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
|| phy_info->attached.device_info
& MPI_SAS_DEVICE_INFO_SMP_INITIATOR
|| phy_info->attached.device_info
& MPI_SAS_DEVICE_INFO_STP_INITIATOR)
ds = "initiator";
if (phy_info->attached.device_info &
MPI_SAS_DEVICE_INFO_SSP_TARGET)
ds = "ssp";
if (phy_info->attached.device_info &
MPI_SAS_DEVICE_INFO_STP_TARGET)
ds = "stp";
if (phy_info->attached.device_info &
MPI_SAS_DEVICE_INFO_SATA_DEVICE)
ds = "sata";
dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
"removing %s device: fw_channel %d, fw_id %d, phy %d,"
"sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
phy_info->attached.id, phy_info->attached.phy_id,
(unsigned long long) sas_address);
port = mptsas_get_port(phy_info);
if (!port) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, fw_id, __LINE__));
return;
}
port_info = phy_info->portinfo;
phy_info_parent = port_info->phy_info;
for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
if (!phy_info_parent->phy)
continue;
if (phy_info_parent->attached.sas_address !=
sas_address)
continue;
dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
ioc->name, phy_info_parent->phy_id,
phy_info_parent->phy);
sas_port_delete_phy(port, phy_info_parent->phy);
}
dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
"delete port %d, sas_addr (0x%llx)\n", ioc->name,
port->port_identifier, (unsigned long long)sas_address);
sas_port_delete(port);
mptsas_set_port(ioc, phy_info, NULL);
mptsas_port_delete(ioc, phy_info->port_details);
}
struct mptsas_phyinfo *
mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
struct mptsas_devinfo *sas_device)
{
struct mptsas_phyinfo *phy_info;
struct mptsas_portinfo *port_info;
int i;
phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
sas_device->sas_address);
if (!phy_info)
goto out;
port_info = phy_info->portinfo;
if (!port_info)
goto out;
mutex_lock(&ioc->sas_topology_mutex);
for (i = 0; i < port_info->num_phys; i++) {
if (port_info->phy_info[i].attached.sas_address !=
sas_device->sas_address)
continue;
port_info->phy_info[i].attached.channel = sas_device->channel;
port_info->phy_info[i].attached.id = sas_device->id;
port_info->phy_info[i].attached.sas_address =
sas_device->sas_address;
port_info->phy_info[i].attached.handle = sas_device->handle;
port_info->phy_info[i].attached.handle_parent =
sas_device->handle_parent;
port_info->phy_info[i].attached.handle_enclosure =
sas_device->handle_enclosure;
}
mutex_unlock(&ioc->sas_topology_mutex);
out:
return phy_info;
}
/**
* mptsas_firmware_event_work - work thread for processing fw events
* @work: work queue payload containing info describing the event
* Context: user
*
*/
static void
mptsas_firmware_event_work(struct work_struct *work)
{
struct fw_event_work *fw_event =
container_of(work, struct fw_event_work, work.work);
MPT_ADAPTER *ioc = fw_event->ioc;
/* events handling turned off during host reset */
if (ioc->fw_events_off) {
mptsas_free_fw_event(ioc, fw_event);
return;
}
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
"event = (0x%02x)\n", ioc->name, __func__, fw_event,
(fw_event->event & 0xFF)));
switch (fw_event->event) {
case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
mptsas_send_sas_event(fw_event);
break;
case MPI_EVENT_INTEGRATED_RAID:
mptsas_send_raid_event(fw_event);
break;
case MPI_EVENT_IR2:
mptsas_send_ir2_event(fw_event);
break;
case MPI_EVENT_PERSISTENT_TABLE_FULL:
mptbase_sas_persist_operation(ioc,
MPI_SAS_OP_CLEAR_NOT_PRESENT);
mptsas_free_fw_event(ioc, fw_event);
break;
}
}
static int static int
mptsas_slave_configure(struct scsi_device *sdev) mptsas_slave_configure(struct scsi_device *sdev)
{ {
struct Scsi_Host *host = sdev->host;
MPT_SCSI_HOST *hd = shost_priv(host);
MPT_ADAPTER *ioc = hd->ioc;
if (sdev->channel == MPTSAS_RAID_CHANNEL) if (sdev->channel == MPTSAS_RAID_CHANNEL)
goto out; goto out;
sas_read_port_mode_page(sdev); sas_read_port_mode_page(sdev);
mptsas_add_device_component_starget(ioc, scsi_target(sdev));
out: out:
return mptscsih_slave_configure(sdev); return mptscsih_slave_configure(sdev);
} }
...@@ -984,11 +1510,15 @@ mptsas_target_destroy(struct scsi_target *starget) ...@@ -984,11 +1510,15 @@ mptsas_target_destroy(struct scsi_target *starget)
struct sas_rphy *rphy; struct sas_rphy *rphy;
struct mptsas_portinfo *p; struct mptsas_portinfo *p;
int i; int i;
MPT_ADAPTER *ioc = hd->ioc; MPT_ADAPTER *ioc = hd->ioc;
VirtTarget *vtarget;
if (!starget->hostdata) if (!starget->hostdata)
return; return;
vtarget = starget->hostdata;
if (starget->channel == MPTSAS_RAID_CHANNEL) if (starget->channel == MPTSAS_RAID_CHANNEL)
goto out; goto out;
...@@ -998,12 +1528,21 @@ mptsas_target_destroy(struct scsi_target *starget) ...@@ -998,12 +1528,21 @@ mptsas_target_destroy(struct scsi_target *starget)
if (p->phy_info[i].attached.sas_address != if (p->phy_info[i].attached.sas_address !=
rphy->identify.sas_address) rphy->identify.sas_address)
continue; continue;
starget_printk(KERN_INFO, starget, MYIOC_s_FMT
"delete device: fw_channel %d, fw_id %d, phy %d, "
"sas_addr 0x%llx\n", ioc->name,
p->phy_info[i].attached.channel,
p->phy_info[i].attached.id,
p->phy_info[i].attached.phy_id, (unsigned long long)
p->phy_info[i].attached.sas_address);
mptsas_set_starget(&p->phy_info[i], NULL); mptsas_set_starget(&p->phy_info[i], NULL);
goto out;
} }
} }
out: out:
vtarget->starget = NULL;
kfree(starget->hostdata); kfree(starget->hostdata);
starget->hostdata = NULL; starget->hostdata = NULL;
} }
...@@ -2471,6 +3010,7 @@ mptsas_discovery_work(struct work_struct *work) ...@@ -2471,6 +3010,7 @@ mptsas_discovery_work(struct work_struct *work)
kfree(ev); kfree(ev);
} }
static struct mptsas_phyinfo * static struct mptsas_phyinfo *
mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
{ {
...@@ -2495,30 +3035,6 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) ...@@ -2495,30 +3035,6 @@ mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
return phy_info; return phy_info;
} }
static struct mptsas_phyinfo *
mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id)
{
struct mptsas_portinfo *port_info;
struct mptsas_phyinfo *phy_info = NULL;
int i;
mutex_lock(&ioc->sas_topology_mutex);
list_for_each_entry(port_info, &ioc->sas_topology, list) {
for (i = 0; i < port_info->num_phys; i++) {
if (!mptsas_is_end_device(
&port_info->phy_info[i].attached))
continue;
if (port_info->phy_info[i].attached.id != id)
continue;
if (port_info->phy_info[i].attached.channel != channel)
continue;
phy_info = &port_info->phy_info[i];
break;
}
}
mutex_unlock(&ioc->sas_topology_mutex);
return phy_info;
}
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 channel, u8 id)
...@@ -2547,17 +3063,6 @@ mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id) ...@@ -2547,17 +3063,6 @@ mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 channel, u8 id)
return phy_info; return phy_info;
} }
/*
* Work queue thread to clear the persitency table
*/
static void
mptsas_persist_clear_table(struct work_struct *work)
{
MPT_ADAPTER *ioc = container_of(work, MPT_ADAPTER, sas_persist_task);
mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT);
}
static void static void
mptsas_reprobe_lun(struct scsi_device *sdev, void *data) mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
{ {
...@@ -2583,7 +3088,8 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) ...@@ -2583,7 +3088,8 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
pRaidVolumePage0_t buffer = NULL; pRaidVolumePage0_t buffer = NULL;
RaidPhysDiskPage0_t phys_disk; RaidPhysDiskPage0_t phys_disk;
int i; int i;
struct mptsas_hotplug_event *ev; struct mptsas_phyinfo *phy_info;
struct mptsas_devinfo sas_device;
memset(&cfg, 0 , sizeof(CONFIGPARMS)); memset(&cfg, 0 , sizeof(CONFIGPARMS));
memset(&hdr, 0 , sizeof(ConfigPageHeader_t)); memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
...@@ -2623,20 +3129,16 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) ...@@ -2623,20 +3129,16 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0) buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
continue; continue;
ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (mptsas_sas_device_pg0(ioc, &sas_device,
if (!ev) { (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
printk(MYIOC_s_WARN_FMT "mptsas: lost hotplug event\n", ioc->name); MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
goto out; (phys_disk.PhysDiskBus << 8) +
} phys_disk.PhysDiskID))
continue;
INIT_WORK(&ev->work, mptsas_hotplug_work); phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
ev->ioc = ioc; sas_device.sas_address);
ev->id = phys_disk.PhysDiskID; mptsas_add_end_device(ioc, phy_info);
ev->channel = phys_disk.PhysDiskBus;
ev->phys_disk_num_valid = 1;
ev->phys_disk_num = phys_disk.PhysDiskNum;
ev->event_type = MPTSAS_ADD_DEVICE;
schedule_work(&ev->work);
} }
out: out:
...@@ -2648,417 +3150,385 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id) ...@@ -2648,417 +3150,385 @@ mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
* Work queue thread to handle SAS hotplug events * Work queue thread to handle SAS hotplug events
*/ */
static void static void
mptsas_hotplug_work(struct work_struct *work) mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
struct mptsas_hotplug_event *hot_plug_info)
{ {
struct mptsas_hotplug_event *ev =
container_of(work, struct mptsas_hotplug_event, work);
MPT_ADAPTER *ioc = ev->ioc;
struct mptsas_phyinfo *phy_info; struct mptsas_phyinfo *phy_info;
struct sas_rphy *rphy;
struct sas_port *port;
struct scsi_device *sdev;
struct scsi_target * starget; struct scsi_target * starget;
struct sas_identify identify;
char *ds = NULL;
struct mptsas_devinfo sas_device; struct mptsas_devinfo sas_device;
VirtTarget *vtarget; VirtTarget *vtarget;
VirtDevice *vdevice; int i;
mutex_lock(&ioc->sas_discovery_mutex); switch (hot_plug_info->event_type) {
switch (ev->event_type) {
case MPTSAS_DEL_DEVICE:
phy_info = NULL; case MPTSAS_ADD_PHYSDISK:
if (ev->phys_disk_num_valid) {
if (ev->hidden_raid_component){ if (!ioc->raid_data.pIocPg2)
if (mptsas_sas_device_pg0(ioc, &sas_device, break;
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
MPI_SAS_DEVICE_PGAD_FORM_SHIFT), for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
(ev->channel << 8) + ev->id)) { if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT hot_plug_info->id) {
"%s: exit at line=%d\n", ioc->name, printk(MYIOC_s_WARN_FMT "firmware bug: unable "
__func__, __LINE__)); "to add hidden disk - target_id matchs "
break; "volume_id\n", ioc->name);
} mptsas_free_fw_event(ioc, fw_event);
phy_info = mptsas_find_phyinfo_by_sas_address( return;
ioc, sas_device.sas_address); }
}else
phy_info = mptsas_find_phyinfo_by_phys_disk_num(
ioc, ev->channel, ev->phys_disk_num);
} }
mpt_findImVolumes(ioc);
case MPTSAS_ADD_DEVICE:
memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
mptsas_sas_device_pg0(ioc, &sas_device,
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
(hot_plug_info->channel << 8) +
hot_plug_info->id);
if (!sas_device.handle)
return;
phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
if (!phy_info) if (!phy_info)
phy_info = mptsas_find_phyinfo_by_target(ioc, break;
ev->channel, ev->id);
/* if (mptsas_get_rphy(phy_info))
* Sanity checks, for non-existing phys and remote rphys. break;
*/
if (!phy_info){ mptsas_add_end_device(ioc, phy_info);
break;
case MPTSAS_DEL_DEVICE:
phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
hot_plug_info->sas_address);
mptsas_del_end_device(ioc, phy_info);
break;
case MPTSAS_DEL_PHYSDISK:
mpt_findImVolumes(ioc);
phy_info = mptsas_find_phyinfo_by_phys_disk_num(
ioc, hot_plug_info->channel,
hot_plug_info->phys_disk_num);
mptsas_del_end_device(ioc, phy_info);
break;
case MPTSAS_ADD_PHYSDISK_REPROBE:
if (mptsas_sas_device_pg0(ioc, &sas_device,
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
(hot_plug_info->channel << 8) + hot_plug_info->id)) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name, "%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, __LINE__)); __func__, hot_plug_info->id, __LINE__));
break; break;
} }
if (!phy_info->port_details) {
phy_info = mptsas_find_phyinfo_by_sas_address(
ioc, sas_device.sas_address);
if (!phy_info) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name, "%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, __LINE__)); __func__, hot_plug_info->id, __LINE__));
break; break;
} }
rphy = mptsas_get_rphy(phy_info);
if (!rphy) { starget = mptsas_get_starget(phy_info);
if (!starget) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name, "%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, __LINE__)); __func__, hot_plug_info->id, __LINE__));
break; break;
} }
port = mptsas_get_port(phy_info); vtarget = starget->hostdata;
if (!port) { if (!vtarget) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name, "%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, __LINE__)); __func__, hot_plug_info->id, __LINE__));
break; break;
} }
starget = mptsas_get_starget(phy_info); mpt_findImVolumes(ioc);
if (starget) {
vtarget = starget->hostdata;
if (!vtarget) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__func__, __LINE__));
break;
}
/* starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
* Handling RAID components "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
*/ ioc->name, hot_plug_info->channel, hot_plug_info->id,
if (ev->phys_disk_num_valid && hot_plug_info->phys_disk_num, (unsigned long long)
ev->hidden_raid_component) { sas_device.sas_address);
printk(MYIOC_s_INFO_FMT
"RAID Hidding: channel=%d, id=%d, "
"physdsk %d \n", ioc->name, ev->channel,
ev->id, ev->phys_disk_num);
vtarget->id = ev->phys_disk_num;
vtarget->tflags |=
MPT_TARGET_FLAGS_RAID_COMPONENT;
mptsas_reprobe_target(starget, 1);
phy_info->attached.phys_disk_num =
ev->phys_disk_num;
break;
}
}
if (phy_info->attached.device_info & vtarget->id = hot_plug_info->phys_disk_num;
MPI_SAS_DEVICE_INFO_SSP_TARGET) vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
ds = "ssp"; phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
if (phy_info->attached.device_info & mptsas_reprobe_target(starget, 1);
MPI_SAS_DEVICE_INFO_STP_TARGET)
ds = "stp";
if (phy_info->attached.device_info &
MPI_SAS_DEVICE_INFO_SATA_DEVICE)
ds = "sata";
printk(MYIOC_s_INFO_FMT
"removing %s device, channel %d, id %d, phy %d\n",
ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
"delete port (%d)\n", ioc->name, port->port_identifier);
sas_port_delete(port);
mptsas_port_delete(ioc, phy_info->port_details);
break; break;
case MPTSAS_ADD_DEVICE:
if (ev->phys_disk_num_valid) case MPTSAS_DEL_PHYSDISK_REPROBE:
mpt_findImVolumes(ioc);
/*
* Refresh sas device pg0 data
*/
if (mptsas_sas_device_pg0(ioc, &sas_device, if (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),
(ev->channel << 8) + ev->id)) { (hot_plug_info->channel << 8) + hot_plug_info->id)) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name, "%s: fw_id=%d exit at line=%d\n",
__func__, __LINE__)); ioc->name, __func__,
hot_plug_info->id, __LINE__));
break; break;
} }
__mptsas_discovery_work(ioc);
phy_info = mptsas_find_phyinfo_by_sas_address(ioc, phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
sas_device.sas_address); sas_device.sas_address);
if (!phy_info) {
if (!phy_info || !phy_info->port_details) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name, "%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, __LINE__)); __func__, hot_plug_info->id, __LINE__));
break; break;
} }
starget = mptsas_get_starget(phy_info); starget = mptsas_get_starget(phy_info);
if (starget && (!ev->hidden_raid_component)){ if (!starget) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
vtarget = starget->hostdata; "%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, hot_plug_info->id, __LINE__));
if (!vtarget) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__func__, __LINE__));
break;
}
/*
* Handling RAID components
*/
if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
printk(MYIOC_s_INFO_FMT
"RAID Exposing: channel=%d, id=%d, "
"physdsk %d \n", ioc->name, ev->channel,
ev->id, ev->phys_disk_num);
vtarget->tflags &=
~MPT_TARGET_FLAGS_RAID_COMPONENT;
vtarget->id = ev->id;
mptsas_reprobe_target(starget, 0);
phy_info->attached.phys_disk_num = ~0;
}
break; break;
} }
if (mptsas_get_rphy(phy_info)) { vtarget = starget->hostdata;
if (!vtarget) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name, "%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, __LINE__)); __func__, hot_plug_info->id, __LINE__));
if (ev->channel) printk("%d\n", __LINE__);
break; break;
} }
port = mptsas_get_port(phy_info); if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
if (!port) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name, "%s: fw_id=%d exit at line=%d\n", ioc->name,
__func__, __LINE__)); __func__, hot_plug_info->id, __LINE__));
break; break;
} }
memcpy(&phy_info->attached, &sas_device,
sizeof(struct mptsas_devinfo));
if (phy_info->attached.device_info &
MPI_SAS_DEVICE_INFO_SSP_TARGET)
ds = "ssp";
if (phy_info->attached.device_info &
MPI_SAS_DEVICE_INFO_STP_TARGET)
ds = "stp";
if (phy_info->attached.device_info &
MPI_SAS_DEVICE_INFO_SATA_DEVICE)
ds = "sata";
printk(MYIOC_s_INFO_FMT
"attaching %s device, channel %d, id %d, phy %d\n",
ioc->name, ds, ev->channel, ev->id, ev->phy_id);
mptsas_parse_device_info(&identify, &phy_info->attached); mpt_findImVolumes(ioc);
rphy = sas_end_device_alloc(port);
if (!rphy) {
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
"%s: exit at line=%d\n", ioc->name,
__func__, __LINE__));
break; /* non-fatal: an rphy can be added later */
}
rphy->identify = identify; starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
if (sas_rphy_add(rphy)) { " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
dfailprintk(ioc, printk(MYIOC_s_ERR_FMT ioc->name, hot_plug_info->channel, hot_plug_info->id,
"%s: exit at line=%d\n", ioc->name, hot_plug_info->phys_disk_num, (unsigned long long)
__func__, __LINE__)); sas_device.sas_address);
sas_rphy_free(rphy);
break; vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
} vtarget->id = hot_plug_info->id;
mptsas_set_rphy(ioc, phy_info, rphy); phy_info->attached.phys_disk_num = ~0;
mptsas_reprobe_target(starget, 0);
mptsas_add_device_component_by_fw(ioc,
hot_plug_info->channel, hot_plug_info->id);
break; break;
case MPTSAS_ADD_RAID: case MPTSAS_ADD_RAID:
sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
ev->id, 0);
if (sdev) {
scsi_device_put(sdev);
break;
}
printk(MYIOC_s_INFO_FMT
"attaching raid volume, channel %d, id %d\n",
ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
mpt_findImVolumes(ioc); mpt_findImVolumes(ioc);
printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
"id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
hot_plug_info->id);
scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
hot_plug_info->id, 0);
break; break;
case MPTSAS_DEL_RAID: case MPTSAS_DEL_RAID:
sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
ev->id, 0);
if (!sdev)
break;
printk(MYIOC_s_INFO_FMT
"removing raid volume, channel %d, id %d\n",
ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
vdevice = sdev->hostdata;
scsi_remove_device(sdev);
scsi_device_put(sdev);
mpt_findImVolumes(ioc); mpt_findImVolumes(ioc);
printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
"id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
hot_plug_info->id);
scsi_remove_device(hot_plug_info->sdev);
scsi_device_put(hot_plug_info->sdev);
break; break;
case MPTSAS_ADD_INACTIVE_VOLUME: case MPTSAS_ADD_INACTIVE_VOLUME:
mpt_findImVolumes(ioc);
mptsas_adding_inactive_raid_components(ioc, mptsas_adding_inactive_raid_components(ioc,
ev->channel, ev->id); hot_plug_info->channel, hot_plug_info->id);
break; break;
case MPTSAS_IGNORE_EVENT:
default: default:
break; break;
} }
mutex_unlock(&ioc->sas_discovery_mutex); mptsas_free_fw_event(ioc, fw_event);
kfree(ev);
} }
static void static void
mptsas_send_sas_event(MPT_ADAPTER *ioc, mptsas_send_sas_event(struct fw_event_work *fw_event)
EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
{ {
struct mptsas_hotplug_event *ev; MPT_ADAPTER *ioc;
u32 device_info = le32_to_cpu(sas_event_data->DeviceInfo); struct mptsas_hotplug_event hot_plug_info;
__le64 sas_address; EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
u32 device_info;
u64 sas_address;
ioc = fw_event->ioc;
sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
fw_event->event_data;
device_info = le32_to_cpu(sas_event_data->DeviceInfo);
if ((device_info & if ((device_info &
(MPI_SAS_DEVICE_INFO_SSP_TARGET | (MPI_SAS_DEVICE_INFO_SSP_TARGET |
MPI_SAS_DEVICE_INFO_STP_TARGET | MPI_SAS_DEVICE_INFO_STP_TARGET |
MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
mptsas_free_fw_event(ioc, fw_event);
return;
}
if (sas_event_data->ReasonCode ==
MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
mptbase_sas_persist_operation(ioc,
MPI_SAS_OP_CLEAR_NOT_PRESENT);
mptsas_free_fw_event(ioc, fw_event);
return; return;
}
switch (sas_event_data->ReasonCode) { switch (sas_event_data->ReasonCode) {
case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
mptsas_target_reset_queue(ioc, sas_event_data);
break;
case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
ev = kzalloc(sizeof(*ev), GFP_ATOMIC); memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
if (!ev) { hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); hot_plug_info.channel = sas_event_data->Bus;
break; hot_plug_info.id = sas_event_data->TargetID;
} hot_plug_info.phy_id = sas_event_data->PhyNum;
INIT_WORK(&ev->work, mptsas_hotplug_work);
ev->ioc = ioc;
ev->handle = le16_to_cpu(sas_event_data->DevHandle);
ev->parent_handle =
le16_to_cpu(sas_event_data->ParentDevHandle);
ev->channel = sas_event_data->Bus;
ev->id = sas_event_data->TargetID;
ev->phy_id = sas_event_data->PhyNum;
memcpy(&sas_address, &sas_event_data->SASAddress, memcpy(&sas_address, &sas_event_data->SASAddress,
sizeof(__le64)); sizeof(u64));
ev->sas_address = le64_to_cpu(sas_address); hot_plug_info.sas_address = le64_to_cpu(sas_address);
ev->device_info = device_info; hot_plug_info.device_info = device_info;
if (sas_event_data->ReasonCode & if (sas_event_data->ReasonCode &
MPI_EVENT_SAS_DEV_STAT_RC_ADDED) MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
ev->event_type = MPTSAS_ADD_DEVICE; hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
else else
ev->event_type = MPTSAS_DEL_DEVICE; hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
schedule_work(&ev->work); mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
break; break;
case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
/* mptbase_sas_persist_operation(ioc,
* Persistent table is full. MPI_SAS_OP_CLEAR_NOT_PRESENT);
*/ mptsas_free_fw_event(ioc, fw_event);
INIT_WORK(&ioc->sas_persist_task,
mptsas_persist_clear_table);
schedule_work(&ioc->sas_persist_task);
break; break;
/*
* TODO, handle other events
*/
case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
case MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: /* TODO */
case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: /* TODO */
case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
default: default:
mptsas_free_fw_event(ioc, fw_event);
break; break;
} }
} }
static void static void
mptsas_send_raid_event(MPT_ADAPTER *ioc, mptsas_send_raid_event(struct fw_event_work *fw_event)
EVENT_DATA_RAID *raid_event_data)
{ {
struct mptsas_hotplug_event *ev; MPT_ADAPTER *ioc;
int status = le32_to_cpu(raid_event_data->SettingsStatus); EVENT_DATA_RAID *raid_event_data;
int state = (status >> 8) & 0xff; struct mptsas_hotplug_event hot_plug_info;
int status;
if (ioc->bus_type != SAS) int state;
return; struct scsi_device *sdev = NULL;
VirtDevice *vdevice = NULL;
ev = kzalloc(sizeof(*ev), GFP_ATOMIC); RaidPhysDiskPage0_t phys_disk;
if (!ev) {
printk(MYIOC_s_WARN_FMT "lost hotplug event\n", ioc->name); ioc = fw_event->ioc;
return; raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
status = le32_to_cpu(raid_event_data->SettingsStatus);
state = (status >> 8) & 0xff;
memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
hot_plug_info.id = raid_event_data->VolumeID;
hot_plug_info.channel = raid_event_data->VolumeBus;
hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
raid_event_data->ReasonCode ==
MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
hot_plug_info.id, 0);
hot_plug_info.sdev = sdev;
if (sdev)
vdevice = sdev->hostdata;
} }
INIT_WORK(&ev->work, mptsas_hotplug_work); devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
ev->ioc = ioc; "ReasonCode=%02x\n", ioc->name, __func__,
ev->id = raid_event_data->VolumeID; raid_event_data->ReasonCode));
ev->channel = raid_event_data->VolumeBus;
ev->event_type = MPTSAS_IGNORE_EVENT;
switch (raid_event_data->ReasonCode) { switch (raid_event_data->ReasonCode) {
case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
ev->phys_disk_num_valid = 1; hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
ev->phys_disk_num = raid_event_data->PhysDiskNum;
ev->event_type = MPTSAS_ADD_DEVICE;
break; break;
case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
ev->phys_disk_num_valid = 1; hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
ev->phys_disk_num = raid_event_data->PhysDiskNum;
ev->hidden_raid_component = 1;
ev->event_type = MPTSAS_DEL_DEVICE;
break; break;
case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED: case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
switch (state) { switch (state) {
case MPI_PD_STATE_ONLINE: case MPI_PD_STATE_ONLINE:
case MPI_PD_STATE_NOT_COMPATIBLE: case MPI_PD_STATE_NOT_COMPATIBLE:
ev->phys_disk_num_valid = 1; mpt_raid_phys_disk_pg0(ioc,
ev->phys_disk_num = raid_event_data->PhysDiskNum; raid_event_data->PhysDiskNum, &phys_disk);
ev->hidden_raid_component = 1; hot_plug_info.id = phys_disk.PhysDiskID;
ev->event_type = MPTSAS_ADD_DEVICE; hot_plug_info.channel = phys_disk.PhysDiskBus;
hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
break; break;
case MPI_PD_STATE_FAILED:
case MPI_PD_STATE_MISSING: case MPI_PD_STATE_MISSING:
case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST: case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
case MPI_PD_STATE_FAILED_AT_HOST_REQUEST: case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON: case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
ev->phys_disk_num_valid = 1; hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
ev->phys_disk_num = raid_event_data->PhysDiskNum;
ev->event_type = MPTSAS_DEL_DEVICE;
break; break;
default: default:
break; break;
} }
break; break;
case MPI_EVENT_RAID_RC_VOLUME_DELETED: case MPI_EVENT_RAID_RC_VOLUME_DELETED:
ev->event_type = MPTSAS_DEL_RAID; if (!sdev)
break;
vdevice->vtarget->deleted = 1; /* block IO */
hot_plug_info.event_type = MPTSAS_DEL_RAID;
break; break;
case MPI_EVENT_RAID_RC_VOLUME_CREATED: case MPI_EVENT_RAID_RC_VOLUME_CREATED:
ev->event_type = MPTSAS_ADD_RAID; if (sdev) {
scsi_device_put(sdev);
break;
}
hot_plug_info.event_type = MPTSAS_ADD_RAID;
break; break;
case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
if (!sdev)
break;
vdevice->vtarget->deleted = 1; /* block IO */
hot_plug_info.event_type = MPTSAS_DEL_RAID;
break;
}
switch (state) { switch (state) {
case MPI_RAIDVOL0_STATUS_STATE_FAILED: case MPI_RAIDVOL0_STATUS_STATE_FAILED:
case MPI_RAIDVOL0_STATUS_STATE_MISSING: case MPI_RAIDVOL0_STATUS_STATE_MISSING:
ev->event_type = MPTSAS_DEL_RAID; if (!sdev)
break;
vdevice->vtarget->deleted = 1; /* block IO */
hot_plug_info.event_type = MPTSAS_DEL_RAID;
break; break;
case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL: case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
case MPI_RAIDVOL0_STATUS_STATE_DEGRADED: case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
ev->event_type = MPTSAS_ADD_RAID; if (sdev) {
scsi_device_put(sdev);
break;
}
hot_plug_info.event_type = MPTSAS_ADD_RAID;
break; break;
default: default:
break; break;
...@@ -3067,7 +3537,11 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc, ...@@ -3067,7 +3537,11 @@ mptsas_send_raid_event(MPT_ADAPTER *ioc,
default: default:
break; break;
} }
schedule_work(&ev->work);
if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
else
mptsas_free_fw_event(ioc, fw_event);
} }
static void static void
...@@ -3106,76 +3580,88 @@ mptsas_send_discovery_event(MPT_ADAPTER *ioc, ...@@ -3106,76 +3580,88 @@ mptsas_send_discovery_event(MPT_ADAPTER *ioc,
* *
*/ */
static void static void
mptsas_send_ir2_event(MPT_ADAPTER *ioc, PTR_MPI_EVENT_DATA_IR2 ir2_data) mptsas_send_ir2_event(struct fw_event_work *fw_event)
{ {
struct mptsas_hotplug_event *ev; MPT_ADAPTER *ioc;
struct mptsas_hotplug_event hot_plug_info;
if (ir2_data->ReasonCode != MPI_EVENT_DATA_IR2 *ir2_data;
MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED) u8 reasonCode;
return;
ioc = fw_event->ioc;
ev = kzalloc(sizeof(*ev), GFP_ATOMIC); ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
if (!ev) reasonCode = ir2_data->ReasonCode;
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
"ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
hot_plug_info.id = ir2_data->TargetID;
hot_plug_info.channel = ir2_data->Bus;
switch (reasonCode) {
case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
break;
default:
mptsas_free_fw_event(ioc, fw_event);
return; return;
}
INIT_WORK(&ev->work, mptsas_hotplug_work); mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
ev->ioc = ioc; }
ev->id = ir2_data->TargetID;
ev->channel = ir2_data->Bus;
ev->event_type = MPTSAS_ADD_INACTIVE_VOLUME;
schedule_work(&ev->work);
};
static int static int
mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
{ {
int rc=1; u32 event = le32_to_cpu(reply->Event);
u8 event = le32_to_cpu(reply->Event) & 0xFF; int sz, event_data_sz;
struct fw_event_work *fw_event;
if (!ioc->sh) unsigned long delay;
goto out;
/* /* events turned off due to host reset or driver unloading */
* sas_discovery_ignore_events if (ioc->fw_events_off)
* return 0;
* This flag is to prevent anymore processing of
* sas events once mptsas_remove function is called.
*/
if (ioc->sas_discovery_ignore_events) {
rc = mptscsih_event_process(ioc, reply);
goto out;
}
delay = msecs_to_jiffies(1);
switch (event) { switch (event) {
case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
mptsas_send_sas_event(ioc, {
(EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
break; (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
case MPI_EVENT_INTEGRATED_RAID:
mptsas_send_raid_event(ioc, if (sas_event_data->ReasonCode ==
(EVENT_DATA_RAID *)reply->Data); MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
break; mptsas_target_reset_queue(ioc, sas_event_data);
case MPI_EVENT_PERSISTENT_TABLE_FULL: return 0;
INIT_WORK(&ioc->sas_persist_task, }
mptsas_persist_clear_table);
schedule_work(&ioc->sas_persist_task);
break; break;
case MPI_EVENT_SAS_DISCOVERY: }
case MPI_EVENT_SAS_DISCOVERY:
mptsas_send_discovery_event(ioc, mptsas_send_discovery_event(ioc,
(EVENT_DATA_SAS_DISCOVERY *)reply->Data); (EVENT_DATA_SAS_DISCOVERY *)reply->Data);
break; break;
case MPI_EVENT_INTEGRATED_RAID:
case MPI_EVENT_PERSISTENT_TABLE_FULL:
case MPI_EVENT_IR2: case MPI_EVENT_IR2:
mptsas_send_ir2_event(ioc, case MPI_EVENT_SAS_PHY_LINK_STATUS:
(PTR_MPI_EVENT_DATA_IR2)reply->Data); case MPI_EVENT_QUEUE_FULL:
break; break;
default: default:
rc = mptscsih_event_process(ioc, reply); return 0;
break;
} }
out:
return rc; event_data_sz = ((reply->MsgLength * 4) -
offsetof(EventNotificationReply_t, Data));
sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
fw_event = kzalloc(sz, GFP_ATOMIC);
if (!fw_event) {
printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
__func__, __LINE__);
return 0;
}
memcpy(fw_event->event_data, reply->Data, event_data_sz);
fw_event->event = event;
fw_event->ioc = ioc;
mptsas_add_fw_event(ioc, fw_event, delay);
return 0;
} }
static int static int
...@@ -3197,6 +3683,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -3197,6 +3683,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return r; return r;
ioc = pci_get_drvdata(pdev); ioc = pci_get_drvdata(pdev);
mptsas_fw_event_off(ioc);
ioc->DoneCtx = mptsasDoneCtx; ioc->DoneCtx = mptsasDoneCtx;
ioc->TaskCtx = mptsasTaskCtx; ioc->TaskCtx = mptsasTaskCtx;
ioc->InternalCtx = mptsasInternalCtx; ioc->InternalCtx = mptsasInternalCtx;
...@@ -3339,6 +3826,9 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -3339,6 +3826,9 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hd->last_queue_full = 0; hd->last_queue_full = 0;
INIT_LIST_HEAD(&hd->target_reset_list); INIT_LIST_HEAD(&hd->target_reset_list);
INIT_LIST_HEAD(&ioc->sas_device_info_list);
mutex_init(&ioc->sas_device_info_mutex);
spin_unlock_irqrestore(&ioc->FreeQlock, flags); spin_unlock_irqrestore(&ioc->FreeQlock, flags);
if (ioc->sas_data.ptClear==1) { if (ioc->sas_data.ptClear==1) {
...@@ -3354,7 +3844,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -3354,7 +3844,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
} }
mptsas_scan_sas_topology(ioc); mptsas_scan_sas_topology(ioc);
mptsas_fw_event_on(ioc);
return 0; return 0;
out_mptsas_probe: out_mptsas_probe:
...@@ -3368,7 +3858,8 @@ mptsas_shutdown(struct pci_dev *pdev) ...@@ -3368,7 +3858,8 @@ mptsas_shutdown(struct pci_dev *pdev)
{ {
MPT_ADAPTER *ioc = pci_get_drvdata(pdev); MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
ioc->sas_discovery_quiesce_io = 0; mptsas_fw_event_off(ioc);
mptsas_cleanup_fw_event_q(ioc);
} }
static void __devexit mptsas_remove(struct pci_dev *pdev) static void __devexit mptsas_remove(struct pci_dev *pdev)
...@@ -3379,6 +3870,8 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) ...@@ -3379,6 +3870,8 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
mptsas_shutdown(pdev); mptsas_shutdown(pdev);
mptsas_del_device_components(ioc);
ioc->sas_discovery_ignore_events = 1; ioc->sas_discovery_ignore_events = 1;
sas_remove_host(ioc->sh); sas_remove_host(ioc->sh);
...@@ -3387,6 +3880,7 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) ...@@ -3387,6 +3880,7 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
list_del(&p->list); list_del(&p->list);
for (i = 0 ; i < p->num_phys ; i++) for (i = 0 ; i < p->num_phys ; i++)
mptsas_port_delete(ioc, p->phy_info[i].port_details); mptsas_port_delete(ioc, p->phy_info[i].port_details);
kfree(p->phy_info); kfree(p->phy_info);
kfree(p); kfree(p);
} }
......
...@@ -61,12 +61,30 @@ enum mptsas_hotplug_action { ...@@ -61,12 +61,30 @@ enum mptsas_hotplug_action {
MPTSAS_DEL_DEVICE, MPTSAS_DEL_DEVICE,
MPTSAS_ADD_RAID, MPTSAS_ADD_RAID,
MPTSAS_DEL_RAID, MPTSAS_DEL_RAID,
MPTSAS_ADD_PHYSDISK,
MPTSAS_ADD_PHYSDISK_REPROBE,
MPTSAS_DEL_PHYSDISK,
MPTSAS_DEL_PHYSDISK_REPROBE,
MPTSAS_ADD_INACTIVE_VOLUME, MPTSAS_ADD_INACTIVE_VOLUME,
MPTSAS_IGNORE_EVENT, MPTSAS_IGNORE_EVENT,
}; };
struct mptsas_mapping{
u8 id;
u8 channel;
};
struct mptsas_device_info {
struct list_head list;
struct mptsas_mapping os; /* operating system mapping*/
struct mptsas_mapping fw; /* firmware mapping */
u64 sas_address;
u32 device_info; /* specific bits for devices */
u16 slot; /* enclosure slot id */
u64 enclosure_logical_id; /*enclosure address */
};
struct mptsas_hotplug_event { struct mptsas_hotplug_event {
struct work_struct work;
MPT_ADAPTER *ioc; MPT_ADAPTER *ioc;
enum mptsas_hotplug_action event_type; enum mptsas_hotplug_action event_type;
u64 sas_address; u64 sas_address;
...@@ -74,11 +92,18 @@ struct mptsas_hotplug_event { ...@@ -74,11 +92,18 @@ struct mptsas_hotplug_event {
u8 id; u8 id;
u32 device_info; u32 device_info;
u16 handle; u16 handle;
u16 parent_handle;
u8 phy_id; u8 phy_id;
u8 phys_disk_num_valid; /* hrc (hidden raid component) */
u8 phys_disk_num; /* hrc - unique index*/ u8 phys_disk_num; /* hrc - unique index*/
u8 hidden_raid_component; /* hrc - don't expose*/ struct scsi_device *sdev;
};
struct fw_event_work {
struct list_head list;
struct delayed_work work;
MPT_ADAPTER *ioc;
u32 event;
u8 retries;
u8 event_data[1];
}; };
struct mptsas_discovery_event { struct mptsas_discovery_event {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment