diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-11-05 14:38:55 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-11-05 14:38:55 -0500 |
commit | 328198acb7407301ddf6005c0fa1e04bd0c539c8 (patch) | |
tree | 9936112bd195bfbaacc9a75f2ea7ff757a2c0546 /drivers/scsi/lpfc | |
parent | 9e0cb06b17be7e562cbdaba2768649f025826dc6 (diff) | |
parent | fecb4a0c87c2bcaee1f3cf800126eef752a07ed3 (diff) |
Merge branch 'master'
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 201 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 21 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_ct.c | 14 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_disc.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 36 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 122 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 69 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_mbox.c | 7 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 21 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 399 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 523 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 22 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 2 |
14 files changed, 649 insertions, 793 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index adb95674823..3062b39fbdb 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -267,10 +267,6 @@ struct lpfc_hba { struct lpfc_nodelist fc_fcpnodev; /* nodelist entry for no device */ uint32_t nport_event_cnt; /* timestamp for nlplist entry */ -#define LPFC_RPI_HASH_SIZE 64 -#define LPFC_RPI_HASH_FUNC(x) ((x) & (0x3f)) - /* ptr to active D_ID / RPIs */ - struct lpfc_nodelist *fc_nlplookup[LPFC_RPI_HASH_SIZE]; uint32_t wwnn[2]; uint32_t RandomData[7]; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index acae7c48ef7..89e8222bc7c 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -200,19 +200,13 @@ lpfc_num_discovered_ports_show(struct class_device *cdev, char *buf) } -static ssize_t -lpfc_issue_lip (struct class_device *cdev, const char *buf, size_t count) +static int +lpfc_issue_lip(struct Scsi_Host *host) { - struct Scsi_Host *host = class_to_shost(cdev); struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata[0]; - int val = 0; LPFC_MBOXQ_t *pmboxq; int mbxstatus = MBXERR_ERROR; - if ((sscanf(buf, "%d", &val) != 1) || - (val != 1)) - return -EINVAL; - if ((phba->fc_flag & FC_OFFLINE_MODE) || (phba->hba_state != LPFC_HBA_READY)) return -EPERM; @@ -229,12 +223,12 @@ lpfc_issue_lip (struct class_device *cdev, const char *buf, size_t count) if (mbxstatus == MBX_TIMEOUT) pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; else - mempool_free( pmboxq, phba->mbox_mem_pool); + mempool_free(pmboxq, phba->mbox_mem_pool); if (mbxstatus == MBXERR_ERROR) return -EIO; - return strlen(buf); + return 0; } static ssize_t @@ -251,8 +245,6 @@ lpfc_board_online_show(struct class_device *cdev, char *buf) struct Scsi_Host *host = class_to_shost(cdev); struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0]; - if (!phba) return 0; - if (phba->fc_flag & FC_OFFLINE_MODE) return snprintf(buf, PAGE_SIZE, "0\n"); else @@ -269,7 +261,7 @@ lpfc_board_online_store(struct class_device *cdev, const char *buf, int val=0, status=0; if (sscanf(buf, "%d", &val) != 1) - return 0; + return -EINVAL; init_completion(&online_compl); @@ -283,7 +275,7 @@ lpfc_board_online_store(struct class_device *cdev, const char *buf, if (!status) return strlen(buf); else - return 0; + return -EIO; } @@ -294,47 +286,83 @@ lpfc_##attr##_show(struct class_device *cdev, char *buf) \ struct Scsi_Host *host = class_to_shost(cdev);\ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\ int val = 0;\ - if (phba){\ - val = phba->cfg_##attr;\ - return snprintf(buf, PAGE_SIZE, "%d\n",\ - phba->cfg_##attr);\ + val = phba->cfg_##attr;\ + return snprintf(buf, PAGE_SIZE, "%d\n",\ + phba->cfg_##attr);\ +} + +#define lpfc_param_hex_show(attr) \ +static ssize_t \ +lpfc_##attr##_show(struct class_device *cdev, char *buf) \ +{ \ + struct Scsi_Host *host = class_to_shost(cdev);\ + struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\ + int val = 0;\ + val = phba->cfg_##attr;\ + return snprintf(buf, PAGE_SIZE, "%#x\n",\ + phba->cfg_##attr);\ +} + +#define lpfc_param_init(attr, default, minval, maxval) \ +static int \ +lpfc_##attr##_init(struct lpfc_hba *phba, int val) \ +{ \ + if (val >= minval && val <= maxval) {\ + phba->cfg_##attr = val;\ + return 0;\ }\ - return 0;\ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \ + "%d:0449 lpfc_"#attr" attribute cannot be set to %d, "\ + "allowed range is ["#minval", "#maxval"]\n", \ + phba->brd_no, val); \ + phba->cfg_##attr = default;\ + return -EINVAL;\ } -#define lpfc_param_store(attr, minval, maxval) \ +#define lpfc_param_set(attr, default, minval, maxval) \ +static int \ +lpfc_##attr##_set(struct lpfc_hba *phba, int val) \ +{ \ + if (val >= minval && val <= maxval) {\ + phba->cfg_##attr = val;\ + return 0;\ + }\ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \ + "%d:0450 lpfc_"#attr" attribute cannot be set to %d, "\ + "allowed range is ["#minval", "#maxval"]\n", \ + phba->brd_no, val); \ + return -EINVAL;\ +} + +#define lpfc_param_store(attr) \ static ssize_t \ lpfc_##attr##_store(struct class_device *cdev, const char *buf, size_t count) \ { \ struct Scsi_Host *host = class_to_shost(cdev);\ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata[0];\ - int val = 0;\ + int val=0;\ if (!isdigit(buf[0]))\ return -EINVAL;\ - if (sscanf(buf, "0x%x", &val) != 1)\ - if (sscanf(buf, "%d", &val) != 1)\ - return -EINVAL;\ - if (phba){\ - if (val >= minval && val <= maxval) {\ - phba->cfg_##attr = val;\ - return strlen(buf);\ - }\ - }\ - return 0;\ + if (sscanf(buf, "%i", &val) != 1)\ + return -EINVAL;\ + if (lpfc_##attr##_set(phba, val) == 0) \ + return strlen(buf);\ + else \ + return -EINVAL;\ } -#define LPFC_ATTR_R_NOINIT(name, desc) \ -extern int lpfc_##name;\ +#define LPFC_ATTR(name, defval, minval, maxval, desc) \ +static int lpfc_##name = defval;\ module_param(lpfc_##name, int, 0);\ MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_param_show(name)\ -static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) +lpfc_param_init(name, defval, minval, maxval) #define LPFC_ATTR_R(name, defval, minval, maxval, desc) \ static int lpfc_##name = defval;\ module_param(lpfc_##name, int, 0);\ MODULE_PARM_DESC(lpfc_##name, desc);\ lpfc_param_show(name)\ +lpfc_param_init(name, defval, minval, maxval)\ static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) #define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \ @@ -342,7 +370,28 @@ static int lpfc_##name = defval;\ module_param(lpfc_##name, int, 0);\ MODULE_PARM_DESC(lpfc_##name, desc);\ lpfc_param_show(name)\ -lpfc_param_store(name, minval, maxval)\ +lpfc_param_init(name, defval, minval, maxval)\ +lpfc_param_set(name, defval, minval, maxval)\ +lpfc_param_store(name)\ +static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ + lpfc_##name##_show, lpfc_##name##_store) + +#define LPFC_ATTR_HEX_R(name, defval, minval, maxval, desc) \ +static int lpfc_##name = defval;\ +module_param(lpfc_##name, int, 0);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_param_hex_show(name)\ +lpfc_param_init(name, defval, minval, maxval)\ +static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) + +#define LPFC_ATTR_HEX_RW(name, defval, minval, maxval, desc) \ +static int lpfc_##name = defval;\ +module_param(lpfc_##name, int, 0);\ +MODULE_PARM_DESC(lpfc_##name, desc);\ +lpfc_param_hex_show(name)\ +lpfc_param_init(name, defval, minval, maxval)\ +lpfc_param_set(name, defval, minval, maxval)\ +lpfc_param_store(name)\ static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ lpfc_##name##_show, lpfc_##name##_store) @@ -364,7 +413,6 @@ static CLASS_DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show, NULL); static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show, NULL); -static CLASS_DEVICE_ATTR(issue_lip, S_IWUSR, NULL, lpfc_issue_lip); static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR, lpfc_board_online_show, lpfc_board_online_store); @@ -388,7 +436,7 @@ static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR, # LOG_LIBDFC 0x2000 LIBDFC events # LOG_ALL_MSG 0xffff LOG all messages */ -LPFC_ATTR_RW(log_verbose, 0x0, 0x0, 0xffff, "Verbose logging bit-mask"); +LPFC_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff, "Verbose logging bit-mask"); /* # lun_queue_depth: This parameter is used to limit the number of outstanding @@ -419,7 +467,7 @@ LPFC_ATTR_R(scan_down, 1, 0, 1, /* # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear -# until the timer expires. Value range is [0,255]. Default value is 20. +# until the timer expires. Value range is [0,255]. Default value is 30. # NOTE: this MUST be less then the SCSI Layer command timeout - 1. */ LPFC_ATTR_RW(nodev_tmo, 30, 0, 255, @@ -475,14 +523,10 @@ LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support"); # is 0. Default value of cr_count is 1. The cr_count feature is disabled if # cr_delay is set to 0. */ -static int lpfc_cr_delay = 0; -module_param(lpfc_cr_delay, int , 0); -MODULE_PARM_DESC(lpfc_cr_delay, "A count of milliseconds after which an " +LPFC_ATTR(cr_delay, 0, 0, 63, "A count of milliseconds after which an" "interrupt response is generated"); -static int lpfc_cr_count = 1; -module_param(lpfc_cr_count, int, 0); -MODULE_PARM_DESC(lpfc_cr_count, "A count of I/O completions after which an " +LPFC_ATTR(cr_count, 1, 1, 255, "A count of I/O completions after which an" "interrupt response is generated"); /* @@ -498,9 +542,7 @@ LPFC_ATTR_RW(fdmi_on, 0, 0, 2, "Enable FDMI support"); # Specifies the maximum number of ELS cmds we can have outstanding (for # discovery). Value range is [1,64]. Default value = 32. */ -static int lpfc_discovery_threads = 32; -module_param(lpfc_discovery_threads, int, 0); -MODULE_PARM_DESC(lpfc_discovery_threads, "Maximum number of ELS commands " +LPFC_ATTR(discovery_threads, 32, 1, 64, "Maximum number of ELS commands" "during discovery"); /* @@ -537,7 +579,6 @@ struct class_device_attribute *lpfc_host_attrs[] = { &class_device_attr_lpfc_max_luns, &class_device_attr_nport_evt_cnt, &class_device_attr_management_version, - &class_device_attr_issue_lip, &class_device_attr_board_online, NULL, }; @@ -992,7 +1033,7 @@ lpfc_get_stats(struct Scsi_Host *shost) struct fc_host_statistics *hs = &phba->link_stats; LPFC_MBOXQ_t *pmboxq; MAILBOX_t *pmb; - int rc=0; + int rc = 0; pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmboxq) @@ -1005,18 +1046,16 @@ lpfc_get_stats(struct Scsi_Host *shost) pmboxq->context1 = NULL; if ((phba->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI2_ACTIVE))){ + (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - } else + else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); if (rc != MBX_SUCCESS) { - if (pmboxq) { - if (rc == MBX_TIMEOUT) - pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - else - mempool_free( pmboxq, phba->mbox_mem_pool); - } + if (rc == MBX_TIMEOUT) + pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + else + mempool_free(pmboxq, phba->mbox_mem_pool); return NULL; } @@ -1027,24 +1066,22 @@ lpfc_get_stats(struct Scsi_Host *shost) hs->rx_frames = pmb->un.varRdStatus.rcvFrameCnt; hs->rx_words = (pmb->un.varRdStatus.rcvByteCnt * 256); - memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); + memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t)); pmb->mbxCommand = MBX_READ_LNK_STAT; pmb->mbxOwner = OWN_HOST; pmboxq->context1 = NULL; if ((phba->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) { + (!(psli->sli_flag & LPFC_SLI2_ACTIVE))) rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - } else + else rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); if (rc != MBX_SUCCESS) { - if (pmboxq) { - if (rc == MBX_TIMEOUT) - pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - else - mempool_free( pmboxq, phba->mbox_mem_pool); - } + if (rc == MBX_TIMEOUT) + pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + else + mempool_free( pmboxq, phba->mbox_mem_pool); return NULL; } @@ -1234,25 +1271,27 @@ struct fc_function_template lpfc_transport_functions = { .get_starget_port_name = lpfc_get_starget_port_name, .show_starget_port_name = 1, + + .issue_fc_host_lip = lpfc_issue_lip, }; void lpfc_get_cfgparam(struct lpfc_hba *phba) { - phba->cfg_log_verbose = lpfc_log_verbose; - phba->cfg_cr_delay = lpfc_cr_delay; - phba->cfg_cr_count = lpfc_cr_count; - phba->cfg_lun_queue_depth = lpfc_lun_queue_depth; - phba->cfg_fcp_class = lpfc_fcp_class; - phba->cfg_use_adisc = lpfc_use_adisc; - phba->cfg_ack0 = lpfc_ack0; - phba->cfg_topology = lpfc_topology; - phba->cfg_scan_down = lpfc_scan_down; - phba->cfg_nodev_tmo = lpfc_nodev_tmo; - phba->cfg_link_speed = lpfc_link_speed; - phba->cfg_fdmi_on = lpfc_fdmi_on; - phba->cfg_discovery_threads = lpfc_discovery_threads; - phba->cfg_max_luns = lpfc_max_luns; + lpfc_log_verbose_init(phba, lpfc_log_verbose); + lpfc_cr_delay_init(phba, lpfc_cr_delay); + lpfc_cr_count_init(phba, lpfc_cr_count); + lpfc_lun_queue_depth_init(phba, lpfc_lun_queue_depth); + lpfc_fcp_class_init(phba, lpfc_fcp_class); + lpfc_use_adisc_init(phba, lpfc_use_adisc); + lpfc_ack0_init(phba, lpfc_ack0); + lpfc_topology_init(phba, lpfc_topology); + lpfc_scan_down_init(phba, lpfc_scan_down); + lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo); + lpfc_link_speed_init(phba, lpfc_link_speed); + lpfc_fdmi_on_init(phba, lpfc_fdmi_on); + lpfc_discovery_threads_init(phba, lpfc_discovery_threads); + lpfc_max_luns_init(phba, lpfc_max_luns); /* * The total number of segments is the configuration value plus 2 diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index bd5135d3eee..d527d05a607 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -62,10 +62,6 @@ void lpfc_disc_timeout(unsigned long); void lpfc_scan_timeout(unsigned long); struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi); -struct lpfc_nodelist *lpfc_findnode_remove_rpi(struct lpfc_hba * phba, - uint16_t rpi); -void lpfc_addnode_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, - uint16_t rpi); int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t); int lpfc_do_work(void *); @@ -147,6 +143,9 @@ LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *); int lpfc_mem_alloc(struct lpfc_hba *); void lpfc_mem_free(struct lpfc_hba *); +struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); +void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); +uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb); int lpfc_sli_hba_setup(struct lpfc_hba *); int lpfc_sli_hba_down(struct lpfc_hba *); int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); @@ -182,15 +181,11 @@ struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq, uint32_t timeout); -int lpfc_sli_issue_iocb_wait_high_priority(struct lpfc_hba * phba, - struct lpfc_sli_ring * pring, - struct lpfc_iocbq * piocb, - uint32_t flag, - struct lpfc_iocbq * prspiocbq, - uint32_t timeout); -void lpfc_sli_wake_iocb_high_priority(struct lpfc_hba * phba, - struct lpfc_iocbq * queue1, - struct lpfc_iocbq * queue2); +int lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba, + struct lpfc_sli_ring * pring, + struct lpfc_iocbq * piocb, + struct lpfc_iocbq * prspiocbq, + uint32_t timeout); void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 1280f0e5463..7f427f9c468 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -224,18 +224,16 @@ lpfc_gen_req(struct lpfc_hba *phba, struct lpfc_dmabuf *bmp, struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; - struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; IOCB_t *icmd; - struct lpfc_iocbq *geniocb = NULL; + struct lpfc_iocbq *geniocb; /* Allocate buffer for command iocb */ spin_lock_irq(phba->host->host_lock); - list_remove_head(lpfc_iocb_list, geniocb, struct lpfc_iocbq, list); + geniocb = lpfc_sli_get_iocbq(phba); spin_unlock_irq(phba->host->host_lock); if (geniocb == NULL) return 1; - memset(geniocb, 0, sizeof (struct lpfc_iocbq)); icmd = &geniocb->iocb; icmd->un.genreq64.bdl.ulpIoTag32 = 0; @@ -279,7 +277,7 @@ lpfc_gen_req(struct lpfc_hba *phba, struct lpfc_dmabuf *bmp, geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT; spin_lock_irq(phba->host->host_lock); if (lpfc_sli_issue_iocb(phba, pring, geniocb, 0) == IOCB_ERROR) { - list_add_tail(&geniocb->list, lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, geniocb); spin_unlock_irq(phba->host->host_lock); return 1; } @@ -487,7 +485,7 @@ out: kfree(inp); kfree(bmp); spin_lock_irq(phba->host->host_lock); - list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, cmdiocb); spin_unlock_irq(phba->host->host_lock); return; } @@ -526,7 +524,7 @@ lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, kfree(inp); kfree(bmp); spin_lock_irq(phba->host->host_lock); - list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, cmdiocb); spin_unlock_irq(phba->host->host_lock); return; } @@ -735,7 +733,7 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba * phba, kfree(inp); kfree(bmp); spin_lock_irq(phba->host->host_lock); - list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, cmdiocb); spin_unlock_irq(phba->host->host_lock); return; } diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 098b8b45c7f..084e7628ce1 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -70,7 +70,6 @@ struct lpfc_nodelist { struct timer_list nlp_tmofunc; /* Used for nodev tmo */ struct fc_rport *rport; /* Corresponding FC transport port structure */ - struct lpfc_nodelist *nlp_rpi_hash_next; struct lpfc_hba *nlp_phba; struct lpfc_work_evt nodev_timeout_evt; struct lpfc_work_evt els_retry_evt; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 63caf7fe972..08a0c00cfc3 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -102,9 +102,8 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint16_t cmdSize, uint8_t retry, struct lpfc_nodelist * ndlp, uint32_t elscmd) { - struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; struct lpfc_sli_ring *pring; - struct lpfc_iocbq *elsiocb = NULL; + struct lpfc_iocbq *elsiocb; struct lpfc_dmabuf *pcmd, *prsp, *pbuflist; struct ulp_bde64 *bpl; IOCB_t *icmd; @@ -114,15 +113,13 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, if (phba->hba_state < LPFC_LINK_UP) return NULL; - /* Allocate buffer for command iocb */ spin_lock_irq(phba->host->host_lock); - list_remove_head(lpfc_iocb_list, elsiocb, struct lpfc_iocbq, list); + elsiocb = lpfc_sli_get_iocbq(phba); spin_unlock_irq(phba->host->host_lock); if (elsiocb == NULL) return NULL; - memset(elsiocb, 0, sizeof (struct lpfc_iocbq)); icmd = &elsiocb->iocb; /* fill in BDEs for command */ @@ -133,7 +130,9 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, if (pcmd) kfree(pcmd); - list_add_tail(&elsiocb->list, lpfc_iocb_list); + spin_lock_irq(phba->host->host_lock); + lpfc_sli_release_iocbq(phba, elsiocb); + spin_unlock_irq(phba->host->host_lock); return NULL; } @@ -150,7 +149,9 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, kfree(prsp); lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); kfree(pcmd); - list_add_tail(&elsiocb->list, lpfc_iocb_list); + spin_lock_irq(phba->host->host_lock); + lpfc_sli_release_iocbq(phba, elsiocb); + spin_unlock_irq(phba->host->host_lock); return NULL; } INIT_LIST_HEAD(&prsp->list); @@ -164,7 +165,9 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pbuflist->phys); if (pbuflist == 0 || pbuflist->virt == 0) { - list_add_tail(&elsiocb->list, lpfc_iocb_list); + spin_lock_irq(phba->host->host_lock); + lpfc_sli_release_iocbq(phba, elsiocb); + spin_unlock_irq(phba->host->host_lock); lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); lpfc_mbuf_free(phba, prsp->virt, prsp->phys); kfree(pcmd); @@ -596,10 +599,8 @@ lpfc_els_abort_flogi(struct lpfc_hba * phba) spin_unlock_irq(phba->host->host_lock); (iocb->iocb_cmpl) (phba, iocb, iocb); spin_lock_irq(phba->host->host_lock); - } else { - list_add_tail(&iocb->list, - &phba->lpfc_iocb_list); - } + } else + lpfc_sli_release_iocbq(phba, iocb); } } } @@ -1713,7 +1714,7 @@ lpfc_els_free_iocb(struct lpfc_hba * phba, struct lpfc_iocbq * elsiocb) kfree(buf_ptr); } spin_lock_irq(phba->host->host_lock); - list_add_tail(&elsiocb->list, &phba->lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, elsiocb); spin_unlock_irq(phba->host->host_lock); return 0; } @@ -2929,9 +2930,8 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba) spin_unlock_irq(phba->host->host_lock); (piocb->iocb_cmpl) (phba, piocb, piocb); spin_lock_irq(phba->host->host_lock); - } else { - list_add_tail(&piocb->list, &phba->lpfc_iocb_list); - } + } else + lpfc_sli_release_iocbq(phba, piocb); } if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) { phba->els_tmofunc.expires = jiffies + HZ * timeout; @@ -2996,7 +2996,7 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba) spin_lock_irq(phba->host->host_lock); } else - list_add_tail(&piocb->list, &phba->lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, piocb); } list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { @@ -3033,7 +3033,7 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba) spin_lock_irq(phba->host->host_lock); } else - list_add_tail(&piocb->list, &phba->lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, 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 56052f4510c..259eeb161b8 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -890,10 +890,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) pmb->context1 = NULL; - if (ndlp->nlp_rpi != 0) - lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi); ndlp->nlp_rpi = mb->un.varWords[0]; - lpfc_addnode_rpi(phba, ndlp, ndlp->nlp_rpi); ndlp->nlp_type |= NLP_FABRIC; ndlp->nlp_state = NLP_STE_UNMAPPED_NODE; lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST); @@ -981,10 +978,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) pmb->context1 = NULL; - if (ndlp->nlp_rpi != 0) - lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi); ndlp->nlp_rpi = mb->un.varWords[0]; - lpfc_addnode_rpi(phba, ndlp, ndlp->nlp_rpi); ndlp->nlp_type |= NLP_FABRIC; ndlp->nlp_state = NLP_STE_UNMAPPED_NODE; lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST); @@ -1028,6 +1022,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba, if (ndlp->nlp_type & NLP_FCP_INITIATOR) rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; + scsi_block_requests(phba->host); ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids); if (!rport) { dev_printk(KERN_WARNING, &phba->pcidev->dev, @@ -1044,6 +1039,23 @@ lpfc_register_remote_port(struct lpfc_hba * phba, } rdata = rport->dd_data; rdata->pnode = ndlp; + scsi_unblock_requests(phba->host); + + return; +} + +static void +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; + + ndlp->rport = NULL; + rdata->pnode = NULL; + scsi_block_requests(phba->host); + fc_remote_port_delete(rport); + scsi_unblock_requests(phba->host); return; } @@ -1260,7 +1272,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) * may have removed the remote port. */ if ((rport_del != none) && nlp->rport) - fc_remote_port_block(nlp->rport); + lpfc_unregister_remote_port(phba, nlp); if (rport_add != none) { /* @@ -1270,8 +1282,6 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) */ if (!nlp->rport) lpfc_register_remote_port(phba, nlp); - else - fc_remote_port_unblock(nlp->rport); /* * if we added to Mapped list, but the remote port @@ -1435,10 +1445,9 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) iocb, iocb); spin_lock_irq(phba->host-> host_lock); - } else { - list_add_tail(&iocb->list, - &phba->lpfc_iocb_list); - } + } else + lpfc_sli_release_iocbq(phba, + iocb); } } spin_unlock_irq(phba->host->host_lock); @@ -1472,7 +1481,6 @@ lpfc_unreg_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) if (rc == MBX_NOT_FINISHED) mempool_free( mbox, phba->mbox_mem_pool); } - lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi); lpfc_no_rpi(phba, ndlp); ndlp->nlp_rpi = 0; return 1; @@ -1490,7 +1498,6 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) LPFC_MBOXQ_t *mb; LPFC_MBOXQ_t *nextmb; struct lpfc_dmabuf *mp; - struct fc_rport *rport; /* Cleanup node for NPort <nlp_DID> */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, @@ -1507,10 +1514,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) * and flush cache's w/o generating flush errors. */ if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) { - rport = ndlp->rport; - ndlp->rport = NULL; - fc_remote_port_unblock(rport); - fc_remote_port_delete(rport); + lpfc_unregister_remote_port(phba, ndlp); ndlp->nlp_sid = NLP_NO_SID; } @@ -2422,10 +2426,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) pmb->context1 = NULL; - if (ndlp->nlp_rpi != 0) - lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi); ndlp->nlp_rpi = mb->un.varWords[0]; - lpfc_addnode_rpi(phba, ndlp, ndlp->nlp_rpi); ndlp->nlp_type |= NLP_FABRIC; ndlp->nlp_state = NLP_STE_UNMAPPED_NODE; lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST); @@ -2451,75 +2452,28 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) } /* - * This routine looks up the ndlp hash - * table for the given RPI. If rpi found + * This routine looks up the ndlp lists + * for the given RPI. If rpi found * it return the node list pointer - * else return 0. + * else return NULL. */ struct lpfc_nodelist * lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi) { - struct lpfc_nodelist *ret; - - ret = phba->fc_nlplookup[LPFC_RPI_HASH_FUNC(rpi)]; - while ((ret != 0) && (ret->nlp_rpi != rpi)) { - ret = ret->nlp_rpi_hash_next; - } - return ret; -} - -/* - * This routine looks up the ndlp hash table for the - * given RPI. If rpi found it return the node list - * pointer else return 0 after deleting the entry - * from hash table. - */ -struct lpfc_nodelist * -lpfc_findnode_remove_rpi(struct lpfc_hba * phba, uint16_t rpi) -{ - struct lpfc_nodelist *ret, *temp;; - - ret = phba->fc_nlplookup[LPFC_RPI_HASH_FUNC(rpi)]; - if (ret == 0) - return NULL; - - if (ret->nlp_rpi == rpi) { - phba->fc_nlplookup[LPFC_RPI_HASH_FUNC(rpi)] = - ret->nlp_rpi_hash_next; - ret->nlp_rpi_hash_next = NULL; - return ret; - } - - while ((ret->nlp_rpi_hash_next != 0) && - (ret->nlp_rpi_hash_next->nlp_rpi != rpi)) { - ret = ret->nlp_rpi_hash_next; - } - - if (ret->nlp_rpi_hash_next != 0) { - temp = ret->nlp_rpi_hash_next; - ret->nlp_rpi_hash_next = temp->nlp_rpi_hash_next; - temp->nlp_rpi_hash_next = NULL; - return temp; - } else { - return NULL; - } -} - -/* - * This routine adds the node list entry to the - * ndlp hash table. - */ -void -lpfc_addnode_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, - uint16_t rpi) -{ + 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; - uint32_t index; + for (i = 0; i < ARRAY_SIZE(lists); i++ ) + list_for_each_entry(ndlp, lists[i], nlp_listp) + if (ndlp->nlp_rpi == rpi) + return (ndlp); - index = LPFC_RPI_HASH_FUNC(rpi); - ndlp->nlp_rpi_hash_next = phba->fc_nlplookup[index]; - phba->fc_nlplookup[index] = ndlp; - return; + return NULL; } void diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 0856ff7d3b3..4e04470321a 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -537,12 +537,6 @@ lpfc_handle_eratt(struct lpfc_hba * phba) lpfc_offline(phba); - /* - * Restart all traffic to this host. Since the fc_transport - * block functions (future) were not called in lpfc_offline, - * don't call them here. - */ - scsi_unblock_requests(phba->host); } } @@ -772,10 +766,12 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) { lpfc_vpd_t *vp; uint32_t id; + uint8_t hdrtype; char str[16]; vp = &phba->vpd; pci_read_config_dword(phba->pcidev, PCI_VENDOR_ID, &id); + pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype); switch ((id >> 16) & 0xffff) { case PCI_DEVICE_ID_FIREFLY: @@ -803,7 +799,10 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) strcpy(str, "LP9802 2"); break; case PCI_DEVICE_ID_THOR: - strcpy(str, "LP10000 2"); + if (hdrtype == 0x80) + strcpy(str, "LP10000DC 2"); + else + strcpy(str, "LP10000 2"); break; case PCI_DEVICE_ID_VIPER: strcpy(str, "LPX1000 10"); @@ -812,10 +811,16 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) strcpy(str, "LP982 2"); break; case PCI_DEVICE_ID_TFLY: - strcpy(str, "LP1050 2"); + if (hdrtype == 0x80) + strcpy(str, "LP1050DC 2"); + else + strcpy(str, "LP1050 2"); break; case PCI_DEVICE_ID_HELIOS: - strcpy(str, "LP11000 4"); + if (hdrtype == 0x80) + strcpy(str, "LP11002 4"); + else + strcpy(str, "LP11000 4"); break; case PCI_DEVICE_ID_BMID: strcpy(str, "LP1150 4"); @@ -824,13 +829,16 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) strcpy(str, "LP111 4"); break; case PCI_DEVICE_ID_ZEPHYR: - strcpy(str, "LP11000e 4"); + if (hdrtype == 0x80) + strcpy(str, "LPe11002 4"); + else + strcpy(str, "LPe11000 4"); break; case PCI_DEVICE_ID_ZMID: - strcpy(str, "LP1150e 4"); + strcpy(str, "LPe1150 4"); break; case PCI_DEVICE_ID_ZSMB: - strcpy(str, "LP111e 4"); + strcpy(str, "LPe111 4"); break; case PCI_DEVICE_ID_LP101: strcpy(str, "LP101 2"); @@ -862,8 +870,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt, int type) { IOCB_t *icmd; - struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; - struct lpfc_iocbq *iocb = NULL; + struct lpfc_iocbq *iocb; struct lpfc_dmabuf *mp1, *mp2; cnt += pring->missbufcnt; @@ -872,13 +879,12 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt, while (cnt > 0) { /* Allocate buffer for command iocb */ spin_lock_irq(phba->host->host_lock); - list_remove_head(lpfc_iocb_list, iocb, struct lpfc_iocbq, list); + iocb = lpfc_sli_get_iocbq(phba); spin_unlock_irq(phba->host->host_lock); if (iocb == NULL) { pring->missbufcnt = cnt; return cnt; } - memset(iocb, 0, sizeof (struct lpfc_iocbq)); icmd = &iocb->iocb; /* 2 buffers can be posted per command */ @@ -891,7 +897,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt, if (mp1) kfree(mp1); spin_lock_irq(phba->host->host_lock); - list_add_tail(&iocb->list, lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, iocb); spin_unlock_irq(phba->host->host_lock); pring->missbufcnt = cnt; return cnt; @@ -910,7 +916,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt, lpfc_mbuf_free(phba, mp1->virt, mp1->phys); kfree(mp1); spin_lock_irq(phba->host->host_lock); - list_add_tail(&iocb->list, lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, iocb); spin_unlock_irq(phba->host->host_lock); pring->missbufcnt = cnt; return cnt; @@ -947,7 +953,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt, kfree(mp2); cnt++; } - list_add_tail(&iocb->list, lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, iocb); pring->missbufcnt = cnt; spin_unlock_irq(phba->host->host_lock); return cnt; @@ -1226,12 +1232,6 @@ lpfc_online(struct lpfc_hba * phba) phba->fc_flag &= ~FC_OFFLINE_MODE; spin_unlock_irq(phba->host->host_lock); - /* - * Restart all traffic to this host. Since the fc_transport block - * functions (future) were not called in lpfc_offline, don't call them - * here. - */ - scsi_unblock_requests(phba->host); return 0; } @@ -1249,13 +1249,6 @@ lpfc_offline(struct lpfc_hba * phba) if (phba->fc_flag & FC_OFFLINE_MODE) return 0; - /* - * Don't call the fc_transport block api (future). The device is - * going offline and causing a timer to fire in the midlayer is - * unproductive. Just block all new requests until the driver - * comes back online. - */ - scsi_block_requests(phba->host); psli = &phba->sli; pring = &psli->ring[psli->fcp_ring]; @@ -1333,6 +1326,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) unsigned long bar0map_len, bar2map_len; int error = -ENODEV, retval; int i; + uint16_t iotag; if (pci_enable_device(pdev)) goto out; @@ -1434,6 +1428,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) if (!phba->slim2p) goto out_iounmap; + memset(phba->slim2p, 0, SLI2_SLIM_SIZE); /* Initialize the SLI Layer to run with lpfc HBAs. */ lpfc_sli_setup(phba); @@ -1456,6 +1451,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) } memset(iocbq_entry, 0, sizeof(struct lpfc_iocbq)); + iotag = lpfc_sli_next_iotag(phba, iocbq_entry); + if (iotag == 0) { + kfree (iocbq_entry); + printk(KERN_ERR "%s: failed to allocate IOTAG. " + "Unloading driver.\n", + __FUNCTION__); + error = -ENOMEM; + goto out_free_iocbq; + } spin_lock_irq(phba->host->host_lock); list_add(&iocbq_entry->list, &phba->lpfc_iocb_list); phba->total_iocbq_bufs++; @@ -1702,6 +1706,7 @@ MODULE_DEVICE_TABLE(pci, lpfc_id_table); static struct pci_driver lpfc_driver = { .name = LPFC_DRIVER_NAME, + .owner = THIS_MODULE, .id_table = lpfc_id_table, .probe = lpfc_pci_probe_one, .remove = __devexit_p(lpfc_pci_remove_one), diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 73eb89f9159..31c20cc0060 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -531,6 +531,7 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) size_t offset; struct lpfc_hgp hgp; void __iomem *to_slim; + int i; memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); mb->mbxCommand = MBX_CONFIG_PORT; @@ -587,7 +588,11 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) /* write HGP data to SLIM at the required longword offset */ memset(&hgp, 0, sizeof(struct lpfc_hgp)); to_slim = phba->MBslimaddr + (SLIMOFF*sizeof (uint32_t)); - lpfc_memcpy_to_slim(to_slim, &hgp, sizeof(struct lpfc_hgp)); + + for (i=0; i < phba->sli.num_rings; i++) { + lpfc_memcpy_to_slim(to_slim, &hgp, sizeof(struct lpfc_hgp)); + to_slim += sizeof (struct lpfc_hgp); + } /* Setup Port Group ring pointer */ offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port - diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 9b35eaac781..507a6af56f4 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -187,10 +187,8 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, spin_unlock_irq(phba->host->host_lock); (iocb->iocb_cmpl) (phba, iocb, iocb); spin_lock_irq(phba->host->host_lock); - } else { - list_add_tail(&iocb->list, - &phba->lpfc_iocb_list); - } + } else + lpfc_sli_release_iocbq(phba, iocb); break; } } @@ -232,10 +230,8 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, spin_unlock_irq(phba->host->host_lock); (iocb->iocb_cmpl) (phba, iocb, iocb); spin_lock_irq(phba->host->host_lock); - } else { - list_add_tail(&iocb->list, - &phba->lpfc_iocb_list); - } + } else + lpfc_sli_release_iocbq(phba, iocb); break; } } @@ -1086,11 +1082,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba, return (ndlp->nlp_state); } - if (ndlp->nlp_rpi != 0) - lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi); - ndlp->nlp_rpi = mb->un.varWords[0]; - lpfc_addnode_rpi(phba, ndlp, ndlp->nlp_rpi); /* Only if we are not a fabric nport do we issue PRLI */ if (!(ndlp->nlp_type & NLP_FABRIC)) { @@ -1593,12 +1585,7 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_hba * phba, pmb = (LPFC_MBOXQ_t *) arg; mb = &pmb->mb; - /* save rpi */ - if (ndlp->nlp_rpi != 0) - lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi); - ndlp->nlp_rpi = mb->un.varWords[0]; - lpfc_addnode_rpi(phba, ndlp, ndlp->nlp_rpi); return (ndlp->nlp_state); } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index b5ad1871d34..c34d3cf4f19 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -50,12 +50,13 @@ * and the BPL BDE is setup in the IOCB. */ static struct lpfc_scsi_buf * -lpfc_get_scsi_buf(struct lpfc_hba * phba) +lpfc_new_scsi_buf(struct lpfc_hba * phba) { struct lpfc_scsi_buf *psb; struct ulp_bde64 *bpl; IOCB_t *iocb; dma_addr_t pdma_phys; + uint16_t iotag; psb = kmalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); if (!psb) @@ -79,6 +80,16 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba) /* Initialize virtual ptrs to dma_buf region. */ memset(psb->data, 0, phba->cfg_sg_dma_buf_size); + /* Allocate iotag for psb->cur_iocbq. */ + iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq); + if (iotag == 0) { + pci_pool_free(phba->lpfc_scsi_dma_buf_pool, + psb->data, psb->dma_handle); + kfree (psb); + return NULL; + } + psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP; + psb->fcp_cmnd = psb->data; psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd); psb->fcp_bpl = psb->data + sizeof(struct fcp_cmnd) + @@ -125,11 +136,19 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba) return psb; } -static void -lpfc_free_scsi_buf(struct lpfc_scsi_buf * psb) +struct lpfc_scsi_buf* +lpfc_sli_get_scsi_buf(struct lpfc_hba * phba) { - struct lpfc_hba *phba = psb->scsi_hba; + struct lpfc_scsi_buf * lpfc_cmd = NULL; + struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list; + + list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list); + return lpfc_cmd; +} +static void +lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb) +{ /* * There are only two special cases to consider. (1) the scsi command * requested scatter-gather usage or (2) the scsi command allocated @@ -147,6 +166,7 @@ lpfc_free_scsi_buf(struct lpfc_scsi_buf * psb) } } + psb->pCmd = NULL; list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list); } @@ -403,14 +423,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, break; } - if (pnode) { - if (pnode->nlp_state != NLP_STE_MAPPED_NODE) - cmd->result = ScsiResult(DID_BUS_BUSY, - SAM_STAT_BUSY); - } - else { - cmd->result = ScsiResult(DID_NO_CONNECT, 0); - } + if ((pnode == NULL ) + || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) + cmd->result = ScsiResult(DID_BUS_BUSY, SAM_STAT_BUSY); } else { cmd->result = ScsiResult(DID_OK, 0); } @@ -426,12 +441,11 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, *lp, *(lp + 3), cmd->retries, cmd->resid); } + cmd->scsi_done(cmd); + spin_lock_irqsave(phba->host->host_lock, iflag); - lpfc_free_scsi_buf(lpfc_cmd); - cmd->host_scribble = NULL; + lpfc_release_scsi_buf(phba, lpfc_cmd); spin_unlock_irqrestore(phba->host->host_lock, iflag); - - cmd->scsi_done(cmd); } static void @@ -539,7 +553,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, struct lpfc_rport_data *rdata = scsi_dev->hostdata; struct lpfc_nodelist *ndlp = rdata->pnode; - if ((ndlp == 0) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { + if ((ndlp == NULL) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { return 0; } @@ -618,8 +632,7 @@ static int lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba) { struct lpfc_iocbq *iocbq; - struct lpfc_iocbq *iocbqrsp = NULL; - struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; + struct lpfc_iocbq *iocbqrsp; int ret; ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_TARGET_RESET); @@ -628,17 +641,14 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba) lpfc_cmd->scsi_hba = phba; iocbq = &lpfc_cmd->cur_iocbq; - list_remove_head(lpfc_iocb_list, iocbqrsp, struct lpfc_iocbq, list); + iocbqrsp = lpfc_sli_get_iocbq(phba); + if (!iocbqrsp) return FAILED; - memset(iocbqrsp, 0, sizeof (struct lpfc_iocbq)); - - iocbq->iocb_flag |= LPFC_IO_POLL; - ret = lpfc_sli_issue_iocb_wait_high_priority(phba, - &phba->sli.ring[phba->sli.fcp_ring], - iocbq, SLI_IOCB_HIGH_PRIORITY, - iocbqrsp, - lpfc_cmd->timeout); + + ret = lpfc_sli_issue_iocb_wait(phba, + &phba->sli.ring[phba->sli.fcp_ring], + iocbq, iocbqrsp, lpfc_cmd->timeout); if (ret != IOCB_SUCCESS) { lpfc_cmd->status = IOSTAT_DRIVER_REJECT; ret = FAILED; @@ -651,45 +661,10 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba) lpfc_cmd->status = IOSTAT_DRIVER_REJECT; } - /* - * All outstanding txcmplq I/Os should have been aborted by the target. - * Unfortunately, some targets do not abide by this forcing the driver - * to double check. - */ - lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring], - lpfc_cmd->pCmd->device->id, - lpfc_cmd->pCmd->device->lun, 0, LPFC_CTX_TGT); - - /* Return response IOCB to free list. */ - list_add_tail(&iocbqrsp->list, lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, iocbqrsp); return ret; } -static void -lpfc_scsi_cmd_iocb_cleanup (struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, - struct lpfc_iocbq *pIocbOut) -{ - unsigned long iflag; - struct lpfc_scsi_buf *lpfc_cmd = - (struct lpfc_scsi_buf *) pIocbIn->context1; - - spin_lock_irqsave(phba->host->host_lock, iflag); - lpfc_free_scsi_buf(lpfc_cmd); - spin_unlock_irqrestore(phba->host->host_lock, iflag); -} - -static void -lpfc_scsi_cmd_iocb_cmpl_aborted(struct lpfc_hba *phba, - struct lpfc_iocbq *pIocbIn, - struct lpfc_iocbq *pIocbOut) -{ - struct scsi_cmnd *ml_cmd = - ((struct lpfc_scsi_buf *) pIocbIn->context1)->pCmd; - - lpfc_scsi_cmd_iocb_cleanup (phba, pIocbIn, pIocbOut); - ml_cmd->host_scribble = NULL; -} - const char * lpfc_info(struct Scsi_Host *host) { @@ -726,43 +701,25 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) struct lpfc_sli *psli = &phba->sli; struct lpfc_rport_data *rdata = cmnd->device->hostdata; struct lpfc_nodelist *ndlp = rdata->pnode; - struct lpfc_scsi_buf *lpfc_cmd = NULL; - struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list; - int err = 0; + struct lpfc_scsi_buf *lpfc_cmd; + struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); + int err; - /* - * The target pointer is guaranteed not to be NULL because the driver - * only clears the device->hostdata field in lpfc_slave_destroy. This - * approach guarantees no further IO calls on this target. - */ - if (!ndlp) { - cmnd->result = ScsiResult(DID_NO_CONNECT, 0); + err = fc_remote_port_chkready(rport); + if (err) { + cmnd->result = err; goto out_fail_command; } /* - * A Fibre Channel target is present and functioning only when the node - * state is MAPPED. Any other state is a failure. + * Catch race where our node has transitioned, but the + * transport is still transitioning. */ - if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) { - if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) || - (ndlp->nlp_state == NLP_STE_UNUSED_NODE)) { - cmnd->result = ScsiResult(DID_NO_CONNECT, 0); - goto out_fail_command; - } - else if (ndlp->nlp_state == NLP_STE_NPR_NODE) { - cmnd->result = ScsiResult(DID_BUS_BUSY, 0); - goto out_fail_command; - } - /* - * The device is most likely recovered and the driver - * needs a bit more time to finish. Ask the midlayer - * to retry. - */ - goto out_host_busy; + if (!ndlp) { + cmnd->result = ScsiResult(DID_BUS_BUSY, 0); + goto out_fail_command; } - - list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list); + lpfc_cmd = lpfc_sli_get_scsi_buf (phba); if (lpfc_cmd == NULL) { printk(KERN_WARNING "%s: No buffer available - list empty, " "total count %d\n", __FUNCTION__, phba->total_scsi_bufs); @@ -792,7 +749,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) return 0; out_host_busy_free_buf: - lpfc_free_scsi_buf(lpfc_cmd); + lpfc_release_scsi_buf(phba, lpfc_cmd); cmnd->host_scribble = NULL; out_host_busy: return SCSI_MLQUEUE_HOST_BUSY; @@ -808,119 +765,92 @@ __lpfc_abort_handler(struct scsi_cmnd *cmnd) struct lpfc_hba *phba = (struct lpfc_hba *)cmnd->device->host->hostdata[0]; struct lpfc_sli_ring *pring = &phba->sli.ring[phba->sli.fcp_ring]; - struct lpfc_iocbq *iocb, *next_iocb; - struct lpfc_iocbq *abtsiocb = NULL; + struct lpfc_iocbq *iocb; + struct lpfc_iocbq *abtsiocb; struct lpfc_scsi_buf *lpfc_cmd; - struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; IOCB_t *cmd, *icmd; - unsigned long snum; - unsigned int id, lun; unsigned int loop_count = 0; - int ret = IOCB_SUCCESS; + int ret = SUCCESS; - /* - * If the host_scribble data area is NULL, then the driver has already - * completed this command, but the midlayer did not see the completion - * before the eh fired. Just return SUCCESS. - */ - lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; - if (!lpfc_cmd) - return SUCCESS; - /* save these now since lpfc_cmd can be freed */ - id = lpfc_cmd->pCmd->device->id; - lun = lpfc_cmd->pCmd->device->lun; - snum = lpfc_cmd->pCmd->serial_number; + lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; + BUG_ON(!lpfc_cmd); - list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { - cmd = &iocb->iocb; - if (iocb->context1 != lpfc_cmd) - continue; + /* + * If pCmd field of the corresponding lpfc_scsi_buf structure + * points to a different SCSI command, then the driver has + * already completed this command, but the midlayer did not + * see the completion before the eh fired. Just return + * SUCCESS. + */ + iocb = &lpfc_cmd->cur_iocbq; + if (lpfc_cmd->pCmd != cmnd) + goto out; - list_del_init(&iocb->list); - pring->txq_cnt--; - if (!iocb->iocb_cmpl) { - list_add_tail(&iocb->list, lpfc_iocb_list); - } - else { - cmd->ulpStatus = IOSTAT_LOCAL_REJECT; - cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; - lpfc_scsi_cmd_iocb_cmpl_aborted(phba, iocb, iocb); - } + BUG_ON(iocb->context1 != lpfc_cmd); + abtsiocb = lpfc_sli_get_iocbq(phba); + if (abtsiocb == NULL) { + ret = FAILED; goto out; } - list_remove_head(lpfc_iocb_list, abtsiocb, struct lpfc_iocbq, list); - if (abtsiocb == NULL) - return FAILED; - - memset(abtsiocb, 0, sizeof (struct lpfc_iocbq)); - /* - * The scsi command was not in the txq. Check the txcmplq and if it is - * found, send an abort to the FW. + * The scsi command can not be in txq and it is in flight because the + * pCmd is still pointig at the SCSI command we have to abort. There + * is no need to search the txcmplq. Just send an abort to the FW. */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { - if (iocb->context1 != lpfc_cmd) - continue; - iocb->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl_aborted; - cmd = &iocb->iocb; - icmd = &abtsiocb->iocb; - icmd->un.acxri.abortType = ABORT_TYPE_ABTS; - icmd->un.acxri.abortContextTag = cmd->ulpContext; - icmd->un.acxri.abortIoTag = cmd->ulpIoTag; - - icmd->ulpLe = 1; - icmd->ulpClass = cmd->ulpClass; - if (phba->hba_state >= LPFC_LINK_UP) - icmd->ulpCommand = CMD_ABORT_XRI_CN; - else - icmd->ulpCommand = CMD_CLOSE_XRI_CN; + cmd = &iocb->iocb; + icmd = &abtsiocb->iocb; + icmd->un.acxri.abortType = ABORT_TYPE_ABTS; + icmd->un.acxri.abortContextTag = cmd->ulpContext; + icmd->un.acxri.abortIoTag = cmd->ulpIoTag; - abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; - if (lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0) == - IOCB_ERROR) { - list_add_tail(&abtsiocb->list, lpfc_iocb_list); - ret = IOCB_ERROR; - break; - } + icmd->ulpLe = 1; + icmd->ulpClass = cmd->ulpClass; + if (phba->hba_state >= LPFC_LINK_UP) + icmd->ulpCommand = CMD_ABORT_XRI_CN; + else + icmd->ulpCommand = CMD_CLOSE_XRI_CN; - /* Wait for abort to complete */ - while (cmnd->host_scribble) - { - spin_unlock_irq(phba->host->host_lock); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(LPFC_ABORT_WAIT*HZ); - spin_lock_irq(phba->host->host_lock); - if (++loop_count - > (2 * phba->cfg_nodev_tmo)/LPFC_ABORT_WAIT) - break; - } + abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; + if (lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0) == IOCB_ERROR) { + lpfc_sli_release_iocbq(phba, abtsiocb); + ret = FAILED; + goto out; + } - if(cmnd->host_scribble) { - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "%d:0748 abort handler timed " - "out waiting for abort to " - "complete. Data: " - "x%x x%x x%x x%lx\n", - phba->brd_no, ret, id, lun, snum); - cmnd->host_scribble = NULL; - iocb->iocb_cmpl = lpfc_scsi_cmd_iocb_cleanup; - ret = IOCB_ERROR; - } + /* Wait for abort to complete */ + while (lpfc_cmd->pCmd == cmnd) + { + spin_unlock_irq(phba->host->host_lock); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(LPFC_ABORT_WAIT*HZ); + spin_lock_irq(phba->host->host_lock); + if (++loop_count + > (2 * phba->cfg_nodev_tmo)/LPFC_ABORT_WAIT) + break; + } - break; + if (lpfc_cmd->pCmd == cmnd) { + ret = FAILED; + lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + "%d:0748 abort handler timed out waiting for " + "abort to complete: ret %#x, ID %d, LUN %d, " + "snum %#lx\n", + phba->brd_no, ret, cmnd->device->id, + cmnd->device->lun, cmnd->serial_number); } out: lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, - "%d:0749 SCSI layer issued abort device " - "Data: x%x x%x x%x x%lx\n", - phba->brd_no, ret, id, lun, snum); + "%d:0749 SCSI layer issued abort device: ret %#x, " + "ID %d, LUN %d, snum %#lx\n", + phba->brd_no, ret, cmnd->device->id, + cmnd->device->lun, cmnd->serial_number); - return ret == IOCB_SUCCESS ? SUCCESS : FAILED; + return ret; } static int @@ -938,11 +868,8 @@ __lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) { struct Scsi_Host *shost = cmnd->device->host; struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0]; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_scsi_buf *lpfc_cmd = NULL; - struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list; - struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; - struct lpfc_iocbq *iocbq, *iocbqrsp = NULL; + struct lpfc_scsi_buf *lpfc_cmd; + struct lpfc_iocbq *iocbq, *iocbqrsp; struct lpfc_rport_data *rdata = cmnd->device->hostdata; struct lpfc_nodelist *pnode = rdata->pnode; int ret = FAILED; @@ -966,7 +893,7 @@ __lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) break; } - list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list); + lpfc_cmd = lpfc_sli_get_scsi_buf (phba); if (lpfc_cmd == NULL) goto out; @@ -981,18 +908,13 @@ __lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) iocbq = &lpfc_cmd->cur_iocbq; /* get a buffer for this IOCB command response */ - list_remove_head(lpfc_iocb_list, iocbqrsp, struct lpfc_iocbq, list); + iocbqrsp = lpfc_sli_get_iocbq(phba); if (iocbqrsp == NULL) goto out_free_scsi_buf; - memset(iocbqrsp, 0, sizeof (struct lpfc_iocbq)); - - iocbq->iocb_flag |= LPFC_IO_POLL; - iocbq->iocb_cmpl = lpfc_sli_wake_iocb_high_priority; - - ret = lpfc_sli_issue_iocb_wait_high_priority(phba, - &phba->sli.ring[psli->fcp_ring], - iocbq, 0, iocbqrsp, 60); + ret = lpfc_sli_issue_iocb_wait(phba, + &phba->sli.ring[phba->sli.fcp_ring], + iocbq, iocbqrsp, lpfc_cmd->timeout); if (ret == IOCB_SUCCESS) ret = SUCCESS; @@ -1027,12 +949,13 @@ __lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) } if (cnt) { - lpfc_printf_log(phba, KERN_INFO, LOG_FCP, + lpfc_printf_log(phba, KERN_ERR, LOG_FCP, "%d:0719 LUN Reset I/O flush failure: cnt x%x\n", phba->brd_no, cnt); + ret = FAILED; } - list_add_tail(&iocbqrsp->list, lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, iocbqrsp); out_free_scsi_buf: lpfc_printf_log(phba, KERN_ERR, LOG_FCP, @@ -1041,7 +964,7 @@ out_free_scsi_buf: phba->brd_no, lpfc_cmd->pCmd->device->id, lpfc_cmd->pCmd->device->lun, ret, lpfc_cmd->status, lpfc_cmd->result); - lpfc_free_scsi_buf(lpfc_cmd); + lpfc_release_scsi_buf(phba, lpfc_cmd); out: return ret; } @@ -1069,10 +992,9 @@ __lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) int ret = FAILED, i, err_count = 0; int cnt, loopcnt; unsigned int midlayer_id = 0; - struct lpfc_scsi_buf * lpfc_cmd = NULL; - struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list; + struct lpfc_scsi_buf * lpfc_cmd; - list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list); + lpfc_cmd = lpfc_sli_get_scsi_buf (phba); if (lpfc_cmd == NULL) goto out; @@ -1136,10 +1058,12 @@ __lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) phba->brd_no, cnt, i); } - if (!err_count) + if (cnt == 0) ret = SUCCESS; + else + ret = FAILED; - lpfc_free_scsi_buf(lpfc_cmd); + lpfc_release_scsi_buf(phba, lpfc_cmd); lpfc_printf_log(phba, KERN_ERR, LOG_FCP, @@ -1163,66 +1087,47 @@ static int lpfc_slave_alloc(struct scsi_device *sdev) { struct lpfc_hba *phba = (struct lpfc_hba *)sdev->host->hostdata[0]; - struct lpfc_nodelist *ndlp = NULL; - int match = 0; struct lpfc_scsi_buf *scsi_buf = NULL; + struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); uint32_t total = 0, i; uint32_t num_to_alloc = 0; unsigned long flags; - struct list_head *listp; - struct list_head *node_list[6]; - - /* - * Store the target pointer in the scsi_device hostdata pointer provided - * the driver has already discovered the target id. - */ - - /* Search the nlp lists other than unmap_list for this target ID */ - node_list[0] = &phba->fc_npr_list; - node_list[1] = &phba->fc_nlpmap_list; - node_list[2] = &phba->fc_prli_list; - node_list[3] = &phba->fc_reglogin_list; - node_list[4] = &phba->fc_adisc_list; - node_list[5] = &phba->fc_plogi_list; - - for (i = 0; i < 6 && !match; i++) { - listp = node_list[i]; - if (list_empty(listp)) - continue; - list_for_each_entry(ndlp, listp, nlp_listp) { - if ((sdev->id == ndlp->nlp_sid) && ndlp->rport) { - match = 1; - break; - } - } - } - if (!match) + if (!rport || fc_remote_port_chkready(rport)) return -ENXIO; - sdev->hostdata = ndlp->rport->dd_data; + sdev->hostdata = rport->dd_data; /* * Populate the cmds_per_lun count scsi_bufs into this host's globally * available list of scsi buffers. Don't allocate more than the - * HBA limit conveyed to the midlayer via the host structure. Note - * that this list of scsi bufs exists for the lifetime of the driver. + * HBA limit conveyed to the midlayer via the host structure. The + * formula accounts for the lun_queue_depth + error handlers + 1 + * extra. This list of scsi bufs exists for the lifetime of the driver. */ total = phba->total_scsi_bufs; - num_to_alloc = LPFC_CMD_PER_LUN; + num_to_alloc = phba->cfg_lun_queue_depth + 2; if (total >= phba->cfg_hba_queue_depth) { - printk(KERN_WARNING "%s, At config limitation of " - "%d allocated scsi_bufs\n", __FUNCTION__, total); + lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, + "%d:0704 At limitation of %d preallocated " + "command buffers\n", phba->brd_no, total); return 0; } else if (total + num_to_alloc > phba->cfg_hba_queue_depth) { + lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, + "%d:0705 Allocation request of %d command " + "buffers will exceed max of %d. Reducing " + "allocation request to %d.\n", phba->brd_no, + num_to_alloc, phba->cfg_hba_queue_depth, + (phba->cfg_hba_queue_depth - total)); num_to_alloc = phba->cfg_hba_queue_depth - total; } for (i = 0; i < num_to_alloc; i++) { - scsi_buf = lpfc_get_scsi_buf(phba); + scsi_buf = lpfc_new_scsi_buf(phba); if (!scsi_buf) { - printk(KERN_ERR "%s, failed to allocate " - "scsi_buf\n", __FUNCTION__); + lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + "%d:0706 Failed to allocate command " + "buffer\n", phba->brd_no); break; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index e74e224fd77..508710001ed 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -65,6 +65,28 @@ typedef enum _lpfc_iocb_type { LPFC_ABORT_IOCB } lpfc_iocb_type; +struct lpfc_iocbq * +lpfc_sli_get_iocbq(struct lpfc_hba * phba) +{ + struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; + struct lpfc_iocbq * iocbq = NULL; + + list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list); + return iocbq; +} + +void +lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq) +{ + size_t start_clean = (size_t)(&((struct lpfc_iocbq *)NULL)->iocb); + + /* + * Clean all volatile data fields, preserve iotag and node struct. + */ + memset((char*)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean); + list_add_tail(&iocbq->list, &phba->lpfc_iocb_list); +} + /* * Translate the iocb command to an iocb command type used to decide the final * disposition of each completed IOCB. @@ -265,41 +287,69 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) return iocb; } -static uint32_t -lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_sli_ring * pring) +uint16_t +lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq) { - uint32_t search_start; + struct lpfc_iocbq ** new_arr; + struct lpfc_iocbq ** old_arr; + size_t new_len; + struct lpfc_sli *psli = &phba->sli; + uint16_t iotag; - if (pring->fast_lookup == NULL) { - pring->iotag_ctr++; - if (pring->iotag_ctr >= pring->iotag_max) - pring->iotag_ctr = 1; - return pring->iotag_ctr; + spin_lock_irq(phba->host->host_lock); + iotag = psli->last_iotag; + if(++iotag < psli->iocbq_lookup_len) { + psli->last_iotag = iotag; + psli->iocbq_lookup[iotag] = iocbq; + spin_unlock_irq(phba->host->host_lock); + iocbq->iotag = iotag; + return iotag; + } + else if (psli->iocbq_lookup_len < (0xffff + - LPFC_IOCBQ_LOOKUP_INCREMENT)) { + new_len = psli->iocbq_lookup_len + LPFC_IOCBQ_LOOKUP_INCREMENT; + spin_unlock_irq(phba->host->host_lock); + new_arr = kmalloc(new_len * sizeof (struct lpfc_iocbq *), + GFP_KERNEL); + if (new_arr) { + memset((char *)new_arr, 0, + new_len * sizeof (struct lpfc_iocbq *)); + spin_lock_irq(phba->host->host_lock); + old_arr = psli->iocbq_lookup; + if (new_len <= psli->iocbq_lookup_len) { + /* highly unprobable case */ + kfree(new_arr); + iotag = psli->last_iotag; + if(++iotag < psli->iocbq_lookup_len) { + psli->last_iotag = iotag; + psli->iocbq_lookup[iotag] = iocbq; + spin_unlock_irq(phba->host->host_lock); + iocbq->iotag = iotag; + return iotag; + } + spin_unlock_irq(phba->host->host_lock); + return 0; + } + if (psli->iocbq_lookup) + memcpy(new_arr, old_arr, + ((psli->last_iotag + 1) * + sizeof (struct lpfc_iocbq *))); + psli->iocbq_lookup = new_arr; + psli->iocbq_lookup_len = new_len; + psli->last_iotag = iotag; + psli->iocbq_lookup[iotag] = iocbq; + spin_unlock_irq(phba->host->host_lock); + iocbq->iotag = iotag; + kfree(old_arr); + return iotag; + } } - search_start = pring->iotag_ctr; - - do { - pring->iotag_ctr++; - if (pring->iotag_ctr >= pring->fast_iotag) - pring->iotag_ctr = 1; - - if (*(pring->fast_lookup + pring->iotag_ctr) == NULL) - return pring->iotag_ctr; - - } while (pring->iotag_ctr != search_start); + lpfc_printf_log(phba, KERN_ERR,LOG_SLI, + "%d:0318 Failed to allocate IOTAG.last IOTAG is %d\n", + phba->brd_no, psli->last_iotag); - /* - * Outstanding I/O count for ring <ringno> is at max <fast_iotag> - */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_SLI, - "%d:0318 Outstanding I/O count for ring %d is at max x%x\n", - phba->brd_no, - pring->ringno, - pring->fast_iotag); - return (0); + return 0; } static void @@ -307,10 +357,9 @@ lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, IOCB_t *iocb, struct lpfc_iocbq *nextiocb) { /* - * Allocate and set up an iotag + * Set up an iotag */ - nextiocb->iocb.ulpIoTag = - lpfc_sli_next_iotag(phba, &phba->sli.ring[phba->sli.fcp_ring]); + nextiocb->iocb.ulpIoTag = (nextiocb->iocb_cmpl) ? nextiocb->iotag : 0; /* * Issue iocb command to adapter @@ -326,16 +375,15 @@ lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, */ if (nextiocb->iocb_cmpl) lpfc_sli_ringtxcmpl_put(phba, pring, nextiocb); - else { - list_add_tail(&nextiocb->list, &phba->lpfc_iocb_list); - } + else + lpfc_sli_release_iocbq(phba, nextiocb); /* * Let the HBA know what IOCB slot will be the next one the * driver will put a command into. */ pring->cmdidx = pring->next_cmdidx; - writeb(pring->cmdidx, phba->MBslimaddr + writel(pring->cmdidx, phba->MBslimaddr + (SLIMOFF + (pring->ringno * 2)) * 4); } @@ -752,80 +800,28 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } static struct lpfc_iocbq * -lpfc_sli_txcmpl_ring_search_slow(struct lpfc_sli_ring * pring, - struct lpfc_iocbq * prspiocb) -{ - IOCB_t *icmd = NULL; - IOCB_t *irsp = NULL; - struct lpfc_iocbq *cmd_iocb; - struct lpfc_iocbq *iocb, *next_iocb; - uint16_t iotag; - - irsp = &prspiocb->iocb; - iotag = irsp->ulpIoTag; - cmd_iocb = NULL; - - /* Search through txcmpl from the begining */ - list_for_each_entry_safe(iocb, next_iocb, &(pring->txcmplq), list) { - icmd = &iocb->iocb; - if (iotag == icmd->ulpIoTag) { - /* Found a match. */ - cmd_iocb = iocb; - list_del(&iocb->list); - pring->txcmplq_cnt--; - break; - } - } - - return (cmd_iocb); -} - -static struct lpfc_iocbq * -lpfc_sli_txcmpl_ring_iotag_lookup(struct lpfc_hba * phba, - struct lpfc_sli_ring * pring, - struct lpfc_iocbq * prspiocb) +lpfc_sli_iocbq_lookup(struct lpfc_hba * phba, + struct lpfc_sli_ring * pring, + struct lpfc_iocbq * prspiocb) { - IOCB_t *irsp = NULL; struct lpfc_iocbq *cmd_iocb = NULL; uint16_t iotag; - if (unlikely(pring->fast_lookup == NULL)) - return NULL; - - /* Use fast lookup based on iotag for completion */ - irsp = &prspiocb->iocb; - iotag = irsp->ulpIoTag; - if (iotag < pring->fast_iotag) { - cmd_iocb = *(pring->fast_lookup + iotag); - *(pring->fast_lookup + iotag) = NULL; - if (cmd_iocb) { - list_del(&cmd_iocb->list); - pring->txcmplq_cnt--; - return cmd_iocb; - } else { - /* - * This is clearly an error. A ring that uses iotags - * should never have a interrupt for a completion that - * is not on the ring. Return NULL and log a error. - */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "%d:0327 Rsp ring %d error - command " - "completion for iotag x%x not found\n", - phba->brd_no, pring->ringno, iotag); - return NULL; - } + iotag = prspiocb->iocb.ulpIoTag; + + if (iotag != 0 && iotag <= phba->sli.last_iotag) { + cmd_iocb = phba->sli.iocbq_lookup[iotag]; + list_del(&cmd_iocb->list); + pring->txcmplq_cnt--; + return cmd_iocb; } - /* - * Rsp ring <ringno> get: iotag <iotag> greater then - * configured max <fast_iotag> wd0 <irsp>. This is an - * error. Just return NULL. - */ lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "%d:0317 Rsp ring %d get: iotag x%x greater then " - "configured max x%x wd0 x%x\n", - phba->brd_no, pring->ringno, iotag, pring->fast_iotag, - *(((uint32_t *) irsp) + 7)); + "%d:0317 iotag x%x is out off " + "range: max iotag x%x wd0 x%x\n", + phba->brd_no, iotag, + phba->sli.last_iotag, + *(((uint32_t *) &prspiocb->iocb) + 7)); return NULL; } @@ -839,7 +835,7 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, /* Based on the iotag field, get the cmd IOCB from the txcmplq */ spin_lock_irqsave(phba->host->host_lock, iflag); - cmdiocbp = lpfc_sli_txcmpl_ring_search_slow(pring, saveq); + cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq); if (cmdiocbp) { if (cmdiocbp->iocb_cmpl) { /* @@ -853,17 +849,13 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, spin_lock_irqsave(phba->host->host_lock, iflag); } else { - if (cmdiocbp->iocb_flag & LPFC_IO_POLL) - rc = 0; - spin_unlock_irqrestore(phba->host->host_lock, iflag); (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); spin_lock_irqsave(phba->host->host_lock, iflag); } - } else { - list_add_tail(&cmdiocbp->list, &phba->lpfc_iocb_list); - } + } else + lpfc_sli_release_iocbq(phba, cmdiocbp); } else { /* * Unknown initiating command based on the response iotag. @@ -889,6 +881,7 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, saveq->iocb.ulpContext); } } + spin_unlock_irqrestore(phba->host->host_lock, iflag); return rc; } @@ -953,7 +946,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba, * structure. The copy involves a byte-swap since the * network byte order and pci byte orders are different. */ - entry = (IOCB_t *) IOCB_ENTRY(pring->rspringaddr, pring->rspidx); + entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx); lpfc_sli_pcimem_bcopy((uint32_t *) entry, (uint32_t *) &rspiocbq.iocb, sizeof (IOCB_t)); @@ -990,9 +983,8 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba, break; } - cmdiocbq = lpfc_sli_txcmpl_ring_iotag_lookup(phba, - pring, - &rspiocbq); + cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring, + &rspiocbq); if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) { spin_unlock_irqrestore( phba->host->host_lock, iflag); @@ -1033,7 +1025,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba, to_slim = phba->MBslimaddr + (SLIMOFF + (pring->ringno * 2) + 1) * 4; - writeb(pring->rspidx, to_slim); + writel(pring->rspidx, to_slim); if (pring->rspidx == portRspPut) portRspPut = le32_to_cpu(pgp->rspPutInx); @@ -1073,7 +1065,6 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, struct lpfc_iocbq *next_iocb; struct lpfc_iocbq *cmdiocbp; struct lpfc_iocbq *saveq; - struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno]; uint8_t iocb_cmd_type; lpfc_iocb_type type; @@ -1115,7 +1106,6 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, } rmb(); - lpfc_iocb_list = &phba->lpfc_iocb_list; while (pring->rspidx != portRspPut) { /* * Build a completion list and call the appropriate handler. @@ -1131,8 +1121,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, * received. */ entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx); - list_remove_head(lpfc_iocb_list, rspiocbp, struct lpfc_iocbq, - list); + rspiocbp = lpfc_sli_get_iocbq(phba); if (rspiocbp == NULL) { printk(KERN_ERR "%s: out of buffers! Failing " "completion.\n", __FUNCTION__); @@ -1147,7 +1136,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, to_slim = phba->MBslimaddr + (SLIMOFF + (pring->ringno * 2) + 1) * 4; - writeb(pring->rspidx, to_slim); + writel(pring->rspidx, to_slim); if (list_empty(&(pring->iocb_continueq))) { list_add(&rspiocbp->list, &(pring->iocb_continueq)); @@ -1213,8 +1202,8 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, } else if (type == LPFC_ABORT_IOCB) { if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) && ((cmdiocbp = - lpfc_sli_txcmpl_ring_search_slow(pring, - saveq)))) { + lpfc_sli_iocbq_lookup(phba, pring, + saveq)))) { /* Call the specified completion routine */ if (cmdiocbp->iocb_cmpl) { @@ -1226,10 +1215,9 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, spin_lock_irqsave( phba->host->host_lock, iflag); - } else { - list_add_tail(&cmdiocbp->list, - lpfc_iocb_list); - } + } else + lpfc_sli_release_iocbq(phba, + cmdiocbp); } } else if (type == LPFC_UNKNOWN_IOCB) { if (irsp->ulpCommand == CMD_ADAPTER_MSG) { @@ -1264,12 +1252,12 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba, next_iocb, &saveq->list, list) { - list_add_tail(&rspiocbp->list, - lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, + rspiocbp); } } - list_add_tail(&saveq->list, lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, saveq); } } @@ -1314,7 +1302,6 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) struct lpfc_iocbq *iocb, *next_iocb; IOCB_t *icmd = NULL, *cmd = NULL; int errcnt; - uint16_t iotag; errcnt = 0; @@ -1331,9 +1318,8 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) spin_unlock_irq(phba->host->host_lock); (iocb->iocb_cmpl) (phba, iocb, iocb); spin_lock_irq(phba->host->host_lock); - } else { - list_add_tail(&iocb->list, &phba->lpfc_iocb_list); - } + } else + lpfc_sli_release_iocbq(phba, iocb); } pring->txq_cnt = 0; INIT_LIST_HEAD(&(pring->txq)); @@ -1343,13 +1329,8 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) cmd = &iocb->iocb; /* - * Imediate abort of IOCB, clear fast_lookup entry, - * if any, deque and call compl + * Imediate abort of IOCB, deque and call compl */ - iotag = cmd->ulpIoTag; - if (iotag && pring->fast_lookup && - (iotag < pring->fast_iotag)) - pring->fast_lookup[iotag] = NULL; list_del_init(&iocb->list); pring->txcmplq_cnt--; @@ -1360,9 +1341,8 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) spin_unlock_irq(phba->host->host_lock); (iocb->iocb_cmpl) (phba, iocb, iocb); spin_lock_irq(phba->host->host_lock); - } else { - list_add_tail(&iocb->list, &phba->lpfc_iocb_list); - } + } else + lpfc_sli_release_iocbq(phba, iocb); } INIT_LIST_HEAD(&pring->txcmplq); @@ -2147,6 +2127,10 @@ lpfc_sli_setup(struct lpfc_hba *phba) psli->next_ring = LPFC_FCP_NEXT_RING; psli->ip_ring = LPFC_IP_RING; + psli->iocbq_lookup = NULL; + psli->iocbq_lookup_len = 0; + psli->last_iotag = 0; + for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; switch (i) { @@ -2222,7 +2206,7 @@ lpfc_sli_queue_setup(struct lpfc_hba * phba) { struct lpfc_sli *psli; struct lpfc_sli_ring *pring; - int i, cnt; + int i; psli = &phba->sli; spin_lock_irq(phba->host->host_lock); @@ -2238,19 +2222,6 @@ lpfc_sli_queue_setup(struct lpfc_hba * phba) INIT_LIST_HEAD(&pring->txcmplq); INIT_LIST_HEAD(&pring->iocb_continueq); INIT_LIST_HEAD(&pring->postbufq); - cnt = pring->fast_iotag; - spin_unlock_irq(phba->host->host_lock); - if (cnt) { - pring->fast_lookup = - kmalloc(cnt * sizeof (struct lpfc_iocbq *), - GFP_KERNEL); - if (pring->fast_lookup == 0) { - return (0); - } - memset((char *)pring->fast_lookup, 0, - cnt * sizeof (struct lpfc_iocbq *)); - } - spin_lock_irq(phba->host->host_lock); } spin_unlock_irq(phba->host->host_lock); return (1); @@ -2292,10 +2263,8 @@ lpfc_sli_hba_down(struct lpfc_hba * phba) flags); (iocb->iocb_cmpl) (phba, iocb, iocb); spin_lock_irqsave(phba->host->host_lock, flags); - } else { - list_add_tail(&iocb->list, - &phba->lpfc_iocb_list); - } + } else + lpfc_sli_release_iocbq(phba, iocb); } INIT_LIST_HEAD(&(pring->txq)); @@ -2436,7 +2405,7 @@ lpfc_sli_abort_elsreq_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, kfree(buf_ptr); } - list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, cmdiocb); return; } @@ -2445,16 +2414,14 @@ lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, struct lpfc_iocbq * cmdiocb) { - struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; - struct lpfc_iocbq *abtsiocbp = NULL; + struct lpfc_iocbq *abtsiocbp; IOCB_t *icmd = NULL; IOCB_t *iabt = NULL; /* issue ABTS for this IOCB based on iotag */ - list_remove_head(lpfc_iocb_list, abtsiocbp, struct lpfc_iocbq, list); + abtsiocbp = lpfc_sli_get_iocbq(phba); if (abtsiocbp == NULL) return 0; - memset(abtsiocbp, 0, sizeof (struct lpfc_iocbq)); iabt = &abtsiocbp->iocb; icmd = &cmdiocb->iocb; @@ -2473,7 +2440,7 @@ lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba, abtsiocbp->iocb_cmpl = lpfc_sli_abort_elsreq_cmpl; break; default: - list_add_tail(&abtsiocbp->list, lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, abtsiocbp); return 0; } @@ -2485,7 +2452,7 @@ lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba, iabt->ulpCommand = CMD_ABORT_MXRI64_CN; if (lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0) == IOCB_ERROR) { - list_add_tail(&abtsiocbp->list, lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, abtsiocbp); return 0; } @@ -2493,28 +2460,37 @@ lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba, } static int -lpfc_sli_validate_iocb_cmd(struct lpfc_scsi_buf *lpfc_cmd, uint16_t tgt_id, - uint64_t lun_id, struct lpfc_iocbq *iocb, - uint32_t ctx, lpfc_ctx_cmd ctx_cmd) +lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, uint16_t tgt_id, + uint64_t lun_id, uint32_t ctx, + lpfc_ctx_cmd ctx_cmd) { + struct lpfc_scsi_buf *lpfc_cmd; + struct scsi_cmnd *cmnd; int rc = 1; - if (lpfc_cmd == NULL) + if (!(iocbq->iocb_flag & LPFC_IO_FCP)) + return rc; + + lpfc_cmd = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq); + cmnd = lpfc_cmd->pCmd; + + if (cmnd == NULL) return rc; switch (ctx_cmd) { case LPFC_CTX_LUN: - if ((lpfc_cmd->pCmd->device->id == tgt_id) && - (lpfc_cmd->pCmd->device->lun == lun_id)) + if ((cmnd->device->id == tgt_id) && + (cmnd->device->lun == lun_id)) rc = 0; break; case LPFC_CTX_TGT: - if (lpfc_cmd->pCmd->device->id == tgt_id) + if (cmnd->device->id == tgt_id) rc = 0; break; case LPFC_CTX_CTX: - if (iocb->iocb.ulpContext == ctx) + if (iocbq->iocb.ulpContext == ctx) rc = 0; + break; case LPFC_CTX_HOST: rc = 0; break; @@ -2531,30 +2507,17 @@ int lpfc_sli_sum_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd ctx_cmd) { - struct lpfc_iocbq *iocb, *next_iocb; - IOCB_t *cmd = NULL; - struct lpfc_scsi_buf *lpfc_cmd; - int sum = 0, ret_val = 0; + struct lpfc_iocbq *iocbq; + int sum, i; - /* Next check the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { - cmd = &iocb->iocb; - - /* Must be a FCP command */ - if ((cmd->ulpCommand != CMD_FCP_ICMND64_CR) && - (cmd->ulpCommand != CMD_FCP_IWRITE64_CR) && - (cmd->ulpCommand != CMD_FCP_IREAD64_CR)) { - continue; - } + for (i = 1, sum = 0; i <= phba->sli.last_iotag; i++) { + iocbq = phba->sli.iocbq_lookup[i]; - /* context1 MUST be a struct lpfc_scsi_buf */ - lpfc_cmd = (struct lpfc_scsi_buf *) (iocb->context1); - ret_val = lpfc_sli_validate_iocb_cmd(lpfc_cmd, tgt_id, lun_id, - NULL, 0, ctx_cmd); - if (ret_val != 0) - continue; - sum++; + if (lpfc_sli_validate_fcp_iocb (iocbq, tgt_id, lun_id, + 0, ctx_cmd) == 0) + sum++; } + return sum; } @@ -2563,7 +2526,7 @@ lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb) { spin_lock_irq(phba->host->host_lock); - list_add_tail(&cmdiocb->list, &phba->lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, cmdiocb); spin_unlock_irq(phba->host->host_lock); return; } @@ -2573,39 +2536,27 @@ lpfc_sli_abort_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint16_t tgt_id, uint64_t lun_id, uint32_t ctx, lpfc_ctx_cmd abort_cmd) { - struct lpfc_iocbq *iocb, *next_iocb; - struct lpfc_iocbq *abtsiocb = NULL; - struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; + struct lpfc_iocbq *iocbq; + struct lpfc_iocbq *abtsiocb; IOCB_t *cmd = NULL; - struct lpfc_scsi_buf *lpfc_cmd; int errcnt = 0, ret_val = 0; + int i; - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { - cmd = &iocb->iocb; - - /* Must be a FCP command */ - if ((cmd->ulpCommand != CMD_FCP_ICMND64_CR) && - (cmd->ulpCommand != CMD_FCP_IWRITE64_CR) && - (cmd->ulpCommand != CMD_FCP_IREAD64_CR)) { - continue; - } + for (i = 1; i <= phba->sli.last_iotag; i++) { + iocbq = phba->sli.iocbq_lookup[i]; - /* context1 MUST be a struct lpfc_scsi_buf */ - lpfc_cmd = (struct lpfc_scsi_buf *) (iocb->context1); - ret_val = lpfc_sli_validate_iocb_cmd(lpfc_cmd, tgt_id, lun_id, - iocb, ctx, abort_cmd); - if (ret_val != 0) + if (lpfc_sli_validate_fcp_iocb (iocbq, tgt_id, lun_id, + 0, abort_cmd) != 0) continue; /* issue ABTS for this IOCB based on iotag */ - list_remove_head(lpfc_iocb_list, abtsiocb, struct lpfc_iocbq, - list); + abtsiocb = lpfc_sli_get_iocbq(phba); if (abtsiocb == NULL) { errcnt++; continue; } - memset(abtsiocb, 0, sizeof (struct lpfc_iocbq)); + cmd = &iocbq->iocb; abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS; abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext; abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag; @@ -2621,7 +2572,7 @@ lpfc_sli_abort_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; ret_val = lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0); if (ret_val == IOCB_ERROR) { - list_add_tail(&abtsiocb->list, lpfc_iocb_list); + lpfc_sli_release_iocbq(phba, abtsiocb); errcnt++; continue; } @@ -2630,83 +2581,99 @@ lpfc_sli_abort_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return errcnt; } -void -lpfc_sli_wake_iocb_high_priority(struct lpfc_hba * phba, - struct lpfc_iocbq * queue1, - struct lpfc_iocbq * queue2) +static void +lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocbq, + struct lpfc_iocbq *rspiocbq) { - if (queue1->context2 && queue2) - memcpy(queue1->context2, queue2, sizeof (struct lpfc_iocbq)); + wait_queue_head_t *pdone_q; + unsigned long iflags; + + spin_lock_irqsave(phba->host->host_lock, iflags); + cmdiocbq->iocb_flag |= LPFC_IO_WAKE; + if (cmdiocbq->context2 && rspiocbq) + memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, + &rspiocbq->iocb, sizeof(IOCB_t)); - /* The waiter is looking for LPFC_IO_HIPRI bit to be set - as a signal to wake up */ - queue1->iocb_flag |= LPFC_IO_HIPRI; + pdone_q = cmdiocbq->context_un.wait_queue; + spin_unlock_irqrestore(phba->host->host_lock, iflags); + if (pdone_q) + wake_up(pdone_q); return; } +/* + * Issue the caller's iocb and wait for its completion, but no longer than the + * caller's timeout. Note that iocb_flags is cleared before the + * lpfc_sli_issue_call since the wake routine sets a unique value and by + * definition this is a wait function. + */ int -lpfc_sli_issue_iocb_wait_high_priority(struct lpfc_hba * phba, - struct lpfc_sli_ring * pring, - struct lpfc_iocbq * piocb, - uint32_t flag, - struct lpfc_iocbq * prspiocbq, - uint32_t timeout) +lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba, + struct lpfc_sli_ring * pring, + struct lpfc_iocbq * piocb, + struct lpfc_iocbq * prspiocbq, + uint32_t timeout) { - int j, delay_time, retval = IOCB_ERROR; - - /* The caller must left context1 empty. */ - if (piocb->context_un.hipri_wait_queue != 0) { - return IOCB_ERROR; - } + DECLARE_WAIT_QUEUE_HEAD(done_q); + long timeleft, timeout_req = 0; + int retval = IOCB_SUCCESS; /* - * If the caller has provided a response iocbq buffer, context2 must - * be NULL or its an error. + * If the caller has provided a response iocbq buffer, then context2 + * is NULL or its an error. */ - if (prspiocbq && piocb->context2) { - return IOCB_ERROR; + if (prspiocbq) { + if (piocb->context2) + return IOCB_ERROR; + piocb->context2 = prspiocbq; } - piocb->context2 = prspiocbq; + piocb->iocb_cmpl = lpfc_sli_wake_iocb_wait; + piocb->context_un.wait_queue = &done_q; + piocb->iocb_flag &= ~LPFC_IO_WAKE; - /* Setup callback routine and issue the command. */ - piocb->iocb_cmpl = lpfc_sli_wake_iocb_high_priority; - retval = lpfc_sli_issue_iocb(phba, pring, piocb, - flag | SLI_IOCB_HIGH_PRIORITY); - if (retval != IOCB_SUCCESS) { - piocb->context2 = NULL; - return IOCB_ERROR; - } - - /* - * This high-priority iocb was sent out-of-band. Poll for its - * completion rather than wait for a signal. Note that the host_lock - * is held by the midlayer and must be released here to allow the - * interrupt handlers to complete the IO and signal this routine via - * the iocb_flag. - * Also, the delay_time is computed to be one second longer than - * the scsi command timeout to give the FW time to abort on - * timeout rather than the driver just giving up. Typically, - * the midlayer does not specify a time for this command so the - * driver is free to enforce its own timeout. - */ + retval = lpfc_sli_issue_iocb(phba, pring, piocb, 0); + if (retval == IOCB_SUCCESS) { + timeout_req = timeout * HZ; + spin_unlock_irq(phba->host->host_lock); + timeleft = wait_event_timeout(done_q, + piocb->iocb_flag & LPFC_IO_WAKE, + timeout_req); + spin_lock_irq(phba->host->host_lock); - delay_time = ((timeout + 1) * 1000) >> 6; - retval = IOCB_ERROR; - spin_unlock_irq(phba->host->host_lock); - for (j = 0; j < 64; j++) { - msleep(delay_time); - if (piocb->iocb_flag & LPFC_IO_HIPRI) { - piocb->iocb_flag &= ~LPFC_IO_HIPRI; - retval = IOCB_SUCCESS; - break; + if (timeleft == 0) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "%d:0329 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)) { + 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, + "%d:0332 IOCB wait issue failed, Data x%x\n", + phba->brd_no, retval); + retval = IOCB_ERROR; } - spin_lock_irq(phba->host->host_lock); - piocb->context2 = NULL; + if (prspiocbq) + piocb->context2 = NULL; + + piocb->context_un.wait_queue = NULL; + piocb->iocb_cmpl = NULL; return retval; } + int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq, uint32_t timeout) diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 6c74f3c85ff..b7a9f970f56 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -33,13 +33,15 @@ typedef enum _lpfc_ctx_cmd { struct lpfc_iocbq { /* lpfc_iocbqs are used in double linked lists */ struct list_head list; + uint16_t iotag; /* pre-assigned IO tag */ + uint16_t rsvd1; + IOCB_t iocb; /* IOCB cmd */ uint8_t retry; /* retry counter for IOCB cmd - if needed */ uint8_t iocb_flag; -#define LPFC_IO_POLL 1 /* Polling mode iocb */ -#define LPFC_IO_LIBDFC 2 /* libdfc iocb */ -#define LPFC_IO_WAIT 4 -#define LPFC_IO_HIPRI 8 /* High Priority Queue signal 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 */ uint8_t abort_count; uint8_t rsvd2; @@ -48,8 +50,7 @@ struct lpfc_iocbq { void *context2; /* caller context information */ void *context3; /* caller context information */ union { - wait_queue_head_t *hipri_wait_queue; /* High Priority Queue wait - queue */ + wait_queue_head_t *wait_queue; struct lpfc_iocbq *rsp_iocb; struct lpfcMboxq *mbox; } context_un; @@ -125,10 +126,10 @@ struct lpfc_sli_ring { uint32_t local_getidx; /* last available cmd index (from cmdGetInx) */ uint32_t next_cmdidx; /* next_cmd index */ + uint32_t rspidx; /* current index in response ring */ + uint32_t cmdidx; /* current index in command ring */ uint8_t rsvd; uint8_t ringno; /* ring number */ - uint8_t rspidx; /* current index in response ring */ - uint8_t cmdidx; /* current index in command ring */ uint16_t numCiocb; /* number of command iocb's per ring */ uint16_t numRiocb; /* number of rsp iocb's per ring */ @@ -200,6 +201,11 @@ struct lpfc_sli { cmd */ uint32_t *MBhostaddr; /* virtual address for mbox cmds */ + +#define LPFC_IOCBQ_LOOKUP_INCREMENT 1024 + struct lpfc_iocbq ** iocbq_lookup; /* array to lookup IOCB by IOTAG */ + size_t iocbq_lookup_len; /* current lengs of the array */ + uint16_t last_iotag; /* last allocated IOTAG */ }; /* Given a pointer to the start of the ring, and the slot number of diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 7e6747b06f9..4f0466fbd5f 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.0.30" +#define LPFC_DRIVER_VERSION "8.1.0" #define LPFC_DRIVER_NAME "lpfc" |