diff options
Diffstat (limited to 'drivers/message/fusion/mptsas.c')
-rw-r--r-- | drivers/message/fusion/mptsas.c | 207 |
1 files changed, 207 insertions, 0 deletions
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 = |