diff options
Diffstat (limited to 'drivers/message/fusion/mptbase.c')
-rw-r--r-- | drivers/message/fusion/mptbase.c | 92 |
1 files changed, 88 insertions, 4 deletions
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 7956a10f9488..e9c6a6047a00 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c | |||
@@ -63,6 +63,8 @@ | |||
63 | #ifdef CONFIG_MTRR | 63 | #ifdef CONFIG_MTRR |
64 | #include <asm/mtrr.h> | 64 | #include <asm/mtrr.h> |
65 | #endif | 65 | #endif |
66 | #include <linux/kthread.h> | ||
67 | #include <scsi/scsi_host.h> | ||
66 | 68 | ||
67 | #include "mptbase.h" | 69 | #include "mptbase.h" |
68 | #include "lsi/mpi_log_fc.h" | 70 | #include "lsi/mpi_log_fc.h" |
@@ -323,6 +325,32 @@ mpt_is_discovery_complete(MPT_ADAPTER *ioc) | |||
323 | return rc; | 325 | return rc; |
324 | } | 326 | } |
325 | 327 | ||
328 | |||
329 | /** | ||
330 | * mpt_remove_dead_ioc_func - kthread context to remove dead ioc | ||
331 | * @arg: input argument, used to derive ioc | ||
332 | * | ||
333 | * Return 0 if controller is removed from pci subsystem. | ||
334 | * Return -1 for other case. | ||
335 | */ | ||
336 | static int mpt_remove_dead_ioc_func(void *arg) | ||
337 | { | ||
338 | MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; | ||
339 | struct pci_dev *pdev; | ||
340 | |||
341 | if ((ioc == NULL)) | ||
342 | return -1; | ||
343 | |||
344 | pdev = ioc->pcidev; | ||
345 | if ((pdev == NULL)) | ||
346 | return -1; | ||
347 | |||
348 | pci_remove_bus_device(pdev); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | |||
353 | |||
326 | /** | 354 | /** |
327 | * mpt_fault_reset_work - work performed on workq after ioc fault | 355 | * mpt_fault_reset_work - work performed on workq after ioc fault |
328 | * @work: input argument, used to derive ioc | 356 | * @work: input argument, used to derive ioc |
@@ -336,12 +364,45 @@ mpt_fault_reset_work(struct work_struct *work) | |||
336 | u32 ioc_raw_state; | 364 | u32 ioc_raw_state; |
337 | int rc; | 365 | int rc; |
338 | unsigned long flags; | 366 | unsigned long flags; |
367 | MPT_SCSI_HOST *hd; | ||
368 | struct task_struct *p; | ||
339 | 369 | ||
340 | if (ioc->ioc_reset_in_progress || !ioc->active) | 370 | if (ioc->ioc_reset_in_progress || !ioc->active) |
341 | goto out; | 371 | goto out; |
342 | 372 | ||
373 | |||
343 | ioc_raw_state = mpt_GetIocState(ioc, 0); | 374 | ioc_raw_state = mpt_GetIocState(ioc, 0); |
344 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_FAULT) { | 375 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_MASK) { |
376 | printk(MYIOC_s_INFO_FMT "%s: IOC is non-operational !!!!\n", | ||
377 | ioc->name, __func__); | ||
378 | |||
379 | /* | ||
380 | * Call mptscsih_flush_pending_cmds callback so that we | ||
381 | * flush all pending commands back to OS. | ||
382 | * This call is required to aovid deadlock at block layer. | ||
383 | * Dead IOC will fail to do diag reset,and this call is safe | ||
384 | * since dead ioc will never return any command back from HW. | ||
385 | */ | ||
386 | hd = shost_priv(ioc->sh); | ||
387 | ioc->schedule_dead_ioc_flush_running_cmds(hd); | ||
388 | |||
389 | /*Remove the Dead Host */ | ||
390 | p = kthread_run(mpt_remove_dead_ioc_func, ioc, | ||
391 | "mpt_dead_ioc_%d", ioc->id); | ||
392 | if (IS_ERR(p)) { | ||
393 | printk(MYIOC_s_ERR_FMT | ||
394 | "%s: Running mpt_dead_ioc thread failed !\n", | ||
395 | ioc->name, __func__); | ||
396 | } else { | ||
397 | printk(MYIOC_s_WARN_FMT | ||
398 | "%s: Running mpt_dead_ioc thread success !\n", | ||
399 | ioc->name, __func__); | ||
400 | } | ||
401 | return; /* don't rearm timer */ | ||
402 | } | ||
403 | |||
404 | if ((ioc_raw_state & MPI_IOC_STATE_MASK) | ||
405 | == MPI_IOC_STATE_FAULT) { | ||
345 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", | 406 | printk(MYIOC_s_WARN_FMT "IOC is in FAULT state (%04xh)!!!\n", |
346 | ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); | 407 | ioc->name, ioc_raw_state & MPI_DOORBELL_DATA_MASK); |
347 | printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", | 408 | printk(MYIOC_s_WARN_FMT "Issuing HardReset from %s!!\n", |
@@ -6413,8 +6474,19 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) | |||
6413 | pReq->Action, ioc->mptbase_cmds.status, timeleft)); | 6474 | pReq->Action, ioc->mptbase_cmds.status, timeleft)); |
6414 | if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) | 6475 | if (ioc->mptbase_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET) |
6415 | goto out; | 6476 | goto out; |
6416 | if (!timeleft) | 6477 | if (!timeleft) { |
6478 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); | ||
6479 | if (ioc->ioc_reset_in_progress) { | ||
6480 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, | ||
6481 | flags); | ||
6482 | printk(MYIOC_s_INFO_FMT "%s: host reset in" | ||
6483 | " progress mpt_config timed out.!!\n", | ||
6484 | __func__, ioc->name); | ||
6485 | return -EFAULT; | ||
6486 | } | ||
6487 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | ||
6417 | issue_hard_reset = 1; | 6488 | issue_hard_reset = 1; |
6489 | } | ||
6418 | goto out; | 6490 | goto out; |
6419 | } | 6491 | } |
6420 | 6492 | ||
@@ -7128,7 +7200,18 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) | |||
7128 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); | 7200 | spin_lock_irqsave(&ioc->taskmgmt_lock, flags); |
7129 | if (ioc->ioc_reset_in_progress) { | 7201 | if (ioc->ioc_reset_in_progress) { |
7130 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | 7202 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); |
7131 | return 0; | 7203 | ioc->wait_on_reset_completion = 1; |
7204 | do { | ||
7205 | ssleep(1); | ||
7206 | } while (ioc->ioc_reset_in_progress == 1); | ||
7207 | ioc->wait_on_reset_completion = 0; | ||
7208 | return ioc->reset_status; | ||
7209 | } | ||
7210 | if (ioc->wait_on_reset_completion) { | ||
7211 | spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); | ||
7212 | rc = 0; | ||
7213 | time_count = jiffies; | ||
7214 | goto exit; | ||
7132 | } | 7215 | } |
7133 | ioc->ioc_reset_in_progress = 1; | 7216 | ioc->ioc_reset_in_progress = 1; |
7134 | if (ioc->alt_ioc) | 7217 | if (ioc->alt_ioc) |
@@ -7165,6 +7248,7 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) | |||
7165 | ioc->ioc_reset_in_progress = 0; | 7248 | ioc->ioc_reset_in_progress = 0; |
7166 | ioc->taskmgmt_quiesce_io = 0; | 7249 | ioc->taskmgmt_quiesce_io = 0; |
7167 | ioc->taskmgmt_in_progress = 0; | 7250 | ioc->taskmgmt_in_progress = 0; |
7251 | ioc->reset_status = rc; | ||
7168 | if (ioc->alt_ioc) { | 7252 | if (ioc->alt_ioc) { |
7169 | ioc->alt_ioc->ioc_reset_in_progress = 0; | 7253 | ioc->alt_ioc->ioc_reset_in_progress = 0; |
7170 | ioc->alt_ioc->taskmgmt_quiesce_io = 0; | 7254 | ioc->alt_ioc->taskmgmt_quiesce_io = 0; |
@@ -7180,7 +7264,7 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) | |||
7180 | ioc->alt_ioc, MPT_IOC_POST_RESET); | 7264 | ioc->alt_ioc, MPT_IOC_POST_RESET); |
7181 | } | 7265 | } |
7182 | } | 7266 | } |
7183 | 7267 | exit: | |
7184 | dtmprintk(ioc, | 7268 | dtmprintk(ioc, |
7185 | printk(MYIOC_s_DEBUG_FMT | 7269 | printk(MYIOC_s_DEBUG_FMT |
7186 | "HardResetHandler: completed (%d seconds): %s\n", ioc->name, | 7270 | "HardResetHandler: completed (%d seconds): %s\n", ioc->name, |