diff options
-rw-r--r-- | drivers/message/fusion/mptbase.h | 1 | ||||
-rw-r--r-- | drivers/message/fusion/mptsas.c | 207 | ||||
-rw-r--r-- | drivers/message/fusion/mptscsih.c | 21 | ||||
-rw-r--r-- | drivers/message/fusion/mptscsih.h | 1 |
4 files changed, 230 insertions, 0 deletions
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 4f3d4c34bcd8..1c8514dc31ca 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h | |||
@@ -758,6 +758,7 @@ typedef struct _MPT_ADAPTER | |||
758 | struct scsi_cmnd **ScsiLookup; | 758 | struct scsi_cmnd **ScsiLookup; |
759 | spinlock_t scsi_lookup_lock; | 759 | spinlock_t scsi_lookup_lock; |
760 | u64 dma_mask; | 760 | u64 dma_mask; |
761 | u32 broadcast_aen_busy; | ||
761 | char reset_work_q_name[MPT_KOBJ_NAME_LEN]; | 762 | char reset_work_q_name[MPT_KOBJ_NAME_LEN]; |
762 | struct workqueue_struct *reset_work_q; | 763 | struct workqueue_struct *reset_work_q; |
763 | struct delayed_work fault_reset_work; | 764 | struct delayed_work fault_reset_work; |
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 10a12d846e85..88a1a6d3bc04 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
@@ -121,6 +121,7 @@ static void mptsas_expander_delete(MPT_ADAPTER *ioc, | |||
121 | static void mptsas_send_expander_event(struct fw_event_work *fw_event); | 121 | static void mptsas_send_expander_event(struct fw_event_work *fw_event); |
122 | static void mptsas_not_responding_devices(MPT_ADAPTER *ioc); | 122 | static void mptsas_not_responding_devices(MPT_ADAPTER *ioc); |
123 | static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); | 123 | static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc); |
124 | static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event); | ||
124 | static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event); | 125 | static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event); |
125 | static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id); | 126 | static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id); |
126 | 127 | ||
@@ -287,6 +288,21 @@ mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, | |||
287 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | 288 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); |
288 | } | 289 | } |
289 | 290 | ||
291 | /* requeue a sas firmware event */ | ||
292 | static void | ||
293 | mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event, | ||
294 | unsigned long delay) | ||
295 | { | ||
296 | unsigned long flags; | ||
297 | spin_lock_irqsave(&ioc->fw_event_lock, flags); | ||
298 | devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task " | ||
299 | "(fw_event=0x%p)\n", ioc->name, __func__, fw_event)); | ||
300 | fw_event->retries++; | ||
301 | queue_delayed_work(ioc->fw_event_q, &fw_event->work, | ||
302 | msecs_to_jiffies(delay)); | ||
303 | spin_unlock_irqrestore(&ioc->fw_event_lock, flags); | ||
304 | } | ||
305 | |||
290 | /* free memory assoicated to a sas firmware event */ | 306 | /* free memory assoicated to a sas firmware event */ |
291 | static void | 307 | static void |
292 | mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) | 308 | mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event) |
@@ -1606,6 +1622,9 @@ mptsas_firmware_event_work(struct work_struct *work) | |||
1606 | MPI_SAS_OP_CLEAR_NOT_PRESENT); | 1622 | MPI_SAS_OP_CLEAR_NOT_PRESENT); |
1607 | mptsas_free_fw_event(ioc, fw_event); | 1623 | mptsas_free_fw_event(ioc, fw_event); |
1608 | break; | 1624 | break; |
1625 | case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: | ||
1626 | mptsas_broadcast_primative_work(fw_event); | ||
1627 | break; | ||
1609 | case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: | 1628 | case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE: |
1610 | mptsas_send_expander_event(fw_event); | 1629 | mptsas_send_expander_event(fw_event); |
1611 | break; | 1630 | break; |
@@ -4325,6 +4344,182 @@ mptsas_send_raid_event(struct fw_event_work *fw_event) | |||
4325 | mptsas_free_fw_event(ioc, fw_event); | 4344 | mptsas_free_fw_event(ioc, fw_event); |
4326 | } | 4345 | } |
4327 | 4346 | ||
4347 | /** | ||
4348 | * mptsas_issue_tm - send mptsas internal tm request | ||
4349 | * @ioc: Pointer to MPT_ADAPTER structure | ||
4350 | * @type: Task Management type | ||
4351 | * @channel: channel number for task management | ||
4352 | * @id: Logical Target ID for reset (if appropriate) | ||
4353 | * @lun: Logical unit for reset (if appropriate) | ||
4354 | * @task_context: Context for the task to be aborted | ||
4355 | * @timeout: timeout for task management control | ||
4356 | * | ||
4357 | * return 0 on success and -1 on failure: | ||
4358 | * | ||
4359 | */ | ||
4360 | static int | ||
4361 | mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun, | ||
4362 | int task_context, ulong timeout, u8 *issue_reset) | ||
4363 | { | ||
4364 | MPT_FRAME_HDR *mf; | ||
4365 | SCSITaskMgmt_t *pScsiTm; | ||
4366 | int retval; | ||
4367 | unsigned long timeleft; | ||
4368 | |||
4369 | *issue_reset = 0; | ||
4370 | mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc); | ||
4371 | if (mf == NULL) { | ||
4372 | retval = -1; /* return failure */ | ||
4373 | dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no " | ||
4374 | "msg frames!!\n", ioc->name)); | ||
4375 | goto out; | ||
4376 | } | ||
4377 | |||
4378 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, " | ||
4379 | "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, " | ||
4380 | "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf, | ||
4381 | type, timeout, channel, id, (unsigned long long)lun, | ||
4382 | task_context)); | ||
4383 | |||
4384 | pScsiTm = (SCSITaskMgmt_t *) mf; | ||
4385 | memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t)); | ||
4386 | pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; | ||
4387 | pScsiTm->TaskType = type; | ||
4388 | pScsiTm->MsgFlags = 0; | ||
4389 | pScsiTm->TargetID = id; | ||
4390 | pScsiTm->Bus = channel; | ||
4391 | pScsiTm->ChainOffset = 0; | ||
4392 | pScsiTm->Reserved = 0; | ||
4393 | pScsiTm->Reserved1 = 0; | ||
4394 | pScsiTm->TaskMsgContext = task_context; | ||
4395 | int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN); | ||
4396 | |||
4397 | INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status) | ||
4398 | CLEAR_MGMT_STATUS(ioc->internal_cmds.status) | ||
4399 | retval = 0; | ||
4400 | mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf); | ||
4401 | |||
4402 | /* Now wait for the command to complete */ | ||
4403 | timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done, | ||
4404 | timeout*HZ); | ||
4405 | if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) { | ||
4406 | retval = -1; /* return failure */ | ||
4407 | dtmprintk(ioc, printk(MYIOC_s_ERR_FMT | ||
4408 | "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf)); | ||
4409 | mpt_free_msg_frame(ioc, mf); | ||
4410 | if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) | ||
4411 | goto out; | ||
4412 | *issue_reset = 1; | ||
4413 | goto out; | ||
4414 | } | ||
4415 | |||
4416 | if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) { | ||
4417 | retval = -1; /* return failure */ | ||
4418 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
4419 | "TaskMgmt request: failed with no reply\n", ioc->name)); | ||
4420 | goto out; | ||
4421 | } | ||
4422 | |||
4423 | out: | ||
4424 | CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status) | ||
4425 | return retval; | ||
4426 | } | ||
4427 | |||
4428 | /** | ||
4429 | * mptsas_broadcast_primative_work - Handle broadcast primitives | ||
4430 | * @work: work queue payload containing info describing the event | ||
4431 | * | ||
4432 | * this will be handled in workqueue context. | ||
4433 | */ | ||
4434 | static void | ||
4435 | mptsas_broadcast_primative_work(struct fw_event_work *fw_event) | ||
4436 | { | ||
4437 | MPT_ADAPTER *ioc = fw_event->ioc; | ||
4438 | MPT_FRAME_HDR *mf; | ||
4439 | VirtDevice *vdevice; | ||
4440 | int ii; | ||
4441 | struct scsi_cmnd *sc; | ||
4442 | SCSITaskMgmtReply_t *pScsiTmReply; | ||
4443 | u8 issue_reset; | ||
4444 | int task_context; | ||
4445 | u8 channel, id; | ||
4446 | int lun; | ||
4447 | u32 termination_count; | ||
4448 | u32 query_count; | ||
4449 | |||
4450 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
4451 | "%s - enter\n", ioc->name, __func__)); | ||
4452 | |||
4453 | mutex_lock(&ioc->taskmgmt_cmds.mutex); | ||
4454 | if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) { | ||
4455 | mutex_unlock(&ioc->taskmgmt_cmds.mutex); | ||
4456 | mptsas_requeue_fw_event(ioc, fw_event, 1000); | ||
4457 | return; | ||
4458 | } | ||
4459 | |||
4460 | issue_reset = 0; | ||
4461 | termination_count = 0; | ||
4462 | query_count = 0; | ||
4463 | mpt_findImVolumes(ioc); | ||
4464 | pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply; | ||
4465 | |||
4466 | for (ii = 0; ii < ioc->req_depth; ii++) { | ||
4467 | if (ioc->fw_events_off) | ||
4468 | goto out; | ||
4469 | sc = mptscsih_get_scsi_lookup(ioc, ii); | ||
4470 | if (!sc) | ||
4471 | continue; | ||
4472 | mf = MPT_INDEX_2_MFPTR(ioc, ii); | ||
4473 | if (!mf) | ||
4474 | continue; | ||
4475 | task_context = mf->u.frame.hwhdr.msgctxu.MsgContext; | ||
4476 | vdevice = sc->device->hostdata; | ||
4477 | if (!vdevice || !vdevice->vtarget) | ||
4478 | continue; | ||
4479 | if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) | ||
4480 | continue; /* skip hidden raid components */ | ||
4481 | if (vdevice->vtarget->raidVolume) | ||
4482 | continue; /* skip hidden raid components */ | ||
4483 | channel = vdevice->vtarget->channel; | ||
4484 | id = vdevice->vtarget->id; | ||
4485 | lun = vdevice->lun; | ||
4486 | if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK, | ||
4487 | channel, id, (u64)lun, task_context, 30, &issue_reset)) | ||
4488 | goto out; | ||
4489 | query_count++; | ||
4490 | termination_count += | ||
4491 | le32_to_cpu(pScsiTmReply->TerminationCount); | ||
4492 | if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) && | ||
4493 | (pScsiTmReply->ResponseCode == | ||
4494 | MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED || | ||
4495 | pScsiTmReply->ResponseCode == | ||
4496 | MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC)) | ||
4497 | continue; | ||
4498 | if (mptsas_issue_tm(ioc, | ||
4499 | MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET, | ||
4500 | channel, id, (u64)lun, 0, 30, &issue_reset)) | ||
4501 | goto out; | ||
4502 | termination_count += | ||
4503 | le32_to_cpu(pScsiTmReply->TerminationCount); | ||
4504 | } | ||
4505 | |||
4506 | out: | ||
4507 | dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT | ||
4508 | "%s - exit, query_count = %d termination_count = %d\n", | ||
4509 | ioc->name, __func__, query_count, termination_count)); | ||
4510 | |||
4511 | ioc->broadcast_aen_busy = 0; | ||
4512 | mpt_clear_taskmgmt_in_progress_flag(ioc); | ||
4513 | mutex_unlock(&ioc->taskmgmt_cmds.mutex); | ||
4514 | |||
4515 | if (issue_reset) { | ||
4516 | printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n", | ||
4517 | ioc->name, __func__); | ||
4518 | mpt_HardResetHandler(ioc, CAN_SLEEP); | ||
4519 | } | ||
4520 | mptsas_free_fw_event(ioc, fw_event); | ||
4521 | } | ||
4522 | |||
4328 | /* | 4523 | /* |
4329 | * mptsas_send_ir2_event - handle exposing hidden disk when | 4524 | * mptsas_send_ir2_event - handle exposing hidden disk when |
4330 | * an inactive raid volume is added | 4525 | * an inactive raid volume is added |
@@ -4388,6 +4583,18 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | |||
4388 | 4583 | ||
4389 | delay = msecs_to_jiffies(1); | 4584 | delay = msecs_to_jiffies(1); |
4390 | switch (event) { | 4585 | switch (event) { |
4586 | case MPI_EVENT_SAS_BROADCAST_PRIMITIVE: | ||
4587 | { | ||
4588 | EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data = | ||
4589 | (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data; | ||
4590 | if (broadcast_event_data->Primitive != | ||
4591 | MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) | ||
4592 | return 0; | ||
4593 | if (ioc->broadcast_aen_busy) | ||
4594 | return 0; | ||
4595 | ioc->broadcast_aen_busy = 1; | ||
4596 | break; | ||
4597 | } | ||
4391 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: | 4598 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: |
4392 | { | 4599 | { |
4393 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data = | 4600 | EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data = |
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index cf1aba18a09f..96681203d4a9 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c | |||
@@ -80,6 +80,7 @@ MODULE_VERSION(my_VERSION); | |||
80 | /* | 80 | /* |
81 | * Other private/forward protos... | 81 | * Other private/forward protos... |
82 | */ | 82 | */ |
83 | struct scsi_cmnd *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); | ||
83 | static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i); | 84 | static struct scsi_cmnd * mptscsih_getclear_scsi_lookup(MPT_ADAPTER *ioc, int i); |
84 | static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd); | 85 | static void mptscsih_set_scsi_lookup(MPT_ADAPTER *ioc, int i, struct scsi_cmnd *scmd); |
85 | static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd); | 86 | static int SCPNT_TO_LOOKUP_IDX(MPT_ADAPTER *ioc, struct scsi_cmnd *scmd); |
@@ -2419,6 +2420,26 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR | |||
2419 | } | 2420 | } |
2420 | } | 2421 | } |
2421 | 2422 | ||
2423 | /** | ||
2424 | * mptscsih_get_scsi_lookup - retrieves scmd entry | ||
2425 | * @ioc: Pointer to MPT_ADAPTER structure | ||
2426 | * @i: index into the array | ||
2427 | * | ||
2428 | * Returns the scsi_cmd pointer | ||
2429 | */ | ||
2430 | struct scsi_cmnd * | ||
2431 | mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i) | ||
2432 | { | ||
2433 | unsigned long flags; | ||
2434 | struct scsi_cmnd *scmd; | ||
2435 | |||
2436 | spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); | ||
2437 | scmd = ioc->ScsiLookup[i]; | ||
2438 | spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); | ||
2439 | |||
2440 | return scmd; | ||
2441 | } | ||
2442 | EXPORT_SYMBOL(mptscsih_get_scsi_lookup); | ||
2422 | 2443 | ||
2423 | /** | 2444 | /** |
2424 | * mptscsih_getclear_scsi_lookup | 2445 | * mptscsih_getclear_scsi_lookup |
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index 572739565f6a..eb3f677528ac 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h | |||
@@ -133,4 +133,5 @@ extern void mptscsih_timer_expired(unsigned long data); | |||
133 | extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id); | 133 | extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id); |
134 | extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id); | 134 | extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id); |
135 | extern struct device_attribute *mptscsih_host_attrs[]; | 135 | extern struct device_attribute *mptscsih_host_attrs[]; |
136 | extern struct scsi_cmnd *mptscsih_get_scsi_lookup(MPT_ADAPTER *ioc, int i); | ||
136 | extern void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code); | 137 | extern void mptscsih_taskmgmt_response_code(MPT_ADAPTER *ioc, u8 response_code); |