diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_attr.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 83 |
1 files changed, 67 insertions, 16 deletions
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 6cc88b198fa..c0b02b11d88 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -20,6 +20,7 @@ *******************************************************************/ #include <linux/ctype.h> +#include <linux/delay.h> #include <linux/pci.h> #include <linux/interrupt.h> @@ -213,6 +214,7 @@ lpfc_issue_lip(struct Scsi_Host *host) int mbxstatus = MBXERR_ERROR; if ((phba->fc_flag & FC_OFFLINE_MODE) || + (phba->fc_flag & FC_BLOCK_MGMT_IO) || (phba->hba_state != LPFC_HBA_READY)) return -EPERM; @@ -247,19 +249,62 @@ lpfc_issue_lip(struct Scsi_Host *host) } static int -lpfc_selective_reset(struct lpfc_hba *phba) +lpfc_do_offline(struct lpfc_hba *phba, uint32_t type) { struct completion online_compl; + struct lpfc_sli_ring *pring; + struct lpfc_sli *psli; int status = 0; + int cnt = 0; + int i; init_completion(&online_compl); lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_OFFLINE); + LPFC_EVT_OFFLINE_PREP); + wait_for_completion(&online_compl); + + if (status != 0) + return -EIO; + + psli = &phba->sli; + + for (i = 0; i < psli->num_rings; i++) { + pring = &psli->ring[i]; + /* The linkdown event takes 30 seconds to timeout. */ + while (pring->txcmplq_cnt) { + msleep(10); + if (cnt++ > 3000) { + lpfc_printf_log(phba, + KERN_WARNING, LOG_INIT, + "%d:0466 Outstanding IO when " + "bringing Adapter offline\n", + phba->brd_no); + break; + } + } + } + + init_completion(&online_compl); + lpfc_workq_post_event(phba, &status, &online_compl, type); wait_for_completion(&online_compl); if (status != 0) return -EIO; + return 0; +} + +static int +lpfc_selective_reset(struct lpfc_hba *phba) +{ + struct completion online_compl; + int status = 0; + + status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); + + if (status != 0) + return status; + init_completion(&online_compl); lpfc_workq_post_event(phba, &status, &online_compl, LPFC_EVT_ONLINE); @@ -324,23 +369,19 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count) init_completion(&online_compl); - if(strncmp(buf, "online", sizeof("online") - 1) == 0) + if(strncmp(buf, "online", sizeof("online") - 1) == 0) { lpfc_workq_post_event(phba, &status, &online_compl, LPFC_EVT_ONLINE); - else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0) - lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_OFFLINE); + wait_for_completion(&online_compl); + } else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0) + status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0) - lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_WARM_START); - else if (strncmp(buf, "error", sizeof("error") - 1) == 0) - lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_KILL); + status = lpfc_do_offline(phba, LPFC_EVT_WARM_START); + else if (strncmp(buf, "error", sizeof("error") - 1) == 0) + status = lpfc_do_offline(phba, LPFC_EVT_KILL); else return -EINVAL; - wait_for_completion(&online_compl); - if (!status) return strlen(buf); else @@ -645,9 +686,7 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count) dev_printk(KERN_NOTICE, &phba->pcidev->dev, "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no); - init_completion(&online_compl); - lpfc_workq_post_event(phba, &stat1, &online_compl, LPFC_EVT_OFFLINE); - wait_for_completion(&online_compl); + stat1 = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); if (stat1) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "%d:0463 lpfc_soft_wwpn attribute set failed to reinit " @@ -1307,6 +1346,12 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) return -EPERM; } + if (phba->fc_flag & FC_BLOCK_MGMT_IO) { + sysfs_mbox_idle(phba); + spin_unlock_irq(host->host_lock); + return -EAGAIN; + } + if ((phba->fc_flag & FC_OFFLINE_MODE) || (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE))){ @@ -1551,6 +1596,9 @@ lpfc_get_stats(struct Scsi_Host *shost) unsigned long seconds; int rc = 0; + if (phba->fc_flag & FC_BLOCK_MGMT_IO) + return NULL; + pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmboxq) return NULL; @@ -1651,6 +1699,9 @@ lpfc_reset_stats(struct Scsi_Host *shost) MAILBOX_t *pmb; int rc = 0; + if (phba->fc_flag & FC_BLOCK_MGMT_IO) + return; + pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmboxq) return; |