From 4530a16967a52e7ff6f8840d7e323cfb589fa2ae Mon Sep 17 00:00:00 2001 From: "vignesh.babu@wipro.com" Date: Mon, 16 Apr 2007 11:35:33 +0530 Subject: [SCSI] ch: kmalloc/memset->kzalloc Replacing kmalloc/memset combination with kzalloc. Signed-off-by: vignesh babu Signed-off-by: James Bottomley diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 2a2cc6c..2311019 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -319,10 +319,9 @@ ch_readconfig(scsi_changer *ch) int result,id,lun,i; u_int elem; - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + buffer = kzalloc(512, GFP_KERNEL | GFP_DMA); if (!buffer) return -ENOMEM; - memset(buffer,0,512); memset(cmd,0,sizeof(cmd)); cmd[0] = MODE_SENSE; @@ -530,10 +529,9 @@ ch_set_voltag(scsi_changer *ch, u_int elem, u_char *buffer; int result; - buffer = kmalloc(512, GFP_KERNEL); + buffer = kzalloc(512, GFP_KERNEL); if (!buffer) return -ENOMEM; - memset(buffer,0,512); dprintk("%s %s voltag: 0x%x => \"%s\"\n", clear ? "clear" : "set", @@ -922,11 +920,10 @@ static int ch_probe(struct device *dev) if (sd->type != TYPE_MEDIUM_CHANGER) return -ENODEV; - ch = kmalloc(sizeof(*ch), GFP_KERNEL); + ch = kzalloc(sizeof(*ch), GFP_KERNEL); if (NULL == ch) return -ENOMEM; - memset(ch,0,sizeof(*ch)); ch->minor = ch_devcount; sprintf(ch->name,"ch%d",ch->minor); mutex_init(&ch->lock); -- cgit v0.10.2 From ab552204599d311988be89fe0bbbe5ea9d84184a Mon Sep 17 00:00:00 2001 From: "vignesh.babu@wipro.com" Date: Mon, 16 Apr 2007 11:35:38 +0530 Subject: [SCSI] dpt_i2o: kmalloc/memset->kzalloc Replacing kmalloc/memset combination with kzalloc. Signed-off-by: vignesh babu Signed-off-by: James Bottomley diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index f7b9dbd..6c384ab 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -1309,13 +1309,12 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba) schedule_timeout_uninterruptible(1); } while (m == EMPTY_QUEUE); - status = kmalloc(4, GFP_KERNEL|ADDR32); + status = kzalloc(4, GFP_KERNEL|ADDR32); if(status == NULL) { adpt_send_nop(pHba, m); printk(KERN_ERR"IOP reset failed - no free memory.\n"); return -ENOMEM; } - memset(status,0,4); msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0; msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID; @@ -1505,21 +1504,19 @@ static int adpt_i2o_parse_lct(adpt_hba* pHba) continue; } if( pHba->channel[bus_no].device[scsi_id] == NULL){ - pDev = kmalloc(sizeof(struct adpt_device),GFP_KERNEL); + pDev = kzalloc(sizeof(struct adpt_device),GFP_KERNEL); if(pDev == NULL) { return -ENOMEM; } pHba->channel[bus_no].device[scsi_id] = pDev; - memset(pDev,0,sizeof(struct adpt_device)); } else { for( pDev = pHba->channel[bus_no].device[scsi_id]; pDev->next_lun; pDev = pDev->next_lun){ } - pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL); + pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL); if(pDev->next_lun == NULL) { return -ENOMEM; } - memset(pDev->next_lun,0,sizeof(struct adpt_device)); pDev = pDev->next_lun; } pDev->tid = tid; @@ -1668,12 +1665,11 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg) reply_size = REPLY_FRAME_SIZE; } reply_size *= 4; - reply = kmalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL); + reply = kzalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL); if(reply == NULL) { printk(KERN_WARNING"%s: Could not allocate reply buffer\n",pHba->name); return -ENOMEM; } - memset(reply,0,REPLY_FRAME_SIZE*4); sg_offset = (msg[0]>>4)&0xf; msg[2] = 0x40000000; // IOCTL context msg[3] = (u32)reply; @@ -2445,7 +2441,7 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) } pDev = pHba->channel[bus_no].device[scsi_id]; if( pDev == NULL){ - pDev = kmalloc(sizeof(struct adpt_device),GFP_KERNEL); + pDev = kzalloc(sizeof(struct adpt_device),GFP_KERNEL); if(pDev == NULL) { return -ENOMEM; } @@ -2454,12 +2450,11 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) while (pDev->next_lun) { pDev = pDev->next_lun; } - pDev = pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL); + pDev = pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL); if(pDev == NULL) { return -ENOMEM; } } - memset(pDev,0,sizeof(struct adpt_device)); pDev->tid = d->lct_data.tid; pDev->scsi_channel = bus_no; pDev->scsi_id = scsi_id; -- cgit v0.10.2 From 4dbc22d7a9644088266a579433a3d621142a01e9 Mon Sep 17 00:00:00 2001 From: "Salyzyn, Mark" Date: Mon, 16 Apr 2007 11:21:50 -0400 Subject: [SCSI] aacraid: kmalloc/memset->kzalloc Inspired somewhat by Vignesh Babu patch to dpt_i2o.c to replace kmalloc/memset sequences with kzalloc, doing the same for the aacraid driver. Signed-off-by: Mark Salyzyn Signed-off-by: James Bottomley diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 33682ce..3009ad8 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -387,12 +387,11 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) * Ok now init the communication subsystem */ - dev->queues = kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL); + dev->queues = kzalloc(sizeof(struct aac_queue_block), GFP_KERNEL); if (dev->queues == NULL) { printk(KERN_ERR "Error could not allocate comm region.\n"); return NULL; } - memset(dev->queues, 0, sizeof(struct aac_queue_block)); if (aac_comm_init(dev)<0){ kfree(dev->queues); diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 5824a75..9aca57e 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1223,13 +1223,11 @@ int aac_check_health(struct aac_dev * aac) * Warning: no sleep allowed while * holding spinlock */ - hw_fib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC); - fib = kmalloc(sizeof(struct fib), GFP_ATOMIC); + hw_fib = kzalloc(sizeof(struct hw_fib), GFP_ATOMIC); + fib = kzalloc(sizeof(struct fib), GFP_ATOMIC); if (fib && hw_fib) { struct aac_aifcmd * aif; - memset(hw_fib, 0, sizeof(struct hw_fib)); - memset(fib, 0, sizeof(struct fib)); fib->hw_fib_va = hw_fib; fib->dev = aac; aac_fib_init(fib); diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c index 42c7dcd..fcd25f7 100644 --- a/drivers/scsi/aacraid/dpcsup.c +++ b/drivers/scsi/aacraid/dpcsup.c @@ -248,16 +248,14 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index) * manage the linked lists. */ if ((!dev->aif_thread) - || (!(fib = kmalloc(sizeof(struct fib),GFP_ATOMIC)))) + || (!(fib = kzalloc(sizeof(struct fib),GFP_ATOMIC)))) return 1; - if (!(hw_fib = kmalloc(sizeof(struct hw_fib),GFP_ATOMIC))) { + if (!(hw_fib = kzalloc(sizeof(struct hw_fib),GFP_ATOMIC))) { kfree (fib); return 1; } - memset(hw_fib, 0, sizeof(struct hw_fib)); memcpy(hw_fib, (struct hw_fib *)(((ptrdiff_t)(dev->regs.sa)) + (index & ~0x00000002L)), sizeof(struct hw_fib)); - memset(fib, 0, sizeof(struct fib)); INIT_LIST_HEAD(&fib->fiblink); fib->type = FSAFS_NTC_FIB_CONTEXT; fib->size = sizeof(struct fib); -- cgit v0.10.2 From b22c9d9bc214d602647c3f94e6072655c36a61db Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 17 Apr 2007 09:58:36 +0200 Subject: [SCSI] qla1280: use DMA_64BIT_MASK instead of ~ 0ULL QLA1280: call pci_set_dma_mask with DMA_64BIT_MASK instead of ~ 0ULL Signed-off-by: Matthias Kaehlcke Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 6777e8a..54d8bdf 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4293,7 +4293,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->devnum = devnum; /* specifies microcode load address */ #ifdef QLA_64BIT_PTR - if (pci_set_dma_mask(ha->pdev, (dma_addr_t) ~ 0ULL)) { + if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK)) { if (pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK)) { printk(KERN_WARNING "scsi(%li): Unable to set a " "suitable DMA mask - aborting\n", ha->host_no); -- cgit v0.10.2 From 2a4aa2c4b206c77b7cf522300ae9b616b0a883a4 Mon Sep 17 00:00:00 2001 From: David Milburn Date: Thu, 19 Apr 2007 12:10:24 -0500 Subject: [SCSI] megaraid: update version reported by MEGAIOC_QDRVRVER Update the driver version reported by MEGAIOC_QDRVRVER to match LSI_COMMON_MOD_VERSION. Signed-off-by: David Milburn Acked-by: "Patro, Sumant" Signed-off-by: James Bottomley diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index f33a678..e075a52 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -60,7 +60,7 @@ EXPORT_SYMBOL(mraid_mm_unregister_adp); EXPORT_SYMBOL(mraid_mm_adapter_app_handle); static int majorno; -static uint32_t drvr_ver = 0x02200206; +static uint32_t drvr_ver = 0x02200207; static int adapters_count_g; static struct list_head adapters_list_g; -- cgit v0.10.2 From e555db930f7512491485cfc43df4306192835373 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 19 Apr 2007 13:59:59 -0500 Subject: [SCSI] use sysfs configured timeout for EH Start Unit timeout Use the sysfs configurable timeout when issuing a START_UNIT command from the scsi error handler. This is needed for devices which take longer than thirty seconds to respond to the start unit. The problem was observed when sending a start unit to a disk array device in an ipr RAID adapter, which results in the adapter firmware sending potentially multiple commands to physical devices as a result of this command, which ended up timing out sometimes. This patch does not change the default value used for this command. Signed-off-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 3963e70..e8350c5 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -38,7 +38,6 @@ #include "scsi_logging.h" #define SENSE_TIMEOUT (10*HZ) -#define START_UNIT_TIMEOUT (30*HZ) /* * These should *probably* be handled by the host itself. @@ -936,7 +935,7 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd) for (i = 0; rtn == NEEDS_RETRY && i < 2; i++) rtn = scsi_send_eh_cmnd(scmd, stu_command, 6, - START_UNIT_TIMEOUT, 0); + scmd->device->timeout, 0); if (rtn == SUCCESS) return 0; -- cgit v0.10.2 From 1dcb58e5680b6673bf984696d3d8b9033b6e41bf Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:51:30 -0400 Subject: [SCSI] lpfc 8.1.12 : Misc bug fixes and code cleanup Misc bug fixes and code cleanup: - Fix system hang while running on systems with IOMMU - Fix use after free issues with rports - Don't free mailbox structure if it's still on the mboxq list - Decrement txq_cnt rather than txcmplq_cnt when parsing the txq list - Use msleep for long delays to prevent soft lockup bug check - Don't remove node during dev_loss_tmo if discovery is active - Fix memory leaks in get/reset statistics and link attention paths - Fixed lpfc_ns_rsp to handle entire GID_FT response. - mbox interface should use MAILBOX_CMD_SIZE rather than sizeof(MAILBOX_t) - Fixed bug check in add_timer. - Fixup messages 0116, 0117, and 0128 to report ELS I/O tag. - Remove unused parameter to lpfc_cleanup. - Change mailbox timeout handling. - Remove unused buflist. Code cleanup. Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index a7de0bc..e57a9f5 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -387,9 +387,6 @@ struct lpfc_hba { mempool_t *mbox_mem_pool; mempool_t *nlp_mem_pool; - struct list_head freebufList; - struct list_head ctrspbuflist; - struct list_head rnidrspbuflist; struct fc_host_statistics link_stats; }; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index f247e78..6cc88b1 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1227,11 +1227,11 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; int rc; - if (off > sizeof(MAILBOX_t)) + if (off > MAILBOX_CMD_SIZE) return -ERANGE; - if ((count + off) > sizeof(MAILBOX_t)) - count = sizeof(MAILBOX_t) - off; + if ((count + off) > MAILBOX_CMD_SIZE) + count = MAILBOX_CMD_SIZE - off; if (off % 4 || count % 4 || (unsigned long)buf % 4) return -EINVAL; @@ -1326,6 +1326,11 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) } if (rc != MBX_SUCCESS) { + if (rc == MBX_TIMEOUT) { + phba->sysfs_mbox.mbox->mbox_cmpl = + lpfc_sli_def_mbox_cmpl; + phba->sysfs_mbox.mbox = NULL; + } sysfs_mbox_idle(phba); spin_unlock_irq(host->host_lock); return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; @@ -1344,7 +1349,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) phba->sysfs_mbox.offset = off + count; - if (phba->sysfs_mbox.offset == sizeof(MAILBOX_t)) + if (phba->sysfs_mbox.offset == MAILBOX_CMD_SIZE) sysfs_mbox_idle(phba); spin_unlock_irq(phba->host->host_lock); @@ -1358,7 +1363,7 @@ static struct bin_attribute sysfs_mbox_attr = { .mode = S_IRUSR | S_IWUSR, .owner = THIS_MODULE, }, - .size = sizeof(MAILBOX_t), + .size = MAILBOX_CMD_SIZE, .read = sysfs_mbox_read, .write = sysfs_mbox_write, }; @@ -1631,6 +1636,8 @@ lpfc_get_stats(struct Scsi_Host *shost) else hs->seconds_since_last_reset = seconds - psli->stats_start; + mempool_free(pmboxq, phba->mbox_mem_pool); + return hs; } @@ -1699,6 +1706,8 @@ lpfc_reset_stats(struct Scsi_Host *shost) psli->stats_start = get_seconds(); + mempool_free(pmboxq, phba->mbox_mem_pool); + return; } diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index a51a41b..50f4533 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -342,9 +342,10 @@ lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size) Size -= Cnt; - if (!ctptr) + if (!ctptr) { + Cnt = FCELSSIZE; ctptr = (uint32_t *) mlast->virt; - else + } else Cnt -= 16; /* subtract length of CT header */ /* Loop through entire NameServer list of DIDs */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index a5f33a0..e1c61db 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -222,16 +222,16 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp, /* Xmit ELS command to remote NPORT */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0116 Xmit ELS command x%x to remote " - "NPORT x%x Data: x%x x%x\n", + "NPORT x%x I/O tag: x%x, HBA state: x%x\n", phba->brd_no, elscmd, - did, icmd->ulpIoTag, phba->hba_state); + did, elsiocb->iotag, phba->hba_state); } else { /* Xmit ELS response to remote NPORT */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0117 Xmit ELS response x%x to remote " - "NPORT x%x Data: x%x x%x\n", + "NPORT x%x I/O tag: x%x, size: x%x\n", phba->brd_no, elscmd, - ndlp->nlp_DID, icmd->ulpIoTag, cmdSize); + ndlp->nlp_DID, elsiocb->iotag, cmdSize); } return elsiocb; @@ -2017,10 +2017,9 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag, /* Xmit ELS ACC response tag */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "%d:0128 Xmit ELS ACC response tag x%x " - "Data: x%x x%x x%x x%x x%x\n", - phba->brd_no, - elsiocb->iocb.ulpIoTag, + "%d:0128 Xmit ELS ACC response tag x%x, XRI: x%x, " + "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n", + phba->brd_no, elsiocb->iotag, elsiocb->iocb.ulpContext, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); @@ -3363,7 +3362,7 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba) els_command = *elscmd; list_del(&piocb->list); - pring->txcmplq_cnt--; + pring->txq_cnt--; cmd->ulpStatus = IOSTAT_LOCAL_REJECT; cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index c39564e..bd7bbed 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -147,11 +147,14 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) ndlp->nlp_state, ndlp->nlp_rpi); } - ndlp->rport = NULL; - rdata->pnode = NULL; - - if (!(phba->fc_flag & FC_UNLOADING)) + if (!(phba->fc_flag & FC_UNLOADING) && + !(ndlp->nlp_flag & NLP_DELAY_TMO) && + !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM); + else { + rdata->pnode = NULL; + ndlp->rport = NULL; + } return; } @@ -1569,16 +1572,6 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) lpfc_nlp_list(phba, ndlp, NLP_JUST_DQ); - /* - * if unloading the driver - just leave the remote port in place. - * The driver unload will force the attached devices to detach - * and flush cache's w/o generating flush errors. - */ - if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) { - lpfc_unregister_remote_port(phba, ndlp); - ndlp->nlp_sid = NLP_NO_SID; - } - /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ if ((mb = phba->sli.mbox_active)) { if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) && @@ -1627,6 +1620,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) int lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) { + struct lpfc_rport_data *rdata; if (ndlp->nlp_flag & NLP_DELAY_TMO) { lpfc_cancel_retry_delay_tmo(phba, ndlp); @@ -1638,6 +1632,13 @@ lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) spin_unlock_irq(phba->host->host_lock); } else { lpfc_freenode(phba, ndlp); + + if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) { + rdata = ndlp->rport->dd_data; + rdata->pnode = NULL; + ndlp->rport = NULL; + } + mempool_free( ndlp, phba->nlp_mem_pool); } return 0; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index dcf6106..62677da 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -386,8 +386,7 @@ lpfc_config_port_post(struct lpfc_hba * phba) * Setup the ring 0 (els) timeout handler */ timeout = phba->fc_ratov << 1; - phba->els_tmofunc.expires = jiffies + HZ * timeout; - add_timer(&phba->els_tmofunc); + mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout); lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; @@ -633,7 +632,7 @@ lpfc_handle_latt_free_mbuf: lpfc_handle_latt_free_mp: kfree(mp); lpfc_handle_latt_free_pmb: - kfree(pmb); + mempool_free(pmb, phba->mbox_mem_pool); lpfc_handle_latt_err_exit: /* Enable Link attention interrupts */ spin_lock_irq(phba->host->host_lock); @@ -1174,7 +1173,7 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit) } static void -lpfc_cleanup(struct lpfc_hba * phba, uint32_t save_bind) +lpfc_cleanup(struct lpfc_hba * phba) { struct lpfc_nodelist *ndlp, *next_ndlp; @@ -1262,21 +1261,6 @@ lpfc_stop_timer(struct lpfc_hba * phba) { struct lpfc_sli *psli = &phba->sli; - /* Instead of a timer, this has been converted to a - * deferred procedding list. - */ - while (!list_empty(&phba->freebufList)) { - - struct lpfc_dmabuf *mp = NULL; - - list_remove_head((&phba->freebufList), mp, - struct lpfc_dmabuf, list); - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - } - del_timer_sync(&phba->fcp_poll_timer); del_timer_sync(&phba->fc_estabtmo); del_timer_sync(&phba->fc_disctmo); @@ -1339,7 +1323,7 @@ lpfc_offline(struct lpfc_hba * phba) pring = &psli->ring[i]; /* The linkdown event takes 30 seconds to timeout. */ while (pring->txcmplq_cnt) { - mdelay(10); + msleep(10); if (cnt++ > 3000) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -1366,7 +1350,7 @@ lpfc_offline(struct lpfc_hba * phba) /* Bring down the SLI Layer and cleanup. The HBA is offline now. */ lpfc_sli_hba_down(phba); - lpfc_cleanup(phba, 1); + lpfc_cleanup(phba); spin_lock_irqsave(phba->host->host_lock, iflag); phba->fc_flag |= FC_OFFLINE_MODE; spin_unlock_irqrestore(phba->host->host_lock, iflag); @@ -1445,9 +1429,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) goto out_put_host; host->unique_id = phba->brd_no; - INIT_LIST_HEAD(&phba->ctrspbuflist); - INIT_LIST_HEAD(&phba->rnidrspbuflist); - INIT_LIST_HEAD(&phba->freebufList); /* Initialize timers used by driver */ init_timer(&phba->fc_estabtmo); @@ -1773,7 +1754,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) free_irq(phba->pcidev->irq, phba); pci_disable_msi(phba->pcidev); - lpfc_cleanup(phba, 0); + lpfc_cleanup(phba); lpfc_stop_timer(phba); phba->work_hba_events = 0; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index c3e68e0..28dbd6b 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -146,6 +146,10 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba) spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag); list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list); + if (lpfc_cmd) { + lpfc_cmd->seg_cnt = 0; + lpfc_cmd->nonsg_phys = 0; + } spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag); return lpfc_cmd; } @@ -466,10 +470,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, result = cmd->result; sdev = cmd->device; + lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); cmd->scsi_done(cmd); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); lpfc_release_scsi_buf(phba, lpfc_cmd); return; } @@ -527,7 +531,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } } - lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); lpfc_release_scsi_buf(phba, lpfc_cmd); } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 9fb6960..54a8f4d 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -693,25 +693,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba * phba) } else { spin_unlock_irq(phba->host->host_lock); /* Turn on IOCB processing */ - for (i = 0; i < phba->sli.num_rings; i++) { + for (i = 0; i < phba->sli.num_rings; i++) lpfc_sli_turn_on_ring(phba, i); - } - - /* Free any lpfc_dmabuf's waiting for mbox cmd cmpls */ - while (!list_empty(&phba->freebufList)) { - struct lpfc_dmabuf *mp; - - mp = NULL; - list_remove_head((&phba->freebufList), - mp, - struct lpfc_dmabuf, - list); - if (mp) { - lpfc_mbuf_free(phba, mp->virt, - mp->phys); - kfree(mp); - } - } } } while (process_next); @@ -1985,42 +1968,6 @@ lpfc_sli_hba_setup_exit: return rc; } -static void -lpfc_mbox_abort(struct lpfc_hba * phba) -{ - LPFC_MBOXQ_t *pmbox; - MAILBOX_t *mb; - - if (phba->sli.mbox_active) { - del_timer_sync(&phba->sli.mbox_tmo); - phba->work_hba_events &= ~WORKER_MBOX_TMO; - pmbox = phba->sli.mbox_active; - mb = &pmbox->mb; - phba->sli.mbox_active = NULL; - if (pmbox->mbox_cmpl) { - mb->mbxStatus = MBX_NOT_FINISHED; - (pmbox->mbox_cmpl) (phba, pmbox); - } - phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - } - - /* Abort all the non active mailbox commands. */ - spin_lock_irq(phba->host->host_lock); - pmbox = lpfc_mbox_get(phba); - while (pmbox) { - mb = &pmbox->mb; - if (pmbox->mbox_cmpl) { - mb->mbxStatus = MBX_NOT_FINISHED; - spin_unlock_irq(phba->host->host_lock); - (pmbox->mbox_cmpl) (phba, pmbox); - spin_lock_irq(phba->host->host_lock); - } - pmbox = lpfc_mbox_get(phba); - } - spin_unlock_irq(phba->host->host_lock); - return; -} - /*! lpfc_mbox_timeout * * \pre @@ -2055,6 +2002,8 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) { LPFC_MBOXQ_t *pmbox; MAILBOX_t *mb; + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; spin_lock_irq(phba->host->host_lock); if (!(phba->work_hba_events & WORKER_MBOX_TMO)) { @@ -2062,8 +2011,6 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) return; } - phba->work_hba_events &= ~WORKER_MBOX_TMO; - pmbox = phba->sli.mbox_active; mb = &pmbox->mb; @@ -2078,17 +2025,32 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) phba->sli.sli_flag, phba->sli.mbox_active); - phba->sli.mbox_active = NULL; - if (pmbox->mbox_cmpl) { - mb->mbxStatus = MBX_NOT_FINISHED; - spin_unlock_irq(phba->host->host_lock); - (pmbox->mbox_cmpl) (phba, pmbox); - spin_lock_irq(phba->host->host_lock); - } - phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - + /* Setting state unknown so lpfc_sli_abort_iocb_ring + * would get IOCB_ERROR from lpfc_sli_issue_iocb, allowing + * it to fail all oustanding SCSI IO. + */ + phba->hba_state = LPFC_STATE_UNKNOWN; + phba->work_hba_events &= ~WORKER_MBOX_TMO; + phba->fc_flag |= FC_ESTABLISH_LINK; + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; spin_unlock_irq(phba->host->host_lock); - lpfc_mbox_abort(phba); + + pring = &psli->ring[psli->fcp_ring]; + lpfc_sli_abort_iocb_ring(phba, pring); + + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "%d:0316 Resetting board due to mailbox timeout\n", + phba->brd_no); + /* + * lpfc_offline calls lpfc_sli_hba_down which will clean up + * on oustanding mailbox commands. + */ + lpfc_offline_prep(phba); + lpfc_offline(phba); + lpfc_sli_brdrestart(phba); + if (lpfc_online(phba) == 0) /* Initialize the HBA */ + mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60); + lpfc_unblock_mgmt_io(phba); return; } @@ -2320,9 +2282,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag) spin_unlock_irqrestore(phba->host->host_lock, drvr_flag); - /* Can be in interrupt context, do not sleep */ - /* (or might be called with interrupts disabled) */ - mdelay(1); + msleep(1); spin_lock_irqsave(phba->host->host_lock, drvr_flag); -- cgit v0.10.2 From 07951076aefa4194e1dbf1d8c89eaff040c45155 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:51:38 -0400 Subject: [SCSI] lpfc 8.1.12 : Modify ELS abort handling to prevent double completion Modify ELS abort handling to prevent double completion Rework portions of ELS abort handling to prevent double completion - Rework ELS iotags and correct abort routine - Move the (badly wrong) ELS completion logic from the initial ELS abort request function to the ELS completion function. - Fixup the iocb completion handling to account for the ELS abort completions. Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 1251788..4132a2d 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -66,8 +66,7 @@ int lpfc_disc_state_machine(struct lpfc_hba *, struct lpfc_nodelist *, void *, int lpfc_check_sparm(struct lpfc_hba *, struct lpfc_nodelist *, struct serv_parm *, uint32_t); -int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp, - int); +int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp); int lpfc_els_abort_flogi(struct lpfc_hba *); int lpfc_initial_flogi(struct lpfc_hba *); int lpfc_issue_els_plogi(struct lpfc_hba *, uint32_t, uint8_t); @@ -162,8 +161,8 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, struct lpfc_sli_ring *, dma_addr_t); -int lpfc_sli_issue_abort_iotag32(struct lpfc_hba *, struct lpfc_sli_ring *, - struct lpfc_iocbq *); +int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *, + struct lpfc_iocbq *); int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t, uint64_t, lpfc_ctx_cmd); int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t, diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index e1c61db..4a9e613 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -582,24 +582,8 @@ lpfc_els_abort_flogi(struct lpfc_hba * phba) icmd = &iocb->iocb; if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) { ndlp = (struct lpfc_nodelist *)(iocb->context1); - if (ndlp && (ndlp->nlp_DID == Fabric_DID)) { - list_del(&iocb->list); - pring->txcmplq_cnt--; - - if ((icmd->un.elsreq64.bdl.ulpIoTag32)) { - lpfc_sli_issue_abort_iotag32 - (phba, pring, iocb); - } - if (iocb->iocb_cmpl) { - icmd->ulpStatus = IOSTAT_LOCAL_REJECT; - icmd->un.ulpWord[4] = - IOERR_SLI_ABORTED; - spin_unlock_irq(phba->host->host_lock); - (iocb->iocb_cmpl) (phba, iocb, iocb); - spin_lock_irq(phba->host->host_lock); - } else - lpfc_sli_release_iocbq(phba, iocb); - } + if (ndlp && (ndlp->nlp_DID == Fabric_DID)) + lpfc_sli_issue_abort_iotag(phba, pring, iocb); } } spin_unlock_irq(phba->host->host_lock); @@ -3245,7 +3229,6 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) struct lpfc_iocbq *tmp_iocb, *piocb; IOCB_t *cmd = NULL; struct lpfc_dmabuf *pcmd; - struct list_head *dlp; uint32_t *elscmd; uint32_t els_command; uint32_t timeout; @@ -3262,7 +3245,6 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) timeout = (uint32_t)(phba->fc_ratov << 1); pring = &phba->sli.ring[LPFC_ELS_RING]; - dlp = &pring->txcmplq; list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { cmd = &piocb->iocb; @@ -3288,19 +3270,12 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) continue; } - list_del(&piocb->list); - pring->txcmplq_cnt--; - if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) { struct lpfc_nodelist *ndlp; spin_unlock_irq(phba->host->host_lock); ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext); spin_lock_irq(phba->host->host_lock); remote_ID = ndlp->nlp_DID; - if (cmd->un.elsreq64.bdl.ulpIoTag32) { - lpfc_sli_issue_abort_iotag32(phba, - pring, piocb); - } } else { remote_ID = cmd->un.elsreq64.remoteID; } @@ -3312,17 +3287,7 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) phba->brd_no, els_command, remote_ID, cmd->ulpCommand, cmd->ulpIoTag); - /* - * The iocb has timed out; abort it. - */ - if (piocb->iocb_cmpl) { - cmd->ulpStatus = IOSTAT_LOCAL_REJECT; - cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; - spin_unlock_irq(phba->host->host_lock); - (piocb->iocb_cmpl) (phba, piocb, piocb); - spin_lock_irq(phba->host->host_lock); - } else - lpfc_sli_release_iocbq(phba, piocb); + lpfc_sli_issue_abort_iotag(phba, pring, piocb); } if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout); @@ -3336,9 +3301,6 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba) struct lpfc_sli_ring *pring; struct lpfc_iocbq *tmp_iocb, *piocb; IOCB_t *cmd = NULL; - struct lpfc_dmabuf *pcmd; - uint32_t *elscmd; - uint32_t els_command; pring = &phba->sli.ring[LPFC_ELS_RING]; spin_lock_irq(phba->host->host_lock); @@ -3357,10 +3319,6 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba) continue; } - pcmd = (struct lpfc_dmabuf *) piocb->context2; - elscmd = (uint32_t *) (pcmd->virt); - els_command = *elscmd; - list_del(&piocb->list); pring->txq_cnt--; @@ -3381,22 +3339,8 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba) if (piocb->iocb_flag & LPFC_IO_LIBDFC) { continue; } - pcmd = (struct lpfc_dmabuf *) piocb->context2; - elscmd = (uint32_t *) (pcmd->virt); - els_command = *elscmd; - - list_del(&piocb->list); - pring->txcmplq_cnt--; - cmd->ulpStatus = IOSTAT_LOCAL_REJECT; - cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; - - if (piocb->iocb_cmpl) { - spin_unlock_irq(phba->host->host_lock); - (piocb->iocb_cmpl) (phba, piocb, piocb); - spin_lock_irq(phba->host->host_lock); - } else - lpfc_sli_release_iocbq(phba, piocb); + lpfc_sli_issue_abort_iotag(phba, pring, piocb); } spin_unlock_irq(phba->host->host_lock); return; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index bd7bbed..485a13f 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1596,7 +1596,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) } spin_unlock_irq(phba->host->host_lock); - lpfc_els_abort(phba,ndlp,0); + lpfc_els_abort(phba,ndlp); spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag &= ~NLP_DELAY_TMO; spin_unlock_irq(phba->host->host_lock); diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 0c7e731..aa7f446 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -168,8 +168,7 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba * phba, * routine effectively results in a "software abort". */ int -lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, - int send_abts) +lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) { struct lpfc_sli *psli; struct lpfc_sli_ring *pring; @@ -215,48 +214,17 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, spin_unlock_irq(phba->host->host_lock); } while (found); - /* Everything on txcmplq will be returned by firmware - * with a no rpi / linkdown / abort error. For ring 0, - * ELS discovery, we want to get rid of it right here. - */ /* Next check the txcmplq */ - do { - found = 0; - spin_lock_irq(phba->host->host_lock); - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, - list) { - /* Check to see if iocb matches the nport we are looking - for */ - if ((lpfc_check_sli_ndlp (phba, pring, iocb, ndlp))) { - found = 1; - /* It matches, so deque and call compl with an - error */ - list_del(&iocb->list); - pring->txcmplq_cnt--; - - icmd = &iocb->iocb; - /* If the driver is completing an ELS - * command early, flush it out of the firmware. - */ - if (send_abts && - (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) && - (icmd->un.elsreq64.bdl.ulpIoTag32)) { - lpfc_sli_issue_abort_iotag32(phba, - pring, iocb); - } - if (iocb->iocb_cmpl) { - icmd->ulpStatus = IOSTAT_LOCAL_REJECT; - icmd->un.ulpWord[4] = IOERR_SLI_ABORTED; - spin_unlock_irq(phba->host->host_lock); - (iocb->iocb_cmpl) (phba, iocb, iocb); - spin_lock_irq(phba->host->host_lock); - } else - lpfc_sli_release_iocbq(phba, iocb); - break; - } + spin_lock_irq(phba->host->host_lock); + list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { + /* Check to see if iocb matches the nport we are looking + for */ + if ((lpfc_check_sli_ndlp (phba, pring, iocb, ndlp))) { + icmd = &iocb->iocb; + lpfc_sli_issue_abort_iotag(phba, pring, iocb); } - spin_unlock_irq(phba->host->host_lock); - } while(found); + } + spin_unlock_irq(phba->host->host_lock); /* If we are delaying issuing an ELS command, cancel it */ if (ndlp->nlp_flag & NLP_DELAY_TMO) @@ -404,7 +372,7 @@ lpfc_rcv_plogi(struct lpfc_hba * phba, */ if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) { /* software abort outstanding PLOGI */ - lpfc_els_abort(phba, ndlp, 1); + lpfc_els_abort(phba, ndlp); } lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0); @@ -697,7 +665,7 @@ lpfc_rcv_logo_plogi_issue(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; /* software abort outstanding PLOGI */ - lpfc_els_abort(phba, ndlp, 1); + lpfc_els_abort(phba, ndlp); lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; @@ -712,7 +680,7 @@ lpfc_rcv_els_plogi_issue(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; /* software abort outstanding PLOGI */ - lpfc_els_abort(phba, ndlp, 1); + lpfc_els_abort(phba, ndlp); if (evt == NLP_EVT_RCV_LOGO) { lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); @@ -855,7 +823,7 @@ lpfc_device_rm_plogi_issue(struct lpfc_hba * phba, } else { /* software abort outstanding PLOGI */ - lpfc_els_abort(phba, ndlp, 1); + lpfc_els_abort(phba, ndlp); lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); return NLP_STE_FREED_NODE; @@ -868,7 +836,7 @@ lpfc_device_recov_plogi_issue(struct lpfc_hba * phba, uint32_t evt) { /* software abort outstanding PLOGI */ - lpfc_els_abort(phba, ndlp, 1); + lpfc_els_abort(phba, ndlp); ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; ndlp->nlp_state = NLP_STE_NPR_NODE; @@ -888,7 +856,7 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_hba * phba, struct lpfc_iocbq *cmdiocb; /* software abort outstanding ADISC */ - lpfc_els_abort(phba, ndlp, 1); + lpfc_els_abort(phba, ndlp); cmdiocb = (struct lpfc_iocbq *) arg; @@ -926,7 +894,7 @@ lpfc_rcv_logo_adisc_issue(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; /* software abort outstanding ADISC */ - lpfc_els_abort(phba, ndlp, 0); + lpfc_els_abort(phba, ndlp); lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; @@ -1016,7 +984,7 @@ lpfc_device_rm_adisc_issue(struct lpfc_hba * phba, } else { /* software abort outstanding ADISC */ - lpfc_els_abort(phba, ndlp, 1); + lpfc_els_abort(phba, ndlp); lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); return NLP_STE_FREED_NODE; @@ -1029,7 +997,7 @@ lpfc_device_recov_adisc_issue(struct lpfc_hba * phba, uint32_t evt) { /* software abort outstanding ADISC */ - lpfc_els_abort(phba, ndlp, 1); + lpfc_els_abort(phba, ndlp); ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; ndlp->nlp_state = NLP_STE_NPR_NODE; @@ -1230,7 +1198,7 @@ lpfc_rcv_logo_prli_issue(struct lpfc_hba * phba, cmdiocb = (struct lpfc_iocbq *) arg; /* Software abort outstanding PRLI before sending acc */ - lpfc_els_abort(phba, ndlp, 1); + lpfc_els_abort(phba, ndlp); lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; @@ -1330,7 +1298,7 @@ lpfc_device_rm_prli_issue(struct lpfc_hba * phba, } else { /* software abort outstanding PLOGI */ - lpfc_els_abort(phba, ndlp, 1); + lpfc_els_abort(phba, ndlp); lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); return NLP_STE_FREED_NODE; @@ -1359,7 +1327,7 @@ lpfc_device_recov_prli_issue(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { /* software abort outstanding PRLI */ - lpfc_els_abort(phba, ndlp, 1); + lpfc_els_abort(phba, ndlp); ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; ndlp->nlp_state = NLP_STE_NPR_NODE; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 54a8f4d..dcd313a 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -816,6 +816,14 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, * All other are passed to the completion callback. */ if (pring->ringno == LPFC_ELS_RING) { + if (cmdiocbp->iocb_flag & LPFC_DRIVER_ABORTED) { + cmdiocbp->iocb_flag &= + ~LPFC_DRIVER_ABORTED; + saveq->iocb.ulpStatus = + IOSTAT_LOCAL_REJECT; + saveq->iocb.un.ulpWord[4] = + IOERR_SLI_ABORTED; + } spin_unlock_irqrestore(phba->host->host_lock, iflag); (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); @@ -2728,85 +2736,81 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } static void -lpfc_sli_abort_elsreq_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, - struct lpfc_iocbq * rspiocb) +lpfc_sli_abort_els_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, + struct lpfc_iocbq * rspiocb) { - struct lpfc_dmabuf *buf_ptr, *buf_ptr1; - /* Free the resources associated with the ELS_REQUEST64 IOCB the driver - * just aborted. - * In this case, context2 = cmd, context2->next = rsp, context3 = bpl - */ - if (cmdiocb->context2) { - buf_ptr1 = (struct lpfc_dmabuf *) cmdiocb->context2; - - /* Free the response IOCB before completing the abort - command. */ - buf_ptr = NULL; - list_remove_head((&buf_ptr1->list), buf_ptr, - struct lpfc_dmabuf, list); - if (buf_ptr) { - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); - } - lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys); - kfree(buf_ptr1); - } - - if (cmdiocb->context3) { - buf_ptr = (struct lpfc_dmabuf *) cmdiocb->context3; - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); - } - + spin_lock_irq(phba->host->host_lock); lpfc_sli_release_iocbq(phba, cmdiocb); + spin_unlock_irq(phba->host->host_lock); return; } int -lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba, - struct lpfc_sli_ring * pring, - struct lpfc_iocbq * cmdiocb) +lpfc_sli_issue_abort_iotag(struct lpfc_hba * phba, + struct lpfc_sli_ring * pring, + struct lpfc_iocbq * cmdiocb) { struct lpfc_iocbq *abtsiocbp; IOCB_t *icmd = NULL; IOCB_t *iabt = NULL; + int retval = IOCB_ERROR; + + /* There are certain command types we don't want + * to abort. + */ + icmd = &cmdiocb->iocb; + if ((icmd->ulpCommand == CMD_ABORT_XRI_CN) || + (icmd->ulpCommand == CMD_CLOSE_XRI_CN)) + return 0; + + /* If we're unloading, interrupts are disabled so we + * need to cleanup the iocb here. + */ + if (phba->fc_flag & FC_UNLOADING) + goto abort_iotag_exit; /* issue ABTS for this IOCB based on iotag */ abtsiocbp = lpfc_sli_get_iocbq(phba); if (abtsiocbp == NULL) return 0; + /* This signals the response to set the correct status + * before calling the completion handler. + */ + cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED; + iabt = &abtsiocbp->iocb; - icmd = &cmdiocb->iocb; - switch (icmd->ulpCommand) { - case CMD_ELS_REQUEST64_CR: - /* Even though we abort the ELS command, the firmware may access - * the BPL or other resources before it processes our - * ABORT_MXRI64. Thus we must delay reusing the cmdiocb - * resources till the actual abort request completes. - */ - abtsiocbp->context1 = (void *)((unsigned long)icmd->ulpCommand); - abtsiocbp->context2 = cmdiocb->context2; - abtsiocbp->context3 = cmdiocb->context3; - cmdiocb->context2 = NULL; - cmdiocb->context3 = NULL; - abtsiocbp->iocb_cmpl = lpfc_sli_abort_elsreq_cmpl; - break; - default: - lpfc_sli_release_iocbq(phba, abtsiocbp); - return 0; - } + iabt->un.acxri.abortType = ABORT_TYPE_ABTS; + iabt->un.acxri.abortContextTag = icmd->ulpContext; + iabt->un.acxri.abortIoTag = icmd->ulpIoTag; + iabt->ulpLe = 1; + iabt->ulpClass = icmd->ulpClass; - iabt->un.amxri.abortType = ABORT_TYPE_ABTS; - iabt->un.amxri.iotag32 = icmd->un.elsreq64.bdl.ulpIoTag32; + if (phba->hba_state >= LPFC_LINK_UP) + iabt->ulpCommand = CMD_ABORT_XRI_CN; + else + iabt->ulpCommand = CMD_CLOSE_XRI_CN; - iabt->ulpLe = 1; - iabt->ulpClass = CLASS3; - iabt->ulpCommand = CMD_ABORT_MXRI64_CN; + abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl; + retval = lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0); - if (lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0) == IOCB_ERROR) { - lpfc_sli_release_iocbq(phba, abtsiocbp); - return 0; +abort_iotag_exit: + + /* If we could not issue an abort dequeue the iocb and handle + * the completion here. + */ + if (retval == IOCB_ERROR) { + list_del(&cmdiocb->list); + pring->txcmplq_cnt--; + + if (cmdiocb->iocb_cmpl) { + icmd->ulpStatus = IOSTAT_LOCAL_REJECT; + icmd->un.ulpWord[4] = IOERR_SLI_ABORTED; + spin_unlock_irq(phba->host->host_lock); + (cmdiocb->iocb_cmpl) (phba, cmdiocb, cmdiocb); + spin_lock_irq(phba->host->host_lock); + } else + lpfc_sli_release_iocbq(phba, cmdiocb); } return 1; diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index a435499..10dd5a9 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -39,9 +39,10 @@ struct lpfc_iocbq { IOCB_t iocb; /* IOCB cmd */ uint8_t retry; /* retry counter for IOCB cmd - if needed */ uint8_t iocb_flag; -#define LPFC_IO_LIBDFC 1 /* libdfc iocb */ -#define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */ -#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ +#define LPFC_IO_LIBDFC 1 /* libdfc iocb */ +#define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */ +#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ +#define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ uint8_t abort_count; uint8_t rsvd2; -- cgit v0.10.2 From 46fa311e6967b526e1fd9b0b44edda6841dcac27 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:51:45 -0400 Subject: [SCSI] lpfc 8.1.12 : Rework offline path to solve HBA reset issues Rework offline path to solve HBA reset issues Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index e57a9f5..6aa9153 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -244,6 +244,7 @@ struct lpfc_hba { #define FC_FABRIC 0x100 /* We are fabric attached */ #define FC_ESTABLISH_LINK 0x200 /* Reestablish Link */ #define FC_RSCN_DISCOVERY 0x400 /* Authenticate all devices after RSCN*/ +#define FC_BLOCK_MGMT_IO 0x800 /* Don't allow mgmt mbx or iocb cmds */ #define FC_LOADING 0x1000 /* HBA in process of loading drvr */ #define FC_UNLOADING 0x2000 /* HBA in process of unloading drvr */ #define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 6cc88b1..c0b02b1 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -20,6 +20,7 @@ *******************************************************************/ #include +#include #include #include @@ -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; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 4132a2d..bf555d3 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -112,7 +112,10 @@ void lpfc_hba_init(struct lpfc_hba *, uint32_t *); int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int); void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int); int lpfc_online(struct lpfc_hba *); -int lpfc_offline(struct lpfc_hba *); +void lpfc_block_mgmt_io(struct lpfc_hba *); +void lpfc_unblock_mgmt_io(struct lpfc_hba *); +void lpfc_offline_prep(struct lpfc_hba *); +void lpfc_offline(struct lpfc_hba *); int lpfc_sli_setup(struct lpfc_hba *); int lpfc_sli_queue_setup(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 9766f90..cfafff0 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -31,6 +31,7 @@ /* worker thread events */ enum lpfc_work_type { LPFC_EVT_ONLINE, + LPFC_EVT_OFFLINE_PREP, LPFC_EVT_OFFLINE, LPFC_EVT_WARM_START, LPFC_EVT_KILL, diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 485a13f..92c0c4b 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -185,29 +185,35 @@ lpfc_work_list_done(struct lpfc_hba * phba) *(int *)(evtp->evt_arg1) = 0; complete((struct completion *)(evtp->evt_arg2)); break; - case LPFC_EVT_OFFLINE: + case LPFC_EVT_OFFLINE_PREP: if (phba->hba_state >= LPFC_LINK_DOWN) - lpfc_offline(phba); + lpfc_offline_prep(phba); + *(int *)(evtp->evt_arg1) = 0; + complete((struct completion *)(evtp->evt_arg2)); + break; + case LPFC_EVT_OFFLINE: + lpfc_offline(phba); lpfc_sli_brdrestart(phba); *(int *)(evtp->evt_arg1) = - lpfc_sli_brdready(phba,HS_FFRDY | HS_MBRDY); + lpfc_sli_brdready(phba, HS_FFRDY | HS_MBRDY); + lpfc_unblock_mgmt_io(phba); complete((struct completion *)(evtp->evt_arg2)); break; case LPFC_EVT_WARM_START: - if (phba->hba_state >= LPFC_LINK_DOWN) - lpfc_offline(phba); + lpfc_offline(phba); lpfc_reset_barrier(phba); lpfc_sli_brdreset(phba); lpfc_hba_down_post(phba); *(int *)(evtp->evt_arg1) = lpfc_sli_brdready(phba, HS_MBRDY); + lpfc_unblock_mgmt_io(phba); complete((struct completion *)(evtp->evt_arg2)); break; case LPFC_EVT_KILL: - if (phba->hba_state >= LPFC_LINK_DOWN) - lpfc_offline(phba); + lpfc_offline(phba); *(int *)(evtp->evt_arg1) = (phba->stopped) ? 0 : lpfc_sli_brdkill(phba); + lpfc_unblock_mgmt_io(phba); complete((struct completion *)(evtp->evt_arg2)); break; } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 62677da..dc0fd2e 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -549,12 +549,15 @@ lpfc_handle_eratt(struct lpfc_hba * phba) * There was a firmware error. Take the hba offline and then * attempt to restart it. */ + lpfc_offline_prep(phba); lpfc_offline(phba); lpfc_sli_brdrestart(phba); if (lpfc_online(phba) == 0) { /* Initialize the HBA */ mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60); + lpfc_unblock_mgmt_io(phba); return; } + lpfc_unblock_mgmt_io(phba); } else { /* The if clause above forces this code path when the status * failure is a value other than FFER6. Do not call the offline @@ -572,7 +575,9 @@ lpfc_handle_eratt(struct lpfc_hba * phba) SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + lpfc_offline_prep(phba); lpfc_offline(phba); + lpfc_unblock_mgmt_io(phba); phba->hba_state = LPFC_HBA_ERROR; lpfc_hba_down_post(phba); } @@ -1286,55 +1291,87 @@ lpfc_online(struct lpfc_hba * phba) "%d:0458 Bring Adapter online\n", phba->brd_no); - if (!lpfc_sli_queue_setup(phba)) + lpfc_block_mgmt_io(phba); + + if (!lpfc_sli_queue_setup(phba)) { + lpfc_unblock_mgmt_io(phba); return 1; + } - if (lpfc_sli_hba_setup(phba)) /* Initialize the HBA */ + if (lpfc_sli_hba_setup(phba)) { /* Initialize the HBA */ + lpfc_unblock_mgmt_io(phba); return 1; + } spin_lock_irq(phba->host->host_lock); phba->fc_flag &= ~FC_OFFLINE_MODE; spin_unlock_irq(phba->host->host_lock); + lpfc_unblock_mgmt_io(phba); return 0; } -int -lpfc_offline(struct lpfc_hba * phba) +void +lpfc_block_mgmt_io(struct lpfc_hba * phba) { - struct lpfc_sli_ring *pring; - struct lpfc_sli *psli; unsigned long iflag; - int i; - int cnt = 0; - if (!phba) - return 0; + spin_lock_irqsave(phba->host->host_lock, iflag); + phba->fc_flag |= FC_BLOCK_MGMT_IO; + spin_unlock_irqrestore(phba->host->host_lock, iflag); +} + +void +lpfc_unblock_mgmt_io(struct lpfc_hba * phba) +{ + unsigned long iflag; + + spin_lock_irqsave(phba->host->host_lock, iflag); + phba->fc_flag &= ~FC_BLOCK_MGMT_IO; + spin_unlock_irqrestore(phba->host->host_lock, iflag); +} + +void +lpfc_offline_prep(struct lpfc_hba * phba) +{ + struct lpfc_nodelist *ndlp, *next_ndlp; + struct list_head *listp, *node_list[7]; + int i; if (phba->fc_flag & FC_OFFLINE_MODE) - return 0; + return; - psli = &phba->sli; + lpfc_block_mgmt_io(phba); lpfc_linkdown(phba); - lpfc_sli_flush_mbox_queue(phba); - 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; - } - } + /* Issue an unreg_login to all nodes */ + node_list[0] = &phba->fc_npr_list; /* MUST do this list first */ + node_list[1] = &phba->fc_nlpmap_list; + node_list[2] = &phba->fc_nlpunmap_list; + node_list[3] = &phba->fc_prli_list; + node_list[4] = &phba->fc_reglogin_list; + node_list[5] = &phba->fc_adisc_list; + node_list[6] = &phba->fc_plogi_list; + for (i = 0; i < 7; i++) { + listp = node_list[i]; + if (list_empty(listp)) + continue; + + list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) + lpfc_unreg_rpi(phba, ndlp); } + lpfc_sli_flush_mbox_queue(phba); +} + +void +lpfc_offline(struct lpfc_hba * phba) +{ + unsigned long iflag; + + if (phba->fc_flag & FC_OFFLINE_MODE) + return; /* stop all timers associated with this hba */ lpfc_stop_timer(phba); @@ -1354,7 +1391,6 @@ lpfc_offline(struct lpfc_hba * phba) spin_lock_irqsave(phba->host->host_lock, iflag); phba->fc_flag |= FC_OFFLINE_MODE; spin_unlock_irqrestore(phba->host->host_lock, iflag); - return 0; } /****************************************************************************** -- cgit v0.10.2 From 2534ba756ec407d343af45168273d3a64825a7ba Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:52:20 -0400 Subject: [SCSI] lpfc 8.1.12 : Fix unlock inside list traversal Fix unlock inside list traversal. Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index bf555d3..80dcfaa 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -57,6 +57,7 @@ void lpfc_disc_start(struct lpfc_hba *); void lpfc_disc_flush_list(struct lpfc_hba *); void lpfc_disc_timeout(unsigned long); +struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi); struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi); int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 4a9e613..e3bebf9 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -3272,9 +3272,7 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) { struct lpfc_nodelist *ndlp; - spin_unlock_irq(phba->host->host_lock); - ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext); - spin_lock_irq(phba->host->host_lock); + ndlp = __lpfc_findnode_rpi(phba, cmd->ulpContext); remote_ID = ndlp->nlp_DID; } else { remote_ID = cmd->un.elsreq64.remoteID; @@ -3298,6 +3296,7 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) void lpfc_els_flush_cmd(struct lpfc_hba * phba) { + LIST_HEAD(completions); struct lpfc_sli_ring *pring; struct lpfc_iocbq *tmp_iocb, *piocb; IOCB_t *cmd = NULL; @@ -3319,18 +3318,9 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba) continue; } - list_del(&piocb->list); + list_move_tail(&piocb->list, &completions); pring->txq_cnt--; - cmd->ulpStatus = IOSTAT_LOCAL_REJECT; - cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; - - if (piocb->iocb_cmpl) { - spin_unlock_irq(phba->host->host_lock); - (piocb->iocb_cmpl) (phba, piocb, piocb); - spin_lock_irq(phba->host->host_lock); - } else - lpfc_sli_release_iocbq(phba, piocb); } list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { @@ -3343,6 +3333,20 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba) lpfc_sli_issue_abort_iotag(phba, pring, piocb); } spin_unlock_irq(phba->host->host_lock); + + while(!list_empty(&completions)) { + piocb = list_get_first(&completions, struct lpfc_iocbq, list); + cmd = &piocb->iocb; + list_del(&piocb->list); + + if (piocb->iocb_cmpl) { + cmd->ulpStatus = IOSTAT_LOCAL_REJECT; + cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; + (piocb->iocb_cmpl) (phba, piocb, piocb); + } else + lpfc_sli_release_iocbq(phba, piocb); + } + return; } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 92c0c4b..2c21641 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1473,6 +1473,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba, static int lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) { + LIST_HEAD(completions); struct lpfc_sli *psli; struct lpfc_sli_ring *pring; struct lpfc_iocbq *iocb, *next_iocb; @@ -1501,29 +1502,29 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) (phba, pring, iocb, ndlp))) { /* It matches, so deque and call compl with an error */ - list_del(&iocb->list); + list_move_tail(&iocb->list, + &completions); pring->txq_cnt--; - if (iocb->iocb_cmpl) { - icmd = &iocb->iocb; - icmd->ulpStatus = - IOSTAT_LOCAL_REJECT; - icmd->un.ulpWord[4] = - IOERR_SLI_ABORTED; - spin_unlock_irq(phba->host-> - host_lock); - (iocb->iocb_cmpl) (phba, - iocb, iocb); - spin_lock_irq(phba->host-> - host_lock); - } else - lpfc_sli_release_iocbq(phba, - iocb); } } spin_unlock_irq(phba->host->host_lock); } } + + while (!list_empty(&completions)) { + iocb = list_get_first(&completions, struct lpfc_iocbq, list); + list_del(&iocb->list); + + if (iocb->iocb_cmpl) { + icmd = &iocb->iocb; + icmd->ulpStatus = IOSTAT_LOCAL_REJECT; + icmd->un.ulpWord[4] = IOERR_SLI_ABORTED; + (iocb->iocb_cmpl) (phba, iocb, iocb); + } else + lpfc_sli_release_iocbq(phba, iocb); + } + return 0; } @@ -1951,11 +1952,11 @@ lpfc_disc_start(struct lpfc_hba * phba) static void lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) { + LIST_HEAD(completions); struct lpfc_sli *psli; IOCB_t *icmd; struct lpfc_iocbq *iocb, *next_iocb; struct lpfc_sli_ring *pring; - struct lpfc_dmabuf *mp; psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; @@ -1963,6 +1964,7 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) /* Error matching iocb on txq or txcmplq * First check the txq. */ + spin_lock_irq(phba->host->host_lock); list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { if (iocb->context1 != ndlp) { continue; @@ -1971,9 +1973,8 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) || (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) { - list_del(&iocb->list); + list_move_tail(&iocb->list, &completions); pring->txq_cnt--; - lpfc_els_free_iocb(phba, iocb); } } @@ -1985,43 +1986,22 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) icmd = &iocb->iocb; if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) || (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) { + lpfc_sli_issue_abort_iotag(phba, pring, iocb); + } + } + spin_unlock_irq(phba->host->host_lock); - iocb->iocb_cmpl = NULL; - /* context2 = cmd, context2->next = rsp, context3 = - bpl */ - if (iocb->context2) { - /* Free the response IOCB before handling the - command. */ - - mp = (struct lpfc_dmabuf *) (iocb->context2); - mp = list_get_first(&mp->list, - struct lpfc_dmabuf, - list); - if (mp) { - /* Delay before releasing rsp buffer to - * give UNREG mbox a chance to take - * effect. - */ - list_add(&mp->list, - &phba->freebufList); - } - lpfc_mbuf_free(phba, - ((struct lpfc_dmabuf *) - iocb->context2)->virt, - ((struct lpfc_dmabuf *) - iocb->context2)->phys); - kfree(iocb->context2); - } + while (!list_empty(&completions)) { + iocb = list_get_first(&completions, struct lpfc_iocbq, list); + list_del(&iocb->list); - if (iocb->context3) { - lpfc_mbuf_free(phba, - ((struct lpfc_dmabuf *) - iocb->context3)->virt, - ((struct lpfc_dmabuf *) - iocb->context3)->phys); - kfree(iocb->context3); - } - } + if (iocb->iocb_cmpl) { + icmd = &iocb->iocb; + icmd->ulpStatus = IOSTAT_LOCAL_REJECT; + icmd->un.ulpWord[4] = IOERR_SLI_ABORTED; + (iocb->iocb_cmpl) (phba, iocb, iocb); + } else + lpfc_sli_release_iocbq(phba, iocb); } return; @@ -2354,7 +2334,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) * else return NULL. */ struct lpfc_nodelist * -lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi) +__lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi) { struct lpfc_nodelist *ndlp; struct list_head * lists[]={&phba->fc_nlpunmap_list, @@ -2364,17 +2344,25 @@ lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi) &phba->fc_reglogin_list}; int i; - spin_lock_irq(phba->host->host_lock); for (i = 0; i < ARRAY_SIZE(lists); i++ ) list_for_each_entry(ndlp, lists[i], nlp_listp) if (ndlp->nlp_rpi == rpi) { - spin_unlock_irq(phba->host->host_lock); return ndlp; } - spin_unlock_irq(phba->host->host_lock); return NULL; } +struct lpfc_nodelist * +lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi) +{ + struct lpfc_nodelist *ndlp; + + spin_lock_irq(phba->host->host_lock); + ndlp = __lpfc_findnode_rpi(phba, rpi); + spin_unlock_irq(phba->host->host_lock); + return ndlp; +} + /* * This routine looks up the ndlp lists * for the given WWPN. If WWPN found diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index aa7f446..1c78a71 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -170,11 +170,11 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba * phba, int lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) { + LIST_HEAD(completions); struct lpfc_sli *psli; struct lpfc_sli_ring *pring; struct lpfc_iocbq *iocb, *next_iocb; - IOCB_t *icmd; - int found = 0; + IOCB_t *cmd; /* Abort outstanding I/O on NPort */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, @@ -187,45 +187,40 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) pring = &psli->ring[LPFC_ELS_RING]; /* First check the txq */ - do { - found = 0; - spin_lock_irq(phba->host->host_lock); - list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { - /* Check to see if iocb matches the nport we are looking - for */ - if ((lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))) { - found = 1; - /* It matches, so deque and call compl with an - error */ - list_del(&iocb->list); - pring->txq_cnt--; - if (iocb->iocb_cmpl) { - icmd = &iocb->iocb; - icmd->ulpStatus = IOSTAT_LOCAL_REJECT; - icmd->un.ulpWord[4] = IOERR_SLI_ABORTED; - spin_unlock_irq(phba->host->host_lock); - (iocb->iocb_cmpl) (phba, iocb, iocb); - spin_lock_irq(phba->host->host_lock); - } else - lpfc_sli_release_iocbq(phba, iocb); - break; - } + spin_lock_irq(phba->host->host_lock); + list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { + /* Check to see if iocb matches the nport we are looking + for */ + if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) { + /* It matches, so deque and call compl with an + error */ + list_move_tail(&iocb->list, &completions); + pring->txq_cnt--; } - spin_unlock_irq(phba->host->host_lock); - } while (found); + } /* Next check the txcmplq */ - spin_lock_irq(phba->host->host_lock); list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { /* Check to see if iocb matches the nport we are looking for */ - if ((lpfc_check_sli_ndlp (phba, pring, iocb, ndlp))) { - icmd = &iocb->iocb; + if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) lpfc_sli_issue_abort_iotag(phba, pring, iocb); - } } spin_unlock_irq(phba->host->host_lock); + while (!list_empty(&completions)) { + iocb = list_get_first(&completions, struct lpfc_iocbq, list); + cmd = &iocb->iocb; + list_del(&iocb->list); + + if (iocb->iocb_cmpl) { + cmd->ulpStatus = IOSTAT_LOCAL_REJECT; + cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; + (iocb->iocb_cmpl) (phba, iocb, iocb); + } else + lpfc_sli_release_iocbq(phba, iocb); + } + /* If we are delaying issuing an ELS command, cancel it */ if (ndlp->nlp_flag & NLP_DELAY_TMO) lpfc_cancel_retry_delay_tmo(phba, ndlp); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index dcd313a..1682524 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1455,8 +1455,9 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, int lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) { + LIST_HEAD(completions); struct lpfc_iocbq *iocb, *next_iocb; - IOCB_t *icmd = NULL, *cmd = NULL; + IOCB_t *cmd = NULL; int errcnt; errcnt = 0; @@ -1465,46 +1466,28 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) * First do the txq. */ spin_lock_irq(phba->host->host_lock); - list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { - list_del_init(&iocb->list); - if (iocb->iocb_cmpl) { - icmd = &iocb->iocb; - icmd->ulpStatus = IOSTAT_LOCAL_REJECT; - icmd->un.ulpWord[4] = IOERR_SLI_ABORTED; - spin_unlock_irq(phba->host->host_lock); - (iocb->iocb_cmpl) (phba, iocb, iocb); - spin_lock_irq(phba->host->host_lock); - } else - lpfc_sli_release_iocbq(phba, iocb); - } + list_splice_init(&pring->txq, &completions); pring->txq_cnt = 0; - INIT_LIST_HEAD(&(pring->txq)); /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { - cmd = &iocb->iocb; + list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) + lpfc_sli_issue_abort_iotag(phba, pring, iocb); - /* - * Imediate abort of IOCB, deque and call compl - */ + spin_unlock_irq(phba->host->host_lock); - list_del_init(&iocb->list); - pring->txcmplq_cnt--; + while (!list_empty(&completions)) { + iocb = list_get_first(&completions, struct lpfc_iocbq, list); + cmd = &iocb->iocb; + list_del(&iocb->list); if (iocb->iocb_cmpl) { cmd->ulpStatus = IOSTAT_LOCAL_REJECT; cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; - spin_unlock_irq(phba->host->host_lock); (iocb->iocb_cmpl) (phba, iocb, iocb); - spin_lock_irq(phba->host->host_lock); } else lpfc_sli_release_iocbq(phba, iocb); } - INIT_LIST_HEAD(&pring->txcmplq); - pring->txcmplq_cnt = 0; - spin_unlock_irq(phba->host->host_lock); - return errcnt; } @@ -2605,11 +2588,12 @@ lpfc_sli_queue_setup(struct lpfc_hba * phba) int lpfc_sli_hba_down(struct lpfc_hba * phba) { + LIST_HEAD(completions); struct lpfc_sli *psli; struct lpfc_sli_ring *pring; LPFC_MBOXQ_t *pmb; - struct lpfc_iocbq *iocb, *next_iocb; - IOCB_t *icmd = NULL; + struct lpfc_iocbq *iocb; + IOCB_t *cmd = NULL; int i; unsigned long flags = 0; @@ -2617,7 +2601,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba) lpfc_hba_down_prep(phba); spin_lock_irqsave(phba->host->host_lock, flags); - for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; pring->flag |= LPFC_DEFERRED_RING_EVENT; @@ -2626,28 +2609,25 @@ lpfc_sli_hba_down(struct lpfc_hba * phba) * Error everything on the txq since these iocbs have not been * given to the FW yet. */ + list_splice_init(&pring->txq, &completions); pring->txq_cnt = 0; - list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { - list_del_init(&iocb->list); - if (iocb->iocb_cmpl) { - icmd = &iocb->iocb; - icmd->ulpStatus = IOSTAT_LOCAL_REJECT; - icmd->un.ulpWord[4] = IOERR_SLI_DOWN; - spin_unlock_irqrestore(phba->host->host_lock, - flags); - (iocb->iocb_cmpl) (phba, iocb, iocb); - spin_lock_irqsave(phba->host->host_lock, flags); - } else - lpfc_sli_release_iocbq(phba, iocb); - } + } + spin_unlock_irqrestore(phba->host->host_lock, flags); - INIT_LIST_HEAD(&(pring->txq)); + while (!list_empty(&completions)) { + iocb = list_get_first(&completions, struct lpfc_iocbq, list); + cmd = &iocb->iocb; + list_del(&iocb->list); + if (iocb->iocb_cmpl) { + cmd->ulpStatus = IOSTAT_LOCAL_REJECT; + cmd->un.ulpWord[4] = IOERR_SLI_DOWN; + (iocb->iocb_cmpl) (phba, iocb, iocb); + } else + lpfc_sli_release_iocbq(phba, iocb); } - spin_unlock_irqrestore(phba->host->host_lock, flags); - /* Return any active mbox cmds */ del_timer_sync(&psli->mbox_tmo); spin_lock_irqsave(phba->host->host_lock, flags); -- cgit v0.10.2 From de0c5b32b50ef2673f4cd434b9c2732237d715dd Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:52:27 -0400 Subject: [SCSI] lpfc 8.1.12 : Reorganize lpfc_nlp_list() and callers to prepare for nodelist simplification Reorganize lpfc_nlp_list() and callers to prepare for nodelist simplification. Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 80dcfaa..b80ddb8 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -43,7 +43,9 @@ void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_nlp_list(struct lpfc_hba *, struct lpfc_nodelist *, int); +void lpfc_dequeue_node(struct lpfc_hba *, struct lpfc_nodelist *); +void lpfc_nlp_set_state(struct lpfc_hba *, struct lpfc_nodelist *, int); +void lpfc_drop_node(struct lpfc_hba *, struct lpfc_nodelist *); void lpfc_set_disctmo(struct lpfc_hba *); int lpfc_can_disctmo(struct lpfc_hba *); int lpfc_unreg_rpi(struct lpfc_hba *, struct lpfc_nodelist *); diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index cfafff0..30b2ba0 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -83,7 +83,6 @@ struct lpfc_nodelist { }; /* Defines for nlp_flag (uint32) */ -#define NLP_NO_LIST 0x0 /* Indicates immediately free node */ #define NLP_UNUSED_LIST 0x1 /* Flg to indicate node will be freed */ #define NLP_PLOGI_LIST 0x2 /* Flg to indicate sent PLOGI */ #define NLP_ADISC_LIST 0x3 /* Flg to indicate sent ADISC */ @@ -92,7 +91,6 @@ struct lpfc_nodelist { #define NLP_UNMAPPED_LIST 0x6 /* Node is now unmapped */ #define NLP_MAPPED_LIST 0x7 /* Node is now mapped */ #define NLP_NPR_LIST 0x8 /* Node is in NPort Recovery state */ -#define NLP_JUST_DQ 0x9 /* just deque ndlp in lpfc_nlp_list */ #define NLP_LIST_MASK 0xf /* mask to see what list node is on */ #define NLP_PLOGI_SND 0x20 /* sent PLOGI request for this entry */ #define NLP_PRLI_SND 0x40 /* sent PRLI request for this entry */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index e3bebf9..14266df 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -387,8 +387,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, sizeof(struct lpfc_name)); memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof(struct lpfc_name)); - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); ndlp->nlp_flag |= NLP_NPR_2B_DISC; } else { /* This side will wait for the PLOGI */ @@ -605,7 +604,7 @@ lpfc_initial_flogi(struct lpfc_hba * phba) return 0; lpfc_nlp_init(phba, ndlp, Fabric_DID); } else { - lpfc_nlp_list(phba, ndlp, NLP_JUST_DQ); + lpfc_dequeue_node(phba, ndlp); } if (lpfc_issue_els_flogi(phba, ndlp, 0)) { mempool_free( ndlp, phba->nlp_mem_pool); @@ -679,18 +678,15 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp, lpfc_unreg_rpi(phba, new_ndlp); new_ndlp->nlp_DID = ndlp->nlp_DID; new_ndlp->nlp_prev_state = ndlp->nlp_prev_state; - new_ndlp->nlp_state = ndlp->nlp_state; - lpfc_nlp_list(phba, new_ndlp, ndlp->nlp_flag & NLP_LIST_MASK); + lpfc_nlp_set_state(phba, new_ndlp, ndlp->nlp_state); /* Move this back to NPR list */ - if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - } + if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) + lpfc_drop_node(phba, ndlp); else { lpfc_unreg_rpi(phba, ndlp); ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */ - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); } return new_ndlp; } @@ -704,7 +700,6 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_dmabuf *prsp; int disc, rc, did, type; - /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->context_un.rsp_iocb = rspiocb; @@ -1538,29 +1533,25 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp) case ELS_CMD_PLOGI: if(!lpfc_issue_els_plogi(phba, ndlp->nlp_DID, retry)) { ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE); } break; case ELS_CMD_ADISC: if (!lpfc_issue_els_adisc(phba, ndlp, retry)) { ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_ADISC_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE); } break; case ELS_CMD_PRLI: if (!lpfc_issue_els_prli(phba, ndlp, retry)) { ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_PRLI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE); } break; case ELS_CMD_LOGO: if (!lpfc_issue_els_logo(phba, ndlp, retry)) { ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); } break; } @@ -1730,8 +1721,7 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, ndlp->nlp_flag |= NLP_DELAY_TMO; ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); ndlp->nlp_last_elscmd = cmd; return 1; @@ -1743,27 +1733,24 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, case ELS_CMD_PLOGI: if (ndlp) { ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); + lpfc_nlp_set_state(phba, ndlp, + NLP_STE_PLOGI_ISSUE); } lpfc_issue_els_plogi(phba, did, cmdiocb->retry); return 1; case ELS_CMD_ADISC: ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_ADISC_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE); lpfc_issue_els_adisc(phba, ndlp, cmdiocb->retry); return 1; case ELS_CMD_PRLI: ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_PRLI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE); lpfc_issue_els_prli(phba, ndlp, cmdiocb->retry); return 1; case ELS_CMD_LOGO: ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); lpfc_issue_els_logo(phba, ndlp, cmdiocb->retry); return 1; } @@ -1827,7 +1814,7 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, switch (ndlp->nlp_state) { case NLP_STE_UNUSED_NODE: /* node is just allocated */ - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); break; case NLP_STE_NPR_NODE: /* NPort Recovery mode */ lpfc_unreg_rpi(phba, ndlp); @@ -1885,8 +1872,7 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; mbox->context2 = ndlp; ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_REG_LOGIN_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_REGLOGIN_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE); if (lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) { @@ -1901,7 +1887,7 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) || (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) { if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); ndlp = NULL; } } @@ -2311,9 +2297,8 @@ lpfc_els_disc_adisc(struct lpfc_hba * phba) if (ndlp->nlp_flag & NLP_NPR_ADISC) { ndlp->nlp_flag &= ~NLP_NPR_ADISC; ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_ADISC_ISSUE; - lpfc_nlp_list(phba, ndlp, - NLP_ADISC_LIST); + lpfc_nlp_set_state(phba, ndlp, + NLP_STE_ADISC_ISSUE); lpfc_issue_els_adisc(phba, ndlp, 0); sentadisc++; phba->num_disc_nodes++; @@ -2349,8 +2334,8 @@ lpfc_els_disc_plogi(struct lpfc_hba * phba) (!(ndlp->nlp_flag & NLP_DELAY_TMO))) { if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); + lpfc_nlp_set_state(phba, ndlp, + NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0); sentplogi++; phba->num_disc_nodes++; @@ -2647,8 +2632,7 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba) lpfc_nlp_init(phba, ndlp, NameServer_DID); ndlp->nlp_type |= NLP_FABRIC; ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(phba, NameServer_DID, 0); /* Wait for NameServer login cmpl before we can continue */ @@ -3074,8 +3058,8 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba, /* Log back into the node before sending the FARP. */ if (fp->Rflags & FARP_REQUEST_PLOGI) { ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); + lpfc_nlp_set_state(phba, ndlp, + NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0); } @@ -3159,7 +3143,7 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, * Clean up old Fabric, Nameserver and * other NLP_FABRIC logins */ - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { /* Fail outstanding I/O now since this * device is marked for PLOGI @@ -3182,14 +3166,14 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, switch (ndlp->nlp_prev_state) { case NLP_STE_UNMAPPED_NODE: ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - ndlp->nlp_state = NLP_STE_UNMAPPED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST); + lpfc_nlp_set_state(phba, ndlp, + NLP_STE_UNMAPPED_NODE); break; case NLP_STE_MAPPED_NODE: ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - ndlp->nlp_state = NLP_STE_MAPPED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST); + lpfc_nlp_set_state(phba, ndlp, + NLP_STE_MAPPED_NODE); break; default: @@ -3431,8 +3415,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba, if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) { ndlp->nlp_type |= NLP_FABRIC; } - ndlp->nlp_state = NLP_STE_UNUSED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE); } phba->fc_stat.elsRcvFrame++; @@ -3460,9 +3443,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba, case ELS_CMD_FLOGI: phba->fc_stat.elsRcvFLOGI++; lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode); - if (newnode) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - } + if (newnode) + lpfc_drop_node(phba, ndlp); break; case ELS_CMD_LOGO: phba->fc_stat.elsRcvLOGO++; @@ -3483,9 +3465,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba, case ELS_CMD_RSCN: phba->fc_stat.elsRcvRSCN++; lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode); - if (newnode) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - } + if (newnode) + lpfc_drop_node(phba, ndlp); break; case ELS_CMD_ADISC: phba->fc_stat.elsRcvADISC++; @@ -3526,30 +3507,26 @@ lpfc_els_unsol_event(struct lpfc_hba * phba, case ELS_CMD_LIRR: phba->fc_stat.elsRcvLIRR++; lpfc_els_rcv_lirr(phba, elsiocb, ndlp); - if (newnode) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - } + if (newnode) + lpfc_drop_node(phba, ndlp); break; case ELS_CMD_RPS: phba->fc_stat.elsRcvRPS++; lpfc_els_rcv_rps(phba, elsiocb, ndlp); - if (newnode) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - } + if (newnode) + lpfc_drop_node(phba, ndlp); break; case ELS_CMD_RPL: phba->fc_stat.elsRcvRPL++; lpfc_els_rcv_rpl(phba, elsiocb, ndlp); - if (newnode) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - } + if (newnode) + lpfc_drop_node(phba, ndlp); break; case ELS_CMD_RNID: phba->fc_stat.elsRcvRNID++; lpfc_els_rcv_rnid(phba, elsiocb, ndlp); - if (newnode) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - } + if (newnode) + lpfc_drop_node(phba, ndlp); break; default: /* Unsupported ELS command, reject */ @@ -3559,9 +3536,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba, lpfc_printf_log(phba, KERN_ERR, LOG_ELS, "%d:0115 Unknown ELS command x%x received from " "NPORT x%x\n", phba->brd_no, cmd, did); - if (newnode) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - } + if (newnode) + lpfc_drop_node(phba, ndlp); break; } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 2c21641..fda8f07 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -429,9 +429,8 @@ lpfc_linkdown(struct lpfc_hba * phba) /* free any ndlp's on unused list */ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list, - nlp_listp) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - } + nlp_listp) + lpfc_drop_node(phba, ndlp); /* Setup myDID for link up if we are in pt2pt mode */ if (phba->fc_flag & FC_PT2PT) { @@ -497,8 +496,8 @@ lpfc_linkup(struct lpfc_hba * phba) /* On Linkup its safe to clean up the * ndlp from Fabric connections. */ - lpfc_nlp_list(phba, ndlp, - NLP_UNUSED_LIST); + lpfc_nlp_set_state(phba, ndlp, + NLP_STE_UNUSED_NODE); } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { /* Fail outstanding IO now since device * is marked for PLOGI. @@ -511,9 +510,8 @@ lpfc_linkup(struct lpfc_hba * phba) /* free any ndlp's on unused list */ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list, - nlp_listp) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); - } + nlp_listp) + lpfc_drop_node(phba, ndlp); return 0; } @@ -993,8 +991,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) ndlp->nlp_rpi = mb->un.varWords[0]; ndlp->nlp_type |= NLP_FABRIC; - ndlp->nlp_state = NLP_STE_UNMAPPED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); if (phba->hba_state == LPFC_FABRIC_CFG_LINK) { /* This NPort has been assigned an NPort_ID by the fabric as a @@ -1024,8 +1021,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) ndlp->nlp_type |= NLP_FABRIC; } } - ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(phba, NameServer_DID, 0); if (phba->cfg_fdmi_on) { ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool, @@ -1068,8 +1064,8 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) if (mb->mbxStatus) { lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - mempool_free( pmb, phba->mbox_mem_pool); - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + mempool_free(pmb, phba->mbox_mem_pool); + lpfc_drop_node(phba, ndlp); /* RegLogin failed, so just use loop map to make discovery list */ @@ -1084,8 +1080,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) ndlp->nlp_rpi = mb->un.varWords[0]; ndlp->nlp_type |= NLP_FABRIC; - ndlp->nlp_state = NLP_STE_UNMAPPED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); if (phba->hba_state < LPFC_HBA_READY) { /* Link up discovery requires Fabrib registration. */ @@ -1170,72 +1165,82 @@ lpfc_unregister_remote_port(struct lpfc_hba * phba, return; } -int -lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) +static void +lpfc_nlp_counters(struct lpfc_hba *phba, int state, int count) { - enum { none, unmapped, mapped } rport_add = none, rport_del = none; - struct lpfc_sli *psli; - - psli = &phba->sli; - /* Sanity check to ensure we are not moving to / from the same list */ - if ((nlp->nlp_flag & NLP_LIST_MASK) == list) - if (list != NLP_NO_LIST) - return 0; - - spin_lock_irq(phba->host->host_lock); - switch (nlp->nlp_flag & NLP_LIST_MASK) { - case NLP_NO_LIST: /* Not on any list */ + switch (state) { + case NLP_STE_UNUSED_NODE: + phba->fc_unused_cnt += count; + break; + case NLP_STE_PLOGI_ISSUE: + phba->fc_plogi_cnt += count; + break; + case NLP_STE_ADISC_ISSUE: + phba->fc_adisc_cnt += count; break; + case NLP_STE_REG_LOGIN_ISSUE: + phba->fc_reglogin_cnt += count; + break; + case NLP_STE_PRLI_ISSUE: + phba->fc_prli_cnt += count; + break; + case NLP_STE_UNMAPPED_NODE: + phba->fc_unmap_cnt += count; + break; + case NLP_STE_MAPPED_NODE: + phba->fc_map_cnt += count; + break; + case NLP_STE_NPR_NODE: + phba->fc_npr_cnt += count; + break; + } +} + +void +lpfc_delink_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) +{ + switch (ndlp->nlp_flag & NLP_LIST_MASK) { case NLP_UNUSED_LIST: - phba->fc_unused_cnt--; - list_del(&nlp->nlp_listp); + list_del_init(&ndlp->nlp_listp); break; case NLP_PLOGI_LIST: - phba->fc_plogi_cnt--; - list_del(&nlp->nlp_listp); + list_del_init(&ndlp->nlp_listp); break; case NLP_ADISC_LIST: - phba->fc_adisc_cnt--; - list_del(&nlp->nlp_listp); + list_del_init(&ndlp->nlp_listp); break; case NLP_REGLOGIN_LIST: - phba->fc_reglogin_cnt--; - list_del(&nlp->nlp_listp); + list_del_init(&ndlp->nlp_listp); break; case NLP_PRLI_LIST: - phba->fc_prli_cnt--; - list_del(&nlp->nlp_listp); + list_del_init(&ndlp->nlp_listp); break; case NLP_UNMAPPED_LIST: - phba->fc_unmap_cnt--; - list_del(&nlp->nlp_listp); - nlp->nlp_flag &= ~NLP_TGT_NO_SCSIID; - nlp->nlp_type &= ~NLP_FC_NODE; - phba->nport_event_cnt++; - if (nlp->rport) - rport_del = unmapped; + list_del_init(&ndlp->nlp_listp); break; case NLP_MAPPED_LIST: - phba->fc_map_cnt--; - list_del(&nlp->nlp_listp); - phba->nport_event_cnt++; - if (nlp->rport) - rport_del = mapped; + list_del_init(&ndlp->nlp_listp); break; case NLP_NPR_LIST: - phba->fc_npr_cnt--; - list_del(&nlp->nlp_listp); - /* Stop delay tmo if taking node off NPR list */ - if ((nlp->nlp_flag & NLP_DELAY_TMO) && - (list != NLP_NPR_LIST)) { - spin_unlock_irq(phba->host->host_lock); - lpfc_cancel_retry_delay_tmo(phba, nlp); - spin_lock_irq(phba->host->host_lock); - } + list_del_init(&ndlp->nlp_listp); break; } - nlp->nlp_flag &= ~NLP_LIST_MASK; + ndlp->nlp_flag &= ~NLP_LIST_MASK; +} + +static int +lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) +{ + struct lpfc_sli *psli; + + psli = &phba->sli; + /* Sanity check to ensure we are not moving to / from the same list */ + if ((nlp->nlp_flag & NLP_LIST_MASK) == list) + return 0; + + spin_lock_irq(phba->host->host_lock); + lpfc_delink_node(phba, nlp); /* Add NPort to list */ lpfc_printf_log(phba, @@ -1246,102 +1251,85 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) nlp->nlp_DID, list, nlp->nlp_flag); switch (list) { - case NLP_NO_LIST: /* No list, just remove it */ - spin_unlock_irq(phba->host->host_lock); - lpfc_nlp_remove(phba, nlp); - spin_lock_irq(phba->host->host_lock); - /* as node removed - stop further transport calls */ - rport_del = none; - break; case NLP_UNUSED_LIST: nlp->nlp_flag |= list; /* Put it at the end of the unused list */ list_add_tail(&nlp->nlp_listp, &phba->fc_unused_list); - phba->fc_unused_cnt++; break; case NLP_PLOGI_LIST: nlp->nlp_flag |= list; /* Put it at the end of the plogi list */ list_add_tail(&nlp->nlp_listp, &phba->fc_plogi_list); - phba->fc_plogi_cnt++; break; case NLP_ADISC_LIST: nlp->nlp_flag |= list; /* Put it at the end of the adisc list */ list_add_tail(&nlp->nlp_listp, &phba->fc_adisc_list); - phba->fc_adisc_cnt++; break; case NLP_REGLOGIN_LIST: nlp->nlp_flag |= list; /* Put it at the end of the reglogin list */ list_add_tail(&nlp->nlp_listp, &phba->fc_reglogin_list); - phba->fc_reglogin_cnt++; break; case NLP_PRLI_LIST: nlp->nlp_flag |= list; /* Put it at the end of the prli list */ list_add_tail(&nlp->nlp_listp, &phba->fc_prli_list); - phba->fc_prli_cnt++; break; case NLP_UNMAPPED_LIST: - rport_add = unmapped; - /* ensure all vestiges of "mapped" significance are gone */ - nlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); nlp->nlp_flag |= list; /* Put it at the end of the unmap list */ list_add_tail(&nlp->nlp_listp, &phba->fc_nlpunmap_list); - phba->fc_unmap_cnt++; - phba->nport_event_cnt++; - nlp->nlp_flag &= ~NLP_NODEV_REMOVE; - nlp->nlp_type |= NLP_FC_NODE; break; case NLP_MAPPED_LIST: - rport_add = mapped; nlp->nlp_flag |= list; /* Put it at the end of the map list */ list_add_tail(&nlp->nlp_listp, &phba->fc_nlpmap_list); - phba->fc_map_cnt++; - phba->nport_event_cnt++; - nlp->nlp_flag &= ~NLP_NODEV_REMOVE; break; case NLP_NPR_LIST: nlp->nlp_flag |= list; /* Put it at the end of the npr list */ list_add_tail(&nlp->nlp_listp, &phba->fc_npr_list); - phba->fc_npr_cnt++; - - nlp->nlp_flag &= ~NLP_RCV_PLOGI; - break; - case NLP_JUST_DQ: break; } spin_unlock_irq(phba->host->host_lock); + return 0; +} - /* - * We make all the calls into the transport after we have - * moved the node between lists. This so that we don't - * release the lock while in-between lists. - */ - - /* Don't upcall midlayer if we're unloading */ - if (!(phba->fc_flag & FC_UNLOADING)) { - /* - * We revalidate the rport pointer as the "add" function - * may have removed the remote port. - */ - if ((rport_del != none) && nlp->rport) - lpfc_unregister_remote_port(phba, nlp); +static void +lpfc_nlp_state_cleanup(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, + int old_state, int new_state) +{ + if (new_state == NLP_STE_UNMAPPED_NODE) { + ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); + ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; + ndlp->nlp_type |= NLP_FC_NODE; + } + if (new_state == NLP_STE_MAPPED_NODE) + ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; + if (new_state == NLP_STE_NPR_NODE) + ndlp->nlp_flag &= ~NLP_RCV_PLOGI; + + /* Transport interface */ + if (ndlp->rport && (old_state == NLP_STE_MAPPED_NODE || + old_state == NLP_STE_UNMAPPED_NODE)) { + phba->nport_event_cnt++; + lpfc_unregister_remote_port(phba, ndlp); + } - if (rport_add != none) { + if (new_state == NLP_STE_MAPPED_NODE || + new_state == NLP_STE_UNMAPPED_NODE) { + phba->nport_event_cnt++; /* * Tell the fc transport about the port, if we haven't * already. If we have, and it's a scsi entity, be * sure to unblock any attached scsi devices */ - if ((!nlp->rport) || (nlp->rport->port_state == - FC_PORTSTATE_BLOCKED)) - lpfc_register_remote_port(phba, nlp); + if (!ndlp->rport || + ndlp->rport->port_state == FC_PORTSTATE_BLOCKED) + lpfc_register_remote_port(phba, ndlp); + } /* * if we added to Mapped list, but the remote port @@ -1349,19 +1337,75 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) * our presentable range - move the node to the * Unmapped List */ - if ((rport_add == mapped) && - ((!nlp->rport) || - (nlp->rport->scsi_target_id == -1) || - (nlp->rport->scsi_target_id >= LPFC_MAX_TARGET))) { - nlp->nlp_state = NLP_STE_UNMAPPED_NODE; - spin_lock_irq(phba->host->host_lock); - nlp->nlp_flag |= NLP_TGT_NO_SCSIID; - spin_unlock_irq(phba->host->host_lock); - lpfc_nlp_list(phba, nlp, NLP_UNMAPPED_LIST); - } - } + if (new_state == NLP_STE_MAPPED_NODE && + (!ndlp->rport || + ndlp->rport->scsi_target_id == -1 || + ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) { + spin_lock_irq(phba->host->host_lock); + ndlp->nlp_flag |= NLP_TGT_NO_SCSIID; + spin_unlock_irq(phba->host->host_lock); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); } - return 0; +} + +void +lpfc_nlp_set_state(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, int state) +{ + int old_state = ndlp->nlp_state; + static int list_id[] = { + [NLP_STE_UNUSED_NODE] = NLP_UNUSED_LIST, + [NLP_STE_PLOGI_ISSUE] = NLP_PLOGI_LIST, + [NLP_STE_ADISC_ISSUE] = NLP_ADISC_LIST, + [NLP_STE_REG_LOGIN_ISSUE] = NLP_REGLOGIN_LIST, + [NLP_STE_PRLI_ISSUE] = NLP_PRLI_LIST, + [NLP_STE_UNMAPPED_NODE] = NLP_UNMAPPED_LIST, + [NLP_STE_MAPPED_NODE] = NLP_MAPPED_LIST, + [NLP_STE_NPR_NODE] = NLP_NPR_LIST, + }; + + if (old_state == NLP_STE_NPR_NODE && + (ndlp->nlp_flag & NLP_DELAY_TMO) != 0 && + state != NLP_STE_NPR_NODE) + lpfc_cancel_retry_delay_tmo(phba, ndlp); + if (old_state == NLP_STE_UNMAPPED_NODE) { + ndlp->nlp_flag &= ~NLP_TGT_NO_SCSIID; + ndlp->nlp_type &= ~NLP_FC_NODE; + } + + if (old_state && !list_empty(&ndlp->nlp_listp)) + lpfc_nlp_counters(phba, old_state, -1); + + ndlp->nlp_state = state; + lpfc_nlp_list(phba, ndlp, list_id[state]); + lpfc_nlp_counters(phba, state, 1); + + lpfc_nlp_state_cleanup(phba, ndlp, old_state, state); +} + +void +lpfc_dequeue_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) +{ + if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0) + lpfc_cancel_retry_delay_tmo(phba, ndlp); + spin_lock_irq(phba->host->host_lock); + if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) + lpfc_nlp_counters(phba, ndlp->nlp_state, -1); + lpfc_delink_node(phba, ndlp); + spin_unlock_irq(phba->host->host_lock); + lpfc_nlp_state_cleanup(phba, ndlp, ndlp->nlp_state, 0); +} + +void +lpfc_drop_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) +{ + if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0) + lpfc_cancel_retry_delay_tmo(phba, ndlp); + spin_lock_irq(phba->host->host_lock); + if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) + lpfc_nlp_counters(phba, ndlp->nlp_state, -1); + lpfc_delink_node(phba, ndlp); + spin_unlock_irq(phba->host->host_lock); + lpfc_nlp_remove(phba, ndlp); } /* @@ -1577,7 +1621,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - lpfc_nlp_list(phba, ndlp, NLP_JUST_DQ); + lpfc_dequeue_node(phba, ndlp); /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ if ((mb = phba->sli.mbox_active)) { @@ -1771,8 +1815,7 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did) if (!ndlp) return NULL; lpfc_nlp_init(phba, ndlp, did); - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); ndlp->nlp_flag |= NLP_NPR_2B_DISC; return ndlp; } @@ -1791,8 +1834,7 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did) flg = ndlp->nlp_flag & NLP_LIST_MASK; if ((flg == NLP_ADISC_LIST) || (flg == NLP_PLOGI_LIST)) return NULL; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); ndlp->nlp_flag |= NLP_NPR_2B_DISC; } return ndlp; @@ -2099,7 +2141,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) nlp_listp) { if (ndlp->nlp_type & NLP_FABRIC) { /* Clean up the ndlp on Fabric connections */ - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { /* Fail outstanding IO now since device * is marked for PLOGI. @@ -2304,8 +2346,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) ndlp->nlp_rpi = mb->un.varWords[0]; ndlp->nlp_type |= NLP_FABRIC; - ndlp->nlp_state = NLP_STE_UNMAPPED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); /* Start issuing Fabric-Device Management Interface (FDMI) * command to 0xfffffa (FDMI well known port) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index dc0fd2e..5f013f1 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1196,7 +1196,7 @@ lpfc_cleanup(struct lpfc_hba * phba) list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list, nlp_listp) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); } list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list, diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 1c78a71..5595c61 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -434,8 +434,7 @@ lpfc_rcv_padisc(struct lpfc_hba * phba, spin_unlock_irq(phba->host->host_lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); return 0; } @@ -465,12 +464,10 @@ lpfc_rcv_logo(struct lpfc_hba * phba, ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); } else { ndlp->nlp_prev_state = ndlp->nlp_state; - ndlp->nlp_state = NLP_STE_UNUSED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE); } spin_lock_irq(phba->host->host_lock); @@ -564,11 +561,10 @@ lpfc_rcv_plogi_unused_node(struct lpfc_hba * phba, if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) { ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; - ndlp->nlp_state = NLP_STE_UNUSED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE); return ndlp->nlp_state; } - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); return NLP_STE_FREED_NODE; } @@ -577,7 +573,7 @@ lpfc_rcv_els_unused_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { lpfc_issue_els_logo(phba, ndlp, 0); - lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE); return ndlp->nlp_state; } @@ -593,7 +589,7 @@ lpfc_rcv_logo_unused_node(struct lpfc_hba * phba, ndlp->nlp_flag |= NLP_LOGO_ACC; spin_unlock_irq(phba->host->host_lock); lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0); - lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE); return ndlp->nlp_state; } @@ -602,7 +598,7 @@ static uint32_t lpfc_cmpl_logo_unused_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); return NLP_STE_FREED_NODE; } @@ -610,7 +606,7 @@ static uint32_t lpfc_device_rm_unused_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); return NLP_STE_FREED_NODE; } @@ -690,8 +686,7 @@ lpfc_rcv_els_plogi_issue(struct lpfc_hba * phba, spin_unlock_irq(phba->host->host_lock); ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); return ndlp->nlp_state; } @@ -766,30 +761,23 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba, goto out; lpfc_unreg_rpi(phba, ndlp); - if (lpfc_reg_login - (phba, irsp->un.elsreq64.remoteID, - (uint8_t *) sp, mbox, 0) == 0) { + if (lpfc_reg_login(phba, irsp->un.elsreq64.remoteID, (uint8_t *) sp, + mbox, 0) == 0) { switch (ndlp->nlp_DID) { case NameServer_DID: - mbox->mbox_cmpl = - lpfc_mbx_cmpl_ns_reg_login; + mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login; break; case FDMI_DID: - mbox->mbox_cmpl = - lpfc_mbx_cmpl_fdmi_reg_login; + mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login; break; default: - mbox->mbox_cmpl = - lpfc_mbx_cmpl_reg_login; + mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; } mbox->context2 = ndlp; if (lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) { - ndlp->nlp_state = - NLP_STE_REG_LOGIN_ISSUE; - lpfc_nlp_list(phba, ndlp, - NLP_REGLOGIN_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE); return ndlp->nlp_state; } mp = (struct lpfc_dmabuf *)mbox->context1; @@ -804,7 +792,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba, out: /* Free this node since the driver cannot login or has the wrong sparm */ - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); return NLP_STE_FREED_NODE; } @@ -820,7 +808,7 @@ lpfc_device_rm_plogi_issue(struct lpfc_hba * phba, /* software abort outstanding PLOGI */ lpfc_els_abort(phba, ndlp); - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); return NLP_STE_FREED_NODE; } } @@ -834,8 +822,7 @@ lpfc_device_recov_plogi_issue(struct lpfc_hba * phba, lpfc_els_abort(phba, ndlp); ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); @@ -859,8 +846,7 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_hba * phba, return ndlp->nlp_state; } ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; - ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0); return ndlp->nlp_state; @@ -950,20 +936,17 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_hba * phba, memset(&ndlp->nlp_portname, 0, sizeof (struct lpfc_name)); ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); lpfc_unreg_rpi(phba, ndlp); return ndlp->nlp_state; } if (ndlp->nlp_type & NLP_FCP_TARGET) { ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; - ndlp->nlp_state = NLP_STE_MAPPED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_MAPPED_NODE); } else { ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; - ndlp->nlp_state = NLP_STE_UNMAPPED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); } return ndlp->nlp_state; } @@ -981,7 +964,7 @@ lpfc_device_rm_adisc_issue(struct lpfc_hba * phba, /* software abort outstanding ADISC */ lpfc_els_abort(phba, ndlp); - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); return NLP_STE_FREED_NODE; } } @@ -995,8 +978,7 @@ lpfc_device_recov_adisc_issue(struct lpfc_hba * phba, lpfc_els_abort(phba, ndlp); ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); ndlp->nlp_flag |= NLP_NPR_ADISC; @@ -1096,8 +1078,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba, */ if (mb->mbxStatus == MBXERR_RPI_FULL) { ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; - ndlp->nlp_state = NLP_STE_UNUSED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE); return ndlp->nlp_state; } @@ -1110,8 +1091,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba, lpfc_issue_els_logo(phba, ndlp, 0); ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); return ndlp->nlp_state; } @@ -1120,13 +1100,11 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba, /* Only if we are not a fabric nport do we issue PRLI */ if (!(ndlp->nlp_type & NLP_FABRIC)) { ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; - ndlp->nlp_state = NLP_STE_PRLI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE); lpfc_issue_els_prli(phba, ndlp, 0); } else { ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; - ndlp->nlp_state = NLP_STE_UNMAPPED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); } return ndlp->nlp_state; } @@ -1141,7 +1119,7 @@ lpfc_device_rm_reglogin_issue(struct lpfc_hba * phba, return ndlp->nlp_state; } else { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); return NLP_STE_FREED_NODE; } } @@ -1152,8 +1130,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_hba * phba, uint32_t evt) { ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); @@ -1242,8 +1219,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_hba * phba, irsp = &rspiocb->iocb; if (irsp->ulpStatus) { ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; - ndlp->nlp_state = NLP_STE_UNMAPPED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); return ndlp->nlp_state; } @@ -1261,8 +1237,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_hba * phba, } ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; - ndlp->nlp_state = NLP_STE_MAPPED_NODE; - lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_MAPPED_NODE); return ndlp->nlp_state; } @@ -1295,7 +1270,7 @@ lpfc_device_rm_prli_issue(struct lpfc_hba * phba, /* software abort outstanding PLOGI */ lpfc_els_abort(phba, ndlp); - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); return NLP_STE_FREED_NODE; } } @@ -1325,8 +1300,7 @@ lpfc_device_recov_prli_issue(struct lpfc_hba * phba, lpfc_els_abort(phba, ndlp); ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); @@ -1399,8 +1373,7 @@ lpfc_device_recov_unmap_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, void *arg, uint32_t evt) { ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); lpfc_disc_set_adisc(phba, ndlp); @@ -1481,8 +1454,7 @@ lpfc_device_recov_mapped_node(struct lpfc_hba * phba, uint32_t evt) { ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE; - ndlp->nlp_state = NLP_STE_NPR_NODE; - lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); spin_unlock_irq(phba->host->host_lock); @@ -1514,8 +1486,7 @@ lpfc_rcv_plogi_npr_node(struct lpfc_hba * phba, /* send PLOGI immediately, move to PLOGI issue state */ if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0); } @@ -1543,16 +1514,13 @@ lpfc_rcv_prli_npr_node(struct lpfc_hba * phba, ndlp->nlp_flag &= ~NLP_NPR_ADISC; spin_unlock_irq(phba->host->host_lock); ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - ndlp->nlp_state = NLP_STE_ADISC_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE); lpfc_issue_els_adisc(phba, ndlp, 0); } else { ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0); } - } return ndlp->nlp_state; } @@ -1590,13 +1558,11 @@ lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba, !(ndlp->nlp_flag & NLP_NPR_2B_DISC)){ if (ndlp->nlp_flag & NLP_NPR_ADISC) { ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - ndlp->nlp_state = NLP_STE_ADISC_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE); lpfc_issue_els_adisc(phba, ndlp, 0); } else { ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); + lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE); lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0); } } @@ -1645,7 +1611,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_hba * phba, irsp = &rspiocb->iocb; if (irsp->ulpStatus) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); return NLP_STE_FREED_NODE; } return ndlp->nlp_state; @@ -1663,7 +1629,7 @@ lpfc_cmpl_prli_npr_node(struct lpfc_hba * phba, irsp = &rspiocb->iocb; if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); return NLP_STE_FREED_NODE; } return ndlp->nlp_state; @@ -1691,7 +1657,7 @@ lpfc_cmpl_adisc_npr_node(struct lpfc_hba * phba, irsp = &rspiocb->iocb; if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); return NLP_STE_FREED_NODE; } return ndlp->nlp_state; @@ -1712,7 +1678,7 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_hba * phba, ndlp->nlp_rpi = mb->un.varWords[0]; else { if (ndlp->nlp_flag & NLP_NODEV_REMOVE) { - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); return NLP_STE_FREED_NODE; } } @@ -1728,7 +1694,7 @@ lpfc_device_rm_npr_node(struct lpfc_hba * phba, ndlp->nlp_flag |= NLP_NODEV_REMOVE; return ndlp->nlp_state; } - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + lpfc_drop_node(phba, ndlp); return NLP_STE_FREED_NODE; } -- cgit v0.10.2 From 7054a606e6724674a5acd103ed74eacb02c73393 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:52:34 -0400 Subject: [SCSI] lpfc 8.1.12 : Round 2 of Miscellaneous fixes Round 2 of Miscellaneous fixes: - Ensure we don't prematurely re-enable IRQs in lpfc_sli_abort_fcp_cmpl(). - Prevent freeing of iocb after IOCB_TIMEDOUT error. - Added code to cleanup REG_LOGIN mailbox command when a LOGO is received. - Fix offline window where more work can sneak in after clearing work_ha - Use target reset instead of LU reset in bus_device_reset_handler - Fixed system hangs due to leaked host_lock. - Fixed NULL pointer dereference during I/O with LIP. - Fixed false iocb timeout. - Fixed name server query response handling. - Change rport dev_loss_tmo value when user change lpfc HBA's dev_loss_tmo. - Fixed a memory leak in lpfc_sli_wake_mbox_wait. - Fixed check for dropped frames. - Removed hba queue depth calculation based on device PCI IDs - Change min cr_count value specified in comment to agree with setting Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 6aa9153..b7193d1 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -27,10 +27,6 @@ struct lpfc_sli2_slim; requests */ #define LPFC_MAX_NS_RETRY 3 /* Number of retry attempts to contact the NameServer before giving up. */ -#define LPFC_DFT_HBA_Q_DEPTH 2048 /* max cmds per hba */ -#define LPFC_LC_HBA_Q_DEPTH 1024 /* max cmds per low cost hba */ -#define LPFC_LP101_HBA_Q_DEPTH 128 /* max cmds per low cost hba */ - #define LPFC_CMD_PER_LUN 3 /* max outstanding cmds per lun */ #define LPFC_SG_SEG_CNT 64 /* sg element count per scsi cmnd */ #define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index c0b02b1..7811aaf 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -828,6 +828,18 @@ lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val) return -EINVAL; } +static void +lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba) +{ + struct lpfc_nodelist *ndlp; + + spin_lock_irq(phba->host->host_lock); + list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) + if (ndlp->rport) + ndlp->rport->dev_loss_tmo = phba->cfg_devloss_tmo; + spin_unlock_irq(phba->host->host_lock); +} + static int lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val) { @@ -843,6 +855,7 @@ lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val) if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) { phba->cfg_nodev_tmo = val; phba->cfg_devloss_tmo = val; + lpfc_update_rport_devloss_tmo(phba); return 0; } @@ -878,6 +891,7 @@ lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val) phba->cfg_nodev_tmo = val; phba->cfg_devloss_tmo = val; phba->dev_loss_tmo_changed = 1; + lpfc_update_rport_devloss_tmo(phba); return 0; } @@ -997,7 +1011,7 @@ LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support"); /* # lpfc_cr_delay & lpfc_cr_count: Default values for I/O colaesing # cr_delay (msec) or cr_count outstanding commands. cr_delay can take -# value [0,63]. cr_count can take value [0,255]. Default value of cr_delay +# value [0,63]. cr_count can take value [1,255]. Default value of cr_delay # is 0. Default value of cr_count is 1. The cr_count feature is disabled if # cr_delay is set to 0. */ @@ -1955,25 +1969,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) sizeof(struct fcp_rsp) + (phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64)); - switch (phba->pcidev->device) { - case PCI_DEVICE_ID_LP101: - case PCI_DEVICE_ID_BSMB: - case PCI_DEVICE_ID_ZSMB: - phba->cfg_hba_queue_depth = LPFC_LP101_HBA_Q_DEPTH; - break; - case PCI_DEVICE_ID_RFLY: - case PCI_DEVICE_ID_PFLY: - case PCI_DEVICE_ID_BMID: - case PCI_DEVICE_ID_ZMID: - case PCI_DEVICE_ID_TFLY: - phba->cfg_hba_queue_depth = LPFC_LC_HBA_Q_DEPTH; - break; - default: - phba->cfg_hba_queue_depth = LPFC_DFT_HBA_Q_DEPTH; - } - if (phba->cfg_hba_queue_depth > lpfc_hba_queue_depth) - lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); + lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); return; } diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 50f4533..48ae235 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -334,22 +334,22 @@ lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size) lpfc_set_disctmo(phba); - Cnt = Size > FCELSSIZE ? FCELSSIZE : Size; list_add_tail(&head, &mp->list); list_for_each_entry_safe(mp, next_mp, &head, list) { mlast = mp; + Cnt = Size > FCELSSIZE ? FCELSSIZE : Size; + Size -= Cnt; if (!ctptr) { - Cnt = FCELSSIZE; ctptr = (uint32_t *) mlast->virt; } else Cnt -= 16; /* subtract length of CT header */ /* Loop through entire NameServer list of DIDs */ - while (Cnt) { + while (Cnt >= sizeof (uint32_t)) { /* Get next DID from NameServer List */ CTentry = *ctptr++; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 14266df..4d9e7f5 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -3214,7 +3214,7 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) IOCB_t *cmd = NULL; struct lpfc_dmabuf *pcmd; uint32_t *elscmd; - uint32_t els_command; + uint32_t els_command=0; uint32_t timeout; uint32_t remote_ID; @@ -3233,12 +3233,16 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { cmd = &piocb->iocb; - if (piocb->iocb_flag & LPFC_IO_LIBDFC) { + if ((piocb->iocb_flag & LPFC_IO_LIBDFC) || + (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN) || + (piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)) { continue; } pcmd = (struct lpfc_dmabuf *) piocb->context2; - elscmd = (uint32_t *) (pcmd->virt); - els_command = *elscmd; + if (pcmd) { + elscmd = (uint32_t *) (pcmd->virt); + els_command = *elscmd; + } if ((els_command == ELS_CMD_FARP) || (els_command == ELS_CMD_FARPR)) { diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 5f013f1..6449ac8 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1375,8 +1375,6 @@ lpfc_offline(struct lpfc_hba * phba) /* stop all timers associated with this hba */ lpfc_stop_timer(phba); - phba->work_hba_events = 0; - phba->work_ha = 0; lpfc_printf_log(phba, KERN_WARNING, @@ -1389,6 +1387,8 @@ lpfc_offline(struct lpfc_hba * phba) lpfc_sli_hba_down(phba); lpfc_cleanup(phba); spin_lock_irqsave(phba->host->host_lock, iflag); + phba->work_hba_events = 0; + phba->work_ha = 0; phba->fc_flag |= FC_OFFLINE_MODE; spin_unlock_irqrestore(phba->host->host_lock, iflag); } diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 5595c61..789a12d 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1019,9 +1019,36 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_hba * phba, uint32_t evt) { struct lpfc_iocbq *cmdiocb; + LPFC_MBOXQ_t *mb; + LPFC_MBOXQ_t *nextmb; + struct lpfc_dmabuf *mp; cmdiocb = (struct lpfc_iocbq *) arg; + /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ + if ((mb = phba->sli.mbox_active)) { + if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) && + (ndlp == (struct lpfc_nodelist *) mb->context2)) { + mb->context2 = NULL; + mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + } + } + + spin_lock_irq(phba->host->host_lock); + list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { + if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) && + (ndlp == (struct lpfc_nodelist *) mb->context2)) { + mp = (struct lpfc_dmabuf *) (mb->context1); + if (mp) { + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + } + list_del(&mb->list); + mempool_free(mb, phba->mbox_mem_pool); + } + } + spin_unlock_irq(phba->host->host_lock); + lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO); return ndlp->nlp_state; } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 28dbd6b..efd1cf6 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -292,13 +292,13 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb) } static void -lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd) +lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb) { struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd; struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp; struct lpfc_hba *phba = lpfc_cmd->scsi_hba; - uint32_t fcpi_parm = lpfc_cmd->cur_iocbq.iocb.un.fcpi.fcpi_parm; + uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm; uint32_t resp_info = fcprsp->rspStatus2; uint32_t scsi_status = fcprsp->rspStatus3; uint32_t *lp; @@ -360,6 +360,24 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd) fcpi_parm, cmnd->cmnd[0], cmnd->underflow); /* + * If there is an under run check if under run reported by + * storage array is same as the under run reported by HBA. + * If this is not same, there is a dropped frame. + */ + if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) && + fcpi_parm && + (cmnd->resid != fcpi_parm)) { + lpfc_printf_log(phba, KERN_WARNING, + LOG_FCP | LOG_FCP_ERROR, + "%d:0735 FCP Read Check Error and Underrun " + "Data: x%x x%x x%x x%x\n", phba->brd_no, + be32_to_cpu(fcpcmd->fcpDl), + cmnd->resid, + fcpi_parm, cmnd->cmnd[0]); + cmnd->resid = cmnd->request_bufflen; + host_status = DID_ERROR; + } + /* * The cmnd->underflow is the minimum number of bytes that must * be transfered for this command. Provided a sense condition * is not present, make sure the actual amount transferred is at @@ -439,7 +457,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, switch (lpfc_cmd->status) { case IOSTAT_FCP_RSP_ERROR: /* Call FCP RSP handler to determine result */ - lpfc_handle_fcp_err(lpfc_cmd); + lpfc_handle_fcp_err(lpfc_cmd,pIocbOut); break; case IOSTAT_NPORT_BSY: case IOSTAT_FABRIC_BSY: @@ -673,6 +691,18 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, return (1); } +static void +lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocbq, + struct lpfc_iocbq *rspiocbq) +{ + struct lpfc_scsi_buf *lpfc_cmd = + (struct lpfc_scsi_buf *) cmdiocbq->context1; + if (lpfc_cmd) + lpfc_release_scsi_buf(phba, lpfc_cmd); + return; +} + static int lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba, unsigned tgt_id, unsigned int lun, @@ -709,8 +739,9 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba, &phba->sli.ring[phba->sli.fcp_ring], iocbq, iocbqrsp, lpfc_cmd->timeout); if (ret != IOCB_SUCCESS) { + if (ret == IOCB_TIMEDOUT) + iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; lpfc_cmd->status = IOSTAT_DRIVER_REJECT; - ret = FAILED; } else { ret = SUCCESS; lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4]; @@ -977,7 +1008,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) } static int -lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) +lpfc_device_reset_handler(struct scsi_cmnd *cmnd) { struct Scsi_Host *shost = cmnd->device->host; struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; @@ -987,6 +1018,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) struct lpfc_nodelist *pnode = rdata->pnode; uint32_t cmd_result = 0, cmd_status = 0; int ret = FAILED; + int iocb_status = IOCB_SUCCESS; int cnt, loopcnt; lpfc_block_error_handler(cmnd); @@ -998,7 +1030,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) */ while ( 1 ) { if (!pnode) - return FAILED; + goto out; if (pnode->nlp_state != NLP_STE_MAPPED_NODE) { spin_unlock_irq(phba->host->host_lock); @@ -1016,7 +1048,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) } pnode = rdata->pnode; if (!pnode) - return FAILED; + goto out; } if (pnode->nlp_state == NLP_STE_MAPPED_NODE) break; @@ -1031,7 +1063,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) lpfc_cmd->rdata = rdata; ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun, - FCP_LUN_RESET); + FCP_TARGET_RESET); if (!ret) goto out_free_scsi_buf; @@ -1043,16 +1075,21 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) goto out_free_scsi_buf; lpfc_printf_log(phba, KERN_INFO, LOG_FCP, - "%d:0703 Issue LUN Reset to TGT %d LUN %d " - "Data: x%x x%x\n", phba->brd_no, cmnd->device->id, + "%d:0703 Issue target reset to TGT %d LUN %d rpi x%x " + "nlp_flag x%x\n", phba->brd_no, cmnd->device->id, cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); - ret = lpfc_sli_issue_iocb_wait(phba, + iocb_status = lpfc_sli_issue_iocb_wait(phba, &phba->sli.ring[phba->sli.fcp_ring], iocbq, iocbqrsp, lpfc_cmd->timeout); - if (ret == IOCB_SUCCESS) - ret = SUCCESS; + if (iocb_status == IOCB_TIMEDOUT) + iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; + + if (iocb_status == IOCB_SUCCESS) + ret = SUCCESS; + else + ret = iocb_status; cmd_result = iocbqrsp->iocb.un.ulpWord[4]; cmd_status = iocbqrsp->iocb.ulpStatus; @@ -1090,18 +1127,19 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) if (cnt) { lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "%d:0719 LUN Reset I/O flush failure: cnt x%x\n", + "%d:0719 device reset I/O flush failure: cnt x%x\n", phba->brd_no, cnt); ret = FAILED; } out_free_scsi_buf: - lpfc_release_scsi_buf(phba, lpfc_cmd); - + if (iocb_status != IOCB_TIMEDOUT) { + lpfc_release_scsi_buf(phba, lpfc_cmd); + } lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "%d:0713 SCSI layer issued LUN reset (%d, %d) " - "Data: x%x x%x x%x\n", - phba->brd_no, cmnd->device->id,cmnd->device->lun, + "%d:0713 SCSI layer issued device reset (%d, %d) " + "return x%x status x%x result x%x\n", + phba->brd_no, cmnd->device->id, cmnd->device->lun, ret, cmd_status, cmd_result); out: @@ -1110,7 +1148,7 @@ out: } static int -lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) +lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) { struct Scsi_Host *shost = cmnd->device->host; struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; @@ -1155,13 +1193,17 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) "%d:0700 Bus Reset on target %d failed\n", phba->brd_no, i); err_count++; + break; } } + if (ret != IOCB_TIMEDOUT) + lpfc_release_scsi_buf(phba, lpfc_cmd); + if (err_count == 0) ret = SUCCESS; - - lpfc_release_scsi_buf(phba, lpfc_cmd); + else + ret = FAILED; /* * All outstanding txcmplq I/Os should have been aborted by @@ -1302,8 +1344,8 @@ struct scsi_host_template lpfc_template = { .info = lpfc_info, .queuecommand = lpfc_queuecommand, .eh_abort_handler = lpfc_abort_handler, - .eh_device_reset_handler= lpfc_reset_lun_handler, - .eh_bus_reset_handler = lpfc_reset_bus_handler, + .eh_device_reset_handler= lpfc_device_reset_handler, + .eh_bus_reset_handler = lpfc_bus_reset_handler, .slave_alloc = lpfc_slave_alloc, .slave_configure = lpfc_slave_configure, .slave_destroy = lpfc_slave_destroy, diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 1682524..dba94c6 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -528,6 +528,7 @@ lpfc_sli_wake_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) * If pdone_q is empty, the driver thread gave up waiting and * continued running. */ + pmboxq->mbox_flag |= LPFC_MBX_WAKE; pdone_q = (wait_queue_head_t *) pmboxq->context1; if (pdone_q) wake_up_interruptible(pdone_q); @@ -538,11 +539,32 @@ void lpfc_sli_def_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) { struct lpfc_dmabuf *mp; + uint16_t rpi; + int rc; + mp = (struct lpfc_dmabuf *) (pmb->context1); + if (mp) { lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); } + + /* + * If a REG_LOGIN succeeded after node is destroyed or node + * is in re-discovery driver need to cleanup the RPI. + */ + if (!(phba->fc_flag & FC_UNLOADING) && + (pmb->mb.mbxCommand == MBX_REG_LOGIN64) && + (!pmb->mb.mbxStatus)) { + + rpi = pmb->mb.un.varWords[0]; + lpfc_unreg_login(phba, rpi, pmb); + pmb->mbox_cmpl=lpfc_sli_def_mbox_cmpl; + rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + if (rc != MBX_NOT_FINISHED) + return; + } + mempool_free( pmb, phba->mbox_mem_pool); return; } @@ -2862,9 +2884,11 @@ void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb) { - spin_lock_irq(phba->host->host_lock); + unsigned long iflags; + + spin_lock_irqsave(phba->host->host_lock, iflags); lpfc_sli_release_iocbq(phba, cmdiocb); - spin_unlock_irq(phba->host->host_lock); + spin_unlock_irqrestore(phba->host->host_lock, iflags); return; } @@ -2987,22 +3011,22 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba, timeout_req); spin_lock_irq(phba->host->host_lock); - if (timeleft == 0) { + if (piocb->iocb_flag & LPFC_IO_WAKE) { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "%d:0331 IOCB wake signaled\n", + phba->brd_no); + } else if (timeleft == 0) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "%d:0338 IOCB wait timeout error - no " "wake response Data x%x\n", phba->brd_no, timeout); retval = IOCB_TIMEDOUT; - } else if (!(piocb->iocb_flag & LPFC_IO_WAKE)) { + } else { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "%d:0330 IOCB wake NOT set, " "Data x%x x%lx\n", phba->brd_no, timeout, (timeleft / jiffies)); retval = IOCB_TIMEDOUT; - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "%d:0331 IOCB wake signaled\n", - phba->brd_no); } } else { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, @@ -3031,8 +3055,6 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq, uint32_t timeout) { DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q); - DECLARE_WAITQUEUE(wq_entry, current); - uint32_t timeleft = 0; int retval; /* The caller must leave context1 empty. */ @@ -3045,27 +3067,25 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq, /* setup context field to pass wait_queue pointer to wake function */ pmboxq->context1 = &done_q; - /* start to sleep before we wait, to avoid races */ - set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&done_q, &wq_entry); - /* now issue the command */ retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); if (retval == MBX_BUSY || retval == MBX_SUCCESS) { - timeleft = schedule_timeout(timeout * HZ); + wait_event_interruptible_timeout(done_q, + pmboxq->mbox_flag & LPFC_MBX_WAKE, + timeout * HZ); + pmboxq->context1 = NULL; - /* if schedule_timeout returns 0, we timed out and were not - woken up */ - if ((timeleft == 0) || signal_pending(current)) - retval = MBX_TIMEOUT; - else + /* + * if LPFC_MBX_WAKE flag is set the mailbox is completed + * else do not free the resources. + */ + if (pmboxq->mbox_flag & LPFC_MBX_WAKE) retval = MBX_SUCCESS; + else + retval = MBX_TIMEOUT; } - - set_current_state(TASK_RUNNING); - remove_wait_queue(&done_q, &wq_entry); return retval; } diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 10dd5a9..eb6a689 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -68,6 +68,8 @@ struct lpfc_iocbq { #define IOCB_ERROR 2 #define IOCB_TIMEDOUT 3 +#define LPFC_MBX_WAKE 1 + typedef struct lpfcMboxq { /* MBOXQs are used in single linked lists */ struct list_head list; /* ptr to next mailbox command */ @@ -76,6 +78,7 @@ typedef struct lpfcMboxq { void *context2; /* caller context information */ void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *); + uint8_t mbox_flag; } LPFC_MBOXQ_t; -- cgit v0.10.2 From 82085718faa6955c8a78b2e6ac2ad95072ac875a Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:52:41 -0400 Subject: [SCSI] lpfc 8.1.12 : Fixed recovery of rport after race with dev_loss_tmo Fixed recovery of rport after race with dev_loss_tmo Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index fda8f07..5f8698b 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -109,6 +109,9 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) return; } + if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) + return; + name = (uint8_t *)&ndlp->nlp_portname; phba = ndlp->nlp_phba; @@ -149,7 +152,8 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) if (!(phba->fc_flag & FC_UNLOADING) && !(ndlp->nlp_flag & NLP_DELAY_TMO) && - !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) + !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && + (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM); else { rdata->pnode = NULL; @@ -1326,8 +1330,6 @@ lpfc_nlp_state_cleanup(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, * already. If we have, and it's a scsi entity, be * sure to unblock any attached scsi devices */ - if (!ndlp->rport || - ndlp->rport->port_state == FC_PORTSTATE_BLOCKED) lpfc_register_remote_port(phba, ndlp); } -- cgit v0.10.2 From 5b8bd0c9be706677327c01df28bf6b54de008f34 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:52:49 -0400 Subject: [SCSI] lpfc 8.1.12 : Improve diagnostic messages and change local loopback message to KERN_INFO Improve diagnostic messages and change local loopback message to KERN_INFO Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index b7193d1..da8b6bb 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -247,6 +247,9 @@ struct lpfc_hba { #define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */ #define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */ #define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */ +#define FC_LOOPBACK_MODE 0x40000 /* NPort is in Loopback mode */ + /* This flag is set while issuing */ + /* INIT_LINK mailbox command */ uint32_t fc_topology; /* link topology, from LINK INIT */ @@ -388,6 +391,13 @@ struct lpfc_hba { struct fc_host_statistics link_stats; }; +static inline void +lpfc_set_loopback_flag(struct lpfc_hba *phba) { + if (phba->cfg_topology == FLAGS_LOCAL_LB) + phba->fc_flag |= FC_LOOPBACK_MODE; + else + phba->fc_flag &= ~FC_LOOPBACK_MODE; +} struct rnidrsp { void *buf; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 7811aaf..df9847e 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -237,6 +237,7 @@ lpfc_issue_lip(struct Scsi_Host *host) phba->fc_ratov * 2); } + lpfc_set_loopback_flag(phba); if (mbxstatus == MBX_TIMEOUT) pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; else diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 4d9e7f5..8f98c5b 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2046,10 +2046,9 @@ lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError, /* Xmit ELS RJT response tag */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "%d:0129 Xmit ELS RJT x%x response tag x%x " - "Data: x%x x%x x%x x%x x%x\n", - phba->brd_no, - rejectError, elsiocb->iocb.ulpIoTag, + "%d:0129 Xmit ELS RJT x%x response tag x%x xri x%x, " + "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", + phba->brd_no, rejectError, elsiocb->iotag, elsiocb->iocb.ulpContext, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); @@ -2088,18 +2087,18 @@ lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba, if (!elsiocb) return 1; + icmd = &elsiocb->iocb; + oldcmd = &oldiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri */ + /* Xmit ADISC ACC response tag */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "%d:0130 Xmit ADISC ACC response tag x%x " - "Data: x%x x%x x%x x%x x%x\n", - phba->brd_no, - elsiocb->iocb.ulpIoTag, + "%d:0130 Xmit ADISC ACC response iotag x%x xri: " + "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n", + phba->brd_no, elsiocb->iotag, elsiocb->iocb.ulpContext, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - icmd = &elsiocb->iocb; - oldcmd = &oldiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri */ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_ACC; @@ -2124,8 +2123,8 @@ lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba, } int -lpfc_els_rsp_prli_acc(struct lpfc_hba * phba, - struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp) +lpfc_els_rsp_prli_acc(struct lpfc_hba *phba, struct lpfc_iocbq *oldiocb, + struct lpfc_nodelist *ndlp) { PRLI *npr; lpfc_vpd_t *vpd; @@ -2147,18 +2146,18 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba * phba, if (!elsiocb) return 1; + icmd = &elsiocb->iocb; + oldcmd = &oldiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri */ + /* Xmit PRLI ACC response tag */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "%d:0131 Xmit PRLI ACC response tag x%x " - "Data: x%x x%x x%x x%x x%x\n", - phba->brd_no, - elsiocb->iocb.ulpIoTag, + "%d:0131 Xmit PRLI ACC response tag x%x xri x%x, " + "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", + phba->brd_no, elsiocb->iotag, elsiocb->iocb.ulpContext, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - icmd = &elsiocb->iocb; - oldcmd = &oldiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri */ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)); @@ -2228,17 +2227,17 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba, if (!elsiocb) return 1; + icmd = &elsiocb->iocb; + oldcmd = &oldiocb->iocb; + icmd->ulpContext = oldcmd->ulpContext; /* Xri */ + /* Xmit RNID ACC response tag */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0132 Xmit RNID ACC response tag x%x " - "Data: x%x\n", - phba->brd_no, - elsiocb->iocb.ulpIoTag, + "xri x%x\n", + phba->brd_no, elsiocb->iotag, elsiocb->iocb.ulpContext); - icmd = &elsiocb->iocb; - oldcmd = &oldiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri */ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_ACC; @@ -2701,6 +2700,7 @@ lpfc_els_rcv_flogi(struct lpfc_hba * phba, mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; rc = lpfc_sli_issue_mbox (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + lpfc_set_loopback_flag(phba); if (rc == MBX_NOT_FINISHED) { mempool_free( mbox, phba->mbox_mem_pool); } @@ -2842,10 +2842,9 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) /* Xmit ELS RPS ACC response tag */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "%d:0118 Xmit ELS RPS ACC response tag x%x " - "Data: x%x x%x x%x x%x x%x\n", - phba->brd_no, - elsiocb->iocb.ulpIoTag, + "%d:0118 Xmit ELS RPS ACC response tag x%x xri x%x, " + "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", + phba->brd_no, elsiocb->iotag, elsiocb->iocb.ulpContext, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); @@ -2951,10 +2950,9 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize, /* Xmit ELS RPL ACC response tag */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "%d:0120 Xmit ELS RPL ACC response tag x%x " - "Data: x%x x%x x%x x%x x%x\n", - phba->brd_no, - elsiocb->iocb.ulpIoTag, + "%d:0120 Xmit ELS RPL ACC response tag x%x xri x%x, " + "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", + phba->brd_no, elsiocb->iotag, elsiocb->iocb.ulpContext, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 5f8698b..164af8a 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -900,12 +900,21 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) if (la->attType == AT_LINK_UP) { phba->fc_stat.LinkUp++; - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, + if (phba->fc_flag & FC_LOOPBACK_MODE) { + lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, + "%d:1306 Link Up Event in loop back mode " + "x%x received Data: x%x x%x x%x x%x\n", + phba->brd_no, la->eventTag, phba->fc_eventTag, + la->granted_AL_PA, la->UlnkSpeed, + phba->alpa_map[0]); + } else { + lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "%d:1303 Link Up Event x%x received " "Data: x%x x%x x%x x%x\n", phba->brd_no, la->eventTag, phba->fc_eventTag, la->granted_AL_PA, la->UlnkSpeed, phba->alpa_map[0]); + } lpfc_mbx_process_link_up(phba, la); } else { phba->fc_stat.LinkDown++; @@ -2251,6 +2260,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0; rc = lpfc_sli_issue_mbox(phba, initlinkmbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + lpfc_set_loopback_flag(phba); if (rc == MBX_NOT_FINISHED) mempool_free(initlinkmbox, phba->mbox_mem_pool); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 6449ac8..4df0a77 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -391,6 +391,7 @@ lpfc_config_port_post(struct lpfc_hba * phba) lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed); pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); + lpfc_set_loopback_flag(phba); if (rc != MBX_SUCCESS) { lpfc_printf_log(phba, KERN_ERR, diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index dba94c6..fd82797 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2794,6 +2794,12 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba * phba, iabt->ulpCommand = CMD_CLOSE_XRI_CN; abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl; + + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "%d:0339 Abort xri x%x, original iotag x%x, abort " + "cmd iotag x%x\n", + phba->brd_no, iabt->un.acxri.abortContextTag, + iabt->un.acxri.abortIoTag, abtsiocbp->iotag); retval = lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0); abort_iotag_exit: -- cgit v0.10.2 From 2680eeaaa03e83a87ece2724e71f7cc816cd3ef0 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:52:55 -0400 Subject: [SCSI] lpfc 8.1.12 : Improve handling of failed ELS aborts Improve handling of failed ELS aborts. Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 8f98c5b..14d204b 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -182,6 +182,7 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp, icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64)); icmd->un.elsreq64.remoteID = did; /* DID */ icmd->ulpCommand = CMD_ELS_REQUEST64_CR; + icmd->ulpTimeout = phba->fc_ratov * 2; } else { icmd->un.elsreq64.bdl.bdeSize = sizeof (struct ulp_bde64); icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index fd82797..645291e 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2403,7 +2403,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (unlikely(phba->hba_state == LPFC_LINK_DOWN)) { /* - * Only CREATE_XRI, CLOSE_XRI, ABORT_XRI, and QUE_RING_BUF + * Only CREATE_XRI, CLOSE_XRI, and QUE_RING_BUF * can be issued if the link is not up. */ switch (piocb->iocb.ulpCommand) { @@ -2417,6 +2417,8 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, piocb->iocb_cmpl = NULL; /*FALLTHROUGH*/ case CMD_CREATE_XRI_CR: + case CMD_CLOSE_XRI_CN: + case CMD_CLOSE_XRI_CX: break; default: goto iocb_busy; @@ -2741,7 +2743,58 @@ static void lpfc_sli_abort_els_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb) { + IOCB_t *irsp; + uint16_t abort_iotag, abort_context; + struct lpfc_iocbq *abort_iocb, *rsp_ab_iocb; + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; + + abort_iocb = NULL; + irsp = &rspiocb->iocb; + spin_lock_irq(phba->host->host_lock); + + if (irsp->ulpStatus) { + abort_context = cmdiocb->iocb.un.acxri.abortContextTag; + abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag; + + if (abort_iotag != 0 && abort_iotag <= phba->sli.last_iotag) + abort_iocb = phba->sli.iocbq_lookup[abort_iotag]; + + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "%d:0327 Cannot abort els iocb %p" + " with tag %x context %x\n", + phba->brd_no, abort_iocb, + abort_iotag, abort_context); + + /* + * make sure we have the right iocbq before taking it + * off the txcmplq and try to call completion routine. + */ + if (abort_iocb && + abort_iocb->iocb.ulpContext == abort_context && + abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) { + list_del(&abort_iocb->list); + pring->txcmplq_cnt--; + + rsp_ab_iocb = lpfc_sli_get_iocbq(phba); + if (rsp_ab_iocb == NULL) + lpfc_sli_release_iocbq(phba, abort_iocb); + else { + abort_iocb->iocb_flag &= + ~LPFC_DRIVER_ABORTED; + rsp_ab_iocb->iocb.ulpStatus = + IOSTAT_LOCAL_REJECT; + rsp_ab_iocb->iocb.un.ulpWord[4] = + IOERR_SLI_ABORTED; + spin_unlock_irq(phba->host->host_lock); + (abort_iocb->iocb_cmpl) + (phba, abort_iocb, rsp_ab_iocb); + spin_lock_irq(phba->host->host_lock); + lpfc_sli_release_iocbq(phba, rsp_ab_iocb); + } + } + } + lpfc_sli_release_iocbq(phba, cmdiocb); spin_unlock_irq(phba->host->host_lock); return; -- cgit v0.10.2 From 329f9bc735b4665d42267259b1612191f72c4d42 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:53:01 -0400 Subject: [SCSI] lpfc 8.1.12 : Reference count node structures for node lifetime management Reference count node structures for node lifetime management. Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index b80ddb8..f61d46f 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -51,8 +51,9 @@ int lpfc_can_disctmo(struct lpfc_hba *); int lpfc_unreg_rpi(struct lpfc_hba *, struct lpfc_nodelist *); int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *, struct lpfc_nodelist *); -int lpfc_nlp_remove(struct lpfc_hba *, struct lpfc_nodelist *); void lpfc_nlp_init(struct lpfc_hba *, struct lpfc_nodelist *, uint32_t); +struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *); +int lpfc_nlp_put(struct lpfc_nodelist *); struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_hba *, uint32_t); void lpfc_disc_list_loopmap(struct lpfc_hba *); void lpfc_disc_start(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 30b2ba0..4561327 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -69,7 +69,6 @@ struct lpfc_nodelist { uint16_t nlp_maxframe; /* Max RCV frame size */ uint8_t nlp_class_sup; /* Supported Classes */ uint8_t nlp_retry; /* used for ELS retries */ - uint8_t nlp_disc_refcnt; /* used for DSM */ uint8_t nlp_fcp_info; /* class info, bits 0-3 */ #define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */ @@ -80,6 +79,7 @@ struct lpfc_nodelist { struct lpfc_work_evt els_retry_evt; unsigned long last_ramp_up_time; /* jiffy of last ramp up */ unsigned long last_q_full_time; /* jiffy of last queue full */ + struct kref kref; }; /* Defines for nlp_flag (uint32) */ @@ -107,7 +107,6 @@ struct lpfc_nodelist { ACC */ #define NLP_NPR_ADISC 0x2000000 /* Issue ADISC when dq'ed from NPR list */ -#define NLP_DELAY_REMOVE 0x4000000 /* Defer removal till end of DSM */ #define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */ /* Defines for list searchs */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 14d204b..cb63c35 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -209,9 +209,9 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp, } /* Save for completion so we can release these resources */ - elsiocb->context1 = (uint8_t *) ndlp; - elsiocb->context2 = (uint8_t *) pcmd; - elsiocb->context3 = (uint8_t *) pbuflist; + elsiocb->context1 = lpfc_nlp_get(ndlp); + elsiocb->context2 = pcmd; + elsiocb->context3 = pbuflist; elsiocb->retry = retry; elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT; @@ -305,7 +305,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, goto fail_free_mbox; mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login; - mbox->context2 = ndlp; + mbox->context2 = lpfc_nlp_get(ndlp); rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB); if (rc == MBX_NOT_FINISHED) @@ -314,6 +314,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, return 0; fail_issue_reg_login: + lpfc_nlp_put(ndlp); mp = (struct lpfc_dmabuf *) mbox->context1; lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); @@ -369,7 +370,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, mempool_free(mbox, phba->mbox_mem_pool); goto fail; } - mempool_free(ndlp, phba->nlp_mem_pool); + lpfc_nlp_put(ndlp); ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, PT2PT_RemoteID); if (!ndlp) { @@ -392,7 +393,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, ndlp->nlp_flag |= NLP_NPR_2B_DISC; } else { /* This side will wait for the PLOGI */ - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_put(ndlp); } spin_lock_irq(phba->host->host_lock); @@ -407,8 +408,8 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, } static void -lpfc_cmpl_els_flogi(struct lpfc_hba * phba, - struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb) +lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) { IOCB_t *irsp = &rspiocb->iocb; struct lpfc_nodelist *ndlp = cmdiocb->context1; @@ -418,7 +419,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba, /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(phba)) { - lpfc_nlp_remove(phba, ndlp); + lpfc_nlp_put(ndlp); goto out; } @@ -433,13 +434,12 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba, phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); spin_unlock_irq(phba->host->host_lock); - /* If private loop, then allow max outstandting els to be + /* If private loop, then allow max outstanding els to be * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no * alpa map would take too long otherwise. */ if (phba->alpa_map[0] == 0) { - phba->cfg_discovery_threads = - LPFC_MAX_DISC_THREADS; + phba->cfg_discovery_threads = LPFC_MAX_DISC_THREADS; } /* FLOGI failure */ @@ -484,7 +484,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba, } flogifail: - lpfc_nlp_remove(phba, ndlp); + lpfc_nlp_put(ndlp); if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT || (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED && @@ -608,7 +608,7 @@ lpfc_initial_flogi(struct lpfc_hba * phba) lpfc_dequeue_node(phba, ndlp); } if (lpfc_issue_els_flogi(phba, ndlp, 0)) { - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_put(ndlp); } return 1; } @@ -1334,7 +1334,7 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry) elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_SCR); if (!elsiocb) { - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_put(ndlp); return 1; } @@ -1353,12 +1353,12 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry) spin_lock_irq(phba->host->host_lock); if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { spin_unlock_irq(phba->host->host_lock); - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_put(ndlp); lpfc_els_free_iocb(phba, elsiocb); return 1; } spin_unlock_irq(phba->host->host_lock); - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_put(ndlp); return 0; } @@ -1387,7 +1387,7 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry) elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_RNID); if (!elsiocb) { - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_put(ndlp); return 1; } @@ -1420,12 +1420,12 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry) spin_lock_irq(phba->host->host_lock); if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { spin_unlock_irq(phba->host->host_lock); - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_put(ndlp); lpfc_els_free_iocb(phba, elsiocb); return 1; } spin_unlock_irq(phba->host->host_lock); - mempool_free( ndlp, phba->nlp_mem_pool); + lpfc_nlp_put(ndlp); return 0; } @@ -1590,7 +1590,7 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, cmd = *elscmd++; } - if(ndlp) + if (ndlp) did = ndlp->nlp_DID; else { /* We should only hit this case for retrying PLOGI */ @@ -1768,10 +1768,14 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, } int -lpfc_els_free_iocb(struct lpfc_hba * phba, struct lpfc_iocbq * elsiocb) +lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) { struct lpfc_dmabuf *buf_ptr, *buf_ptr1; + if (elsiocb->context1) { + lpfc_nlp_put(elsiocb->context1); + elsiocb->context1 = NULL; + } /* context2 = cmd, context2->next = rsp, context3 = bpl */ if (elsiocb->context2) { buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; @@ -1828,8 +1832,8 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, } static void -lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, - struct lpfc_iocbq * rspiocb) +lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) { IOCB_t *irsp; struct lpfc_nodelist *ndlp; @@ -1844,14 +1848,14 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, /* Check to see if link went down during discovery */ - if ((lpfc_els_chk_latt(phba)) || !ndlp) { + if (lpfc_els_chk_latt(phba) || !ndlp) { if (mbox) { mp = (struct lpfc_dmabuf *) mbox->context1; if (mp) { lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); } - mempool_free( mbox, phba->mbox_mem_pool); + mempool_free(mbox, phba->mbox_mem_pool); } goto out; } @@ -1871,7 +1875,7 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { lpfc_unreg_rpi(phba, ndlp); mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; - mbox->context2 = ndlp; + mbox->context2 = lpfc_nlp_get(ndlp); ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE); if (lpfc_sli_issue_mbox(phba, mbox, @@ -1879,6 +1883,7 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, != MBX_NOT_FINISHED) { goto out; } + lpfc_nlp_put(ndlp); /* NOTE: we should have messages for unsuccessful reglogin */ } else { @@ -1983,8 +1988,10 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag, return 1; } - if (newnode) + if (newnode) { + lpfc_nlp_put(ndlp); elsiocb->context1 = NULL; + } /* Xmit ELS ACC response tag */ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, @@ -2201,9 +2208,8 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba *phba, struct lpfc_iocbq *oldiocb, } static int -lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba, - uint8_t format, - struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp) +lpfc_els_rsp_rnid_acc(struct lpfc_hba *phba, uint8_t format, + struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp) { RNID *rn; IOCB_t *icmd; @@ -2270,6 +2276,7 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba, phba->fc_stat.elsXmitACC++; elsiocb->iocb_cmpl = lpfc_cmpl_els_acc; + lpfc_nlp_put(ndlp); elsiocb->context1 = NULL; /* Don't need ndlp for cmpl, * it could be freed */ @@ -2447,7 +2454,7 @@ lpfc_rscn_payload_check(struct lpfc_hba * phba, uint32_t did) } static int -lpfc_rscn_recovery_check(struct lpfc_hba * phba) +lpfc_rscn_recovery_check(struct lpfc_hba *phba) { struct lpfc_nodelist *ndlp = NULL, *next_ndlp; struct list_head *listp; @@ -2703,7 +2710,7 @@ lpfc_els_rcv_flogi(struct lpfc_hba * phba, (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); lpfc_set_loopback_flag(phba); if (rc == MBX_NOT_FINISHED) { - mempool_free( mbox, phba->mbox_mem_pool); + mempool_free(mbox, phba->mbox_mem_pool); } return 1; } else if (rc > 0) { /* greater than */ @@ -2768,8 +2775,8 @@ lpfc_els_rcv_rnid(struct lpfc_hba * phba, } static int -lpfc_els_rcv_lirr(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, - struct lpfc_nodelist * ndlp) +lpfc_els_rcv_lirr(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) { struct ls_rjt stat; @@ -2783,7 +2790,7 @@ lpfc_els_rcv_lirr(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, } static void -lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) +lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_sli *psli; struct lpfc_sli_ring *pring; @@ -2806,14 +2813,15 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) pmb->context2 = NULL; if (mb->mbxStatus) { - mempool_free( pmb, phba->mbox_mem_pool); + mempool_free(pmb, phba->mbox_mem_pool); return; } cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t); - mempool_free( pmb, phba->mbox_mem_pool); + mempool_free(pmb, phba->mbox_mem_pool); elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, lpfc_max_els_tries, ndlp, ndlp->nlp_DID, ELS_CMD_ACC); + lpfc_nlp_put(ndlp); if (!elsiocb) return; @@ -2890,13 +2898,14 @@ lpfc_els_rcv_rps(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, lpfc_read_lnk_stat(phba, mbox); mbox->context1 = (void *)((unsigned long)cmdiocb->iocb.ulpContext); - mbox->context2 = ndlp; + mbox->context2 = lpfc_nlp_get(ndlp); mbox->mbox_cmpl = lpfc_els_rsp_rps_acc; if (lpfc_sli_issue_mbox (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) { /* Mbox completion will send ELS Response */ return 0; } + lpfc_nlp_put(ndlp); mempool_free(mbox, phba->mbox_mem_pool); } } @@ -3281,14 +3290,13 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) } void -lpfc_els_flush_cmd(struct lpfc_hba * phba) +lpfc_els_flush_cmd(struct lpfc_hba *phba) { LIST_HEAD(completions); - struct lpfc_sli_ring *pring; + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; struct lpfc_iocbq *tmp_iocb, *piocb; IOCB_t *cmd = NULL; - pring = &phba->sli.ring[LPFC_ELS_RING]; spin_lock_irq(phba->host->host_lock); list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) { cmd = &piocb->iocb; @@ -3298,12 +3306,11 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba) } /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */ - if ((cmd->ulpCommand == CMD_QUE_RING_BUF_CN) || - (cmd->ulpCommand == CMD_QUE_RING_BUF64_CN) || - (cmd->ulpCommand == CMD_CLOSE_XRI_CN) || - (cmd->ulpCommand == CMD_ABORT_XRI_CN)) { + if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN || + cmd->ulpCommand == CMD_QUE_RING_BUF64_CN || + cmd->ulpCommand == CMD_CLOSE_XRI_CN || + cmd->ulpCommand == CMD_ABORT_XRI_CN) continue; - } list_move_tail(&piocb->list, &completions); pring->txq_cnt--; @@ -3422,7 +3429,9 @@ lpfc_els_unsol_event(struct lpfc_hba * phba, } phba->fc_stat.elsRcvFrame++; - elsiocb->context1 = ndlp; + if (elsiocb->context1) + lpfc_nlp_put(elsiocb->context1); + elsiocb->context1 = lpfc_nlp_get(ndlp); elsiocb->context2 = mp; if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) { @@ -3553,6 +3562,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba, lpfc_els_rsp_reject(phba, stat.un.lsRjtError, elsiocb, ndlp); } + lpfc_nlp_put(elsiocb->context1); + elsiocb->context1 = NULL; if (elsiocb->context2) { lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 164af8a..8ba2f4e 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -158,6 +158,8 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) else { rdata->pnode = NULL; ndlp->rport = NULL; + lpfc_nlp_put(ndlp); + put_device(&rport->dev); } return; @@ -960,6 +962,7 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free( pmb, phba->mbox_mem_pool); + lpfc_nlp_put(ndlp); return; } @@ -986,11 +989,14 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) ndlp = (struct lpfc_nodelist *) pmb->context2; mp = (struct lpfc_dmabuf *) (pmb->context1); + pmb->context1 = NULL; + pmb->context2 = NULL; + if (mb->mbxStatus) { lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - mempool_free( pmb, phba->mbox_mem_pool); - mempool_free( ndlp, phba->nlp_mem_pool); + mempool_free(pmb, phba->mbox_mem_pool); + lpfc_nlp_put(ndlp); /* FLOGI failed, so just use loop map to make discovery list */ lpfc_disc_list_loopmap(phba); @@ -1000,12 +1006,12 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) return; } - pmb->context1 = NULL; - ndlp->nlp_rpi = mb->un.varWords[0]; ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); + lpfc_nlp_put(ndlp); /* Drop the reference from the mbox */ + if (phba->hba_state == LPFC_FABRIC_CFG_LINK) { /* This NPort has been assigned an NPort_ID by the fabric as a * result of the completed fabric login. Issue a State Change @@ -1027,7 +1033,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) lpfc_disc_start(phba); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - mempool_free( pmb, phba->mbox_mem_pool); + mempool_free(pmb, phba->mbox_mem_pool); return; } else { lpfc_nlp_init(phba, ndlp, NameServer_DID); @@ -1050,7 +1056,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - mempool_free( pmb, phba->mbox_mem_pool); + mempool_free(pmb, phba->mbox_mem_pool); return; } @@ -1075,6 +1081,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) mp = (struct lpfc_dmabuf *) (pmb->context1); if (mb->mbxStatus) { + lpfc_nlp_put(ndlp); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); @@ -1110,6 +1117,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) lpfc_disc_start(phba); } + lpfc_nlp_put(ndlp); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free( pmb, phba->mbox_mem_pool); @@ -1118,8 +1126,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) } static void -lpfc_register_remote_port(struct lpfc_hba * phba, - struct lpfc_nodelist * ndlp) +lpfc_register_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) { struct fc_rport *rport; struct lpfc_rport_data *rdata; @@ -1131,8 +1138,19 @@ lpfc_register_remote_port(struct lpfc_hba * phba, rport_ids.port_id = ndlp->nlp_DID; rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; + /* + * We leave our node pointer in rport->dd_data when we unregister a + * FCP target port. But fc_remote_port_add zeros the space to which + * rport->dd_data points. So, if we're reusing a previously + * registered port, drop the reference that we took the last time we + * registered the port. + */ + if (ndlp->rport && ndlp->rport->dd_data && + *(struct lpfc_rport_data **) ndlp->rport->dd_data) { + lpfc_nlp_put(ndlp); + } ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids); - if (!rport) { + if (!rport || !get_device(&rport->dev)) { dev_printk(KERN_WARNING, &phba->pcidev->dev, "Warning: fc_remote_port_add failed\n"); return; @@ -1142,7 +1160,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba, rport->maxframe_size = ndlp->nlp_maxframe; rport->supported_classes = ndlp->nlp_class_sup; rdata = rport->dd_data; - rdata->pnode = ndlp; + rdata->pnode = lpfc_nlp_get(ndlp); if (ndlp->nlp_type & NLP_FCP_TARGET) rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; @@ -1162,8 +1180,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba, } static void -lpfc_unregister_remote_port(struct lpfc_hba * phba, - struct lpfc_nodelist * ndlp) +lpfc_unregister_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) { struct fc_rport *rport = ndlp->rport; struct lpfc_rport_data *rdata = rport->dd_data; @@ -1171,6 +1188,8 @@ lpfc_unregister_remote_port(struct lpfc_hba * phba, if (rport->scsi_target_id == -1) { ndlp->rport = NULL; rdata->pnode = NULL; + lpfc_nlp_put(ndlp); + put_device(&rport->dev); } fc_remote_port_delete(rport); @@ -1416,7 +1435,7 @@ lpfc_drop_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) lpfc_nlp_counters(phba, ndlp->nlp_state, -1); lpfc_delink_node(phba, ndlp); spin_unlock_irq(phba->host->host_lock); - lpfc_nlp_remove(phba, ndlp); + lpfc_nlp_put(ndlp); } /* @@ -1654,6 +1673,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) } list_del(&mb->list); mempool_free(mb, phba->mbox_mem_pool); + lpfc_nlp_put(ndlp); } } spin_unlock_irq(phba->host->host_lock); @@ -1679,8 +1699,8 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) * If we are in the middle of using the nlp in the discovery state * machine, defer the free till we reach the end of the state machine. */ -int -lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) +static void +lpfc_nlp_remove(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) { struct lpfc_rport_data *rdata; @@ -1688,22 +1708,14 @@ lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) lpfc_cancel_retry_delay_tmo(phba, ndlp); } - if (ndlp->nlp_disc_refcnt) { - spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag |= NLP_DELAY_REMOVE; - spin_unlock_irq(phba->host->host_lock); - } else { - lpfc_freenode(phba, ndlp); - - if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) { - rdata = ndlp->rport->dd_data; - rdata->pnode = NULL; - ndlp->rport = NULL; - } + lpfc_freenode(phba, ndlp); - mempool_free( ndlp, phba->nlp_mem_pool); + if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) { + put_device(&ndlp->rport->dev); + rdata = ndlp->rport->dd_data; + rdata->pnode = NULL; + ndlp->rport = NULL; } - return 0; } static int @@ -2069,14 +2081,14 @@ lpfc_disc_flush_list(struct lpfc_hba * phba) list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list, nlp_listp) { lpfc_free_tx(phba, ndlp); - lpfc_nlp_remove(phba, ndlp); + lpfc_nlp_put(ndlp); } } if (phba->fc_adisc_cnt) { list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list, nlp_listp) { lpfc_free_tx(phba, ndlp); - lpfc_nlp_remove(phba, ndlp); + lpfc_nlp_put(ndlp); } } return; @@ -2195,7 +2207,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) /* Next look for NameServer ndlp */ ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID); if (ndlp) - lpfc_nlp_remove(phba, ndlp); + lpfc_nlp_put(ndlp); /* Start discovery */ lpfc_disc_start(phba); break; @@ -2373,9 +2385,11 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60); } + /* Mailbox took a reference to the node */ + lpfc_nlp_put(ndlp); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - mempool_free( pmb, phba->mbox_mem_pool); + mempool_free(pmb, phba->mbox_mem_pool); return; } @@ -2460,8 +2474,7 @@ lpfc_findnode_wwpn(struct lpfc_hba * phba, uint32_t order, } void -lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, - uint32_t did) +lpfc_nlp_init(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did) { memset(ndlp, 0, sizeof (struct lpfc_nodelist)); INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); @@ -2471,5 +2484,29 @@ lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, ndlp->nlp_DID = did; ndlp->nlp_phba = phba; ndlp->nlp_sid = NLP_NO_SID; + kref_init(&ndlp->kref); return; } + +void +lpfc_nlp_release(struct kref *kref) +{ + struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist, + kref); + lpfc_nlp_remove(ndlp->nlp_phba, ndlp); + mempool_free(ndlp, ndlp->nlp_phba->nlp_mem_pool); +} + +struct lpfc_nodelist * +lpfc_nlp_get(struct lpfc_nodelist *ndlp) +{ + if (ndlp) + kref_get(&ndlp->kref); + return ndlp; +} + +int +lpfc_nlp_put(struct lpfc_nodelist *ndlp) +{ + return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0; +} diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 4df0a77..388b92a 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1187,12 +1187,12 @@ lpfc_cleanup(struct lpfc_hba * phba) lpfc_can_disctmo(phba); list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpunmap_list, nlp_listp) { - lpfc_nlp_remove(phba, ndlp); + lpfc_nlp_put(ndlp); } list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpmap_list, nlp_listp) { - lpfc_nlp_remove(phba, ndlp); + lpfc_nlp_put(ndlp); } list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list, @@ -1202,27 +1202,27 @@ lpfc_cleanup(struct lpfc_hba * phba) list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list, nlp_listp) { - lpfc_nlp_remove(phba, ndlp); + lpfc_nlp_put(ndlp); } list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list, nlp_listp) { - lpfc_nlp_remove(phba, ndlp); + lpfc_nlp_put(ndlp); } list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_reglogin_list, nlp_listp) { - lpfc_nlp_remove(phba, ndlp); + lpfc_nlp_put(ndlp); } list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_prli_list, nlp_listp) { - lpfc_nlp_remove(phba, ndlp); + lpfc_nlp_put(ndlp); } list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, nlp_listp) { - lpfc_nlp_remove(phba, ndlp); + lpfc_nlp_put(ndlp); } INIT_LIST_HEAD(&phba->fc_nlpmap_list); @@ -1510,7 +1510,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) INIT_LIST_HEAD(&phba->fc_prli_list); INIT_LIST_HEAD(&phba->fc_npr_list); - pci_set_master(pdev); retval = pci_set_mwi(pdev); if (retval) diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 789a12d..f03284a 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -353,7 +353,10 @@ lpfc_rcv_plogi(struct lpfc_hba * phba, * queue this mbox command to be processed later. */ mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; - mbox->context2 = ndlp; + /* + * mbox->context2 = lpfc_nlp_get(ndlp) deferred until mailbox + * command issued in lpfc_cmpl_els_acc(). + */ ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI); /* @@ -773,13 +776,14 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba, default: mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; } - mbox->context2 = ndlp; + mbox->context2 = lpfc_nlp_get(ndlp); if (lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) { lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE); return ndlp->nlp_state; } + lpfc_nlp_put(ndlp); mp = (struct lpfc_dmabuf *)mbox->context1; lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); @@ -1920,7 +1924,7 @@ lpfc_disc_state_machine(struct lpfc_hba * phba, uint32_t(*func) (struct lpfc_hba *, struct lpfc_nodelist *, void *, uint32_t); - ndlp->nlp_disc_refcnt++; + lpfc_nlp_get(ndlp); cur_state = ndlp->nlp_state; /* DSM in event on NPort in state */ @@ -1943,18 +1947,7 @@ lpfc_disc_state_machine(struct lpfc_hba * phba, phba->brd_no, rc, ndlp->nlp_DID, ndlp->nlp_flag); - ndlp->nlp_disc_refcnt--; + lpfc_nlp_put(ndlp); - /* Check to see if ndlp removal is deferred */ - if ((ndlp->nlp_disc_refcnt == 0) - && (ndlp->nlp_flag & NLP_DELAY_REMOVE)) { - spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_DELAY_REMOVE; - spin_unlock_irq(phba->host->host_lock); - lpfc_nlp_remove(phba, ndlp); - return NLP_STE_FREED_NODE; - } - if (rc == NLP_STE_FREED_NODE) - return NLP_STE_FREED_NODE; return rc; } -- cgit v0.10.2 From 685f0bf7afe087940d34f98ac0fd1df84091d360 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:53:08 -0400 Subject: [SCSI] lpfc 8.1.12 : Collapse discovery lists to a single node list Collapse discovery lists to a single node list. Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index da8b6bb..ccc4ca1 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -255,17 +255,7 @@ struct lpfc_hba { struct lpfc_stats fc_stat; - /* These are the head/tail pointers for the bind, plogi, adisc, unmap, - * and map lists. Their counters are immediately following. - */ - struct list_head fc_plogi_list; - struct list_head fc_adisc_list; - struct list_head fc_reglogin_list; - struct list_head fc_prli_list; - struct list_head fc_nlpunmap_list; - struct list_head fc_nlpmap_list; - struct list_head fc_npr_list; - struct list_head fc_unused_list; + struct list_head fc_nodes; /* Keep counters for the number of entries in each list. */ uint16_t fc_plogi_cnt; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index df9847e..2605bd3 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1781,67 +1781,51 @@ lpfc_reset_stats(struct Scsi_Host *shost) * The LPFC driver treats linkdown handling as target loss events so there * are no sysfs handlers for link_down_tmo. */ -static void -lpfc_get_starget_port_id(struct scsi_target *starget) + +static struct lpfc_nodelist * +lpfc_get_node_by_target(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata; - uint32_t did = -1; - struct lpfc_nodelist *ndlp = NULL; + struct lpfc_nodelist *ndlp; spin_lock_irq(shost->host_lock); - /* Search the mapped list for this target ID */ - list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) { - if (starget->id == ndlp->nlp_sid) { - did = ndlp->nlp_DID; - break; + /* Search for this, mapped, target ID */ + list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) { + if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && + starget->id == ndlp->nlp_sid) { + spin_unlock_irq(shost->host_lock); + return ndlp; } } spin_unlock_irq(shost->host_lock); + return NULL; +} - fc_starget_port_id(starget) = did; +static void +lpfc_get_starget_port_id(struct scsi_target *starget) +{ + struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget); + + fc_starget_port_id(starget) = ndlp ? ndlp->nlp_DID : -1; } static void lpfc_get_starget_node_name(struct scsi_target *starget) { - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata; - u64 node_name = 0; - struct lpfc_nodelist *ndlp = NULL; + struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget); - spin_lock_irq(shost->host_lock); - /* Search the mapped list for this target ID */ - list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) { - if (starget->id == ndlp->nlp_sid) { - node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn); - break; - } - } - spin_unlock_irq(shost->host_lock); - - fc_starget_node_name(starget) = node_name; + fc_starget_node_name(starget) = + ndlp ? wwn_to_u64(ndlp->nlp_nodename.u.wwn) : 0; } static void lpfc_get_starget_port_name(struct scsi_target *starget) { - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata; - u64 port_name = 0; - struct lpfc_nodelist *ndlp = NULL; - - spin_lock_irq(shost->host_lock); - /* Search the mapped list for this target ID */ - list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) { - if (starget->id == ndlp->nlp_sid) { - port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn); - break; - } - } - spin_unlock_irq(shost->host_lock); + struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget); - fc_starget_port_name(starget) = port_name; + fc_starget_port_name(starget) = + ndlp ? wwn_to_u64(ndlp->nlp_portname.u.wwn) : 0; } static void diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index f61d46f..9f70b5b 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -18,6 +18,8 @@ * included with this package. * *******************************************************************/ +typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param); + struct fc_rport; void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *); @@ -178,9 +180,8 @@ int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t, void lpfc_mbox_timeout(unsigned long); void lpfc_mbox_timeout_handler(struct lpfc_hba *); -struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t, uint32_t); -struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, uint32_t, - struct lpfc_name *); +struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t); +struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, struct lpfc_name *); int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq, uint32_t timeout); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 48ae235..af81988 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -443,10 +443,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) { phba->fc_ns_retry++; /* CT command is being retried */ - ndlp = - lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED, - NameServer_DID); - if (ndlp) { + ndlp = lpfc_findnode_did(phba, NameServer_DID); + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) == 0) { goto out; @@ -730,7 +728,7 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba * phba, uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp; uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp; - ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID); + ndlp = lpfc_findnode_did(phba, FDMI_DID); if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { /* FDMI rsp failed */ lpfc_printf_log(phba, @@ -1162,7 +1160,7 @@ lpfc_fdmi_tmo_handler(struct lpfc_hba *phba) { struct lpfc_nodelist *ndlp; - ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID); + ndlp = lpfc_findnode_did(phba, FDMI_DID); if (ndlp) { if (init_utsname()->nodename[0] != '\0') { lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA); diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 4561327..971b0f8 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -83,15 +83,6 @@ struct lpfc_nodelist { }; /* Defines for nlp_flag (uint32) */ -#define NLP_UNUSED_LIST 0x1 /* Flg to indicate node will be freed */ -#define NLP_PLOGI_LIST 0x2 /* Flg to indicate sent PLOGI */ -#define NLP_ADISC_LIST 0x3 /* Flg to indicate sent ADISC */ -#define NLP_REGLOGIN_LIST 0x4 /* Flg to indicate sent REG_LOGIN */ -#define NLP_PRLI_LIST 0x5 /* Flg to indicate sent PRLI */ -#define NLP_UNMAPPED_LIST 0x6 /* Node is now unmapped */ -#define NLP_MAPPED_LIST 0x7 /* Node is now mapped */ -#define NLP_NPR_LIST 0x8 /* Node is in NPort Recovery state */ -#define NLP_LIST_MASK 0xf /* mask to see what list node is on */ #define NLP_PLOGI_SND 0x20 /* sent PLOGI request for this entry */ #define NLP_PRLI_SND 0x40 /* sent PRLI request for this entry */ #define NLP_ADISC_SND 0x80 /* sent ADISC request for this entry */ @@ -109,17 +100,6 @@ struct lpfc_nodelist { NPR list */ #define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */ -/* Defines for list searchs */ -#define NLP_SEARCH_MAPPED 0x1 /* search mapped */ -#define NLP_SEARCH_UNMAPPED 0x2 /* search unmapped */ -#define NLP_SEARCH_PLOGI 0x4 /* search plogi */ -#define NLP_SEARCH_ADISC 0x8 /* search adisc */ -#define NLP_SEARCH_REGLOGIN 0x10 /* search reglogin */ -#define NLP_SEARCH_PRLI 0x20 /* search prli */ -#define NLP_SEARCH_NPR 0x40 /* search npr */ -#define NLP_SEARCH_UNUSED 0x80 /* search mapped */ -#define NLP_SEARCH_ALL 0xff /* search all lists */ - /* There are 4 different double linked lists nodelist entries can reside on. * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used * when Link Up discovery or Registered State Change Notification (RSCN) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index cb63c35..ddf7f22 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -372,7 +372,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, } lpfc_nlp_put(ndlp); - ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, PT2PT_RemoteID); + ndlp = lpfc_findnode_did(phba, PT2PT_RemoteID); if (!ndlp) { /* * Cannot find existing Fabric ndlp, so allocate a @@ -592,12 +592,12 @@ lpfc_els_abort_flogi(struct lpfc_hba * phba) } int -lpfc_initial_flogi(struct lpfc_hba * phba) +lpfc_initial_flogi(struct lpfc_hba *phba) { struct lpfc_nodelist *ndlp; /* First look for the Fabric ndlp */ - ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, Fabric_DID); + ndlp = lpfc_findnode_did(phba, Fabric_DID); if (!ndlp) { /* Cannot find existing Fabric ndlp, so allocate a new one */ ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); @@ -637,7 +637,7 @@ lpfc_more_plogi(struct lpfc_hba * phba) } static struct lpfc_nodelist * -lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp, +lpfc_plogi_confirm_nport(struct lpfc_hba *phba, struct lpfc_dmabuf *prsp, struct lpfc_nodelist *ndlp) { struct lpfc_nodelist *new_ndlp; @@ -654,12 +654,12 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp, lp = (uint32_t *) prsp->virt; sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); - memset(name, 0, sizeof (struct lpfc_name)); + memset(name, 0, sizeof(struct lpfc_name)); - /* Now we to find out if the NPort we are logging into, matches the WWPN + /* Now we find out if the NPort we are logging into, matches the WWPN * we have for that ndlp. If not, we have some work to do. */ - new_ndlp = lpfc_findnode_wwpn(phba, NLP_SEARCH_ALL, &sp->portName); + new_ndlp = lpfc_findnode_wwpn(phba, &sp->portName); if (new_ndlp == ndlp) return ndlp; @@ -705,8 +705,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, cmdiocb->context_un.rsp_iocb = rspiocb; irsp = &rspiocb->iocb; - ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, - irsp->un.elsreq64.remoteID); + ndlp = lpfc_findnode_did(phba, irsp->un.elsreq64.remoteID); if (!ndlp) goto out; @@ -1408,7 +1407,7 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry) memcpy(&fp->RportName, &phba->fc_portname, sizeof (struct lpfc_name)); memcpy(&fp->RnodeName, &phba->fc_nodename, sizeof (struct lpfc_name)); - if ((ondlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, nportid))) { + if ((ondlp = lpfc_findnode_did(phba, nportid))) { memcpy(&fp->OportName, &ondlp->nlp_portname, sizeof (struct lpfc_name)); memcpy(&fp->OnodeName, &ondlp->nlp_nodename, @@ -1595,7 +1594,7 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, else { /* We should only hit this case for retrying PLOGI */ did = irsp->un.elsreq64.remoteID; - ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did); + ndlp = lpfc_findnode_did(phba, did); if (!ndlp && (cmd != ELS_CMD_PLOGI)) return 1; } @@ -2291,31 +2290,31 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba *phba, uint8_t format, } int -lpfc_els_disc_adisc(struct lpfc_hba * phba) +lpfc_els_disc_adisc(struct lpfc_hba *phba) { int sentadisc; struct lpfc_nodelist *ndlp, *next_ndlp; sentadisc = 0; - /* go thru NPR list and issue any remaining ELS ADISCs */ - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, - nlp_listp) { - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - if (ndlp->nlp_flag & NLP_NPR_ADISC) { - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(phba, ndlp, - NLP_STE_ADISC_ISSUE); - lpfc_issue_els_adisc(phba, ndlp, 0); - sentadisc++; - phba->num_disc_nodes++; - if (phba->num_disc_nodes >= - phba->cfg_discovery_threads) { - spin_lock_irq(phba->host->host_lock); - phba->fc_flag |= FC_NLP_MORE; - spin_unlock_irq(phba->host->host_lock); - break; - } + /* go thru NPR nodes and issue any remaining ELS ADISCs */ + list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) { + if (ndlp->nlp_state == NLP_STE_NPR_NODE && + (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && + (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) { + spin_lock_irq(phba->host->host_lock); + ndlp->nlp_flag &= ~NLP_NPR_ADISC; + spin_unlock_irq(phba->host->host_lock); + ndlp->nlp_prev_state = ndlp->nlp_state; + lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE); + lpfc_issue_els_adisc(phba, ndlp, 0); + sentadisc++; + phba->num_disc_nodes++; + if (phba->num_disc_nodes >= + phba->cfg_discovery_threads) { + spin_lock_irq(phba->host->host_lock); + phba->fc_flag |= FC_NLP_MORE; + spin_unlock_irq(phba->host->host_lock); + break; } } } @@ -2335,24 +2334,22 @@ lpfc_els_disc_plogi(struct lpfc_hba * phba) sentplogi = 0; /* go thru NPR list and issue any remaining ELS PLOGIs */ - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, - nlp_listp) { - if ((ndlp->nlp_flag & NLP_NPR_2B_DISC) && - (!(ndlp->nlp_flag & NLP_DELAY_TMO))) { - if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(phba, ndlp, - NLP_STE_PLOGI_ISSUE); - lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0); - sentplogi++; - phba->num_disc_nodes++; - if (phba->num_disc_nodes >= - phba->cfg_discovery_threads) { - spin_lock_irq(phba->host->host_lock); - phba->fc_flag |= FC_NLP_MORE; - spin_unlock_irq(phba->host->host_lock); - break; - } + list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) { + if (ndlp->nlp_state == NLP_STE_NPR_NODE && + (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && + (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 && + (ndlp->nlp_flag & NLP_NPR_ADISC) == 0) { + ndlp->nlp_prev_state = ndlp->nlp_state; + lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE); + lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0); + sentplogi++; + phba->num_disc_nodes++; + if (phba->num_disc_nodes >= + phba->cfg_discovery_threads) { + spin_lock_irq(phba->host->host_lock); + phba->fc_flag |= FC_NLP_MORE; + spin_unlock_irq(phba->host->host_lock); + break; } } } @@ -2456,40 +2453,28 @@ lpfc_rscn_payload_check(struct lpfc_hba * phba, uint32_t did) static int lpfc_rscn_recovery_check(struct lpfc_hba *phba) { - struct lpfc_nodelist *ndlp = NULL, *next_ndlp; - struct list_head *listp; - struct list_head *node_list[7]; - int i; + struct lpfc_nodelist *ndlp = NULL; /* Look at all nodes effected by pending RSCNs and move - * them to NPR list. + * them to NPR state. */ - node_list[0] = &phba->fc_npr_list; /* MUST do this list first */ - node_list[1] = &phba->fc_nlpmap_list; - node_list[2] = &phba->fc_nlpunmap_list; - node_list[3] = &phba->fc_prli_list; - node_list[4] = &phba->fc_reglogin_list; - node_list[5] = &phba->fc_adisc_list; - node_list[6] = &phba->fc_plogi_list; - for (i = 0; i < 7; i++) { - listp = node_list[i]; - if (list_empty(listp)) - continue; - list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) { - if (!(lpfc_rscn_payload_check(phba, ndlp->nlp_DID))) - continue; + list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) { + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE || + lpfc_rscn_payload_check(phba, ndlp->nlp_DID) == 0) + continue; - lpfc_disc_state_machine(phba, ndlp, NULL, + lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); - /* Make sure NLP_DELAY_TMO is NOT running - * after a device recovery event. - */ - if (ndlp->nlp_flag & NLP_DELAY_TMO) - lpfc_cancel_retry_delay_tmo(phba, ndlp); - } + /* + * Make sure NLP_DELAY_TMO is NOT running after a device + * recovery event. + */ + if (ndlp->nlp_flag & NLP_DELAY_TMO) + lpfc_cancel_retry_delay_tmo(phba, ndlp); } + return 0; } @@ -2614,8 +2599,8 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba) /* To process RSCN, first compare RSCN data with NameServer */ phba->fc_ns_retry = 0; - ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED, NameServer_DID); - if (ndlp) { + ndlp = lpfc_findnode_did(phba, NameServer_DID); + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { /* Good ndlp, issue CT Request to NameServer */ if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) == 0) { /* Wait for NameServer query cmpl before we can @@ -2625,7 +2610,7 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba) } else { /* If login to NameServer does not exist, issue one */ /* Good status, issue PLOGI to NameServer */ - ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID); + ndlp = lpfc_findnode_did(phba, NameServer_DID); if (ndlp) { /* Wait for NameServer login cmpl before we can continue */ @@ -2859,6 +2844,7 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) elsiocb->iocb_cmpl = lpfc_cmpl_els_acc; phba->fc_stat.elsXmitACC++; + if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); } @@ -3144,8 +3130,9 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, */ list_for_each_entry_safe(ndlp, next_ndlp, - &phba->fc_npr_list, nlp_listp) { - + &phba->fc_nodes, nlp_listp) { + if (ndlp->nlp_state != NLP_STE_NPR_NODE) + continue; if (ndlp->nlp_type & NLP_FABRIC) { /* * Clean up old Fabric, Nameserver and @@ -3168,8 +3155,10 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, /* Discovery not needed, * move the nodes to their original state. */ - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, - nlp_listp) { + list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, + nlp_listp) { + if (ndlp->nlp_state != NLP_STE_NPR_NODE) + continue; switch (ndlp->nlp_prev_state) { case NLP_STE_UNMAPPED_NODE: @@ -3409,7 +3398,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba, } did = icmd->un.rcvels.remoteID; - ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did); + ndlp = lpfc_findnode_did(phba, did); if (!ndlp) { /* Cannot find existing Fabric ndlp, so allocate a new one */ ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 8ba2f4e..0ebde24 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -374,13 +374,12 @@ lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2, } int -lpfc_linkdown(struct lpfc_hba * phba) +lpfc_linkdown(struct lpfc_hba *phba) { struct lpfc_sli *psli; struct lpfc_nodelist *ndlp, *next_ndlp; - struct list_head *listp, *node_list[7]; - LPFC_MBOXQ_t *mb; - int rc, i; + LPFC_MBOXQ_t *mb; + int rc; psli = &phba->sli; /* sysfs or selective reset may call this routine to clean up */ @@ -412,32 +411,18 @@ lpfc_linkdown(struct lpfc_hba * phba) /* Cleanup any outstanding ELS commands */ lpfc_els_flush_cmd(phba); - /* Issue a LINK DOWN event to all nodes */ - node_list[0] = &phba->fc_npr_list; /* MUST do this list first */ - node_list[1] = &phba->fc_nlpmap_list; - node_list[2] = &phba->fc_nlpunmap_list; - node_list[3] = &phba->fc_prli_list; - node_list[4] = &phba->fc_reglogin_list; - node_list[5] = &phba->fc_adisc_list; - node_list[6] = &phba->fc_plogi_list; - for (i = 0; i < 7; i++) { - listp = node_list[i]; - if (list_empty(listp)) - continue; - - list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) { - + /* + * Issue a LINK DOWN event to all nodes. + */ + list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) { + /* free any ndlp's on unused list */ + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + lpfc_drop_node(phba, ndlp); + else /* otherwise, force node recovery. */ rc = lpfc_disc_state_machine(phba, ndlp, NULL, - NLP_EVT_DEVICE_RECOVERY); - - } + NLP_EVT_DEVICE_RECOVERY); } - /* free any ndlp's on unused list */ - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list, - nlp_listp) - lpfc_drop_node(phba, ndlp); - /* Setup myDID for link up if we are in pt2pt mode */ if (phba->fc_flag & FC_PT2PT) { phba->fc_myDID = 0; @@ -466,11 +451,9 @@ lpfc_linkdown(struct lpfc_hba * phba) } static int -lpfc_linkup(struct lpfc_hba * phba) +lpfc_linkup(struct lpfc_hba *phba) { struct lpfc_nodelist *ndlp, *next_ndlp; - struct list_head *listp, *node_list[7]; - int i; fc_host_post_event(phba->host, fc_get_event_number(), FCH_EVT_LINKUP, 0); @@ -484,29 +467,20 @@ lpfc_linkup(struct lpfc_hba * phba) spin_unlock_irq(phba->host->host_lock); - node_list[0] = &phba->fc_plogi_list; - node_list[1] = &phba->fc_adisc_list; - node_list[2] = &phba->fc_reglogin_list; - node_list[3] = &phba->fc_prli_list; - node_list[4] = &phba->fc_nlpunmap_list; - node_list[5] = &phba->fc_nlpmap_list; - node_list[6] = &phba->fc_npr_list; - for (i = 0; i < 7; i++) { - listp = node_list[i]; - if (list_empty(listp)) - continue; - - list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) { - if (phba->fc_flag & FC_LBIT) { + if (phba->fc_flag & FC_LBIT) { + list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) { + if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) { if (ndlp->nlp_type & NLP_FABRIC) { - /* On Linkup its safe to clean up the + /* + * On Linkup its safe to clean up the * ndlp from Fabric connections. */ lpfc_nlp_set_state(phba, ndlp, - NLP_STE_UNUSED_NODE); + NLP_STE_UNUSED_NODE); } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { - /* Fail outstanding IO now since device - * is marked for PLOGI. + /* + * Fail outstanding IO now since + * device is marked for PLOGI. */ lpfc_unreg_rpi(phba, ndlp); } @@ -515,9 +489,11 @@ lpfc_linkup(struct lpfc_hba * phba) } /* free any ndlp's on unused list */ - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list, - nlp_listp) - lpfc_drop_node(phba, ndlp); + list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, + nlp_listp) { + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + lpfc_drop_node(phba, ndlp); + } return 0; } @@ -1021,7 +997,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) */ lpfc_issue_els_scr(phba, SCR_DID, 0); - ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID); + ndlp = lpfc_findnode_did(phba, NameServer_DID); if (!ndlp) { /* Allocate a new node instance. If the pool is empty, * start the discovery process and skip the Nameserver @@ -1200,6 +1176,7 @@ lpfc_unregister_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) static void lpfc_nlp_counters(struct lpfc_hba *phba, int state, int count) { + spin_lock_irq(phba->host->host_lock); switch (state) { case NLP_STE_UNUSED_NODE: phba->fc_unused_cnt += count; @@ -1226,107 +1203,7 @@ lpfc_nlp_counters(struct lpfc_hba *phba, int state, int count) phba->fc_npr_cnt += count; break; } -} - -void -lpfc_delink_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) -{ - switch (ndlp->nlp_flag & NLP_LIST_MASK) { - case NLP_UNUSED_LIST: - list_del_init(&ndlp->nlp_listp); - break; - case NLP_PLOGI_LIST: - list_del_init(&ndlp->nlp_listp); - break; - case NLP_ADISC_LIST: - list_del_init(&ndlp->nlp_listp); - break; - case NLP_REGLOGIN_LIST: - list_del_init(&ndlp->nlp_listp); - break; - case NLP_PRLI_LIST: - list_del_init(&ndlp->nlp_listp); - break; - case NLP_UNMAPPED_LIST: - list_del_init(&ndlp->nlp_listp); - break; - case NLP_MAPPED_LIST: - list_del_init(&ndlp->nlp_listp); - break; - case NLP_NPR_LIST: - list_del_init(&ndlp->nlp_listp); - break; - } - - ndlp->nlp_flag &= ~NLP_LIST_MASK; -} - -static int -lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) -{ - struct lpfc_sli *psli; - - psli = &phba->sli; - /* Sanity check to ensure we are not moving to / from the same list */ - if ((nlp->nlp_flag & NLP_LIST_MASK) == list) - return 0; - - spin_lock_irq(phba->host->host_lock); - lpfc_delink_node(phba, nlp); - - /* Add NPort to list */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_NODE, - "%d:0904 Add NPort x%x to %d list Data: x%x\n", - phba->brd_no, - nlp->nlp_DID, list, nlp->nlp_flag); - - switch (list) { - case NLP_UNUSED_LIST: - nlp->nlp_flag |= list; - /* Put it at the end of the unused list */ - list_add_tail(&nlp->nlp_listp, &phba->fc_unused_list); - break; - case NLP_PLOGI_LIST: - nlp->nlp_flag |= list; - /* Put it at the end of the plogi list */ - list_add_tail(&nlp->nlp_listp, &phba->fc_plogi_list); - break; - case NLP_ADISC_LIST: - nlp->nlp_flag |= list; - /* Put it at the end of the adisc list */ - list_add_tail(&nlp->nlp_listp, &phba->fc_adisc_list); - break; - case NLP_REGLOGIN_LIST: - nlp->nlp_flag |= list; - /* Put it at the end of the reglogin list */ - list_add_tail(&nlp->nlp_listp, &phba->fc_reglogin_list); - break; - case NLP_PRLI_LIST: - nlp->nlp_flag |= list; - /* Put it at the end of the prli list */ - list_add_tail(&nlp->nlp_listp, &phba->fc_prli_list); - break; - case NLP_UNMAPPED_LIST: - nlp->nlp_flag |= list; - /* Put it at the end of the unmap list */ - list_add_tail(&nlp->nlp_listp, &phba->fc_nlpunmap_list); - break; - case NLP_MAPPED_LIST: - nlp->nlp_flag |= list; - /* Put it at the end of the map list */ - list_add_tail(&nlp->nlp_listp, &phba->fc_nlpmap_list); - break; - case NLP_NPR_LIST: - nlp->nlp_flag |= list; - /* Put it at the end of the npr list */ - list_add_tail(&nlp->nlp_listp, &phba->fc_npr_list); - break; - } - spin_unlock_irq(phba->host->host_lock); - return 0; } static void @@ -1378,21 +1255,39 @@ lpfc_nlp_state_cleanup(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, } } +static char * +lpfc_nlp_state_name(char *buffer, size_t size, int state) +{ + static char *states[] = { + [NLP_STE_UNUSED_NODE] = "UNUSED", + [NLP_STE_PLOGI_ISSUE] = "PLOGI", + [NLP_STE_ADISC_ISSUE] = "ADISC", + [NLP_STE_REG_LOGIN_ISSUE] = "REGLOGIN", + [NLP_STE_PRLI_ISSUE] = "PRLI", + [NLP_STE_UNMAPPED_NODE] = "UNMAPPED", + [NLP_STE_MAPPED_NODE] = "MAPPED", + [NLP_STE_NPR_NODE] = "NPR", + }; + + if (state < ARRAY_SIZE(states) && states[state]) + strlcpy(buffer, states[state], size); + else + snprintf(buffer, size, "unknown (%d)", state); + return buffer; +} + void lpfc_nlp_set_state(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, int state) { int old_state = ndlp->nlp_state; - static int list_id[] = { - [NLP_STE_UNUSED_NODE] = NLP_UNUSED_LIST, - [NLP_STE_PLOGI_ISSUE] = NLP_PLOGI_LIST, - [NLP_STE_ADISC_ISSUE] = NLP_ADISC_LIST, - [NLP_STE_REG_LOGIN_ISSUE] = NLP_REGLOGIN_LIST, - [NLP_STE_PRLI_ISSUE] = NLP_PRLI_LIST, - [NLP_STE_UNMAPPED_NODE] = NLP_UNMAPPED_LIST, - [NLP_STE_MAPPED_NODE] = NLP_MAPPED_LIST, - [NLP_STE_NPR_NODE] = NLP_NPR_LIST, - }; + char name1[16], name2[16]; + lpfc_printf_log(phba, KERN_INFO, LOG_NODE, + "%d:0904 NPort state transition x%06x, %s -> %s\n", + phba->brd_no, + ndlp->nlp_DID, + lpfc_nlp_state_name(name1, sizeof(name1), old_state), + lpfc_nlp_state_name(name2, sizeof(name2), state)); if (old_state == NLP_STE_NPR_NODE && (ndlp->nlp_flag & NLP_DELAY_TMO) != 0 && state != NLP_STE_NPR_NODE) @@ -1402,13 +1297,15 @@ lpfc_nlp_set_state(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, int state) ndlp->nlp_type &= ~NLP_FC_NODE; } - if (old_state && !list_empty(&ndlp->nlp_listp)) + if (list_empty(&ndlp->nlp_listp)) { + spin_lock_irq(phba->host->host_lock); + list_add_tail(&ndlp->nlp_listp, &phba->fc_nodes); + spin_unlock_irq(phba->host->host_lock); + } else if (old_state) lpfc_nlp_counters(phba, old_state, -1); ndlp->nlp_state = state; - lpfc_nlp_list(phba, ndlp, list_id[state]); lpfc_nlp_counters(phba, state, 1); - lpfc_nlp_state_cleanup(phba, ndlp, old_state, state); } @@ -1417,10 +1314,10 @@ lpfc_dequeue_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) { if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0) lpfc_cancel_retry_delay_tmo(phba, ndlp); - spin_lock_irq(phba->host->host_lock); if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) lpfc_nlp_counters(phba, ndlp->nlp_state, -1); - lpfc_delink_node(phba, ndlp); + spin_lock_irq(phba->host->host_lock); + list_del_init(&ndlp->nlp_listp); spin_unlock_irq(phba->host->host_lock); lpfc_nlp_state_cleanup(phba, ndlp, ndlp->nlp_state, 0); } @@ -1430,10 +1327,10 @@ lpfc_drop_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) { if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0) lpfc_cancel_retry_delay_tmo(phba, ndlp); - spin_lock_irq(phba->host->host_lock); if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) lpfc_nlp_counters(phba, ndlp->nlp_state, -1); - lpfc_delink_node(phba, ndlp); + spin_lock_irq(phba->host->host_lock); + list_del_init(&ndlp->nlp_listp); spin_unlock_irq(phba->host->host_lock); lpfc_nlp_put(ndlp); } @@ -1638,7 +1535,7 @@ lpfc_unreg_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) * so it can be freed. */ static int -lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) +lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) { LPFC_MBOXQ_t *mb; LPFC_MBOXQ_t *nextmb; @@ -1708,7 +1605,7 @@ lpfc_nlp_remove(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) lpfc_cancel_retry_delay_tmo(phba, ndlp); } - lpfc_freenode(phba, ndlp); + lpfc_cleanup_node(phba, ndlp); if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) { put_device(&ndlp->rport->dev); @@ -1719,7 +1616,7 @@ lpfc_nlp_remove(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) } static int -lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did) +lpfc_matchdid(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did) { D_ID mydid; D_ID ndlpdid; @@ -1768,57 +1665,36 @@ lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did) return 0; } -/* Search for a nodelist entry on a specific list */ +/* Search for a nodelist entry */ struct lpfc_nodelist * -lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did) +lpfc_findnode_did(struct lpfc_hba *phba, uint32_t did) { struct lpfc_nodelist *ndlp; - struct list_head *lists[]={&phba->fc_nlpunmap_list, - &phba->fc_nlpmap_list, - &phba->fc_plogi_list, - &phba->fc_adisc_list, - &phba->fc_reglogin_list, - &phba->fc_prli_list, - &phba->fc_npr_list, - &phba->fc_unused_list}; - uint32_t search[]={NLP_SEARCH_UNMAPPED, - NLP_SEARCH_MAPPED, - NLP_SEARCH_PLOGI, - NLP_SEARCH_ADISC, - NLP_SEARCH_REGLOGIN, - NLP_SEARCH_PRLI, - NLP_SEARCH_NPR, - NLP_SEARCH_UNUSED}; - int i; uint32_t data1; spin_lock_irq(phba->host->host_lock); - for (i = 0; i < ARRAY_SIZE(lists); i++ ) { - if (!(order & search[i])) - continue; - list_for_each_entry(ndlp, lists[i], nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0929 FIND node DID " - " Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - spin_unlock_irq(phba->host->host_lock); - return ndlp; - } + list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) { + if (lpfc_matchdid(phba, ndlp, did)) { + data1 = (((uint32_t) ndlp->nlp_state << 24) | + ((uint32_t) ndlp->nlp_xri << 16) | + ((uint32_t) ndlp->nlp_type << 8) | + ((uint32_t) ndlp->nlp_rpi & 0xff)); + lpfc_printf_log(phba, KERN_INFO, LOG_NODE, + "%d:0929 FIND node DID " + " Data: x%p x%x x%x x%x\n", + phba->brd_no, + ndlp, ndlp->nlp_DID, + ndlp->nlp_flag, data1); + spin_unlock_irq(phba->host->host_lock); + return ndlp; } } spin_unlock_irq(phba->host->host_lock); /* FIND node did NOT FOUND */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0932 FIND node did x%x NOT FOUND Data: x%x\n", - phba->brd_no, did, order); + "%d:0932 FIND node did x%x NOT FOUND.\n", + phba->brd_no, did); return NULL; } @@ -1826,9 +1702,8 @@ struct lpfc_nodelist * lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did) { struct lpfc_nodelist *ndlp; - uint32_t flg; - ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did); + ndlp = lpfc_findnode_did(phba, did); if (!ndlp) { if ((phba->fc_flag & FC_RSCN_MODE) && ((lpfc_rscn_payload_check(phba, did) == 0))) @@ -1854,8 +1729,8 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did) } else ndlp = NULL; } else { - flg = ndlp->nlp_flag & NLP_LIST_MASK; - if ((flg == NLP_ADISC_LIST) || (flg == NLP_PLOGI_LIST)) + if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE || + ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) return NULL; lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); ndlp->nlp_flag |= NLP_NPR_2B_DISC; @@ -1915,8 +1790,9 @@ lpfc_disc_start(struct lpfc_hba * phba) struct lpfc_sli *psli; LPFC_MBOXQ_t *mbox; struct lpfc_nodelist *ndlp, *next_ndlp; - uint32_t did_changed, num_sent; + uint32_t num_sent; uint32_t clear_la_pending; + int did_changed; int rc; psli = &phba->sli; @@ -1950,14 +1826,13 @@ lpfc_disc_start(struct lpfc_hba * phba) phba->fc_plogi_cnt, phba->fc_adisc_cnt); /* If our did changed, we MUST do PLOGI */ - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, - nlp_listp) { - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - if (did_changed) { - spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(phba->host->host_lock); - } + list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) { + if (ndlp->nlp_state == NLP_STE_NPR_NODE && + (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && + did_changed) { + spin_lock_irq(phba->host->host_lock); + ndlp->nlp_flag &= ~NLP_NPR_ADISC; + spin_unlock_irq(phba->host->host_lock); } } @@ -2077,21 +1952,16 @@ lpfc_disc_flush_list(struct lpfc_hba * phba) { struct lpfc_nodelist *ndlp, *next_ndlp; - if (phba->fc_plogi_cnt) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list, - nlp_listp) { - lpfc_free_tx(phba, ndlp); - lpfc_nlp_put(ndlp); - } - } - if (phba->fc_adisc_cnt) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list, - nlp_listp) { - lpfc_free_tx(phba, ndlp); - lpfc_nlp_put(ndlp); + if (phba->fc_plogi_cnt || phba->fc_adisc_cnt) { + list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, + nlp_listp) { + if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || + ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { + lpfc_free_tx(phba, ndlp); + lpfc_nlp_put(ndlp); + } } } - return; } /*****************************************************************************/ @@ -2160,8 +2030,10 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) phba->brd_no); /* Start discovery by sending FLOGI, clean up old rpis */ - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, - nlp_listp) { + list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, + nlp_listp) { + if (ndlp->nlp_state != NLP_STE_NPR_NODE) + continue; if (ndlp->nlp_type & NLP_FABRIC) { /* Clean up the ndlp on Fabric connections */ lpfc_drop_node(phba, ndlp); @@ -2205,7 +2077,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) "login\n", phba->brd_no); /* Next look for NameServer ndlp */ - ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID); + ndlp = lpfc_findnode_did(phba, NameServer_DID); if (ndlp) lpfc_nlp_put(ndlp); /* Start discovery */ @@ -2220,9 +2092,8 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) phba->brd_no, phba->fc_ns_retry, LPFC_MAX_NS_RETRY); - ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED, - NameServer_DID); - if (ndlp) { + ndlp = lpfc_findnode_did(phba, NameServer_DID); + if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) { /* Try it one more time */ rc = lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT); @@ -2394,31 +2265,63 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) return; } +static int +lpfc_filter_by_rpi(struct lpfc_nodelist *ndlp, void *param) +{ + uint16_t *rpi = param; + + return ndlp->nlp_rpi == *rpi; +} + +static int +lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param) +{ + return memcmp(&ndlp->nlp_portname, param, + sizeof(ndlp->nlp_portname)) == 0; +} + /* - * This routine looks up the ndlp lists - * for the given RPI. If rpi found - * it return the node list pointer - * else return NULL. + * Search node lists for a remote port matching filter criteria + * Caller needs to hold host_lock before calling this routine. */ struct lpfc_nodelist * -__lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi) +__lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param) { struct lpfc_nodelist *ndlp; - struct list_head * lists[]={&phba->fc_nlpunmap_list, - &phba->fc_nlpmap_list, - &phba->fc_plogi_list, - &phba->fc_adisc_list, - &phba->fc_reglogin_list}; - int i; - for (i = 0; i < ARRAY_SIZE(lists); i++ ) - list_for_each_entry(ndlp, lists[i], nlp_listp) - if (ndlp->nlp_rpi == rpi) { - return ndlp; - } + list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) { + if (ndlp->nlp_state != NLP_STE_UNUSED_NODE && + filter(ndlp, param)) + return ndlp; + } return NULL; } +/* + * Search node lists for a remote port matching filter criteria + * This routine is used when the caller does NOT have host_lock. + */ +struct lpfc_nodelist * +lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param) +{ + struct lpfc_nodelist *ndlp; + + spin_lock_irq(phba->host->host_lock); + ndlp = __lpfc_find_node(phba, filter, param); + spin_unlock_irq(phba->host->host_lock); + return ndlp; +} + +/* + * This routine looks up the ndlp lists for the given RPI. If rpi found it + * returns the node list pointer else return NULL. + */ +struct lpfc_nodelist * +__lpfc_findnode_rpi(struct lpfc_hba *phba, uint16_t rpi) +{ + return __lpfc_find_node(phba, lpfc_filter_by_rpi, &rpi); +} + struct lpfc_nodelist * lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi) { @@ -2431,44 +2334,16 @@ lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi) } /* - * This routine looks up the ndlp lists - * for the given WWPN. If WWPN found - * it return the node list pointer - * else return NULL. + * This routine looks up the ndlp lists for the given WWPN. If WWPN found it + * returns the node list pointer else return NULL. */ struct lpfc_nodelist * -lpfc_findnode_wwpn(struct lpfc_hba * phba, uint32_t order, - struct lpfc_name * wwpn) +lpfc_findnode_wwpn(struct lpfc_hba *phba, struct lpfc_name *wwpn) { struct lpfc_nodelist *ndlp; - struct list_head * lists[]={&phba->fc_nlpunmap_list, - &phba->fc_nlpmap_list, - &phba->fc_npr_list, - &phba->fc_plogi_list, - &phba->fc_adisc_list, - &phba->fc_reglogin_list, - &phba->fc_prli_list}; - uint32_t search[]={NLP_SEARCH_UNMAPPED, - NLP_SEARCH_MAPPED, - NLP_SEARCH_NPR, - NLP_SEARCH_PLOGI, - NLP_SEARCH_ADISC, - NLP_SEARCH_REGLOGIN, - NLP_SEARCH_PRLI}; - int i; spin_lock_irq(phba->host->host_lock); - for (i = 0; i < ARRAY_SIZE(lists); i++ ) { - if (!(order & search[i])) - continue; - list_for_each_entry(ndlp, lists[i], nlp_listp) { - if (memcmp(&ndlp->nlp_portname, wwpn, - sizeof(struct lpfc_name)) == 0) { - spin_unlock_irq(phba->host->host_lock); - return ndlp; - } - } - } + ndlp = __lpfc_find_node(phba, lpfc_filter_by_wwpn, wwpn); spin_unlock_irq(phba->host->host_lock); return NULL; } @@ -2484,6 +2359,7 @@ lpfc_nlp_init(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did) ndlp->nlp_DID = did; ndlp->nlp_phba = phba; ndlp->nlp_sid = NLP_NO_SID; + INIT_LIST_HEAD(&ndlp->nlp_listp); kref_init(&ndlp->kref); return; } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 388b92a..5e9a839 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1185,63 +1185,11 @@ lpfc_cleanup(struct lpfc_hba * phba) /* clean up phba - lpfc specific */ lpfc_can_disctmo(phba); - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpunmap_list, - nlp_listp) { + list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) lpfc_nlp_put(ndlp); - } - - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpmap_list, - nlp_listp) { - lpfc_nlp_put(ndlp); - } - - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list, - nlp_listp) { - lpfc_drop_node(phba, ndlp); - } - - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list, - nlp_listp) { - lpfc_nlp_put(ndlp); - } - - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list, - nlp_listp) { - lpfc_nlp_put(ndlp); - } - - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_reglogin_list, - nlp_listp) { - lpfc_nlp_put(ndlp); - } - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_prli_list, - nlp_listp) { - lpfc_nlp_put(ndlp); - } + INIT_LIST_HEAD(&phba->fc_nodes); - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, - nlp_listp) { - lpfc_nlp_put(ndlp); - } - - INIT_LIST_HEAD(&phba->fc_nlpmap_list); - INIT_LIST_HEAD(&phba->fc_nlpunmap_list); - INIT_LIST_HEAD(&phba->fc_unused_list); - INIT_LIST_HEAD(&phba->fc_plogi_list); - INIT_LIST_HEAD(&phba->fc_adisc_list); - INIT_LIST_HEAD(&phba->fc_reglogin_list); - INIT_LIST_HEAD(&phba->fc_prli_list); - INIT_LIST_HEAD(&phba->fc_npr_list); - - phba->fc_map_cnt = 0; - phba->fc_unmap_cnt = 0; - phba->fc_plogi_cnt = 0; - phba->fc_adisc_cnt = 0; - phba->fc_reglogin_cnt = 0; - phba->fc_prli_cnt = 0; - phba->fc_npr_cnt = 0; - phba->fc_unused_cnt= 0; return; } @@ -1336,8 +1284,6 @@ void lpfc_offline_prep(struct lpfc_hba * phba) { struct lpfc_nodelist *ndlp, *next_ndlp; - struct list_head *listp, *node_list[7]; - int i; if (phba->fc_flag & FC_OFFLINE_MODE) return; @@ -1347,21 +1293,9 @@ lpfc_offline_prep(struct lpfc_hba * phba) lpfc_linkdown(phba); /* Issue an unreg_login to all nodes */ - node_list[0] = &phba->fc_npr_list; /* MUST do this list first */ - node_list[1] = &phba->fc_nlpmap_list; - node_list[2] = &phba->fc_nlpunmap_list; - node_list[3] = &phba->fc_prli_list; - node_list[4] = &phba->fc_reglogin_list; - node_list[5] = &phba->fc_adisc_list; - node_list[6] = &phba->fc_plogi_list; - for (i = 0; i < 7; i++) { - listp = node_list[i]; - if (list_empty(listp)) - continue; - - list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) + list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) + if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) lpfc_unreg_rpi(phba, ndlp); - } lpfc_sli_flush_mbox_queue(phba); } @@ -1500,15 +1434,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) host->max_lun = phba->cfg_max_luns; host->this_id = -1; - /* Initialize all internally managed lists. */ - INIT_LIST_HEAD(&phba->fc_nlpmap_list); - INIT_LIST_HEAD(&phba->fc_nlpunmap_list); - INIT_LIST_HEAD(&phba->fc_unused_list); - INIT_LIST_HEAD(&phba->fc_plogi_list); - INIT_LIST_HEAD(&phba->fc_adisc_list); - INIT_LIST_HEAD(&phba->fc_reglogin_list); - INIT_LIST_HEAD(&phba->fc_prli_list); - INIT_LIST_HEAD(&phba->fc_npr_list); + INIT_LIST_HEAD(&phba->fc_nodes); pci_set_master(pdev); retval = pci_set_mwi(pdev); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index efd1cf6..cc0f845 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1175,10 +1175,12 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) * fail, this routine returns failure to the midlayer. */ for (i = 0; i < LPFC_MAX_TARGET; i++) { - /* Search the mapped list for this target ID */ + /* Search for mapped node by target ID */ match = 0; - list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) { - if ((i == ndlp->nlp_sid) && ndlp->rport) { + list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) { + if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && + i == ndlp->nlp_sid && + ndlp->rport) { match = 1; break; } -- cgit v0.10.2 From ebdbe65f07bb26baf69fcb0ee332702064888018 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:53:15 -0400 Subject: [SCSI] lpfc 8.1.12 : Don't process ERATT interrupts when issuing KILL_BOARD mbx command Don't process ERATT interrupts when issuing KILL_BOARD mbx command Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index ccc4ca1..913e08e 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -250,6 +250,7 @@ struct lpfc_hba { #define FC_LOOPBACK_MODE 0x40000 /* NPort is in Loopback mode */ /* This flag is set while issuing */ /* INIT_LINK mailbox command */ +#define FC_IGNORE_ERATT 0x80000 /* intr handler should ignore ERATT */ uint32_t fc_topology; /* link topology, from LINK INIT */ diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 645291e..1508b3f 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1584,6 +1584,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba) hc_copy = readl(phba->HCregaddr); writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr); readl(phba->HCregaddr); /* flush */ + phba->fc_flag |= FC_IGNORE_ERATT; if (readl(phba->HAregaddr) & HA_ERATT) { /* Clear Chip error bit */ @@ -1626,6 +1627,7 @@ clear_errat: } restore_hc: + phba->fc_flag &= ~FC_IGNORE_ERATT; writel(hc_copy, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ } @@ -1661,6 +1663,7 @@ lpfc_sli_brdkill(struct lpfc_hba * phba) status &= ~HC_ERINT_ENA; writel(status, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ + phba->fc_flag |= FC_IGNORE_ERATT; spin_unlock_irq(phba->host->host_lock); lpfc_kill_board(phba, pmb); @@ -1670,6 +1673,9 @@ lpfc_sli_brdkill(struct lpfc_hba * phba) if (retval != MBX_SUCCESS) { if (retval != MBX_BUSY) mempool_free(pmb, phba->mbox_mem_pool); + spin_lock_irq(phba->host->host_lock); + phba->fc_flag &= ~FC_IGNORE_ERATT; + spin_unlock_irq(phba->host->host_lock); return 1; } @@ -1696,6 +1702,7 @@ lpfc_sli_brdkill(struct lpfc_hba * phba) } spin_lock_irq(phba->host->host_lock); psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; + phba->fc_flag &= ~FC_IGNORE_ERATT; spin_unlock_irq(phba->host->host_lock); psli->mbox_active = NULL; @@ -3207,6 +3214,11 @@ lpfc_intr_handler(int irq, void *dev_id) */ spin_lock(phba->host->host_lock); ha_copy = readl(phba->HAregaddr); + /* If somebody is waiting to handle an eratt don't process it + * here. The brdkill function will do this. + */ + if (phba->fc_flag & FC_IGNORE_ERATT) + ha_copy &= ~HA_ERATT; writel((ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr); readl(phba->HAregaddr); /* flush */ spin_unlock(phba->host->host_lock); -- cgit v0.10.2 From 47a8617c7df6cc8b8617a3deb5a36bbae1997d13 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:53:22 -0400 Subject: [SCSI] lpfc 8.1.12 : Add support for async scanning Add support for async scanning Notes: This is the async scan patch to our driver from Matthew Wilcox. The async scan logic is still subject to errors in insmod/rmmod, as the async scan threads don't get shutdown when the module unloads underneath them. See http://marc.info/?l=linux-scsi&m=117551999925582&w=2 Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 9f70b5b..e4454bc 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -200,6 +200,9 @@ void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t); /* Function prototypes. */ const char* lpfc_info(struct Scsi_Host *); +void lpfc_scan_start(struct Scsi_Host *); +int lpfc_scan_finished(struct Scsi_Host *, unsigned long); + void lpfc_get_cfgparam(struct lpfc_hba *); int lpfc_alloc_sysfs_attr(struct lpfc_hba *); void lpfc_free_sysfs_attr(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 5e9a839..7cb92c7 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -418,33 +418,6 @@ lpfc_config_port_post(struct lpfc_hba * phba) return (0); } -static int -lpfc_discovery_wait(struct lpfc_hba *phba) -{ - int i = 0; - - while ((phba->hba_state != LPFC_HBA_READY) || - (phba->num_disc_nodes) || (phba->fc_prli_sent) || - ((phba->fc_map_cnt == 0) && (i<2)) || - (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)) { - /* Check every second for 30 retries. */ - i++; - if (i > 30) { - return -ETIMEDOUT; - } - if ((i >= 15) && (phba->hba_state <= LPFC_LINK_DOWN)) { - /* The link is down. Set linkdown timeout */ - return -ETIMEDOUT; - } - - /* Delay for 1 second to give discovery time to complete. */ - msleep(1000); - - } - - return 0; -} - /************************************************************************/ /* */ /* lpfc_hba_down_prep */ @@ -1362,6 +1335,156 @@ lpfc_scsi_free(struct lpfc_hba * phba) return 0; } +void lpfc_remove_device(struct lpfc_hba *phba) +{ + unsigned long iflag; + + lpfc_free_sysfs_attr(phba); + + spin_lock_irqsave(phba->host->host_lock, iflag); + phba->fc_flag |= FC_UNLOADING; + + spin_unlock_irqrestore(phba->host->host_lock, iflag); + + fc_remove_host(phba->host); + scsi_remove_host(phba->host); + + kthread_stop(phba->worker_thread); + + /* + * Bring down the SLI Layer. This step disable all interrupts, + * clears the rings, discards all mailbox commands, and resets + * the HBA. + */ + lpfc_sli_hba_down(phba); + lpfc_sli_brdrestart(phba); + + /* Release the irq reservation */ + free_irq(phba->pcidev->irq, phba); + pci_disable_msi(phba->pcidev); + + lpfc_cleanup(phba); + lpfc_stop_timer(phba); + phba->work_hba_events = 0; + + /* + * Call scsi_free before mem_free since scsi bufs are released to their + * corresponding pools here. + */ + lpfc_scsi_free(phba); + lpfc_mem_free(phba); + + /* Free resources associated with SLI2 interface */ + dma_free_coherent(&phba->pcidev->dev, SLI2_SLIM_SIZE, + phba->slim2p, phba->slim2p_mapping); + + /* unmap adapter SLIM and Control Registers */ + iounmap(phba->ctrl_regs_memmap_p); + iounmap(phba->slim_memmap_p); + + pci_release_regions(phba->pcidev); + pci_disable_device(phba->pcidev); + + idr_remove(&lpfc_hba_index, phba->brd_no); + scsi_host_put(phba->host); +} + +void lpfc_scan_start(struct Scsi_Host *host) +{ + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata; + + if (lpfc_alloc_sysfs_attr(phba)) + goto error; + + phba->MBslimaddr = phba->slim_memmap_p; + phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET; + phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET; + phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; + phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; + + if (lpfc_sli_hba_setup(phba)) + goto error; + + /* + * hba setup may have changed the hba_queue_depth so we need to adjust + * the value of can_queue. + */ + host->can_queue = phba->cfg_hba_queue_depth - 10; + return; + +error: + lpfc_remove_device(phba); +} + +int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time) +{ + struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata; + + if (!phba->host) + return 1; + if (time >= 30 * HZ) + goto finished; + + if (phba->hba_state != LPFC_HBA_READY) + return 0; + if (phba->num_disc_nodes || phba->fc_prli_sent) + return 0; + if ((phba->fc_map_cnt == 0) && (time < 2 * HZ)) + return 0; + if (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) + return 0; + if ((phba->hba_state > LPFC_LINK_DOWN) || (time < 15 * HZ)) + return 0; + +finished: + if (phba->cfg_poll & DISABLE_FCP_RING_INT) { + spin_lock_irq(shost->host_lock); + lpfc_poll_start_timer(phba); + spin_unlock_irq(shost->host_lock); + } + + /* + * set fixed host attributes + * Must done after lpfc_sli_hba_setup() + */ + + fc_host_node_name(shost) = wwn_to_u64(phba->fc_nodename.u.wwn); + fc_host_port_name(shost) = wwn_to_u64(phba->fc_portname.u.wwn); + fc_host_supported_classes(shost) = FC_COS_CLASS3; + + memset(fc_host_supported_fc4s(shost), 0, + sizeof(fc_host_supported_fc4s(shost))); + fc_host_supported_fc4s(shost)[2] = 1; + fc_host_supported_fc4s(shost)[7] = 1; + + lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost)); + + fc_host_supported_speeds(shost) = 0; + if (phba->lmt & LMT_10Gb) + fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT; + if (phba->lmt & LMT_4Gb) + fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT; + if (phba->lmt & LMT_2Gb) + fc_host_supported_speeds(shost) |= FC_PORTSPEED_2GBIT; + if (phba->lmt & LMT_1Gb) + fc_host_supported_speeds(shost) |= FC_PORTSPEED_1GBIT; + + fc_host_maxframe_size(shost) = + ((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) | + (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb); + + /* This value is also unchanging */ + memset(fc_host_active_fc4s(shost), 0, + sizeof(fc_host_active_fc4s(shost))); + fc_host_active_fc4s(shost)[2] = 1; + fc_host_active_fc4s(shost)[7] = 1; + + spin_lock_irq(shost->host_lock); + phba->fc_flag &= ~FC_LOADING; + spin_unlock_irq(shost->host_lock); + + return 1; +} static int __devinit lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) @@ -1552,13 +1675,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) host->transportt = lpfc_transport_template; pci_set_drvdata(pdev, host); - error = scsi_add_host(host, &pdev->dev); - if (error) - goto out_kthread_stop; - - error = lpfc_alloc_sysfs_attr(phba); - if (error) - goto out_remove_host; if (phba->cfg_use_msi) { error = pci_enable_msi(phba->pcidev); @@ -1574,73 +1690,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "%d:0451 Enable interrupt handler failed\n", phba->brd_no); - goto out_free_sysfs_attr; + goto out_kthread_stop; } - phba->MBslimaddr = phba->slim_memmap_p; - phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET; - phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET; - phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; - phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; - error = lpfc_sli_hba_setup(phba); - if (error) { - error = -ENODEV; + error = scsi_add_host(host, &pdev->dev); + if (error) goto out_free_irq; - } - - /* - * hba setup may have changed the hba_queue_depth so we need to adjust - * the value of can_queue. - */ - host->can_queue = phba->cfg_hba_queue_depth - 10; - - lpfc_discovery_wait(phba); - - if (phba->cfg_poll & DISABLE_FCP_RING_INT) { - spin_lock_irq(phba->host->host_lock); - lpfc_poll_start_timer(phba); - spin_unlock_irq(phba->host->host_lock); - } - /* - * set fixed host attributes - * Must done after lpfc_sli_hba_setup() - */ - - fc_host_node_name(host) = wwn_to_u64(phba->fc_nodename.u.wwn); - fc_host_port_name(host) = wwn_to_u64(phba->fc_portname.u.wwn); - fc_host_supported_classes(host) = FC_COS_CLASS3; - - memset(fc_host_supported_fc4s(host), 0, - sizeof(fc_host_supported_fc4s(host))); - fc_host_supported_fc4s(host)[2] = 1; - fc_host_supported_fc4s(host)[7] = 1; - - lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(host)); - - fc_host_supported_speeds(host) = 0; - if (phba->lmt & LMT_10Gb) - fc_host_supported_speeds(host) |= FC_PORTSPEED_10GBIT; - if (phba->lmt & LMT_4Gb) - fc_host_supported_speeds(host) |= FC_PORTSPEED_4GBIT; - if (phba->lmt & LMT_2Gb) - fc_host_supported_speeds(host) |= FC_PORTSPEED_2GBIT; - if (phba->lmt & LMT_1Gb) - fc_host_supported_speeds(host) |= FC_PORTSPEED_1GBIT; - - fc_host_maxframe_size(host) = - ((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) | - (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb); - - /* This value is also unchanging */ - memset(fc_host_active_fc4s(host), 0, - sizeof(fc_host_active_fc4s(host))); - fc_host_active_fc4s(host)[2] = 1; - fc_host_active_fc4s(host)[7] = 1; + scsi_scan_host(host); - spin_lock_irq(phba->host->host_lock); - phba->fc_flag &= ~FC_LOADING; - spin_unlock_irq(phba->host->host_lock); return 0; out_free_irq: @@ -1648,11 +1706,6 @@ out_free_irq: phba->work_hba_events = 0; free_irq(phba->pcidev->irq, phba); pci_disable_msi(phba->pcidev); -out_free_sysfs_attr: - lpfc_free_sysfs_attr(phba); -out_remove_host: - fc_remove_host(phba->host); - scsi_remove_host(phba->host); out_kthread_stop: kthread_stop(phba->worker_thread); out_free_iocbq: @@ -1690,56 +1743,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev) { struct Scsi_Host *host = pci_get_drvdata(pdev); struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata; - unsigned long iflag; - - lpfc_free_sysfs_attr(phba); - - spin_lock_irqsave(phba->host->host_lock, iflag); - phba->fc_flag |= FC_UNLOADING; - - spin_unlock_irqrestore(phba->host->host_lock, iflag); - - fc_remove_host(phba->host); - scsi_remove_host(phba->host); - - kthread_stop(phba->worker_thread); - - /* - * Bring down the SLI Layer. This step disable all interrupts, - * clears the rings, discards all mailbox commands, and resets - * the HBA. - */ - lpfc_sli_hba_down(phba); - lpfc_sli_brdrestart(phba); - /* Release the irq reservation */ - free_irq(phba->pcidev->irq, phba); - pci_disable_msi(phba->pcidev); - - lpfc_cleanup(phba); - lpfc_stop_timer(phba); - phba->work_hba_events = 0; - - /* - * Call scsi_free before mem_free since scsi bufs are released to their - * corresponding pools here. - */ - lpfc_scsi_free(phba); - lpfc_mem_free(phba); - - /* Free resources associated with SLI2 interface */ - dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, - phba->slim2p, phba->slim2p_mapping); - - /* unmap adapter SLIM and Control Registers */ - iounmap(phba->ctrl_regs_memmap_p); - iounmap(phba->slim_memmap_p); - - pci_release_regions(phba->pcidev); - pci_disable_device(phba->pcidev); - - idr_remove(&lpfc_hba_index, phba->brd_no); - scsi_host_put(phba->host); + lpfc_remove_device(phba); pci_set_drvdata(pdev, NULL); } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index cc0f845..f09f3d2 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1351,6 +1351,8 @@ struct scsi_host_template lpfc_template = { .slave_alloc = lpfc_slave_alloc, .slave_configure = lpfc_slave_configure, .slave_destroy = lpfc_slave_destroy, + .scan_finished = lpfc_scan_finished, + .scan_start = lpfc_scan_start, .this_id = -1, .sg_tablesize = LPFC_SG_SEG_CNT, .cmd_per_lun = LPFC_CMD_PER_LUN, -- cgit v0.10.2 From b87eab38be141c16026cb830064d661ca705ad23 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:53:28 -0400 Subject: [SCSI] lpfc 8.1.12 : Added support for 8G speed and new HBAs Added support for 8G speed and new HBAs. Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 2605bd3..4d547b3 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -985,9 +985,10 @@ LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology"); # 1 = 1 Gigabaud # 2 = 2 Gigabaud # 4 = 4 Gigabaud -# Value range is [0,4]. Default value is 0. +# 8 = 8 Gigabaud +# Value range is [0,8]. Default value is 0. */ -LPFC_ATTR_R(link_speed, 0, 0, 4, "Select link speed"); +LPFC_ATTR_R(link_speed, 0, 0, 8, "Select link speed"); /* # lpfc_fcp_class: Determines FC class to use for the FCP protocol. @@ -1559,6 +1560,9 @@ lpfc_get_host_speed(struct Scsi_Host *shost) case LA_4GHZ_LINK: fc_host_speed(shost) = FC_PORTSPEED_4GBIT; break; + case LA_8GHZ_LINK: + fc_host_speed(shost) = FC_PORTSPEED_8GBIT; + break; default: fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; break; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index af81988..fb821ae 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1038,6 +1038,9 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode) case LA_4GHZ_LINK: ae->un.PortSpeed = HBA_PORTSPEED_4GBIT; break; + case LA_8GHZ_LINK: + ae->un.PortSpeed = HBA_PORTSPEED_8GBIT; + break; default: ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 0ebde24..3ba2a2d 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -723,6 +723,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) case LA_4GHZ_LINK: phba->fc_linkspeed = LA_4GHZ_LINK; break; + case LA_8GHZ_LINK: + phba->fc_linkspeed = LA_8GHZ_LINK; + break; default: phba->fc_linkspeed = LA_UNKNW_LINK; break; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index f79cb61..a06f950 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1078,6 +1078,8 @@ typedef struct { /* Start FireFly Register definitions */ #define PCI_VENDOR_ID_EMULEX 0x10df #define PCI_DEVICE_ID_FIREFLY 0x1ae5 +#define PCI_DEVICE_ID_SAT_SMB 0xf011 +#define PCI_DEVICE_ID_SAT_MID 0xf015 #define PCI_DEVICE_ID_RFLY 0xf095 #define PCI_DEVICE_ID_PFLY 0xf098 #define PCI_DEVICE_ID_LP101 0xf0a1 @@ -1089,6 +1091,9 @@ typedef struct { #define PCI_DEVICE_ID_NEPTUNE 0xf0f5 #define PCI_DEVICE_ID_NEPTUNE_SCSP 0xf0f6 #define PCI_DEVICE_ID_NEPTUNE_DCSP 0xf0f7 +#define PCI_DEVICE_ID_SAT 0xf100 +#define PCI_DEVICE_ID_SAT_SCSP 0xf111 +#define PCI_DEVICE_ID_SAT_DCSP 0xf112 #define PCI_DEVICE_ID_SUPERFLY 0xf700 #define PCI_DEVICE_ID_DRAGONFLY 0xf800 #define PCI_DEVICE_ID_CENTAUR 0xf900 @@ -1098,6 +1103,7 @@ typedef struct { #define PCI_DEVICE_ID_LP10000S 0xfc00 #define PCI_DEVICE_ID_LP11000S 0xfc10 #define PCI_DEVICE_ID_LPE11000S 0xfc20 +#define PCI_DEVICE_ID_SAT_S 0xfc40 #define PCI_DEVICE_ID_HELIOS 0xfd00 #define PCI_DEVICE_ID_HELIOS_SCSP 0xfd11 #define PCI_DEVICE_ID_HELIOS_DCSP 0xfd12 @@ -1118,6 +1124,7 @@ typedef struct { #define HELIOS_JEDEC_ID 0x0364 #define ZEPHYR_JEDEC_ID 0x0577 #define VIPER_JEDEC_ID 0x4838 +#define SATURN_JEDEC_ID 0x1004 #define JEDEC_ID_MASK 0x0FFFF000 #define JEDEC_ID_SHIFT 12 @@ -1565,7 +1572,7 @@ typedef struct { #define LINK_SPEED_1G 1 /* 1 Gigabaud */ #define LINK_SPEED_2G 2 /* 2 Gigabaud */ #define LINK_SPEED_4G 4 /* 4 Gigabaud */ -#define LINK_SPEED_8G 8 /* 4 Gigabaud */ +#define LINK_SPEED_8G 8 /* 8 Gigabaud */ #define LINK_SPEED_10G 16 /* 10 Gigabaud */ } INIT_LINK_VAR; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 7cb92c7..6ad25da 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -903,6 +903,24 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) m = (typeof(m)){"LPe11000-S", max_speed, "PCIe"}; break; + case PCI_DEVICE_ID_SAT: + m = (typeof(m)){"LPe12000", max_speed, "PCIe"}; + break; + case PCI_DEVICE_ID_SAT_MID: + m = (typeof(m)){"LPe1250", max_speed, "PCIe"}; + break; + case PCI_DEVICE_ID_SAT_SMB: + m = (typeof(m)){"LPe121", max_speed, "PCIe"}; + break; + case PCI_DEVICE_ID_SAT_DCSP: + m = (typeof(m)){"LPe12002-SP", max_speed, "PCIe"}; + break; + case PCI_DEVICE_ID_SAT_SCSP: + m = (typeof(m)){"LPe12000-SP", max_speed, "PCIe"}; + break; + case PCI_DEVICE_ID_SAT_S: + m = (typeof(m)){"LPe12000-S", max_speed, "PCIe"}; + break; default: m = (typeof(m)){ NULL }; break; @@ -1889,6 +1907,18 @@ static struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LPE11000S, PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_MID, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SMB, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_DCSP, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SCSP, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_S, + PCI_ANY_ID, PCI_ANY_ID, }, { 0 } }; diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 4d016c2..76d8de7 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -212,6 +212,7 @@ lpfc_init_link(struct lpfc_hba * phba, case LINK_SPEED_1G: case LINK_SPEED_2G: case LINK_SPEED_4G: + case LINK_SPEED_8G: mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; mb->un.varInitLnk.link_speed = linkspeed; -- cgit v0.10.2 From 9413afff8fc8c349aea35326824748d027f39db9 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:53:35 -0400 Subject: [SCSI] lpfc 8.1.12 : Update copyright year to 2007 Update copyright year to 2007 Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 913e08e..82e8f90 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 4d547b3..95fe77e 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index e4454bc..b8c2a88 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index fb821ae..34a9e3b 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 971b0f8..498059f 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index ddf7f22..638b3cd 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 3ba2a2d..61caa8d 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index a06f950..2623a9b 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 6ad25da..dcb4ba0 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 76d8de7..8041c3f 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index f03284a..b309841 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index f09f3d2..9a12d05 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 1508b3f..a1e7214 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index eb6a689..41c38d3 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * -- cgit v0.10.2 From 15061f23a134e1e92f430a1aeb37a73e4af2a2a9 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 25 Apr 2007 09:53:42 -0400 Subject: [SCSI] lpfc 8.1.12 : Change version number to 8.1.12 Change version number to 8.1.12 Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index a61ef3d1..92a9107 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2007 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -18,12 +18,12 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.1.11" +#define LPFC_DRIVER_VERSION "8.1.12" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ LPFC_DRIVER_VERSION -#define LPFC_COPYRIGHT "Copyright(c) 2004-2006 Emulex. All rights reserved." +#define LPFC_COPYRIGHT "Copyright(c) 2004-2007 Emulex. All rights reserved." #define DFC_API_VERSION "0.0.0" -- cgit v0.10.2 From 4797547778fd51e6ee929c5dd67ab3807898eb82 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 26 Apr 2007 00:35:16 -0700 Subject: [SCSI] qla4xxx: possible cleanups - make needlessly global code static - #if 0 unused functions Signed-off-by: Adrian Bunk Acked-by: Ravi Anand Signed-off-by: Andrew Morton Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c index 7b4e077..6437d024 100644 --- a/drivers/scsi/qla4xxx/ql4_dbg.c +++ b/drivers/scsi/qla4xxx/ql4_dbg.c @@ -8,6 +8,8 @@ #include "ql4_def.h" #include +#if 0 + static void qla4xxx_print_srb_info(struct srb * srb) { printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags); @@ -195,3 +197,5 @@ void qla4xxx_dump_buffer(void *b, uint32_t size) if (cnt % 16) printk(KERN_DEBUG "\n"); } + +#endif /* 0 */ diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index e021eb5..5b00cb0 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -43,8 +43,6 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, uint16_t *tcp_source_port_num, uint16_t *connection_id); -struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host * ha, - uint32_t fw_ddb_index); int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, dma_addr_t fw_ddb_entry_dma); @@ -55,18 +53,11 @@ void qla4xxx_get_crash_record(struct scsi_qla_host * ha); struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha); int qla4xxx_add_sess(struct ddb_entry *); void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry); -int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha, - uint16_t fw_ddb_index, - uint16_t connection_id, - uint16_t option); -int qla4xxx_clear_database_entry(struct scsi_qla_host * ha, - uint16_t fw_ddb_index); int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha); int qla4xxx_get_fw_version(struct scsi_qla_host * ha); void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha, uint32_t intr_status); int qla4xxx_init_rings(struct scsi_qla_host * ha); -void qla4xxx_dump_buffer(void *b, uint32_t size); struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index); void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb); int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha); diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index b907b06..6365df2 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -7,9 +7,8 @@ #include "ql4_def.h" -/* - * QLogic ISP4xxx Hardware Support Function Prototypes. - */ +static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, + uint32_t fw_ddb_index); static void ql4xxx_set_mac_number(struct scsi_qla_host *ha) { @@ -48,7 +47,8 @@ static void ql4xxx_set_mac_number(struct scsi_qla_host *ha) * This routine deallocates and unlinks the specified ddb_entry from the * adapter's **/ -void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry) +static void qla4xxx_free_ddb(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry) { /* Remove device entry from list */ list_del_init(&ddb_entry->list); @@ -370,9 +370,9 @@ static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha, * must be initialized prior to calling this routine * **/ -int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, - uint32_t fw_ddb_index) +static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry, + uint32_t fw_ddb_index) { struct dev_db_entry *fw_ddb_entry = NULL; dma_addr_t fw_ddb_entry_dma; @@ -450,8 +450,8 @@ int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha, * This routine allocates a ddb_entry, ititializes some values, and * inserts it into the ddb list. **/ -struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, - uint32_t fw_ddb_index) +static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha, + uint32_t fw_ddb_index) { struct ddb_entry *ddb_entry; diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c index d41ce38..a216a17 100644 --- a/drivers/scsi/qla4xxx/ql4_iocb.c +++ b/drivers/scsi/qla4xxx/ql4_iocb.c @@ -19,8 +19,8 @@ * - advances the request_in pointer * - checks for queue full **/ -int qla4xxx_get_req_pkt(struct scsi_qla_host *ha, - struct queue_entry **queue_entry) +static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha, + struct queue_entry **queue_entry) { uint16_t request_in; uint8_t status = QLA_SUCCESS; @@ -62,8 +62,8 @@ int qla4xxx_get_req_pkt(struct scsi_qla_host *ha, * * This routine issues a marker IOCB. **/ -int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, int lun) +static int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry, int lun) { struct marker_entry *marker_entry; unsigned long flags = 0; @@ -96,7 +96,7 @@ exit_send_marker: return status; } -struct continuation_t1_entry* qla4xxx_alloc_cont_entry( +static struct continuation_t1_entry* qla4xxx_alloc_cont_entry( struct scsi_qla_host *ha) { struct continuation_t1_entry *cont_entry; @@ -120,7 +120,7 @@ struct continuation_t1_entry* qla4xxx_alloc_cont_entry( return cont_entry; } -uint16_t qla4xxx_calc_request_entries(uint16_t dsds) +static uint16_t qla4xxx_calc_request_entries(uint16_t dsds) { uint16_t iocbs; @@ -133,9 +133,9 @@ uint16_t qla4xxx_calc_request_entries(uint16_t dsds) return iocbs; } -void qla4xxx_build_scsi_iocbs(struct srb *srb, - struct command_t3_entry *cmd_entry, - uint16_t tot_dsds) +static void qla4xxx_build_scsi_iocbs(struct srb *srb, + struct command_t3_entry *cmd_entry, + uint16_t tot_dsds) { struct scsi_qla_host *ha; uint16_t avail_dsds; diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 7f28657..f116ff9 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -20,9 +20,9 @@ * If outCount is 0, this routine completes successfully WITHOUT waiting * for the mailbox command to complete. **/ -int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, - uint8_t outCount, uint32_t *mbx_cmd, - uint32_t *mbx_sts) +static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, + uint8_t outCount, uint32_t *mbx_cmd, + uint32_t *mbx_sts) { int status = QLA_ERROR; uint8_t i; @@ -170,6 +170,8 @@ mbox_exit: } +#if 0 + /** * qla4xxx_issue_iocb - issue mailbox iocb command * @ha: adapter state pointer. @@ -243,6 +245,8 @@ int qla4xxx_clear_database_entry(struct scsi_qla_host * ha, return QLA_SUCCESS; } +#endif /* 0 */ + /** * qla4xxx_initialize_fw_cb - initializes firmware control block. * @ha: Pointer to host adapter structure. @@ -570,6 +574,7 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, return qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]); } +#if 0 int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha, uint16_t fw_ddb_index) { @@ -594,6 +599,7 @@ int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha, return status; } +#endif /* 0 */ /** * qla4xxx_get_crash_record - retrieves crash record. @@ -649,6 +655,7 @@ exit_get_crash_record: crash_record, crash_record_dma); } +#if 0 /** * qla4xxx_get_conn_event_log - retrieves connection event log * @ha: Pointer to host adapter structure. @@ -738,6 +745,7 @@ exit_get_event_log: dma_free_coherent(&ha->pdev->dev, event_log_size, event_log, event_log_dma); } +#endif /* 0 */ /** * qla4xxx_reset_lun - issues LUN Reset @@ -834,7 +842,8 @@ int qla4xxx_get_fw_version(struct scsi_qla_host * ha) return QLA_SUCCESS; } -int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr) +static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, + dma_addr_t dma_addr) { uint32_t mbox_cmd[MBOX_REG_COUNT]; uint32_t mbox_sts[MBOX_REG_COUNT]; @@ -855,7 +864,7 @@ int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr) return QLA_SUCCESS; } -int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index) +static int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index) { uint32_t mbox_cmd[MBOX_REG_COUNT]; uint32_t mbox_sts[MBOX_REG_COUNT]; diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 0bfddf8..da21f5f 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -14,7 +14,7 @@ /* * Driver version */ -char qla4xxx_version_str[40]; +static char qla4xxx_version_str[40]; /* * SRB allocation cache @@ -45,8 +45,7 @@ int ql4_mod_unload = 0; /* * SCSI host template entry points */ - -void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha); +static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha); /* * iSCSI template entry points @@ -1352,7 +1351,7 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) * At exit, the @ha's flags.enable_64bit_addressing set to indicated * supported addressing method. */ -void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) +static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) { int retval; @@ -1627,7 +1626,7 @@ static struct pci_device_id qla4xxx_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); -struct pci_driver qla4xxx_pci_driver = { +static struct pci_driver qla4xxx_pci_driver = { .name = DRIVER_NAME, .id_table = qla4xxx_pci_tbl, .probe = qla4xxx_probe_adapter, -- cgit v0.10.2 From d7a54e30d324b6f3b29a6cf2ff24c95b135013f5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 26 Apr 2007 09:38:01 -0400 Subject: [SCSI] sas_scsi_host: Convert to use the kthread API Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 897a5e2..b4b5269 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -23,6 +23,8 @@ * */ +#include + #include "sas_internal.h" #include @@ -184,7 +186,7 @@ static int sas_queue_up(struct sas_task *task) list_add_tail(&task->list, &core->task_queue); core->task_queue_size += 1; spin_unlock_irqrestore(&core->task_queue_lock, flags); - up(&core->queue_thread_sema); + wake_up_process(core->queue_thread); return 0; } @@ -819,7 +821,7 @@ static void sas_queue(struct sas_ha_struct *sas_ha) struct sas_internal *i = to_sas_internal(core->shost->transportt); spin_lock_irqsave(&core->task_queue_lock, flags); - while (!core->queue_thread_kill && + while (!kthread_should_stop() && !list_empty(&core->task_queue)) { can_queue = sas_ha->lldd_queue_size - core->task_queue_size; @@ -858,8 +860,6 @@ static void sas_queue(struct sas_ha_struct *sas_ha) spin_unlock_irqrestore(&core->task_queue_lock, flags); } -static DECLARE_COMPLETION(queue_th_comp); - /** * sas_queue_thread -- The Task Collector thread * @_sas_ha: pointer to struct sas_ha @@ -867,40 +867,33 @@ static DECLARE_COMPLETION(queue_th_comp); static int sas_queue_thread(void *_sas_ha) { struct sas_ha_struct *sas_ha = _sas_ha; - struct scsi_core *core = &sas_ha->core; - daemonize("sas_queue_%d", core->shost->host_no); current->flags |= PF_NOFREEZE; - complete(&queue_th_comp); - while (1) { - down_interruptible(&core->queue_thread_sema); + set_current_state(TASK_INTERRUPTIBLE); + schedule(); sas_queue(sas_ha); - if (core->queue_thread_kill) + if (kthread_should_stop()) break; } - complete(&queue_th_comp); - return 0; } int sas_init_queue(struct sas_ha_struct *sas_ha) { - int res; struct scsi_core *core = &sas_ha->core; spin_lock_init(&core->task_queue_lock); core->task_queue_size = 0; INIT_LIST_HEAD(&core->task_queue); - init_MUTEX_LOCKED(&core->queue_thread_sema); - res = kernel_thread(sas_queue_thread, sas_ha, 0); - if (res >= 0) - wait_for_completion(&queue_th_comp); - - return res < 0 ? res : 0; + core->queue_thread = kthread_run(sas_queue_thread, sas_ha, + "sas_queue_%d", core->shost->host_no); + if (IS_ERR(core->queue_thread)) + return PTR_ERR(core->queue_thread); + return 0; } void sas_shutdown_queue(struct sas_ha_struct *sas_ha) @@ -909,10 +902,7 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha) struct scsi_core *core = &sas_ha->core; struct sas_task *task, *n; - init_completion(&queue_th_comp); - core->queue_thread_kill = 1; - up(&core->queue_thread_sema); - wait_for_completion(&queue_th_comp); + kthread_stop(core->queue_thread); if (!list_empty(&core->task_queue)) SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n", diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index ad0182e..2e6bdc4 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -314,8 +314,7 @@ struct scsi_core { struct list_head task_queue; int task_queue_size; - struct semaphore queue_thread_sema; - int queue_thread_kill; + struct task_struct *queue_thread; }; struct sas_ha_event { -- cgit v0.10.2 From 970ea2941199f9c5f3b4faffd68e7e9a4505de8e Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 26 Apr 2007 16:00:06 -0500 Subject: [SCSI] ipr: Prevent overlapped adapter resets This patch fixes some scenarios where an ipr adapter could get reset overlapped, which could cause very long timeouts to occur, or PCI bus errors. Signed-off-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 2c7b77e..f7af86f 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -2635,8 +2635,13 @@ static ssize_t ipr_store_diagnostics(struct class_device *class_dev, if (!capable(CAP_SYS_ADMIN)) return -EACCES; - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + } + ioa_cfg->errors_logged = 0; ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL); @@ -2958,6 +2963,11 @@ static int ipr_update_ioa_ucode(struct ipr_ioa_cfg *ioa_cfg, unsigned long lock_flags; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + } if (ioa_cfg->ucode_sglist) { spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); @@ -7428,6 +7438,12 @@ static void __ipr_remove(struct pci_dev *pdev) ENTER; spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); + } + ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL); spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); @@ -7551,6 +7567,12 @@ static void ipr_shutdown(struct pci_dev *pdev) unsigned long lock_flags = 0; spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + while(ioa_cfg->in_reset_reload) { + spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); + wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); + spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); + } + ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL); spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); -- cgit v0.10.2 From 68c96e5960e6f4b0ce7cf6034f252294484f78a8 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 26 Apr 2007 16:00:07 -0500 Subject: [SCSI] ipr: Allow driver_data to be passed for dynamic ids Since driver_data for pci ids in the ipr driver is now just flags, we can allow these to be passed in from userspace for dynamic ids. Signed-off-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index f7af86f..818ebf3 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -7649,6 +7649,7 @@ static struct pci_driver ipr_driver = { .remove = ipr_remove, .shutdown = ipr_shutdown, .err_handler = &ipr_err_handler, + .dynids.use_driver_data = 1 }; /** -- cgit v0.10.2 From 6bb0417074e914e8d002df20c419e67732ae103e Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 26 Apr 2007 16:00:08 -0500 Subject: [SCSI] ipr: Handle UA on disk array following an adapter reset On certain ipr RAID adapters, which are capable of multi-initiator configurations, the disk array, or VSET, resources will be in a POR Unit Attention state following an adapter reset. In order for the midlayer to handle the UA, I must report a bus reset to the logical disk array bus at the end of an adapter reset. Signed-off-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 818ebf3..0724b58 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -5373,6 +5373,7 @@ static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd) ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb); } + scsi_report_bus_reset(ioa_cfg->host, IPR_VSET_BUS); dev_info(&ioa_cfg->pdev->dev, "IOA initialized.\n"); ioa_cfg->reset_retries = 0; -- cgit v0.10.2 From 8a048994f4be7d0b670a358cea7812c6d5232105 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 26 Apr 2007 16:00:10 -0500 Subject: [SCSI] ipr: Handle check condition status from disk array device On newer levels of microcode for ipr RAID adapters supporting multi-initiator configurations, the disk array, or VSET, resources are capable of generating a check condition. This patch prevents ipr from generating sense data in this scenario and retrieving it from the logical device instead. Signed-off-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 0724b58..d871dd3 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4666,18 +4666,19 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; struct ipr_resource_entry *res = scsi_cmd->device->hostdata; u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + u32 masked_ioasc = ioasc & IPR_IOASC_IOASC_MASK; if (!res) { ipr_scsi_eh_done(ipr_cmd); return; } - if (!ipr_is_gscsi(res)) + if (!ipr_is_gscsi(res) && masked_ioasc != IPR_IOASC_HW_DEV_BUS_STATUS) ipr_gen_sense(ipr_cmd); ipr_dump_ioasa(ioa_cfg, ipr_cmd, res); - switch (ioasc & IPR_IOASC_IOASC_MASK) { + switch (masked_ioasc) { case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST: if (ipr_is_naca_model(res)) scsi_cmd->result |= (DID_ABORT << 16); -- cgit v0.10.2 From 65f5647544960a68030352015d0b4a6234a818f8 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 26 Apr 2007 16:00:12 -0500 Subject: [SCSI] ipr: Handle IOA reset request In ipr dual adapter configurations, the ipr adapter firmware may require an adapter reset for various reasons. The reset is requested by the adapter firmware logging an error with an IOASC of 0x02048000. Add support to log this error, and reset the adapter. Signed-off-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index d871dd3..393eda1 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -206,6 +206,8 @@ struct ipr_error_table_t ipr_error_table[] = { "8009: Impending cache battery pack failure"}, {0x02040400, 0, 0, "34FF: Disk device format in progress"}, + {0x02048000, 0, IPR_DEFAULT_LOG_LEVEL, + "9070: IOA requested reset"}, {0x023F0000, 0, 0, "Synchronization required"}, {0x024E0000, 0, 0, @@ -1672,12 +1674,15 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd) struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + u32 fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc); list_del(&hostrcb->queue); list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); if (!ioasc) { ipr_handle_log_data(ioa_cfg, hostrcb); + if (fd_ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED) + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_ABBREV); } else if (ioasc != IPR_IOASC_IOA_WAS_RESET) { dev_err(&ioa_cfg->pdev->dev, "Host RCB failed with IOASC: 0x%08X\n", ioasc); @@ -6290,6 +6295,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) struct ipr_hostrcb *hostrcb; struct ipr_uc_sdt sdt; int rc, length; + u32 ioasc; mailbox = readl(ioa_cfg->ioa_mailbox); @@ -6322,9 +6328,13 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) (__be32 *)&hostrcb->hcam, min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32)); - if (!rc) + if (!rc) { ipr_handle_log_data(ioa_cfg, hostrcb); - else + ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc); + if (ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED && + ioa_cfg->sdt_state == GET_DUMP) + ioa_cfg->sdt_state = WAIT_FOR_DUMP; + } else ipr_unit_check_no_data(ioa_cfg); list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q); diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index bc53d7c..c7e045a 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -91,6 +91,7 @@ * IOASCs */ #define IPR_IOASC_NR_INIT_CMD_REQUIRED 0x02040200 +#define IPR_IOASC_NR_IOA_RESET_REQUIRED 0x02048000 #define IPR_IOASC_SYNC_REQUIRED 0x023f0000 #define IPR_IOASC_MED_DO_NOT_REALLOC 0x03110C00 #define IPR_IOASC_HW_SEL_TIMEOUT 0x04050000 -- cgit v0.10.2 From 22d2e402d1f671ca66919a36e04a650b735f4f0d Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 26 Apr 2007 16:00:13 -0500 Subject: [SCSI] ipr: Increase adapter operational timeout Increases the adapter operational timeout for some adapters that support dual controller configurations, since they may take longer to come ready. Signed-off-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 393eda1..d4e6dbf 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -7611,19 +7611,22 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = { { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, IPR_USE_LONG_TRANSOP_TIMEOUT }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT}, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, IPR_USE_LONG_TRANSOP_TIMEOUT }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0, 0 }, + PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0, + IPR_USE_LONG_TRANSOP_TIMEOUT }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575D, 0, 0, IPR_USE_LONG_TRANSOP_TIMEOUT }, -- cgit v0.10.2 From 8cf093e275d0d703d3e6c23725e340006082beec Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 26 Apr 2007 16:00:14 -0500 Subject: [SCSI] ipr: Improved dual adapter errors Formats ipr dual adapter errors so that they are more compact. Signed-off-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index d4e6dbf..d9f2083 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -953,6 +953,53 @@ static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd) } /** + * strip_and_pad_whitespace - Strip and pad trailing whitespace. + * @i: index into buffer + * @buf: string to modify + * + * This function will strip all trailing whitespace, pad the end + * of the string with a single space, and NULL terminate the string. + * + * Return value: + * new length of string + **/ +static int strip_and_pad_whitespace(int i, char *buf) +{ + while (i && buf[i] == ' ') + i--; + buf[i+1] = ' '; + buf[i+2] = '\0'; + return i + 2; +} + +/** + * ipr_log_vpd_compact - Log the passed extended VPD compactly. + * @prefix: string to print at start of printk + * @hostrcb: hostrcb pointer + * @vpd: vendor/product id/sn struct + * + * Return value: + * none + **/ +static void ipr_log_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb, + struct ipr_vpd *vpd) +{ + char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN + IPR_SERIAL_NUM_LEN + 3]; + int i = 0; + + memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN); + i = strip_and_pad_whitespace(IPR_VENDOR_ID_LEN - 1, buffer); + + memcpy(&buffer[i], vpd->vpids.product_id, IPR_PROD_ID_LEN); + i = strip_and_pad_whitespace(i + IPR_PROD_ID_LEN - 1, buffer); + + memcpy(&buffer[i], vpd->sn, IPR_SERIAL_NUM_LEN); + buffer[IPR_SERIAL_NUM_LEN + i] = '\0'; + + ipr_hcam_err(hostrcb, "%s VPID/SN: %s\n", prefix, buffer); +} + +/** * ipr_log_vpd - Log the passed VPD to the error log. * @vpd: vendor/product id/sn struct * @@ -976,6 +1023,23 @@ static void ipr_log_vpd(struct ipr_vpd *vpd) } /** + * ipr_log_ext_vpd_compact - Log the passed extended VPD compactly. + * @prefix: string to print at start of printk + * @hostrcb: hostrcb pointer + * @vpd: vendor/product id/sn/wwn struct + * + * Return value: + * none + **/ +static void ipr_log_ext_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb, + struct ipr_ext_vpd *vpd) +{ + ipr_log_vpd_compact(prefix, hostrcb, &vpd->vpd); + ipr_hcam_err(hostrcb, "%s WWN: %08X%08X\n", prefix, + be32_to_cpu(vpd->wwid[0]), be32_to_cpu(vpd->wwid[1])); +} + +/** * ipr_log_ext_vpd - Log the passed extended VPD to the error log. * @vpd: vendor/product id/sn/wwn struct * @@ -1289,10 +1353,11 @@ static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, error = &hostrcb->hcam.u.error.u.type_17_error; error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; + strstrip(error->failure_reason); - ipr_err("%s\n", error->failure_reason); - ipr_err("Remote Adapter VPD:\n"); - ipr_log_ext_vpd(&error->vpd); + ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason, + be32_to_cpu(hostrcb->hcam.u.error.prc)); + ipr_log_ext_vpd_compact("Remote IOA", hostrcb, &error->vpd); ipr_log_hex_data(ioa_cfg, error->data, be32_to_cpu(hostrcb->hcam.length) - (offsetof(struct ipr_hostrcb_error, u) + @@ -1314,10 +1379,11 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, error = &hostrcb->hcam.u.error.u.type_07_error; error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; + strstrip(error->failure_reason); - ipr_err("%s\n", error->failure_reason); - ipr_err("Remote Adapter VPD:\n"); - ipr_log_vpd(&error->vpd); + ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason, + be32_to_cpu(hostrcb->hcam.u.error.prc)); + ipr_log_vpd_compact("Remote IOA", hostrcb, &error->vpd); ipr_log_hex_data(ioa_cfg, error->data, be32_to_cpu(hostrcb->hcam.length) - (offsetof(struct ipr_hostrcb_error, u) + -- cgit v0.10.2 From ac09c349080008fdd54a15616a1b14771772d867 Mon Sep 17 00:00:00 2001 From: Brian King Date: Thu, 26 Apr 2007 16:00:16 -0500 Subject: [SCSI] ipr: Enable multi-initator RAID support Enables multi-initiator support on ipr RAID adapters that support it. Signed-off-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index d9f2083..b15dfcb 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -92,6 +92,7 @@ static unsigned int ipr_fastfail = 0; static unsigned int ipr_transop_timeout = 0; static unsigned int ipr_enable_cache = 1; static unsigned int ipr_debug = 0; +static unsigned int ipr_dual_ioa_raid = 1; static DEFINE_SPINLOCK(ipr_driver_lock); /* This table describes the differences between DMA controller chips */ @@ -158,6 +159,8 @@ module_param_named(enable_cache, ipr_enable_cache, int, 0); MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)"); module_param_named(debug, ipr_debug, int, 0); MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)"); +module_param_named(dual_ioa_raid, ipr_dual_ioa_raid, int, 0); +MODULE_PARM_DESC(dual_ioa_raid, "Enable dual adapter RAID support. Set to 1 to enable. (default: 1)"); MODULE_LICENSE("GPL"); MODULE_VERSION(IPR_DRIVER_VERSION); @@ -5882,6 +5885,94 @@ static int ipr_ioafp_mode_sense_page28(struct ipr_cmnd *ipr_cmd) } /** + * ipr_ioafp_mode_select_page24 - Issue Mode Select to IOA + * @ipr_cmd: ipr command struct + * + * This function enables dual IOA RAID support if possible. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_mode_select_page24(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_mode_pages *mode_pages = &ioa_cfg->vpd_cbs->mode_pages; + struct ipr_mode_page24 *mode_page; + int length; + + ENTER; + mode_page = ipr_get_mode_page(mode_pages, 0x24, + sizeof(struct ipr_mode_page24)); + + if (mode_page) + mode_page->flags |= IPR_ENABLE_DUAL_IOA_AF; + + length = mode_pages->hdr.length + 1; + mode_pages->hdr.length = 0; + + ipr_build_mode_select(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), 0x11, + ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages), + length); + + ipr_cmd->job_step = ipr_ioafp_mode_sense_page28; + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_reset_mode_sense_page24_failed - Handle failure of IOAFP mode sense + * @ipr_cmd: ipr command struct + * + * This function handles the failure of a Mode Sense to the IOAFP. + * Some adapters do not handle all mode pages. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_reset_mode_sense_page24_failed(struct ipr_cmnd *ipr_cmd) +{ + u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc); + + if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) { + ipr_cmd->job_step = ipr_ioafp_mode_sense_page28; + return IPR_RC_JOB_CONTINUE; + } + + return ipr_reset_cmd_failed(ipr_cmd); +} + +/** + * ipr_ioafp_mode_sense_page24 - Issue Page 24 Mode Sense to IOA + * @ipr_cmd: ipr command struct + * + * This function send a mode sense to the IOA to retrieve + * the IOA Advanced Function Control mode page. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_mode_sense_page24(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + + ENTER; + ipr_build_mode_sense(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), + 0x24, ioa_cfg->vpd_cbs_dma + + offsetof(struct ipr_misc_cbs, mode_pages), + sizeof(struct ipr_mode_pages)); + + ipr_cmd->job_step = ipr_ioafp_mode_select_page24; + ipr_cmd->job_step_failed = ipr_reset_mode_sense_page24_failed; + + ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); + + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** * ipr_init_res_table - Initialize the resource table * @ipr_cmd: ipr command struct * @@ -5949,7 +6040,10 @@ static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd) } } - ipr_cmd->job_step = ipr_ioafp_mode_sense_page28; + if (ioa_cfg->dual_raid && ipr_dual_ioa_raid) + ipr_cmd->job_step = ipr_ioafp_mode_sense_page24; + else + ipr_cmd->job_step = ipr_ioafp_mode_sense_page28; LEAVE; return IPR_RC_JOB_CONTINUE; @@ -5971,8 +6065,11 @@ static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd) struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl; struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data; + struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap; ENTER; + if (cap->cap & IPR_CAP_DUAL_IOA_RAID) + ioa_cfg->dual_raid = 1; dev_info(&ioa_cfg->pdev->dev, "Adapter firmware version: %02X%02X%02X%02X\n", ucode_vpd->major_release, ucode_vpd->card_type, ucode_vpd->minor_release[0], ucode_vpd->minor_release[1]); @@ -6056,6 +6153,37 @@ static int ipr_inquiry_page_supported(struct ipr_inquiry_page0 *page0, u8 page) } /** + * ipr_ioafp_cap_inquiry - Send a Page 0xD0 Inquiry to the adapter. + * @ipr_cmd: ipr command struct + * + * This function sends a Page 0xD0 inquiry to the adapter + * to retrieve adapter capabilities. + * + * Return value: + * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN + **/ +static int ipr_ioafp_cap_inquiry(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data; + struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap; + + ENTER; + ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg; + memset(cap, 0, sizeof(*cap)); + + if (ipr_inquiry_page_supported(page0, 0xD0)) { + ipr_ioafp_inquiry(ipr_cmd, 1, 0xD0, + ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, cap), + sizeof(struct ipr_inquiry_cap)); + return IPR_RC_JOB_RETURN; + } + + LEAVE; + return IPR_RC_JOB_CONTINUE; +} + +/** * ipr_ioafp_page3_inquiry - Send a Page 3 Inquiry to the adapter. * @ipr_cmd: ipr command struct * @@ -6075,7 +6203,7 @@ static int ipr_ioafp_page3_inquiry(struct ipr_cmnd *ipr_cmd) if (!ipr_inquiry_page_supported(page0, 1)) ioa_cfg->cache_state = CACHE_NONE; - ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg; + ipr_cmd->job_step = ipr_ioafp_cap_inquiry; ipr_ioafp_inquiry(ipr_cmd, 1, 3, ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page3_data), @@ -6679,12 +6807,14 @@ static int ipr_reset_shutdown_ioa(struct ipr_cmnd *ipr_cmd) ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN; ipr_cmd->ioarcb.cmd_pkt.cdb[1] = shutdown_type; - if (shutdown_type == IPR_SHUTDOWN_ABBREV) - timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT; + if (shutdown_type == IPR_SHUTDOWN_NORMAL) + timeout = IPR_SHUTDOWN_TIMEOUT; else if (shutdown_type == IPR_SHUTDOWN_PREPARE_FOR_NORMAL) timeout = IPR_INTERNAL_TIMEOUT; + else if (ioa_cfg->dual_raid && ipr_dual_ioa_raid) + timeout = IPR_DUAL_IOA_ABBR_SHUTDOWN_TO; else - timeout = IPR_SHUTDOWN_TIMEOUT; + timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT; ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, timeout); diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index c7e045a..daa96ee 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -37,8 +37,8 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.3.2" -#define IPR_DRIVER_DATE "(March 23, 2007)" +#define IPR_DRIVER_VERSION "2.4.0" +#define IPR_DRIVER_DATE "(April 24, 2007)" /* * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding @@ -180,6 +180,7 @@ #define IPR_SHUTDOWN_TIMEOUT (ipr_fastfail ? 60 * HZ : 10 * 60 * HZ) #define IPR_VSET_RW_TIMEOUT (ipr_fastfail ? 30 * HZ : 2 * 60 * HZ) #define IPR_ABBREV_SHUTDOWN_TIMEOUT (10 * HZ) +#define IPR_DUAL_IOA_ABBR_SHUTDOWN_TO (2 * 60 * HZ) #define IPR_DEVICE_RESET_TIMEOUT (ipr_fastfail ? 10 * HZ : 30 * HZ) #define IPR_CANCEL_ALL_TIMEOUT (ipr_fastfail ? 10 * HZ : 30 * HZ) #define IPR_ABORT_TASK_TIMEOUT (ipr_fastfail ? 10 * HZ : 30 * HZ) @@ -603,6 +604,12 @@ struct ipr_mode_page28 { struct ipr_dev_bus_entry bus[0]; }__attribute__((packed)); +struct ipr_mode_page24 { + struct ipr_mode_page_hdr hdr; + u8 flags; +#define IPR_ENABLE_DUAL_IOA_AF 0x80 +}__attribute__((packed)); + struct ipr_ioa_vpd { struct ipr_std_inq_data std_inq_data; u8 ascii_part_num[12]; @@ -625,6 +632,19 @@ struct ipr_inquiry_page3 { u8 patch_number[4]; }__attribute__((packed)); +struct ipr_inquiry_cap { + u8 peri_qual_dev_type; + u8 page_code; + u8 reserved1; + u8 page_length; + u8 ascii_len; + u8 reserved2; + u8 sis_version[2]; + u8 cap; +#define IPR_CAP_DUAL_IOA_RAID 0x80 + u8 reserved3[15]; +}__attribute__((packed)); + #define IPR_INQUIRY_PAGE0_ENTRIES 20 struct ipr_inquiry_page0 { u8 peri_qual_dev_type; @@ -963,6 +983,7 @@ struct ipr_misc_cbs { struct ipr_ioa_vpd ioa_vpd; struct ipr_inquiry_page0 page0_data; struct ipr_inquiry_page3 page3_data; + struct ipr_inquiry_cap cap; struct ipr_mode_pages mode_pages; struct ipr_supported_device supp_dev; }; @@ -1069,6 +1090,7 @@ struct ipr_ioa_cfg { u8 allow_cmds:1; u8 allow_ml_add_del:1; u8 needs_hard_reset:1; + u8 dual_raid:1; enum ipr_cache_state cache_state; u16 type; /* CCIN of the card */ -- cgit v0.10.2 From 92740b24ce6ddac6534fae985aab602548692186 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 27 Apr 2007 11:53:17 -0400 Subject: [SCSI] fc_transport: make all rports wait dev_loss_tmo before removing them Per the comment in the change - it's not always prudent to immediately remove the rport upon first notice of a disconnect. Make all rports wait dev_loss_tmo before being deleted (and each could have a separate dev_loss_tmo value). The original post was: http://marc.info/?l=linux-scsi&m=117392196006703&w=2 The repost contains the following changes: - Bug fix in fc_starget_delete(). Dev_loss_tmo_callbk() was called prior to tearing down the target. The callback is to be the last thing called, as it tells the LLDD that the rport is completely finished and can be torn down. Rework so that terminate_rport_io() is called to terminate the outstanding io. Isolated work so it's is simply "starget" work. - Fix holes in original patch. There were code paths that did not expect the dev_loss_tmo timer to be running for the non-fcp rports. - Bug Fix: the transport wasn't protecting against a LLDD calling fc_remote_port_delete() back-to-back. Thus, the dev_loss_tmo timer could be restarted such that it fires after the rport had been deleted. Validate rport state before starting the timer. Signed-off-by: James Smart Signed-off-by: James Bottomley diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 14c4f06..b4d1ece 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -1718,31 +1718,12 @@ fc_starget_delete(struct work_struct *work) struct fc_rport *rport = container_of(work, struct fc_rport, stgt_delete_work); struct Scsi_Host *shost = rport_to_shost(rport); - unsigned long flags; struct fc_internal *i = to_fc_internal(shost->transportt); - /* - * Involve the LLDD if possible. All io on the rport is to - * be terminated, either as part of the dev_loss_tmo callback - * processing, or via the terminate_rport_io function. - */ - if (i->f->dev_loss_tmo_callbk) - i->f->dev_loss_tmo_callbk(rport); - else if (i->f->terminate_rport_io) + /* Involve the LLDD if possible to terminate all io on the rport. */ + if (i->f->terminate_rport_io) i->f->terminate_rport_io(rport); - spin_lock_irqsave(shost->host_lock, flags); - if (rport->flags & FC_RPORT_DEVLOSS_PENDING) { - spin_unlock_irqrestore(shost->host_lock, flags); - if (!cancel_delayed_work(&rport->fail_io_work)) - fc_flush_devloss(shost); - if (!cancel_delayed_work(&rport->dev_loss_work)) - fc_flush_devloss(shost); - spin_lock_irqsave(shost->host_lock, flags); - rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; - } - spin_unlock_irqrestore(shost->host_lock, flags); - scsi_remove_target(&rport->dev); } @@ -1760,6 +1741,7 @@ fc_rport_final_delete(struct work_struct *work) struct device *dev = &rport->dev; struct Scsi_Host *shost = rport_to_shost(rport); struct fc_internal *i = to_fc_internal(shost->transportt); + unsigned long flags; /* * if a scan is pending, flush the SCSI Host work_q so that @@ -1768,13 +1750,37 @@ fc_rport_final_delete(struct work_struct *work) if (rport->flags & FC_RPORT_SCAN_PENDING) scsi_flush_work(shost); + /* involve the LLDD to terminate all pending i/o */ + if (i->f->terminate_rport_io) + i->f->terminate_rport_io(rport); + + /* + * Cancel any outstanding timers. These should really exist + * only when rmmod'ing the LLDD and we're asking for + * immediate termination of the rports + */ + spin_lock_irqsave(shost->host_lock, flags); + if (rport->flags & FC_RPORT_DEVLOSS_PENDING) { + spin_unlock_irqrestore(shost->host_lock, flags); + if (!cancel_delayed_work(&rport->fail_io_work)) + fc_flush_devloss(shost); + if (!cancel_delayed_work(&rport->dev_loss_work)) + fc_flush_devloss(shost); + spin_lock_irqsave(shost->host_lock, flags); + rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; + } + spin_unlock_irqrestore(shost->host_lock, flags); + /* Delete SCSI target and sdevs */ if (rport->scsi_target_id != -1) fc_starget_delete(&rport->stgt_delete_work); - else if (i->f->dev_loss_tmo_callbk) + + /* + * Notify the driver that the rport is now dead. The LLDD will + * also guarantee that any communication to the rport is terminated + */ + if (i->f->dev_loss_tmo_callbk) i->f->dev_loss_tmo_callbk(rport); - else if (i->f->terminate_rport_io) - i->f->terminate_rport_io(rport); transport_remove_device(dev); device_del(dev); @@ -1963,8 +1969,6 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, } if (match) { - struct delayed_work *work = - &rport->dev_loss_work; memcpy(&rport->node_name, &ids->node_name, sizeof(rport->node_name)); @@ -1982,46 +1986,61 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, fci->f->dd_fcrport_size); /* - * If we were blocked, we were a target. - * If no longer a target, we leave the timer - * running in case the port changes roles - * prior to the timer expiring. If the timer - * fires, the target will be torn down. + * If we were not a target, cancel the + * io terminate and rport timers, and + * we're done. + * + * If we were a target, but our new role + * doesn't indicate a target, leave the + * timers running expecting the role to + * change as the target fully logs in. If + * it doesn't, the target will be torn down. + * + * If we were a target, and our role shows + * we're still a target, cancel the timers + * and kick off a scan. */ - if (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET)) - return rport; - /* restart the target */ + /* was a target, not in roles */ + if ((rport->scsi_target_id != -1) && + (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET))) + return rport; /* - * Stop the target timers first. Take no action - * on the del_timer failure as the state - * machine state change will validate the - * transaction. + * Stop the fail io and dev_loss timers. + * If they flush, the port_state will + * be checked and will NOOP the function. */ if (!cancel_delayed_work(&rport->fail_io_work)) fc_flush_devloss(shost); - if (!cancel_delayed_work(work)) + if (!cancel_delayed_work(&rport->dev_loss_work)) fc_flush_devloss(shost); spin_lock_irqsave(shost->host_lock, flags); rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; - /* initiate a scan of the target */ - rport->flags |= FC_RPORT_SCAN_PENDING; - scsi_queue_work(shost, &rport->scan_work); - - spin_unlock_irqrestore(shost->host_lock, flags); - - scsi_target_unblock(&rport->dev); + /* if target, initiate a scan */ + if (rport->scsi_target_id != -1) { + rport->flags |= FC_RPORT_SCAN_PENDING; + scsi_queue_work(shost, + &rport->scan_work); + spin_unlock_irqrestore(shost->host_lock, + flags); + scsi_target_unblock(&rport->dev); + } else + spin_unlock_irqrestore(shost->host_lock, + flags); return rport; } } } - /* Search the bindings array */ + /* + * Search the bindings array + * Note: if never a FCP target, you won't be on this list + */ if (fc_host->tgtid_bind_type != FC_TGTID_BIND_NONE) { /* search for a matching consistent binding */ @@ -2158,15 +2177,24 @@ fc_remote_port_delete(struct fc_rport *rport) spin_lock_irqsave(shost->host_lock, flags); - /* If no scsi target id mapping, delete it */ - if (rport->scsi_target_id == -1) { - list_del(&rport->peers); - rport->port_state = FC_PORTSTATE_DELETED; - fc_queue_work(shost, &rport->rport_delete_work); + if (rport->port_state != FC_PORTSTATE_ONLINE) { spin_unlock_irqrestore(shost->host_lock, flags); return; } + /* + * In the past, we if this was not an FCP-Target, we would + * unconditionally just jump to deleting the rport. + * However, rports can be used as node containers by the LLDD, + * and its not appropriate to just terminate the rport at the + * first sign of a loss in connectivity. The LLDD may want to + * send ELS traffic to re-validate the login. If the rport is + * immediately deleted, it makes it inappropriate for a node + * container. + * So... we now unconditionally wait dev_loss_tmo before + * destroying an rport. + */ + rport->port_state = FC_PORTSTATE_BLOCKED; rport->flags |= FC_RPORT_DEVLOSS_PENDING; @@ -2263,11 +2291,11 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) EXPORT_SYMBOL(fc_remote_port_rolechg); /** - * fc_timeout_deleted_rport - Timeout handler for a deleted remote port that - * was a SCSI target (thus was blocked), and failed - * to return in the alloted time. + * fc_timeout_deleted_rport - Timeout handler for a deleted remote port, + * which we blocked, and has now failed to return + * in the allotted time. * - * @work: rport target that failed to reappear in the alloted time. + * @work: rport target that failed to reappear in the allotted time. **/ static void fc_timeout_deleted_rport(struct work_struct *work) @@ -2283,10 +2311,12 @@ fc_timeout_deleted_rport(struct work_struct *work) rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; /* - * If the port is ONLINE, then it came back. Validate it's still an - * FCP target. If not, tear down the scsi_target on it. + * If the port is ONLINE, then it came back. If it was a SCSI + * target, validate it still is. If not, tear down the + * scsi_target on it. */ if ((rport->port_state == FC_PORTSTATE_ONLINE) && + (rport->scsi_target_id != -1) && !(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { dev_printk(KERN_ERR, &rport->dev, "blocked FC remote port time out: no longer" @@ -2297,18 +2327,24 @@ fc_timeout_deleted_rport(struct work_struct *work) return; } + /* NOOP state - we're flushing workq's */ if (rport->port_state != FC_PORTSTATE_BLOCKED) { spin_unlock_irqrestore(shost->host_lock, flags); dev_printk(KERN_ERR, &rport->dev, - "blocked FC remote port time out: leaving target alone\n"); + "blocked FC remote port time out: leaving" + " rport%s alone\n", + (rport->scsi_target_id != -1) ? " and starget" : ""); return; } - if (fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) { + if ((fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) || + (rport->scsi_target_id == -1)) { list_del(&rport->peers); rport->port_state = FC_PORTSTATE_DELETED; dev_printk(KERN_ERR, &rport->dev, - "blocked FC remote port time out: removing target\n"); + "blocked FC remote port time out: removing" + " rport%s\n", + (rport->scsi_target_id != -1) ? " and starget" : ""); fc_queue_work(shost, &rport->rport_delete_work); spin_unlock_irqrestore(shost->host_lock, flags); return; -- cgit v0.10.2 From a6bcbc2f5ddd6de8a0e08ea3871585abcc82ecd6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 30 Apr 2007 00:05:48 +0200 Subject: [SCSI] deprecate the old NCR53C9x driver Now that we have the much better esp_scsi driver and low level drivers are easy to port over deprecate the old NCR53C9x driver. I've Cc'ed the m68k and mips lists because all but one bus glues are for these platforms. Chances stand bad for the remaining driver, mca_53c9x which hasn't gotten any non-trivial update since it was merge in late 2.1.x and whos maintainers mail address bounces. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 5f96cb3..94fd03f 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -51,6 +51,15 @@ Who: Dan Dennedy , Stefan Richter --------------------------- +What: old NCR53C9x driver +When: October 2007 +Why: Replaced by the much better esp_scsi driver. Actual low-level + driver can ported over almost trivially. +Who: David Miller + Christoph Hellwig + +--------------------------- + What: Video4Linux API 1 ioctls and video_decoder.h from Video devices. When: December 2006 Why: V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6 -- cgit v0.10.2 From 473b1e8ed2e4f545de22e58c8c073471b18459e8 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 2 May 2007 10:44:11 -0500 Subject: [SCSI] ipr: Better handle adapter boot time errors If an ipr adapter encounters an adapter error requiring an adapter reset to recover from prior to driver load time, the error will be ignored and recovery will not happen until the initial timeout occurs waiting for the firmware to come ready, which means a five minute timeout. Fix is to read the interrupt register before clearing any of the interrupts at probe time. Signed-off-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index b15dfcb..101e519 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -7444,7 +7444,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, unsigned long ipr_regs_pci; void __iomem *ipr_regs; int rc = PCIBIOS_SUCCESSFUL; - volatile u32 mask, uproc; + volatile u32 mask, uproc, interrupts; ENTER; @@ -7551,9 +7551,14 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, * the card is in an unknown state and needs a hard reset */ mask = readl(ioa_cfg->regs.sense_interrupt_mask_reg); + interrupts = readl(ioa_cfg->regs.sense_interrupt_reg); uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg); if ((mask & IPR_PCII_HRRQ_UPDATED) == 0 || (uproc & IPR_UPROCI_RESET_ALERT)) ioa_cfg->needs_hard_reset = 1; + if (interrupts & IPR_PCII_ERROR_INTERRUPTS) + ioa_cfg->needs_hard_reset = 1; + if (interrupts & IPR_PCII_IOA_UNIT_CHECKED) + ioa_cfg->ioa_unit_checked = 1; ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); rc = request_irq(pdev->irq, ipr_isr, IRQF_SHARED, IPR_NAME, ioa_cfg); -- cgit v0.10.2 From 860bfecf71495fc2b82c878958c97b0b6b601626 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 4 May 2007 22:57:37 +0200 Subject: [SCSI] tmscsim: remove long dead DMA_INT DMA_INT code is disabled since 1998, remove it to prepare for further cleanup. Signed-off-by: G. Liakhovetski Signed-off-by: James Bottomley diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 3158949..bc0a007 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -625,70 +625,6 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr return 0; } -//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/ -#define DMA_INT 0 - -#if DMA_INT -/* This is similar to AM53C974.c ... */ -static u8 -dc390_dma_intr (struct dc390_acb* pACB) -{ - struct dc390_srb* pSRB; - u8 dstate; - DEBUG0(u16 pstate; struct pci_dev *pdev = pACB->pdev); - - DEBUG0(pci_read_config_word(pdev, PCI_STATUS, &pstate)); - DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\ - { printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \ - pci_write_config_word(pdev, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));}); - - dstate = DC390_read8 (DMA_Status); - - if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate; - else pSRB = pACB->pActiveDCB->pActiveSRB; - - if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT)) - { - printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate); - return dstate; - } - if (dstate & DMA_XFER_DONE) - { - u32 residual, xferCnt; int ctr = 6000000; - if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION)) - { - do - { - DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n")); - dstate = DC390_read8 (DMA_Status); - residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 | - DC390_read8 (CtcReg_High) << 16; - residual += DC390_read8 (Current_Fifo) & 0x1f; - } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr); - if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); - /* residual = ... */ - } - else - residual = 0; - - /* ??? */ - - xferCnt = pSRB->SGToBeXferLen - residual; - pSRB->SGBusAddr += xferCnt; - pSRB->TotalXferredLen += xferCnt; - pSRB->SGToBeXferLen = residual; -# ifdef DC390_DEBUG0 - printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", - (unsigned int)residual, (unsigned int)xferCnt); -# endif - - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); - } - dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24; - return dstate; -} -#endif - static void __inline__ dc390_InvalidCmd(struct dc390_acb* pACB) @@ -708,9 +644,6 @@ DC390_Interrupt(void *dev_id) u8 phase; void (*stateV)( struct dc390_acb*, struct dc390_srb*, u8 *); u8 istate, istatus; -#if DMA_INT - u8 dstatus; -#endif sstatus = DC390_read8 (Scsi_Status); if( !(sstatus & INTERRUPT) ) @@ -718,22 +651,9 @@ DC390_Interrupt(void *dev_id) DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus)); -#if DMA_INT - spin_lock_irq(pACB->pScsiHost->host_lock); - dstatus = dc390_dma_intr (pACB); - spin_unlock_irq(pACB->pScsiHost->host_lock); - - DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus)); - if (! (dstatus & SCSI_INTERRUPT)) - { - DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n")); - return IRQ_NONE; - } -#else //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT); //dstatus = DC390_read8 (DMA_Status); //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT); -#endif spin_lock_irq(pACB->pScsiHost->host_lock); @@ -879,7 +799,7 @@ dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) } if ((*psstatus & 7) != SCSI_DATA_OUT) { - DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); } } @@ -924,7 +844,7 @@ dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) + ((unsigned long) DC390_read8 (CtcReg_Low))); DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%i,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen)); - DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); pSRB->TotalXferredLen += pSRB->SGToBeXferLen; pSRB->SGIndex++; @@ -973,7 +893,7 @@ din_1: } /* It seems a DMA Blast abort isn't that bad ... */ if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n"); - //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24; DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval)); @@ -1013,7 +933,7 @@ din_1: if ((*psstatus & 7) != SCSI_DATA_IN) { DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); } } @@ -1391,7 +1311,7 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir) if( pSRB->SGIndex < pSRB->SGcount ) { - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */); + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); if( !pSRB->SGToBeXferLen ) { psgl = pSRB->pSegmentList; @@ -1410,12 +1330,12 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir) DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen); DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr); - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */ + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); pSRB->SRBState = SRB_DATA_XFER; DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD); - DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); + DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir); //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT)); //DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status))); //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT)); @@ -1436,8 +1356,8 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir) pSRB->SRBState |= SRB_XFERPAD; DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE); /* - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT; - DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); + DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir); */ } } -- cgit v0.10.2 From 46e5ba2b644d1c7be1253ec32e7cd6ab1dcdf790 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 4 May 2007 22:59:40 +0200 Subject: [SCSI] tmscsim: remove bogus endianness conversions cpu_to_le32 endianness conversions in tmscsim.c, followed by arithmetic operations don't look correct. Besides, {in,out}[wl] already perform the necessary conversions. Further, bus addresses of request buffers are guaranteed to be (mapped) under 4G by current scsi- and block-layer defaults. This could be explicitly enforced by using blk_queue_bounce_limit(), which, however, doesn't seem to be the common practice among SCSI drivers. Signed-off-by: G. Liakhovetski Signed-off-by: James Bottomley diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index bc0a007..12d8fea 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -778,8 +778,8 @@ dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) pSRB->pSegmentList++; psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl))); - pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl)); + pSRB->SGBusAddr = sg_dma_address(psgl); + pSRB->SGToBeXferLen = sg_dma_len(psgl); } else pSRB->SGToBeXferLen = 0; @@ -842,7 +842,7 @@ dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) DEBUG1(ResidCnt = ((unsigned long) DC390_read8 (CtcReg_High) << 16) \ + ((unsigned long) DC390_read8 (CtcReg_Mid) << 8) \ + ((unsigned long) DC390_read8 (CtcReg_Low))); - DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%i,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen)); + DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%u,ToBeXfer=%lu),", ResidCnt, pSRB->SGToBeXferLen)); DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); @@ -853,8 +853,8 @@ dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) pSRB->pSegmentList++; psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl))); - pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl)); + pSRB->SGBusAddr = sg_dma_address(psgl); + pSRB->SGToBeXferLen = sg_dma_len(psgl); } else pSRB->SGToBeXferLen = 0; @@ -921,11 +921,12 @@ din_1: ptr = (u8 *) bus_to_virt( pSRB->SGBusAddr ); *ptr = bval; - pSRB->SGBusAddr++; xferCnt++; + pSRB->SGBusAddr++; + xferCnt++; pSRB->TotalXferredLen++; pSRB->SGToBeXferLen--; } - DEBUG1(printk (KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\ + DEBUG1(printk (KERN_DEBUG "Xfered: %lu, Total: %lu, Remaining: %lu\n", xferCnt,\ pSRB->TotalXferredLen, pSRB->SGToBeXferLen)); } @@ -1157,14 +1158,14 @@ dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB) { pSRB->pSegmentList++; psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl))); - pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl)); + pSRB->SGBusAddr = sg_dma_address(psgl); + pSRB->SGToBeXferLen = sg_dma_len(psgl); } else pSRB->SGToBeXferLen = 0; } - pSRB->SGToBeXferLen -= (pSRB->Saved_Ptr - pSRB->TotalXferredLen); - pSRB->SGBusAddr += (pSRB->Saved_Ptr - pSRB->TotalXferredLen); + pSRB->SGToBeXferLen -= pSRB->Saved_Ptr - pSRB->TotalXferredLen; + pSRB->SGBusAddr += pSRB->Saved_Ptr - pSRB->TotalXferredLen; printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n", pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr); @@ -1315,8 +1316,8 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir) if( !pSRB->SGToBeXferLen ) { psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl))); - pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl)); + pSRB->SGBusAddr = sg_dma_address(psgl); + pSRB->SGToBeXferLen = sg_dma_len(psgl); DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.")); } lval = pSRB->SGToBeXferLen; diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h index 9b66fa8..c3d8c80 100644 --- a/drivers/scsi/tmscsim.h +++ b/drivers/scsi/tmscsim.h @@ -19,14 +19,6 @@ #define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */ -#define pci_dma_lo32(a) (a & 0xffffffff) - -typedef u8 UCHAR; /* 8 bits */ -typedef u16 USHORT; /* 16 bits */ -typedef u32 UINT; /* 32 bits */ -typedef unsigned long ULONG; /* 32/64 bits */ - - /* ;----------------------------------------------------------------------- ; SCSI Request Block @@ -43,7 +35,9 @@ struct scatterlist *pSegmentList; struct scatterlist Segmentx; /* make a one entry of S/G list table */ -unsigned long SGBusAddr; /*;a segment starting address as seen by AM53C974A*/ +unsigned long SGBusAddr; /*;a segment starting address as seen by AM53C974A + in CPU endianness. We're only getting 32-bit bus + addresses by default */ unsigned long SGToBeXferLen; /*; to be xfer length */ unsigned long TotalXferredLen; unsigned long SavedTotXLen; -- cgit v0.10.2 From 859232113c734db359646e8229f9036047a81495 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 4 May 2007 23:00:49 +0200 Subject: [SCSI] tmscsim: Remove the last bus_to_virt() Dynamically map the buffer for PIO for the residue byte. Signed-off-by: G. Liakhovetski Signed-off-by: James Bottomley diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index 12d8fea..e7b85e8 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -351,6 +351,27 @@ static u8 dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20}; * (DCBs, SRBs, Queueing) * **********************************************************************/ +static void inline dc390_start_segment(struct dc390_srb* pSRB) +{ + struct scatterlist *psgl = pSRB->pSegmentList; + + /* start new sg segment */ + pSRB->SGBusAddr = sg_dma_address(psgl); + pSRB->SGToBeXferLen = sg_dma_len(psgl); +} + +static unsigned long inline dc390_advance_segment(struct dc390_srb* pSRB, u32 residue) +{ + unsigned long xfer = pSRB->SGToBeXferLen - residue; + + /* xfer more bytes transferred */ + pSRB->SGBusAddr += xfer; + pSRB->TotalXferredLen += xfer; + pSRB->SGToBeXferLen = residue; + + return xfer; +} + static struct dc390_dcb __inline__ *dc390_findDCB ( struct dc390_acb* pACB, u8 id, u8 lun) { struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return NULL; @@ -741,11 +762,10 @@ static irqreturn_t do_DC390_Interrupt(int irq, void *dev_id) } static void -dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) +dc390_DataOut_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) { u8 sstatus; - struct scatterlist *psgl; - u32 ResidCnt, xferCnt; + u32 ResidCnt; u8 dstate = 0; sstatus = *psstatus; @@ -776,25 +796,20 @@ dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) if( pSRB->SGIndex < pSRB->SGcount ) { pSRB->pSegmentList++; - psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = sg_dma_address(psgl); - pSRB->SGToBeXferLen = sg_dma_len(psgl); + dc390_start_segment(pSRB); } else pSRB->SGToBeXferLen = 0; } else { - ResidCnt = (u32) DC390_read8 (Current_Fifo) & 0x1f; - ResidCnt |= (u32) DC390_read8 (CtcReg_High) << 16; - ResidCnt |= (u32) DC390_read8 (CtcReg_Mid) << 8; - ResidCnt += (u32) DC390_read8 (CtcReg_Low); - - xferCnt = pSRB->SGToBeXferLen - ResidCnt; - pSRB->SGBusAddr += xferCnt; - pSRB->TotalXferredLen += xferCnt; - pSRB->SGToBeXferLen = ResidCnt; + ResidCnt = ((u32) DC390_read8 (Current_Fifo) & 0x1f) + + (((u32) DC390_read8 (CtcReg_High) << 16) | + ((u32) DC390_read8 (CtcReg_Mid) << 8) | + (u32) DC390_read8 (CtcReg_Low)); + + dc390_advance_segment(pSRB, ResidCnt); } } if ((*psstatus & 7) != SCSI_DATA_OUT) @@ -805,13 +820,11 @@ dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) } static void -dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) +dc390_DataIn_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) { u8 sstatus, residual, bval; - struct scatterlist *psgl; - u32 ResidCnt, i; + u32 ResidCnt, i; unsigned long xferCnt; - u8 *ptr; sstatus = *psstatus; @@ -851,10 +864,8 @@ dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) if( pSRB->SGIndex < pSRB->SGcount ) { pSRB->pSegmentList++; - psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = sg_dma_address(psgl); - pSRB->SGToBeXferLen = sg_dma_len(psgl); + dc390_start_segment(pSRB); } else pSRB->SGToBeXferLen = 0; @@ -894,41 +905,38 @@ din_1: /* It seems a DMA Blast abort isn't that bad ... */ if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n"); //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); - dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24; + dc390_laststatus &= ~0xff000000; + dc390_laststatus |= bval << 24; DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval)); - ResidCnt = (u32) DC390_read8 (CtcReg_High); - ResidCnt <<= 8; - ResidCnt |= (u32) DC390_read8 (CtcReg_Mid); - ResidCnt <<= 8; - ResidCnt |= (u32) DC390_read8 (CtcReg_Low); - - xferCnt = pSRB->SGToBeXferLen - ResidCnt; - pSRB->SGBusAddr += xferCnt; - pSRB->TotalXferredLen += xferCnt; - pSRB->SGToBeXferLen = ResidCnt; - - if( residual ) - { - static int feedback_requested; + ResidCnt = (((u32) DC390_read8 (CtcReg_High) << 16) | + ((u32) DC390_read8 (CtcReg_Mid) << 8)) | + (u32) DC390_read8 (CtcReg_Low); + + xferCnt = dc390_advance_segment(pSRB, ResidCnt); + + if (residual) { + size_t count = 1; + size_t offset = pSRB->SGBusAddr - sg_dma_address(pSRB->pSegmentList); + unsigned long flags; + u8 *ptr; + bval = DC390_read8 (ScsiFifo); /* get one residual byte */ - if (!feedback_requested) { - feedback_requested = 1; - printk(KERN_WARNING "%s: Please, contact " - "to help improve support for your system.\n", __FILE__); + local_irq_save(flags); + ptr = scsi_kmap_atomic_sg(pSRB->pSegmentList, pSRB->SGcount, &offset, &count); + if (likely(ptr)) { + *(ptr + offset) = bval; + scsi_kunmap_atomic_sg(ptr); } + local_irq_restore(flags); + WARN_ON(!ptr); - ptr = (u8 *) bus_to_virt( pSRB->SGBusAddr ); - *ptr = bval; - pSRB->SGBusAddr++; - xferCnt++; - pSRB->TotalXferredLen++; - pSRB->SGToBeXferLen--; + /* 1 more byte read */ + xferCnt += dc390_advance_segment(pSRB, pSRB->SGToBeXferLen - 1); } DEBUG1(printk (KERN_DEBUG "Xfered: %lu, Total: %lu, Remaining: %lu\n", xferCnt,\ pSRB->TotalXferredLen, pSRB->SGToBeXferLen)); - } } if ((*psstatus & 7) != SCSI_DATA_IN) @@ -1137,7 +1145,7 @@ dc390_MsgIn_set_sync (struct dc390_acb* pACB, struct dc390_srb* pSRB) /* handle RESTORE_PTR */ -/* I presume, this command is already mapped, so, have to remap. */ +/* This doesn't look very healthy... to-be-fixed */ static void dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB) { @@ -1146,6 +1154,7 @@ dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB) pSRB->TotalXferredLen = 0; pSRB->SGIndex = 0; if (pcmd->use_sg) { + size_t saved; pSRB->pSegmentList = (struct scatterlist *)pcmd->request_buffer; psgl = pSRB->pSegmentList; //dc390_pci_sync(pSRB); @@ -1157,15 +1166,16 @@ dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB) if( pSRB->SGIndex < pSRB->SGcount ) { pSRB->pSegmentList++; - psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = sg_dma_address(psgl); - pSRB->SGToBeXferLen = sg_dma_len(psgl); + + dc390_start_segment(pSRB); } else pSRB->SGToBeXferLen = 0; } - pSRB->SGToBeXferLen -= pSRB->Saved_Ptr - pSRB->TotalXferredLen; - pSRB->SGBusAddr += pSRB->Saved_Ptr - pSRB->TotalXferredLen; + + saved = pSRB->Saved_Ptr - pSRB->TotalXferredLen; + pSRB->SGToBeXferLen -= saved; + pSRB->SGBusAddr += saved; printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n", pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr); @@ -1286,7 +1296,6 @@ dc390_MsgIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) static void dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir) { - struct scatterlist *psgl; unsigned long lval; struct dc390_dcb* pDCB = pACB->pActiveDCB; @@ -1315,9 +1324,8 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir) DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); if( !pSRB->SGToBeXferLen ) { - psgl = pSRB->pSegmentList; - pSRB->SGBusAddr = sg_dma_address(psgl); - pSRB->SGToBeXferLen = sg_dma_len(psgl); + dc390_start_segment(pSRB); + DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.")); } lval = pSRB->SGToBeXferLen; -- cgit v0.10.2 From a5694ec545a880f9d23463fddc894f5096cc68fa Mon Sep 17 00:00:00 2001 From: "Salyzyn, Mark" Date: Mon, 30 Apr 2007 13:22:24 -0400 Subject: [SCSI] aacraid: kexec fix (reset interrupt handler) Another layer on this onion also discovered by Duane, the interrupt enable handler also needed to be set ... The interrupt enable was called from within the synchronous command handler. Signed-off-by: Mark Salyzyn Signed-off-by: James Bottomley diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 0c71315..b6ee3c0 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -539,6 +539,8 @@ int _aac_rx_init(struct aac_dev *dev) } /* Failure to reset here is an option ... */ + dev->a_ops.adapter_sync_cmd = rx_sync_cmd; + dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt; dev->OIMR = status = rx_readb (dev, MUnit.OIMR); if ((((status & 0xff) != 0xff) || reset_devices) && !aac_rx_restart_adapter(dev, 0)) -- cgit v0.10.2 From 9e4d4a5d71d673901d9c1df5146ce545c2cc0cc0 Mon Sep 17 00:00:00 2001 From: "Salyzyn, Mark" Date: Tue, 1 May 2007 11:43:06 -0400 Subject: [SCSI] aacraid: superfluous adapter reset for IBM 8 series ServeRAID controllers The kexec patch introduced a superfluous (and otherwise inert) reset of some adapters. The register can have a hardware default value that has zeros for the undefined interrupts. This patch refines the test of the interrupt enable register to focus on only the interrupts that affect the driver in order to detect if an incomplete shutdown of the Adapter had occurred (kdump). Signed-off-by: Mark Salyzyn Signed-off-by: James Bottomley diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index b6ee3c0..291cd14 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -542,7 +542,7 @@ int _aac_rx_init(struct aac_dev *dev) dev->a_ops.adapter_sync_cmd = rx_sync_cmd; dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt; dev->OIMR = status = rx_readb (dev, MUnit.OIMR); - if ((((status & 0xff) != 0xff) || reset_devices) && + if ((((status & 0x0c) != 0x0c) || reset_devices) && !aac_rx_restart_adapter(dev, 0)) ++restart; /* -- cgit v0.10.2 From 39580f2c15485ee7f40923af731b3052f70cb890 Mon Sep 17 00:00:00 2001 From: "Salyzyn, Mark" Date: Thu, 3 May 2007 16:08:39 -0400 Subject: [SCSI] aacraid: correct SUN products to README Correct SUN products in aacraid documentation, preliminary names were changed from internal project to customer product prior to release. Signed-off-by: Mark Salyzyn Signed-off-by: James Bottomley diff --git a/Documentation/scsi/aacraid.txt b/Documentation/scsi/aacraid.txt index 2368e7e..ce3cb42 100644 --- a/Documentation/scsi/aacraid.txt +++ b/Documentation/scsi/aacraid.txt @@ -98,8 +98,8 @@ Supported Cards/Chipsets 9005:0285:9005:02b0 (Sunrise Lake ARK) 9005:0285:9005:02b1 Adaptec (Voodoo 8 internal 8 external) 9005:0285:108e:7aac SUN STK RAID REM (Voodoo44 Coyote) - 9005:0285:108e:0286 SUN SG-XPCIESAS-R-IN (Cougar) - 9005:0285:108e:0287 SUN SG-XPCIESAS-R-EX (Prometheus) + 9005:0285:108e:0286 SUN STK RAID INT (Cougar) + 9005:0285:108e:0287 SUN STK RAID EXT (Prometheus) People ------------------------- -- cgit v0.10.2 From 84a3c97b93ec5b4509637801a703693bb710cd4c Mon Sep 17 00:00:00 2001 From: walter harms Date: Thu, 26 Apr 2007 00:35:09 -0700 Subject: [SCSI] megaraid: fix warnings when CONFIG_PROC_FS=n drivers/scsi/megaraid.c: In function 'megaraid_probe_one': drivers/scsi/megaraid.c:4893: warning: implicit declaration of function 'mega_create_proc_entry' drivers/scsi/megaraid.c: In function 'megaraid_remove_one': drivers/scsi/megaraid.c:4968: warning: unused variable 'buf' Fix by adding #defines Signed-off-by: walter harms Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: James Bottomley diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 7fc6e06..65bc130 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -3177,7 +3177,10 @@ proc_rdrv(adapter_t *adapter, char *page, int start, int end ) return len; } - +#else +static inline void mega_create_proc_entry(int index, struct proc_dir_entry *parent) +{ +} #endif @@ -4342,7 +4345,7 @@ mega_support_cluster(adapter_t *adapter) return 0; } - +#ifdef CONFIG_PROC_FS /** * mega_adapinq() * @adapter - pointer to our soft state @@ -4447,7 +4450,7 @@ mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt, return rval; } - +#endif /** * mega_internal_command() @@ -4965,7 +4968,6 @@ megaraid_remove_one(struct pci_dev *pdev) { struct Scsi_Host *host = pci_get_drvdata(pdev); adapter_t *adapter = (adapter_t *)host->hostdata; - char buf[12] = { 0 }; scsi_remove_host(host); @@ -5011,8 +5013,11 @@ megaraid_remove_one(struct pci_dev *pdev) remove_proc_entry("raiddrives-30-39", adapter->controller_proc_dir_entry); #endif - sprintf(buf, "hba%d", adapter->host->host_no); - remove_proc_entry(buf, mega_proc_dir_entry); + { + char buf[12] = { 0 }; + sprintf(buf, "hba%d", adapter->host->host_no); + remove_proc_entry(buf, mega_proc_dir_entry); + } } #endif diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index c6e7464..ee70bd4 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -1002,7 +1002,6 @@ static int megaraid_reset(Scsi_Cmnd *); static int megaraid_abort_and_reset(adapter_t *, Scsi_Cmnd *, int); static int megaraid_biosparam(struct scsi_device *, struct block_device *, sector_t, int []); -static int mega_print_inquiry(char *, char *); static int mega_build_sglist (adapter_t *adapter, scb_t *scb, u32 *buffer, u32 *length); @@ -1024,6 +1023,7 @@ static int mega_init_scb (adapter_t *); static int mega_is_bios_enabled (adapter_t *); #ifdef CONFIG_PROC_FS +static int mega_print_inquiry(char *, char *); static void mega_create_proc_entry(int, struct proc_dir_entry *); static int proc_read_config(char *, char **, off_t, int, int *, void *); static int proc_read_stat(char *, char **, off_t, int, int *, void *); @@ -1040,10 +1040,10 @@ static int proc_rdrv_20(char *, char **, off_t, int, int *, void *); static int proc_rdrv_30(char *, char **, off_t, int, int *, void *); static int proc_rdrv_40(char *, char **, off_t, int, int *, void *); static int proc_rdrv(adapter_t *, char *, int, int); -#endif static int mega_adapinq(adapter_t *, dma_addr_t); static int mega_internal_dev_inquiry(adapter_t *, u8, u8, dma_addr_t); +#endif static int mega_support_ext_cdb(adapter_t *); static mega_passthru* mega_prepare_passthru(adapter_t *, scb_t *, -- cgit v0.10.2 From e1fa0ceaf366ba8042a388d02ce841b36d063fe2 Mon Sep 17 00:00:00 2001 From: Amol Lad Date: Thu, 26 Apr 2007 00:35:13 -0700 Subject: [SCSI] megaraid: replace yield() with cond_resched() For this driver cond_resched() seems to be a better alternative Signed-off-by: Amol Lad Signed-off-by: Andrew Morton Signed-off-by: James Bottomley diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 65bc130..3cce75d 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -1754,7 +1754,8 @@ __mega_busywait_mbox (adapter_t *adapter) for (counter = 0; counter < 10000; counter++) { if (!mbox->m_in.busy) return 0; - udelay(100); yield(); + udelay(100); + cond_resched(); } return -1; /* give up after 1 second */ } -- cgit v0.10.2 From 2135be5f24ee6620ea6f2a594087d51b6a67ce7e Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Thu, 26 Apr 2007 00:35:19 -0700 Subject: [SCSI] mesh: cleanup variable usage in interrupt handler _ convert void* to struct mesh_state* - remove unused irq argument from mesh_interrupt() Signed-off-by: Olaf Hering Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: James Bottomley diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index 1fd3c75..6f50a5b 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -185,7 +185,7 @@ struct mesh_state { * Driver is too messy, we need a few prototypes... */ static void mesh_done(struct mesh_state *ms, int start_next); -static void mesh_interrupt(int irq, void *dev_id); +static void mesh_interrupt(struct mesh_state *ms); static void cmd_complete(struct mesh_state *ms); static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd); static void halt_dma(struct mesh_state *ms); @@ -466,7 +466,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd) dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x", MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count)); - mesh_interrupt(0, (void *)ms); + mesh_interrupt(ms); if (ms->phase != arbitrating) return; } @@ -504,7 +504,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd) dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x", MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count)); - mesh_interrupt(0, (void *)ms); + mesh_interrupt(ms); if (ms->phase != arbitrating) return; dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x", @@ -1018,10 +1018,11 @@ static void handle_reset(struct mesh_state *ms) static irqreturn_t do_mesh_interrupt(int irq, void *dev_id) { unsigned long flags; - struct Scsi_Host *dev = ((struct mesh_state *)dev_id)->host; + struct mesh_state *ms = dev_id; + struct Scsi_Host *dev = ms->host; spin_lock_irqsave(dev->host_lock, flags); - mesh_interrupt(irq, dev_id); + mesh_interrupt(ms); spin_unlock_irqrestore(dev->host_lock, flags); return IRQ_HANDLED; } @@ -1661,9 +1662,8 @@ static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) * handler (do_mesh_interrupt) or by other functions in * exceptional circumstances */ -static void mesh_interrupt(int irq, void *dev_id) +static void mesh_interrupt(struct mesh_state *ms) { - struct mesh_state *ms = (struct mesh_state *) dev_id; volatile struct mesh_regs __iomem *mr = ms->mesh; int intr; -- cgit v0.10.2 From b03670e5277224d1166cb5e4f610fc388186b065 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Mon, 7 May 2007 16:35:04 +0200 Subject: [SCSI] zfcp: Stop system after memory corruption For each request that is sent to the FCP adapter, zfcp allocates memory. Status information and data that is being read from the device is written to this memory by the hardware. After that, the hardware signals this via the response queue and zfcp continues processing. Now, if zfcp detects that there is a signal for an incoming response from the hardware, but there is no outstanding request for that request id, then some memory that can be in use anywhere in the system has just been overwritten. This should never happen, but if it does, stop the system with a panic. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 1e12a78..e50e6ad 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -285,8 +285,8 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device, /** * zfcp_qdio_reqid_check - checks for valid reqids or unsolicited status */ -static int zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, - unsigned long req_id) +static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, + unsigned long req_id) { struct zfcp_fsf_req *fsf_req; unsigned long flags; @@ -298,9 +298,7 @@ static int zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, if (!fsf_req) { spin_unlock_irqrestore(&adapter->req_list_lock, flags); - ZFCP_LOG_NORMAL("error: unknown request id (%ld).\n", req_id); - zfcp_erp_adapter_reopen(adapter, 0); - return -EINVAL; + panic("error: unknown request id (%ld).\n", req_id); } zfcp_reqlist_remove(adapter, req_id); @@ -309,8 +307,6 @@ static int zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, /* finish the FSF request */ zfcp_fsf_req_complete(fsf_req); - - return 0; } /* @@ -374,27 +370,9 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device, /* look for QDIO request identifiers in SB */ buffere = &buffer->element[buffere_index]; - retval = zfcp_qdio_reqid_check(adapter, - (unsigned long) buffere->addr); - - if (retval) { - ZFCP_LOG_NORMAL("bug: unexpected inbound " - "packet on adapter %s " - "(reqid=0x%lx, " - "first_element=%d, " - "elements_processed=%d)\n", - zfcp_get_busid_by_adapter(adapter), - (unsigned long) buffere->addr, - first_element, - elements_processed); - ZFCP_LOG_NORMAL("hex dump of inbound buffer " - "at address %p " - "(buffer_index=%d, " - "buffere_index=%d)\n", buffer, - buffer_index, buffere_index); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, - (char *) buffer, SBAL_SIZE); - } + zfcp_qdio_reqid_check(adapter, + (unsigned long) buffere->addr); + /* * A single used SBALE per inbound SBALE has been * implemented by QDIO so far. Hope they will -- cgit v0.10.2 From 765140bf22adfaecd7077ce10cd6198ef872094c Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 7 May 2007 07:42:58 -0700 Subject: [SCSI] qla2xxx: Error-out during probe() if we're unable to complete HBA initialization. Remove a stale check against ha->device_flags (DFLG_NO_CABLE) as topology scanning is performed within the DPC-thread context. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index b78919a..0a36912 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1577,9 +1577,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_failed; } - if (qla2x00_initialize_adapter(ha) && - !(ha->device_flags & DFLG_NO_CABLE)) { - + if (qla2x00_initialize_adapter(ha)) { qla_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); -- cgit v0.10.2 From a7b6184225d747e5ae0bee30a388e6ebb70d5b8e Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 7 May 2007 07:42:59 -0700 Subject: [SCSI] qla2xxx: Honor NVRAM port-down-retry-count settings. Hardcoding the qlport_down_retry module-parameter effectively disallowed any user-defined NVRAM setting to go into effect. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 0a36912..dd076da 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -36,7 +36,7 @@ module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xlogintimeout, "Login timeout value in seconds."); -int qlport_down_retry = 30; +int qlport_down_retry; module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(qlport_down_retry, "Maximum number of command retries to a port that returns " -- cgit v0.10.2 From 75edf81d337ea84a291f0fdae2777cfd07045eca Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 7 May 2007 07:43:00 -0700 Subject: [SCSI] qla2xxx: Attempt to stop firmware only if it had been previously executed. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 3e296ab..6ad1588 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3931,6 +3931,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha) if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) return; + if (!ha->fw_major_version) + return; ret = qla2x00_stop_firmware(ha); for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) { -- cgit v0.10.2 From a157b1014f9eaf7f80f9105defed2117c5f6653c Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 7 May 2007 07:43:01 -0700 Subject: [SCSI] qla2xxx: Correct pci_set_msi() usage semantics. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 6ad1588..db998d8 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -130,18 +130,17 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) int qla2100_pci_config(scsi_qla_host_t *ha) { - uint16_t w, mwi; + int ret; + uint16_t w; uint32_t d; unsigned long flags; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; pci_set_master(ha->pdev); - mwi = 0; - if (pci_set_mwi(ha->pdev)) - mwi = PCI_COMMAND_INVALIDATE; + ret = pci_set_mwi(ha->pdev); pci_read_config_word(ha->pdev, PCI_COMMAND, &w); - w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); + w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); pci_write_config_word(ha->pdev, PCI_COMMAND, w); /* Reset expansion ROM address decode enable */ @@ -166,22 +165,22 @@ qla2100_pci_config(scsi_qla_host_t *ha) int qla2300_pci_config(scsi_qla_host_t *ha) { - uint16_t w, mwi; + int ret; + uint16_t w; uint32_t d; unsigned long flags = 0; uint32_t cnt; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; pci_set_master(ha->pdev); - mwi = 0; - if (pci_set_mwi(ha->pdev)) - mwi = PCI_COMMAND_INVALIDATE; + ret = pci_set_mwi(ha->pdev); pci_read_config_word(ha->pdev, PCI_COMMAND, &w); - w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); + w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); if (IS_QLA2322(ha) || IS_QLA6322(ha)) w &= ~PCI_COMMAND_INTX_DISABLE; + pci_write_config_word(ha->pdev, PCI_COMMAND, w); /* * If this is a 2300 card and not 2312, reset the @@ -210,7 +209,7 @@ qla2300_pci_config(scsi_qla_host_t *ha) ha->fb_rev = RD_FB_CMD_REG(ha, reg); if (ha->fb_rev == FPM_2300) - w &= ~PCI_COMMAND_INVALIDATE; + pci_clear_mwi(ha->pdev); /* Deselect FPM registers. */ WRT_REG_WORD(®->ctrl_status, 0x0); @@ -227,7 +226,6 @@ qla2300_pci_config(scsi_qla_host_t *ha) spin_unlock_irqrestore(&ha->hardware_lock, flags); } - pci_write_config_word(ha->pdev, PCI_COMMAND, w); pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80); @@ -253,19 +251,18 @@ qla2300_pci_config(scsi_qla_host_t *ha) int qla24xx_pci_config(scsi_qla_host_t *ha) { - uint16_t w, mwi; + int ret; + uint16_t w; uint32_t d; unsigned long flags = 0; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; int pcix_cmd_reg, pcie_dctl_reg; pci_set_master(ha->pdev); - mwi = 0; - if (pci_set_mwi(ha->pdev)) - mwi = PCI_COMMAND_INVALIDATE; + ret = pci_set_mwi(ha->pdev); pci_read_config_word(ha->pdev, PCI_COMMAND, &w); - w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); + w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); w &= ~PCI_COMMAND_INTX_DISABLE; pci_write_config_word(ha->pdev, PCI_COMMAND, w); -- cgit v0.10.2 From cbedb601868821c9bfdcf1e9194be160deceeecb Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 7 May 2007 07:43:02 -0700 Subject: [SCSI] qla2xxx: Add MSI support. Supported ISP types include ISP2422 and revision-2 type ISP2432 chips. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index d488561..ca46346 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1726,6 +1726,17 @@ qla2x00_request_irqs(scsi_qla_host_t *ha) qla_printk(KERN_WARNING, ha, "MSI-X: Falling back-to INTa mode -- %d.\n", ret); skip_msix: + + if (!IS_QLA24XX(ha)) + goto skip_msi; + + ret = pci_enable_msi(ha->pdev); + if (!ret) { + DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n")); + ha->flags.msi_enabled = 1; + } +skip_msi: + ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler, IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha); if (!ret) { @@ -1746,6 +1757,8 @@ qla2x00_free_irqs(scsi_qla_host_t *ha) if (ha->flags.msix_enabled) qla24xx_disable_msix(ha); - else if (ha->flags.inta_enabled) + else if (ha->flags.inta_enabled) { free_irq(ha->host->irq, ha); + pci_disable_msi(ha->pdev); + } } -- cgit v0.10.2 From d24f8e8fef43aa9fc98ea7a5ae6eee0eed4cdc06 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Mon, 7 May 2007 07:43:03 -0700 Subject: [SCSI] qla2xxx: Update version number to 8.01.07-k7. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index dc85495..c375a4e 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.07-k6" +#define QLA2XXX_VERSION "8.01.07-k7" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 -- cgit v0.10.2 From 463fc696ed723a9d854113e370cc177b0b63de42 Mon Sep 17 00:00:00 2001 From: Brian King Date: Mon, 7 May 2007 17:09:05 -0500 Subject: [SCSI] ipr: Use PCI-E reset API for new ipr adapter Use a newly added PCI API to issue a PCI Fundamental reset (warm reset) to a new ipr PCI-E adapter. Typically, the ipr adapter uses the start BIST bit in config space to reset an adapter. Issuing start BIST on this particular adapter results in the PCI-E logic on the card losing sync, which causes PCI-E errors, making the card unusable. The only reset mechanism that exists on this hardware that does not have this problem is PCI Fundamental reset (warm reset). Signed-off-by: Brian King Signed-off-by: James Bottomley diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 101e519..4baa79e 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6641,6 +6641,48 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) } /** + * ipr_reset_slot_reset_done - Clear PCI reset to the adapter + * @ipr_cmd: ipr command struct + * + * Description: This clears PCI reset to the adapter and delays two seconds. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_reset_slot_reset_done(struct ipr_cmnd *ipr_cmd) +{ + ENTER; + pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev, pcie_deassert_reset); + ipr_cmd->job_step = ipr_reset_bist_done; + ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** + * ipr_reset_slot_reset - Reset the PCI slot of the adapter. + * @ipr_cmd: ipr command struct + * + * Description: This asserts PCI reset to the adapter. + * + * Return value: + * IPR_RC_JOB_RETURN + **/ +static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd) +{ + struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; + struct pci_dev *pdev = ioa_cfg->pdev; + + ENTER; + pci_block_user_cfg_access(pdev); + pci_set_pcie_reset_state(pdev, pcie_warm_reset); + ipr_cmd->job_step = ipr_reset_slot_reset_done; + ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT); + LEAVE; + return IPR_RC_JOB_RETURN; +} + +/** * ipr_reset_allowed - Query whether or not IOA can be reset * @ioa_cfg: ioa config struct * @@ -6679,7 +6721,7 @@ static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd) ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT; ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT); } else { - ipr_cmd->job_step = ipr_reset_start_bist; + ipr_cmd->job_step = ioa_cfg->reset; rc = IPR_RC_JOB_CONTINUE; } @@ -6712,7 +6754,7 @@ static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd) writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg); ipr_cmd->job_step = ipr_reset_wait_to_start_bist; } else { - ipr_cmd->job_step = ipr_reset_start_bist; + ipr_cmd->job_step = ioa_cfg->reset; } ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT; @@ -6994,8 +7036,11 @@ static pci_ers_result_t ipr_pci_slot_reset(struct pci_dev *pdev) struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); spin_lock_irqsave(ioa_cfg->host->host_lock, flags); - _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space, - IPR_SHUTDOWN_NONE); + if (ioa_cfg->needs_warm_reset) + ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); + else + _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space, + IPR_SHUTDOWN_NONE); spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); return PCI_ERS_RESULT_RECOVERED; } @@ -7483,6 +7528,14 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, else ioa_cfg->transop_timeout = IPR_OPERATIONAL_TIMEOUT; + rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &ioa_cfg->revid); + + if (rc != PCIBIOS_SUCCESSFUL) { + dev_err(&pdev->dev, "Failed to read PCI revision ID\n"); + rc = -EIO; + goto out_scsi_host_put; + } + ipr_regs_pci = pci_resource_start(pdev, 0); rc = pci_request_regions(pdev, IPR_NAME); @@ -7569,6 +7622,13 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, goto cleanup_nolog; } + if ((dev_id->driver_data & IPR_USE_PCI_WARM_RESET) || + (dev_id->device == PCI_DEVICE_ID_IBM_OBSIDIAN_E && !ioa_cfg->revid)) { + ioa_cfg->needs_warm_reset = 1; + ioa_cfg->reset = ipr_reset_slot_reset; + } else + ioa_cfg->reset = ipr_reset_start_bist; + spin_lock(&ipr_driver_lock); list_add_tail(&ioa_cfg->queue, &ipr_ioa_head); spin_unlock(&ipr_driver_lock); @@ -7835,7 +7895,7 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = { PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, + IPR_USE_LONG_TRANSOP_TIMEOUT | IPR_USE_PCI_WARM_RESET }, { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, 0 }, { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index daa96ee..d931566 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -37,7 +37,7 @@ /* * Literals */ -#define IPR_DRIVER_VERSION "2.4.0" +#define IPR_DRIVER_VERSION "2.4.1" #define IPR_DRIVER_DATE "(April 24, 2007)" /* @@ -112,6 +112,7 @@ /* Driver data flags */ #define IPR_USE_LONG_TRANSOP_TIMEOUT 0x00000001 +#define IPR_USE_PCI_WARM_RESET 0x00000002 #define IPR_DEFAULT_MAX_ERROR_DUMP 984 #define IPR_NUM_LOG_HCAMS 2 @@ -193,6 +194,7 @@ #define IPR_WAIT_FOR_RESET_TIMEOUT (2 * HZ) #define IPR_CHECK_FOR_RESET_TIMEOUT (HZ / 10) #define IPR_WAIT_FOR_BIST_TIMEOUT (2 * HZ) +#define IPR_PCI_RESET_TIMEOUT (HZ / 2) #define IPR_DUMP_TIMEOUT (15 * HZ) /* @@ -1091,6 +1093,9 @@ struct ipr_ioa_cfg { u8 allow_ml_add_del:1; u8 needs_hard_reset:1; u8 dual_raid:1; + u8 needs_warm_reset:1; + + u8 revid; enum ipr_cache_state cache_state; u16 type; /* CCIN of the card */ @@ -1184,6 +1189,7 @@ struct ipr_ioa_cfg { struct pci_pool *ipr_cmd_pool; struct ipr_cmnd *reset_cmd; + int (*reset) (struct ipr_cmnd *); struct ata_host ata_host; char ipr_cmd_label[8]; -- cgit v0.10.2 From 1d589edf9eeb60c9c8e62753d05cf4c8e094e5a7 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 8 May 2007 11:14:41 +0200 Subject: [SCSI] zfcp: print S_ID and D_ID with 3 bytes S_ID and D_ID are defined in the FCP spec as 3 byte fields. Change the output in zfcp print statements accordingly to print them with only 3 bytes. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 1f9554e..ec3f664 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -1497,7 +1497,7 @@ zfcp_fsf_incoming_els_plogi(struct zfcp_adapter *adapter, if (!port || (port->wwpn != (*(wwn_t *) &els_plogi->serv_param.wwpn))) { ZFCP_LOG_DEBUG("ignored incoming PLOGI for nonexisting port " - "with d_id 0x%08x on adapter %s\n", + "with d_id 0x%06x on adapter %s\n", status_buffer->d_id, zfcp_get_busid_by_adapter(adapter)); } else { @@ -1522,7 +1522,7 @@ zfcp_fsf_incoming_els_logo(struct zfcp_adapter *adapter, if (!port || (port->wwpn != els_logo->nport_wwpn)) { ZFCP_LOG_DEBUG("ignored incoming LOGO for nonexisting port " - "with d_id 0x%08x on adapter %s\n", + "with d_id 0x%06x on adapter %s\n", status_buffer->d_id, zfcp_get_busid_by_adapter(adapter)); } else { @@ -1704,7 +1704,7 @@ static void zfcp_ns_gid_pn_handler(unsigned long data) /* looks like a valid d_id */ port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); - ZFCP_LOG_DEBUG("adapter %s: wwpn=0x%016Lx ---> d_id=0x%08x\n", + ZFCP_LOG_DEBUG("adapter %s: wwpn=0x%016Lx ---> d_id=0x%06x\n", zfcp_get_busid_by_port(port), port->wwpn, port->d_id); goto out; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index c1f2d4b..f326bbe 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -342,9 +342,9 @@ zfcp_erp_adisc(struct zfcp_port *port) adisc->wwpn = fc_host_port_name(adapter->scsi_host); adisc->wwnn = fc_host_node_name(adapter->scsi_host); adisc->nport_id = fc_host_port_id(adapter->scsi_host); - ZFCP_LOG_INFO("ADISC request from s_id 0x%08x to d_id 0x%08x " + ZFCP_LOG_INFO("ADISC request from s_id 0x%06x to d_id 0x%06x " "(wwpn=0x%016Lx, wwnn=0x%016Lx, " - "hard_nport_id=0x%08x, nport_id=0x%08x)\n", + "hard_nport_id=0x%06x, nport_id=0x%06x)\n", adisc->nport_id, send_els->d_id, (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn, adisc->hard_nport_id, adisc->nport_id); @@ -352,7 +352,7 @@ zfcp_erp_adisc(struct zfcp_port *port) retval = zfcp_fsf_send_els(send_els); if (retval != 0) { ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port " - "0x%08x on adapter %s\n", send_els->d_id, + "0x%06x on adapter %s\n", send_els->d_id, zfcp_get_busid_by_adapter(adapter)); goto freemem; } @@ -398,7 +398,7 @@ zfcp_erp_adisc_handler(unsigned long data) if (send_els->status != 0) { ZFCP_LOG_NORMAL("ELS request rejected/timed out, " "force physical port reopen " - "(adapter %s, port d_id=0x%08x)\n", + "(adapter %s, port d_id=0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); debug_text_event(adapter->erp_dbf, 3, "forcreop"); if (zfcp_erp_port_forced_reopen(port, 0)) @@ -411,9 +411,9 @@ zfcp_erp_adisc_handler(unsigned long data) adisc = zfcp_sg_to_address(send_els->resp); - ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id " - "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, " - "hard_nport_id=0x%08x, nport_id=0x%08x)\n", + ZFCP_LOG_INFO("ADISC response from d_id 0x%06x to s_id " + "0x%06x (wwpn=0x%016Lx, wwnn=0x%016Lx, " + "hard_nport_id=0x%06x, nport_id=0x%06x)\n", d_id, fc_host_port_id(adapter->scsi_host), (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn, adisc->hard_nport_id, adisc->nport_id); @@ -1377,7 +1377,7 @@ zfcp_erp_port_failed(struct zfcp_port *port) if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status)) ZFCP_LOG_NORMAL("port erp failed (adapter %s, " - "port d_id=0x%08x)\n", + "port d_id=0x%06x)\n", zfcp_get_busid_by_port(port), port->d_id); else ZFCP_LOG_NORMAL("port erp failed (adapter %s, wwpn=0x%016Lx)\n", @@ -2401,7 +2401,7 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action) retval = ZFCP_ERP_FAILED; } } else { - ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%08x -> " + ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> " "trying open\n", port->wwpn, port->d_id); retval = zfcp_erp_port_strategy_open_port(erp_action); } @@ -2441,7 +2441,7 @@ zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action) case ZFCP_ERP_STEP_UNINITIALIZED: case ZFCP_ERP_STEP_PHYS_PORT_CLOSING: case ZFCP_ERP_STEP_PORT_CLOSING: - ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%08x -> trying open\n", + ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> trying open\n", port->wwpn, port->d_id); retval = zfcp_erp_port_strategy_open_port(erp_action); break; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 4c0a59a..f120b16 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -828,7 +828,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req) if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) { ZFCP_LOG_NORMAL("bug: Reopen port indication received for" - "nonexisting port with d_id 0x%08x on " + "nonexisting port with d_id 0x%06x on " "adapter %s. Ignored.\n", status_buffer->d_id & ZFCP_DID_MASK, zfcp_get_busid_by_adapter(adapter)); @@ -853,7 +853,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req) &status_buffer->status_subtype, sizeof (u32)); ZFCP_LOG_NORMAL("bug: Undefined status subtype received " "for a reopen indication on port with " - "d_id 0x%08x on the adapter %s. " + "d_id 0x%06x on the adapter %s. " "Ignored. (debug info 0x%x)\n", status_buffer->d_id, zfcp_get_busid_by_adapter(adapter), @@ -1156,7 +1156,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id, } ZFCP_LOG_DEBUG("Abort FCP Command request initiated " - "(adapter%s, port d_id=0x%08x, " + "(adapter%s, port d_id=0x%06x, " "unit x%016Lx, old_req_id=0x%lx)\n", zfcp_get_busid_by_adapter(adapter), unit->port->d_id, @@ -1554,7 +1554,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) case FSF_ACCESS_DENIED: ZFCP_LOG_NORMAL("access denied, cannot send generic service " - "command (adapter %s, port d_id=0x%08x)\n", + "command (adapter %s, port d_id=0x%06x)\n", zfcp_get_busid_by_port(port), port->d_id); for (counter = 0; counter < 2; counter++) { subtable = header->fsf_status_qual.halfword[counter * 2]; @@ -1576,7 +1576,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) case FSF_GENERIC_COMMAND_REJECTED: ZFCP_LOG_INFO("generic service command rejected " - "(adapter %s, port d_id=0x%08x)\n", + "(adapter %s, port d_id=0x%06x)\n", zfcp_get_busid_by_port(port), port->d_id); ZFCP_LOG_INFO("status qualifier:\n"); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO, @@ -1602,7 +1602,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) case FSF_PORT_BOXED: ZFCP_LOG_INFO("port needs to be reopened " - "(adapter %s, port d_id=0x%08x)\n", + "(adapter %s, port d_id=0x%06x)\n", zfcp_get_busid_by_port(port), port->d_id); debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed"); zfcp_erp_port_boxed(port); @@ -1683,7 +1683,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) NULL, &lock_flags, &fsf_req); if (ret < 0) { ZFCP_LOG_INFO("error: creation of ELS request failed " - "(adapter %s, port d_id: 0x%08x)\n", + "(adapter %s, port d_id: 0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); goto failed_req; } @@ -1708,7 +1708,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) ZFCP_MAX_SBALS_PER_ELS_REQ); if (bytes <= 0) { ZFCP_LOG_INFO("error: creation of ELS request failed " - "(adapter %s, port d_id: 0x%08x)\n", + "(adapter %s, port d_id: 0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); if (bytes == 0) { ret = -ENOMEM; @@ -1725,7 +1725,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) ZFCP_MAX_SBALS_PER_ELS_REQ); if (bytes <= 0) { ZFCP_LOG_INFO("error: creation of ELS request failed " - "(adapter %s, port d_id: 0x%08x)\n", + "(adapter %s, port d_id: 0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); if (bytes == 0) { ret = -ENOMEM; @@ -1739,7 +1739,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) /* reject request */ ZFCP_LOG_INFO("error: microcode does not support chained SBALs" ", ELS request too big (adapter %s, " - "port d_id: 0x%08x)\n", + "port d_id: 0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); ret = -EOPNOTSUPP; goto failed_send; @@ -1760,13 +1760,13 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) ret = zfcp_fsf_req_send(fsf_req); if (ret) { ZFCP_LOG_DEBUG("error: initiation of ELS request failed " - "(adapter %s, port d_id: 0x%08x)\n", + "(adapter %s, port d_id: 0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); goto failed_send; } ZFCP_LOG_DEBUG("ELS request initiated (adapter %s, port d_id: " - "0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id); + "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); goto out; failed_send: @@ -1859,7 +1859,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) case FSF_ELS_COMMAND_REJECTED: ZFCP_LOG_INFO("ELS has been rejected because command filter " "prohibited sending " - "(adapter: %s, port d_id: 0x%08x)\n", + "(adapter: %s, port d_id: 0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); break; @@ -1907,7 +1907,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) case FSF_ACCESS_DENIED: ZFCP_LOG_NORMAL("access denied, cannot send ELS command " - "(adapter %s, port d_id=0x%08x)\n", + "(adapter %s, port d_id=0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id); for (counter = 0; counter < 2; counter++) { subtable = header->fsf_status_qual.halfword[counter * 2]; @@ -2070,7 +2070,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n" "WWNN 0x%016Lx, " "WWPN 0x%016Lx, " - "S_ID 0x%08x,\n" + "S_ID 0x%06x,\n" "adapter version 0x%x, " "LIC version 0x%x, " "FC link speed %d Gb/s\n", -- cgit v0.10.2 From 801e0ced1891a2b8cad1a435c45234a719b3b6bf Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 8 May 2007 11:15:48 +0200 Subject: [SCSI] zfcp: Locking for req_no and req_seq_no There is a possible race condition while generating the unique request ids and sequence numbers. Both might be read at the same time and have the same value. Fix this by serializing the access through the queue lock of the adapter: First call zfcp_fsf_req_sbal_get that acquires the lock, then read and increment the unique ids. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index f120b16..07094c3 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -4645,23 +4645,22 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, fsf_req->adapter = adapter; fsf_req->fsf_command = fsf_cmd; INIT_LIST_HEAD(&fsf_req->list); - - /* this is serialized (we are holding req_queue-lock of adapter */ - if (adapter->req_no == 0) - adapter->req_no++; - fsf_req->req_id = adapter->req_no++; - init_timer(&fsf_req->timer); - zfcp_fsf_req_qtcb_init(fsf_req); /* initialize waitqueue which may be used to wait on this request completion */ init_waitqueue_head(&fsf_req->completion_wq); ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags); - if(ret < 0) { + if (ret < 0) goto failed_sbals; - } + + /* this is serialized (we are holding req_queue-lock of adapter) */ + if (adapter->req_no == 0) + adapter->req_no++; + fsf_req->req_id = adapter->req_no++; + + zfcp_fsf_req_qtcb_init(fsf_req); /* * We hold queue_lock here. Check if QDIOUP is set and let request fail -- cgit v0.10.2 From 5f852be9e11d62223ea063f6ceed4f9677f54051 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 8 May 2007 11:16:52 +0200 Subject: [SCSI] zfcp: Fix deadlock between zfcp ERP and SCSI The SCSI stack requires low level drivers to register and unregister devices. For zfcp this leads to the situation where zfcp calls the SCSI stack, the SCSI tries to scan the new device and the scan SCSI command fails. This would require the zfcp erp, but the erp thread is already blocked in the register call. The fix is to make sure that the calls from the ERP thread to the SCSI stack do not block the ERP thread. In detail: 1) Use a workqueue to avoid blocking of the scsi_scan_target calls. 2) When removing a unit make sure that no scsi_scan_target call is pending. 3) Replace scsi_flush_work with scsi_target_unblock. This avoids blocking and has the same result. Signed-off-by: Christof Schmitt Signed-off-by: Swen Schillig Signed-off-by: James Bottomley diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index ec3f664..49d5fc7 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -913,6 +913,8 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun) unit->sysfs_device.release = zfcp_sysfs_unit_release; dev_set_drvdata(&unit->sysfs_device, unit); + init_waitqueue_head(&unit->scsi_scan_wq); + /* mark unit unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 32933ed..07b0957 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -637,6 +637,7 @@ do { \ #define ZFCP_STATUS_UNIT_SHARED 0x00000004 #define ZFCP_STATUS_UNIT_READONLY 0x00000008 #define ZFCP_STATUS_UNIT_REGISTERED 0x00000010 +#define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING 0x00000020 /* FSF request status (this does not have a common part) */ #define ZFCP_STATUS_FSFREQ_NOT_INIT 0x00000000 @@ -980,6 +981,10 @@ struct zfcp_unit { struct scsi_device *device; /* scsi device struct pointer */ struct zfcp_erp_action erp_action; /* pending error recovery */ atomic_t erp_counter; + wait_queue_head_t scsi_scan_wq; /* can be used to wait until + all scsi_scan_target + requests have been + completed. */ }; /* FSF request */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index f326bbe..8855723 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -1591,6 +1591,62 @@ zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result) return result; } +struct zfcp_erp_add_work { + struct zfcp_unit *unit; + struct work_struct work; +}; + +/** + * zfcp_erp_scsi_scan + * @data: pointer to a struct zfcp_erp_add_work + * + * Registers a logical unit with the SCSI stack. + */ +static void zfcp_erp_scsi_scan(struct work_struct *work) +{ + struct zfcp_erp_add_work *p = + container_of(work, struct zfcp_erp_add_work, work); + struct zfcp_unit *unit = p->unit; + struct fc_rport *rport = unit->port->rport; + scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, + unit->scsi_lun, 0); + atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); + wake_up(&unit->scsi_scan_wq); + zfcp_unit_put(unit); + kfree(p); +} + +/** + * zfcp_erp_schedule_work + * @unit: pointer to unit which should be registered with SCSI stack + * + * Schedules work which registers a unit with the SCSI stack + */ +static void +zfcp_erp_schedule_work(struct zfcp_unit *unit) +{ + struct zfcp_erp_add_work *p; + + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (!p) { + ZFCP_LOG_NORMAL("error: Out of resources. Could not register " + "the FCP-LUN 0x%Lx connected to " + "the port with WWPN 0x%Lx connected to " + "the adapter %s with the SCSI stack.\n", + unit->fcp_lun, + unit->port->wwpn, + zfcp_get_busid_by_unit(unit)); + return; + } + + zfcp_unit_get(unit); + memset(p, 0, sizeof(*p)); + atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); + INIT_WORK(&p->work, zfcp_erp_scsi_scan); + p->unit = unit; + schedule_work(&p->work); +} + /* * function: * @@ -3092,9 +3148,9 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, && port->rport) { atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); - scsi_scan_target(&port->rport->dev, 0, - port->rport->scsi_target_id, - unit->scsi_lun, 0); + if (atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, + &unit->status) == 0) + zfcp_erp_schedule_work(unit); } zfcp_unit_put(unit); break; @@ -3121,7 +3177,7 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, zfcp_get_busid_by_port(port), port->wwpn); else { - scsi_flush_work(adapter->scsi_host); + scsi_target_unblock(&port->rport->dev); port->rport->maxframe_size = port->maxframe_size; port->rport->supported_classes = port->supported_classes; diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 99db020..e742b3d 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -22,6 +22,7 @@ #define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI #include "zfcp_ext.h" +#include static void zfcp_scsi_slave_destroy(struct scsi_device *sdp); static int zfcp_scsi_slave_alloc(struct scsi_device *sdp); @@ -179,6 +180,10 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; if (unit) { + zfcp_erp_wait(unit->port->adapter); + wait_event(unit->scsi_scan_wq, + atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, + &unit->status) == 0); atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); sdpnt->hostdata = NULL; unit->device = NULL; -- cgit v0.10.2 From ca2d02c2f9ea476062ae181eec60b8bcd97857d6 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 8 May 2007 11:17:54 +0200 Subject: [SCSI] zfcp: rework request ID management. Simplify request ID management and make sure that frequently used functions are inlined. Also fix a memory leak in zfcp_adapter_enqueue() which only gets hit in error handling. Signed-off-by: Heiko Carstens Signed-off-by: Swen Schillig Signed-off-by: James Bottomley diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 49d5fc7..324899c 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -118,97 +118,32 @@ _zfcp_hex_dump(char *addr, int count) #define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF -static int zfcp_reqlist_init(struct zfcp_adapter *adapter) +static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) { - int i; + int idx; adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head), GFP_KERNEL); - if (!adapter->req_list) return -ENOMEM; - for (i=0; ireq_list[i]); - + for (idx = 0; idx < REQUEST_LIST_SIZE; idx++) + INIT_LIST_HEAD(&adapter->req_list[idx]); return 0; } static void zfcp_reqlist_free(struct zfcp_adapter *adapter) { - struct zfcp_fsf_req *request, *tmp; - unsigned int i; - - for (i=0; ireq_list[i])) - continue; - - list_for_each_entry_safe(request, tmp, - &adapter->req_list[i], list) - list_del(&request->list); - } - kfree(adapter->req_list); } -void zfcp_reqlist_add(struct zfcp_adapter *adapter, - struct zfcp_fsf_req *fsf_req) -{ - unsigned int i; - - i = fsf_req->req_id % REQUEST_LIST_SIZE; - list_add_tail(&fsf_req->list, &adapter->req_list[i]); -} - -void zfcp_reqlist_remove(struct zfcp_adapter *adapter, unsigned long req_id) -{ - struct zfcp_fsf_req *request, *tmp; - unsigned int i, counter; - u64 dbg_tmp[2]; - - i = req_id % REQUEST_LIST_SIZE; - BUG_ON(list_empty(&adapter->req_list[i])); - - counter = 0; - list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list) { - if (request->req_id == req_id) { - dbg_tmp[0] = (u64) atomic_read(&adapter->reqs_active); - dbg_tmp[1] = (u64) counter; - debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16); - list_del(&request->list); - break; - } - counter++; - } -} - -struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *adapter, - unsigned long req_id) -{ - struct zfcp_fsf_req *request, *tmp; - unsigned int i; - - /* 0 is reserved as an invalid req_id */ - if (req_id == 0) - return NULL; - - i = req_id % REQUEST_LIST_SIZE; - - list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list) - if (request->req_id == req_id) - return request; - - return NULL; -} - int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) { - unsigned int i; + unsigned int idx; - for (i=0; ireq_list[i])) + for (idx = 0; idx < REQUEST_LIST_SIZE; idx++) + if (!list_empty(&adapter->req_list[idx])) return 0; - return 1; } @@ -1106,7 +1041,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) /* initialize list of fsf requests */ spin_lock_init(&adapter->req_list_lock); - retval = zfcp_reqlist_init(adapter); + retval = zfcp_reqlist_alloc(adapter); if (retval) { ZFCP_LOG_INFO("request list initialization failed\n"); goto failed_low_mem_buffers; @@ -1167,6 +1102,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device) zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev); sysfs_failed: dev_set_drvdata(&ccw_device->dev, NULL); + zfcp_reqlist_free(adapter); failed_low_mem_buffers: zfcp_free_low_mem_buffers(adapter); if (qdio_free(ccw_device) != 0) diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 07b0957..2264963 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -1090,6 +1090,42 @@ extern void _zfcp_hex_dump(char *, int); #define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port)) /* + * Helper functions for request ID management. + */ +static inline int zfcp_reqlist_hash(unsigned long req_id) +{ + return req_id % REQUEST_LIST_SIZE; +} + +static inline void zfcp_reqlist_add(struct zfcp_adapter *adapter, + struct zfcp_fsf_req *fsf_req) +{ + unsigned int idx; + + idx = zfcp_reqlist_hash(fsf_req->req_id); + list_add_tail(&fsf_req->list, &adapter->req_list[idx]); +} + +static inline void zfcp_reqlist_remove(struct zfcp_adapter *adapter, + struct zfcp_fsf_req *fsf_req) +{ + list_del(&fsf_req->list); +} + +static inline struct zfcp_fsf_req * +zfcp_reqlist_find(struct zfcp_adapter *adapter, unsigned long req_id) +{ + struct zfcp_fsf_req *request; + unsigned int idx; + + idx = zfcp_reqlist_hash(req_id); + list_for_each_entry(request, &adapter->req_list[idx], list) + if (request->req_id == req_id) + return request; + return NULL; +} + +/* * functions needed for reference/usage counting */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 8855723..e2a3d6f 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -847,8 +847,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) if (erp_action->fsf_req) { /* take lock to ensure that request is not deleted meanwhile */ spin_lock(&adapter->req_list_lock); - if (zfcp_reqlist_ismember(adapter, - erp_action->fsf_req->req_id)) { + if (zfcp_reqlist_find(adapter, erp_action->fsf_req->req_id)) { /* fsf_req still exists */ debug_text_event(adapter->erp_dbf, 3, "a_ca_req"); debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req, diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 01386ac..991d456 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -184,10 +184,6 @@ extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *, unsigned long); extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *, struct scsi_cmnd *); -extern void zfcp_reqlist_add(struct zfcp_adapter *, struct zfcp_fsf_req *); -extern void zfcp_reqlist_remove(struct zfcp_adapter *, unsigned long); -extern struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *, - unsigned long); extern int zfcp_reqlist_isempty(struct zfcp_adapter *); #endif /* ZFCP_EXT_H */ diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 07094c3..083308b 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -4787,7 +4787,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req) retval = -EIO; del_timer(&fsf_req->timer); spin_lock(&adapter->req_list_lock); - zfcp_reqlist_remove(adapter, fsf_req->req_id); + zfcp_reqlist_remove(adapter, fsf_req); spin_unlock(&adapter->req_list_lock); /* undo changes in request queue made for this request */ zfcp_qdio_zero_sbals(req_queue->buffer, diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index e50e6ad..cb08ca3 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -283,7 +283,7 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device, } /** - * zfcp_qdio_reqid_check - checks for valid reqids or unsolicited status + * zfcp_qdio_reqid_check - checks for valid reqids. */ static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, unsigned long req_id) @@ -294,14 +294,17 @@ static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, debug_long_event(adapter->erp_dbf, 4, req_id); spin_lock_irqsave(&adapter->req_list_lock, flags); - fsf_req = zfcp_reqlist_ismember(adapter, req_id); + fsf_req = zfcp_reqlist_find(adapter, req_id); - if (!fsf_req) { - spin_unlock_irqrestore(&adapter->req_list_lock, flags); - panic("error: unknown request id (%ld).\n", req_id); - } + if (!fsf_req) + /* + * Unknown request means that we have potentially memory + * corruption and must stop the machine immediatly. + */ + panic("error: unknown request id (%ld) on adapter %s.\n", + req_id, zfcp_get_busid_by_adapter(adapter)); - zfcp_reqlist_remove(adapter, req_id); + zfcp_reqlist_remove(adapter, fsf_req); atomic_dec(&adapter->reqs_active); spin_unlock_irqrestore(&adapter->req_list_lock, flags); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index e742b3d..16e2d64 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -407,8 +407,8 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) /* Check whether corresponding fsf_req is still pending */ spin_lock(&adapter->req_list_lock); - fsf_req = zfcp_reqlist_ismember(adapter, (unsigned long) - scpnt->host_scribble); + fsf_req = zfcp_reqlist_find(adapter, + (unsigned long) scpnt->host_scribble); spin_unlock(&adapter->req_list_lock); if (!fsf_req) { write_unlock_irqrestore(&adapter->abort_lock, flags); -- cgit v0.10.2 From 3b02191aaeedfffe8cba258ebc212c577c278dbe Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 8 May 2007 11:18:50 +0200 Subject: [SCSI] zfcp: clear adapter failed flag if an fsf request times out. Must clear adapter failed flag if an fsf request times out. This is necessary because on link down situations the failed flags gets set but the QDIO queues are still up. Since an adapter reopen will be skipped if the failed flag is set an adapter_reopen that is issued on fsf request timeout has no effect if the local link is down. Might lead to locked up system if the SCSI stack is waiting for abort completion. Signed-off-by: Heiko Carstens Signed-off-by: Swen Schillig Signed-off-by: James Bottomley diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index e2a3d6f..aef66bc 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -179,7 +179,7 @@ static void zfcp_close_fsf(struct zfcp_adapter *adapter) static void zfcp_fsf_request_timeout_handler(unsigned long data) { struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; - zfcp_erp_adapter_reopen(adapter, 0); + zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED); } void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout) -- cgit v0.10.2 From b64ddf96456cde17be22bf74cafed381a29d58ba Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 8 May 2007 11:19:57 +0200 Subject: [SCSI] zfcp: clear boxed flag on unit reopen. The boxed flag for units was never cleared. This doesn't hurt, but on ACL updates the error recovery could reopen more units than needed. Signed-off-by: Heiko Carstens Signed-off-by: Swen Schillig Signed-off-by: James Bottomley diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 083308b..a8b0254 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -3043,6 +3043,7 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) queue_designator = &header->fsf_status_qual.fsf_queue_designator; atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | + ZFCP_STATUS_COMMON_ACCESS_BOXED | ZFCP_STATUS_UNIT_SHARED | ZFCP_STATUS_UNIT_READONLY, &unit->status); -- cgit v0.10.2