diff options
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 17 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 262 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 5 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 14 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_ct.c | 53 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.c | 10 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_disc.h | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 76 | ||||
-rwxr-xr-x[-rw-r--r--] | drivers/scsi/lpfc/lpfc_hbadisc.c | 129 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 34 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 131 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 515 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_mbox.c | 35 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 7 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 394 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 1240 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 27 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 34 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 3 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_vport.c | 4 |
20 files changed, 1999 insertions, 995 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index aa10f795163..1cc23a69db5 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -109,7 +109,8 @@ struct hbq_dmabuf { struct lpfc_dmabuf dbuf; uint32_t size; uint32_t tag; - struct lpfc_rcqe rcqe; + struct lpfc_cq_event cq_event; + unsigned long time_stamp; }; /* Priority bit. Set value to exceed low water mark in lpfc_mem. */ @@ -201,6 +202,7 @@ struct lpfc_stats { uint32_t elsRcvLIRR; uint32_t elsRcvRPS; uint32_t elsRcvRPL; + uint32_t elsRcvRRQ; uint32_t elsXmitFLOGI; uint32_t elsXmitFDISC; uint32_t elsXmitPLOGI; @@ -289,8 +291,8 @@ struct lpfc_vport { uint16_t vpi; uint16_t vfi; - uint8_t vfi_state; -#define LPFC_VFI_REGISTERED 0x1 + uint8_t vpi_state; +#define LPFC_VPI_REGISTERED 0x1 uint32_t fc_flag; /* FC flags */ /* Several of these flags are HBA centric and should be moved to @@ -405,6 +407,7 @@ struct lpfc_vport { uint8_t stat_data_enabled; uint8_t stat_data_blocked; struct list_head rcv_buffer_list; + unsigned long rcv_buffer_time_stamp; uint32_t vport_flag; #define STATIC_VPORT 1 }; @@ -527,13 +530,16 @@ struct lpfc_hba { #define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */ #define DEFER_ERATT 0x2 /* Deferred error attention in progress */ #define HBA_FCOE_SUPPORT 0x4 /* HBA function supports FCOE */ -#define HBA_RECEIVE_BUFFER 0x8 /* Rcv buffer posted to worker thread */ +#define HBA_SP_QUEUE_EVT 0x8 /* Slow-path qevt posted to worker thread*/ #define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */ #define FCP_XRI_ABORT_EVENT 0x20 #define ELS_XRI_ABORT_EVENT 0x40 #define ASYNC_EVENT 0x80 #define LINK_DISABLED 0x100 /* Link disabled by user */ #define FCF_DISC_INPROGRESS 0x200 /* FCF discovery in progress */ +#define HBA_FIP_SUPPORT 0x400 /* FIP support in HBA */ +#define HBA_AER_ENABLED 0x800 /* AER enabled with HBA */ + uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ struct lpfc_dmabuf slim2p; MAILBOX_t *mbox; @@ -551,6 +557,7 @@ struct lpfc_hba { uint8_t fc_linkspeed; /* Link speed after last READ_LA */ uint32_t fc_eventTag; /* event tag for link attention */ + uint32_t link_events; /* These fields used to be binfo */ uint32_t fc_pref_DID; /* preferred D_ID */ @@ -604,8 +611,8 @@ struct lpfc_hba { uint32_t cfg_enable_hba_reset; uint32_t cfg_enable_hba_heartbeat; uint32_t cfg_enable_bg; - uint32_t cfg_enable_fip; uint32_t cfg_log_verbose; + uint32_t cfg_aer_support; lpfc_vpd_t vpd; /* vital product data */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index e1a30a16a9f..75523603b91 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -23,12 +23,14 @@ #include <linux/delay.h> #include <linux/pci.h> #include <linux/interrupt.h> +#include <linux/aer.h> #include <scsi/scsi.h> #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> #include <scsi/scsi_transport_fc.h> +#include <scsi/fc/fc_fs.h> #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -98,6 +100,28 @@ lpfc_drvr_version_show(struct device *dev, struct device_attribute *attr, return snprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n"); } +/** + * lpfc_enable_fip_show - Return the fip mode of the HBA + * @dev: class unused variable. + * @attr: device attribute, not used. + * @buf: on return contains the module description text. + * + * Returns: size of formatted string. + **/ +static ssize_t +lpfc_enable_fip_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + + if (phba->hba_flag & HBA_FIP_SUPPORT) + return snprintf(buf, PAGE_SIZE, "1\n"); + else + return snprintf(buf, PAGE_SIZE, "0\n"); +} + static ssize_t lpfc_bg_info_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -762,9 +786,15 @@ lpfc_board_mode_store(struct device *dev, struct device_attribute *attr, } 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) - status = lpfc_do_offline(phba, LPFC_EVT_WARM_START); + if (phba->sli_rev == LPFC_SLI_REV4) + return -EINVAL; + else + 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); + if (phba->sli_rev == LPFC_SLI_REV4) + return -EINVAL; + else + status = lpfc_do_offline(phba, LPFC_EVT_KILL); else return -EINVAL; @@ -1126,6 +1156,9 @@ lpfc_poll_store(struct device *dev, struct device_attribute *attr, if ((val & 0x3) != val) return -EINVAL; + if (phba->sli_rev == LPFC_SLI_REV4) + val = 0; + spin_lock_irq(&phba->hbalock); old_val = phba->cfg_poll; @@ -1589,6 +1622,7 @@ static DEVICE_ATTR(num_discovered_ports, S_IRUGO, static DEVICE_ATTR(menlo_mgmt_mode, S_IRUGO, lpfc_mlomgmt_show, NULL); static DEVICE_ATTR(nport_evt_cnt, S_IRUGO, lpfc_nport_evt_cnt_show, NULL); static DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show, NULL); +static DEVICE_ATTR(lpfc_enable_fip, S_IRUGO, lpfc_enable_fip_show, NULL); static DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR, lpfc_board_mode_show, lpfc_board_mode_store); static DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset); @@ -2759,6 +2793,196 @@ static DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR, lpfc_link_speed_show, lpfc_link_speed_store); /* +# lpfc_aer_support: Support PCIe device Advanced Error Reporting (AER) +# 0 = aer disabled or not supported +# 1 = aer supported and enabled (default) +# Value range is [0,1]. Default value is 1. +*/ + +/** + * lpfc_aer_support_store - Set the adapter for aer support + * + * @dev: class device that is converted into a Scsi_host. + * @attr: device attribute, not used. + * @buf: containing the string "selective". + * @count: unused variable. + * + * Description: + * If the val is 1 and currently the device's AER capability was not + * enabled, invoke the kernel's enable AER helper routine, trying to + * enable the device's AER capability. If the helper routine enabling + * AER returns success, update the device's cfg_aer_support flag to + * indicate AER is supported by the device; otherwise, if the device + * AER capability is already enabled to support AER, then do nothing. + * + * If the val is 0 and currently the device's AER support was enabled, + * invoke the kernel's disable AER helper routine. After that, update + * the device's cfg_aer_support flag to indicate AER is not supported + * by the device; otherwise, if the device AER capability is already + * disabled from supporting AER, then do nothing. + * + * Returns: + * length of the buf on success if val is in range the intended mode + * is supported. + * -EINVAL if val out of range or intended mode is not supported. + **/ +static ssize_t +lpfc_aer_support_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + int val = 0, rc = -EINVAL; + + /* AER not supported on OC devices yet */ + if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) + return -EPERM; + if (!isdigit(buf[0])) + return -EINVAL; + if (sscanf(buf, "%i", &val) != 1) + return -EINVAL; + + switch (val) { + case 0: + if (phba->hba_flag & HBA_AER_ENABLED) { + rc = pci_disable_pcie_error_reporting(phba->pcidev); + if (!rc) { + spin_lock_irq(&phba->hbalock); + phba->hba_flag &= ~HBA_AER_ENABLED; + spin_unlock_irq(&phba->hbalock); + phba->cfg_aer_support = 0; + rc = strlen(buf); + } else + rc = -EPERM; + } else { + phba->cfg_aer_support = 0; + rc = strlen(buf); + } + break; + case 1: + if (!(phba->hba_flag & HBA_AER_ENABLED)) { + rc = pci_enable_pcie_error_reporting(phba->pcidev); + if (!rc) { + spin_lock_irq(&phba->hbalock); + phba->hba_flag |= HBA_AER_ENABLED; + spin_unlock_irq(&phba->hbalock); + phba->cfg_aer_support = 1; + rc = strlen(buf); + } else + rc = -EPERM; + } else { + phba->cfg_aer_support = 1; + rc = strlen(buf); + } + break; + default: + rc = -EINVAL; + break; + } + return rc; +} + +static int lpfc_aer_support = 1; +module_param(lpfc_aer_support, int, 1); +MODULE_PARM_DESC(lpfc_aer_support, "Enable PCIe device AER support"); +lpfc_param_show(aer_support) + +/** + * lpfc_aer_support_init - Set the initial adapters aer support flag + * @phba: lpfc_hba pointer. + * @val: link speed value. + * + * Description: + * If val is in a valid range [0,1], then set the adapter's initial + * cfg_aer_support field. It will be up to the driver's probe_one + * routine to determine whether the device's AER support can be set + * or not. + * + * Notes: + * If the value is not in range log a kernel error message, and + * choose the default value of setting AER support and return. + * + * Returns: + * zero if val saved. + * -EINVAL val out of range + **/ +static int +lpfc_aer_support_init(struct lpfc_hba *phba, int val) +{ + /* AER not supported on OC devices yet */ + if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) { + phba->cfg_aer_support = 0; + return -EPERM; + } + + if (val == 0 || val == 1) { + phba->cfg_aer_support = val; + return 0; + } + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2712 lpfc_aer_support attribute value %d out " + "of range, allowed values are 0|1, setting it " + "to default value of 1\n", val); + /* By default, try to enable AER on a device */ + phba->cfg_aer_support = 1; + return -EINVAL; +} + +static DEVICE_ATTR(lpfc_aer_support, S_IRUGO | S_IWUSR, + lpfc_aer_support_show, lpfc_aer_support_store); + +/** + * lpfc_aer_cleanup_state - Clean up aer state to the aer enabled device + * @dev: class device that is converted into a Scsi_host. + * @attr: device attribute, not used. + * @buf: containing the string "selective". + * @count: unused variable. + * + * Description: + * If the @buf contains 1 and the device currently has the AER support + * enabled, then invokes the kernel AER helper routine + * pci_cleanup_aer_uncorrect_error_status to clean up the uncorrectable + * error status register. + * + * Notes: + * + * Returns: + * -EINVAL if the buf does not contain the 1 or the device is not currently + * enabled with the AER support. + **/ +static ssize_t +lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + int val, rc = -1; + + /* AER not supported on OC devices yet */ + if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) + return -EPERM; + if (!isdigit(buf[0])) + return -EINVAL; + if (sscanf(buf, "%i", &val) != 1) + return -EINVAL; + if (val != 1) + return -EINVAL; + + if (phba->hba_flag & HBA_AER_ENABLED) + rc = pci_cleanup_aer_uncorrect_error_status(phba->pcidev); + + if (rc == 0) + return strlen(buf); + else + return -EPERM; +} + +static DEVICE_ATTR(lpfc_aer_state_cleanup, S_IWUSR, NULL, + lpfc_aer_cleanup_state); + +/* # lpfc_fcp_class: Determines FC class to use for the FCP protocol. # Value range is [2,3]. Default value is 3. */ @@ -2846,7 +3070,7 @@ LPFC_ATTR_R(multi_ring_support, 1, 1, 2, "Determines number of primary " # identifies what rctl value to configure the additional ring for. # Value range is [1,0xff]. Default value is 4 (Unsolicated Data). */ -LPFC_ATTR_R(multi_ring_rctl, FC_UNSOL_DATA, 1, +LPFC_ATTR_R(multi_ring_rctl, FC_RCTL_DD_UNSOL_DATA, 1, 255, "Identifies RCTL for additional ring configuration"); /* @@ -2854,7 +3078,7 @@ LPFC_ATTR_R(multi_ring_rctl, FC_UNSOL_DATA, 1, # identifies what type value to configure the additional ring for. # Value range is [1,0xff]. Default value is 5 (LLC/SNAP). */ -LPFC_ATTR_R(multi_ring_type, FC_LLC_SNAP, 1, +LPFC_ATTR_R(multi_ring_type, FC_TYPE_IP, 1, 255, "Identifies TYPE for additional ring configuration"); /* @@ -2947,15 +3171,6 @@ LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat."); LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support"); /* -# lpfc_enable_fip: When set, FIP is required to start discovery. If not -# set, the driver will add an FCF record manually if the port has no -# FCF records available and start discovery. -# Value range is [0,1]. Default value is 1 (enabled) -*/ -LPFC_ATTR_RW(enable_fip, 0, 0, 1, "Enable FIP Discovery"); - - -/* # lpfc_prot_mask: i # - Bit mask of host protection capabilities used to register with the # SCSI mid-layer @@ -3013,6 +3228,7 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_num_discovered_ports, &dev_attr_menlo_mgmt_mode, &dev_attr_lpfc_drvr_version, + &dev_attr_lpfc_enable_fip, &dev_attr_lpfc_temp_sensor, &dev_attr_lpfc_log_verbose, &dev_attr_lpfc_lun_queue_depth, @@ -3020,7 +3236,6 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_peer_port_login, &dev_attr_lpfc_nodev_tmo, &dev_attr_lpfc_devloss_tmo, - &dev_attr_lpfc_enable_fip, &dev_attr_lpfc_fcp_class, &dev_attr_lpfc_use_adisc, &dev_attr_lpfc_ack0, @@ -3061,6 +3276,8 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_max_scsicmpl_time, &dev_attr_lpfc_stat_data_ctrl, &dev_attr_lpfc_prot_sg_seg_cnt, + &dev_attr_lpfc_aer_support, + &dev_attr_lpfc_aer_state_cleanup, NULL, }; @@ -3073,7 +3290,6 @@ struct device_attribute *lpfc_vport_attrs[] = { &dev_attr_lpfc_lun_queue_depth, &dev_attr_lpfc_nodev_tmo, &dev_attr_lpfc_devloss_tmo, - &dev_attr_lpfc_enable_fip, &dev_attr_lpfc_hba_queue_depth, &dev_attr_lpfc_peer_port_login, &dev_attr_lpfc_restrict_login, @@ -3815,7 +4031,11 @@ lpfc_get_stats(struct Scsi_Host *shost) hs->invalid_crc_count -= lso->invalid_crc_count; hs->error_frames -= lso->error_frames; - if (phba->fc_topology == TOPOLOGY_LOOP) { + if (phba->hba_flag & HBA_FCOE_SUPPORT) { + hs->lip_count = -1; + hs->nos_count = (phba->link_events >> 1); + hs->nos_count -= lso->link_events; + } else if (phba->fc_topology == TOPOLOGY_LOOP) { hs->lip_count = (phba->fc_eventTag >> 1); hs->lip_count -= lso->link_events; hs->nos_count = -1; @@ -3906,7 +4126,10 @@ lpfc_reset_stats(struct Scsi_Host *shost) lso->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord; lso->invalid_crc_count = pmb->un.varRdLnk.crcCnt; lso->error_frames = pmb->un.varRdLnk.crcCnt; - lso->link_events = (phba->fc_eventTag >> 1); + if (phba->hba_flag & HBA_FCOE_SUPPORT) + lso->link_events = (phba->link_events >> 1); + else + lso->link_events = (phba->fc_eventTag >> 1); psli->stats_start = get_seconds(); @@ -4222,14 +4445,17 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset); lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat); lpfc_enable_bg_init(phba, lpfc_enable_bg); + if (phba->sli_rev == LPFC_SLI_REV4) + phba->cfg_poll = 0; + else phba->cfg_poll = lpfc_poll; phba->cfg_soft_wwnn = 0L; phba->cfg_soft_wwpn = 0L; lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); lpfc_prot_sg_seg_cnt_init(phba, lpfc_prot_sg_seg_cnt); lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); - lpfc_enable_fip_init(phba, lpfc_enable_fip); lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); + lpfc_aer_support_init(phba, lpfc_aer_support); return; } diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index da6bf5aac9d..a5d9048235d 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -26,6 +26,7 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_transport_fc.h> #include <scsi/scsi_bsg_fc.h> +#include <scsi/fc/fc_fs.h> #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -148,8 +149,8 @@ lpfc_bsg_rport_ct(struct fc_bsg_job *job) cmd->ulpCommand = CMD_GEN_REQUEST64_CR; cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); cmd->un.genreq64.w5.hcsw.Dfctl = 0; - cmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL; - cmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP; + cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; + cmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; cmd->ulpBdeCount = 1; cmd->ulpLe = 1; cmd->ulpClass = CLASS3; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 0830f37409a..650494d622c 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -49,6 +49,8 @@ void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *); struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); +void lpfc_cleanup_rcv_buffers(struct lpfc_vport *); +void lpfc_rcv_seq_check_edtov(struct lpfc_vport *); void lpfc_cleanup_rpis(struct lpfc_vport *, int); int lpfc_linkdown(struct lpfc_hba *); void lpfc_linkdown_port(struct lpfc_vport *); @@ -144,6 +146,8 @@ void lpfc_hb_timeout_handler(struct lpfc_hba *); void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_iocbq *); +void lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, + struct lpfc_iocbq *); int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t); int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int); void lpfc_fdmi_tmo(unsigned long); @@ -188,7 +192,7 @@ int lpfc_mbox_tmo_val(struct lpfc_hba *, int); void lpfc_init_vfi(struct lpfcMboxq *, struct lpfc_vport *); void lpfc_reg_vfi(struct lpfcMboxq *, struct lpfc_vport *, dma_addr_t); void lpfc_init_vpi(struct lpfc_hba *, struct lpfcMboxq *, uint16_t); -void lpfc_unreg_vfi(struct lpfcMboxq *, uint16_t); +void lpfc_unreg_vfi(struct lpfcMboxq *, struct lpfc_vport *); void lpfc_reg_fcfi(struct lpfc_hba *, struct lpfcMboxq *); void lpfc_unreg_fcfi(struct lpfcMboxq *, uint16_t); void lpfc_resume_rpi(struct lpfcMboxq *, struct lpfc_nodelist *); @@ -212,7 +216,10 @@ void lpfc_stop_vport_timers(struct lpfc_vport *); void lpfc_poll_timeout(unsigned long ptr); void lpfc_poll_start_timer(struct lpfc_hba *); void lpfc_poll_eratt(unsigned long); -void lpfc_sli_poll_fcp_ring(struct lpfc_hba *); +int +lpfc_sli_handle_fast_ring_event(struct lpfc_hba *, + struct lpfc_sli_ring *, uint32_t); + struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *); uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *); @@ -235,7 +242,7 @@ void lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *); int lpfc_sli_check_eratt(struct lpfc_hba *); void lpfc_sli_handle_slow_ring_event(struct lpfc_hba *, struct lpfc_sli_ring *, uint32_t); -int lpfc_sli4_handle_received_buffer(struct lpfc_hba *); +void lpfc_sli4_handle_received_buffer(struct lpfc_hba *, struct hbq_dmabuf *); void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *, uint32_t); @@ -361,6 +368,7 @@ void lpfc_stop_port(struct lpfc_hba *); void lpfc_parse_fcoe_conf(struct lpfc_hba *, uint8_t *, uint32_t); int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int); void lpfc_start_fdiscs(struct lpfc_hba *phba); +struct lpfc_vport *lpfc_find_vport_by_vpid(struct lpfc_hba *, uint16_t); #define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) #define HBA_EVENT_RSCN 5 diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 9a1bd9534d7..0ebcd9baca7 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -31,6 +31,7 @@ #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport_fc.h> +#include <scsi/fc/fc_fs.h> #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -87,7 +88,6 @@ void lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocbq) { - struct lpfc_dmabuf *mp = NULL; IOCB_t *icmd = &piocbq->iocb; int i; @@ -160,6 +160,39 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } } +/** + * lpfc_sli4_ct_abort_unsol_event - Default handle for sli4 unsol abort + * @phba: Pointer to HBA context object. + * @pring: Pointer to the driver internal I/O ring. + * @piocbq: Pointer to the IOCBQ. + * + * This function serves as the default handler for the sli4 unsolicited + * abort event. It shall be invoked when there is no application interface + * registered unsolicited abort handler. This handler does nothing but + * just simply releases the dma buffer used by the unsol abort event. + **/ +void +lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *phba, + struct lpfc_sli_ring *pring, + struct lpfc_iocbq *piocbq) +{ + IOCB_t *icmd = &piocbq->iocb; + struct lpfc_dmabuf *bdeBuf; + uint32_t size; + + /* Forward abort event to any process registered to receive ct event */ + lpfc_bsg_ct_unsol_event(phba, pring, piocbq); + + /* If there is no BDE associated with IOCB, there is nothing to do */ + if (icmd->ulpBdeCount == 0) + return; + bdeBuf = piocbq->context2; + piocbq->context2 = NULL; + size = icmd->un.cont64[0].tus.f.bdeSize; + lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size); + lpfc_in_buf_free(phba, bdeBuf); +} + static void lpfc_free_ct_rsp(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist) { @@ -304,8 +337,8 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, /* Fill in rest of iocb */ icmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); icmd->un.genreq64.w5.hcsw.Dfctl = 0; - icmd->un.genreq64.w5.hcsw.Rctl = FC_UNSOL_CTL; - icmd->un.genreq64.w5.hcsw.Type = FC_COMMON_TRANSPORT_ULP; + icmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; + icmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; if (!tmo) { /* FC spec states we need 3 * ratov for CT requests */ @@ -363,9 +396,14 @@ lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp, outmp = lpfc_alloc_ct_rsp(phba, cmdcode, bpl, rsp_size, &cnt); if (!outmp) return -ENOMEM; - + /* + * Form the CT IOCB. The total number of BDEs in this IOCB + * is the single command plus response count from + * lpfc_alloc_ct_rsp. + */ + cnt += 1; status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0, - cnt+1, 0, retry); + cnt, 0, retry); if (status) { lpfc_free_ct_rsp(phba, outmp); return -ENOMEM; @@ -501,6 +539,9 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) SLI_CTNS_GFF_ID, 0, Did) == 0) vport->num_disc_nodes++; + else + lpfc_setup_disc_node + (vport, Did); } else { lpfc_debugfs_disc_trc(vport, @@ -1209,7 +1250,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, be16_to_cpu(SLI_CTNS_RFF_ID); CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID); CtReq->un.rff.fbits = FC4_FEATURE_INIT; - CtReq->un.rff.type_code = FC_FCP_DATA; + CtReq->un.rff.type_code = FC_TYPE_FCP; cmpl = lpfc_cmpl_ct_cmd_rff_id; break; } diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 8d0f0de76b6..391584183d8 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -926,7 +926,7 @@ lpfc_debugfs_dumpData_open(struct inode *inode, struct file *file) goto out; /* Round to page boundry */ - printk(KERN_ERR "BLKGRD %s: _dump_buf_data=0x%p\n", + printk(KERN_ERR "9059 BLKGRD: %s: _dump_buf_data=0x%p\n", __func__, _dump_buf_data); debug->buffer = _dump_buf_data; if (!debug->buffer) { @@ -956,8 +956,8 @@ lpfc_debugfs_dumpDif_open(struct inode *inode, struct file *file) goto out; /* Round to page boundry */ - printk(KERN_ERR "BLKGRD %s: _dump_buf_dif=0x%p file=%s\n", __func__, - _dump_buf_dif, file->f_dentry->d_name.name); + printk(KERN_ERR "9060 BLKGRD: %s: _dump_buf_dif=0x%p file=%s\n", + __func__, _dump_buf_dif, file->f_dentry->d_name.name); debug->buffer = _dump_buf_dif; if (!debug->buffer) { kfree(debug); @@ -1377,7 +1377,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) debugfs_create_dir(name, phba->hba_debugfs_root); if (!vport->vport_debugfs_root) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0417 Cant create debugfs"); + "0417 Cant create debugfs\n"); goto debug_failed; } atomic_inc(&phba->debugfs_vport_count); @@ -1430,7 +1430,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) vport, &lpfc_debugfs_op_nodelist); if (!vport->debug_nodelist) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0409 Cant create debugfs nodelist"); + "0409 Cant create debugfs nodelist\n"); goto debug_failed; } debug_failed: diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 1142070e948..2851d75ffc6 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -19,7 +19,7 @@ *******************************************************************/ #define FC_MAX_HOLD_RSCN 32 /* max number of deferred RSCNs */ -#define FC_MAX_NS_RSP 65536 /* max size NameServer rsp */ +#define FC_MAX_NS_RSP 64512 /* max size NameServer rsp */ #define FC_MAXLOOP 126 /* max devices supported on a fc loop */ #define LPFC_DISC_FLOGI_TMO 10 /* Discovery FLOGI ratov */ @@ -105,8 +105,6 @@ struct lpfc_nodelist { struct lpfc_vport *vport; struct lpfc_work_evt els_retry_evt; struct lpfc_work_evt dev_loss_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; atomic_t cmd_pending; uint32_t cmd_qdepth; diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 45337cd23fe..a079bbc03cf 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -173,13 +173,26 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, * in FIP mode send FLOGI, FDISC and LOGO as FIP frames. */ if ((did == Fabric_DID) && - bf_get(lpfc_fip_flag, &phba->sli4_hba.sli4_flags) && + (phba->hba_flag & HBA_FIP_SUPPORT) && ((elscmd == ELS_CMD_FLOGI) || (elscmd == ELS_CMD_FDISC) || (elscmd == ELS_CMD_LOGO))) - elsiocb->iocb_flag |= LPFC_FIP_ELS; + switch (elscmd) { + case ELS_CMD_FLOGI: + elsiocb->iocb_flag |= ((ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT) + & LPFC_FIP_ELS_ID_MASK); + break; + case ELS_CMD_FDISC: + elsiocb->iocb_flag |= ((ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT) + & LPFC_FIP_ELS_ID_MASK); + break; + case ELS_CMD_LOGO: + elsiocb->iocb_flag |= ((ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT) + & LPFC_FIP_ELS_ID_MASK); + break; + } else - elsiocb->iocb_flag &= ~LPFC_FIP_ELS; + elsiocb->iocb_flag &= ~LPFC_FIP_ELS_ID_MASK; icmd = &elsiocb->iocb; @@ -591,7 +604,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } else { ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - if (vport->vfi_state & LPFC_VFI_REGISTERED) { + if (vport->vpi_state & LPFC_VPI_REGISTERED) { lpfc_start_fdiscs(phba); lpfc_do_scr_ns_plogi(phba, vport); } else @@ -2452,6 +2465,7 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp) */ del_timer_sync(&ndlp->nlp_delayfunc); retry = ndlp->nlp_retry; + ndlp->nlp_retry = 0; switch (cmd) { case ELS_CMD_FLOGI: @@ -2711,12 +2725,16 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, !lpfc_error_lost_link(irsp)) { /* FLOGI retry policy */ retry = 1; - maxretry = 48; - if (cmdiocb->retry >= 32) + /* retry forever */ + maxretry = 0; + if (cmdiocb->retry >= 100) + delay = 5000; + else if (cmdiocb->retry >= 32) delay = 1000; } - if ((++cmdiocb->retry) >= maxretry) { + cmdiocb->retry++; + if (maxretry && (cmdiocb->retry >= maxretry)) { phba->fc_stat.elsRetryExceeded++; retry = 0; } @@ -4503,6 +4521,29 @@ lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, } /** + * lpfc_els_rcv_rrq - Process an unsolicited rrq iocb + * @vport: pointer to a host virtual N_Port data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @ndlp: pointer to a node-list data structure. + * + * This routine processes a Reinstate Recovery Qualifier (RRQ) IOCB + * received as an ELS unsolicited event. A request to RRQ shall only + * be accepted if the Originator Nx_Port N_Port_ID or the Responder + * Nx_Port N_Port_ID of the target Exchange is the same as the + * N_Port_ID of the Nx_Port that makes the request. If the RRQ is + * not accepted, an LS_RJT with reason code "Unable to perform + * command request" and reason code explanation "Invalid Originator + * S_ID" shall be returned. For now, we just unconditionally accept + * RRQ from the target. + **/ +static void +lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +{ + lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); +} + +/** * lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd * @phba: pointer to lpfc hba data structure. * @pmb: pointer to the driver internal queue element for mailbox command. @@ -5396,7 +5437,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (lpfc_els_chk_latt(vport)) goto dropit; - /* Ignore traffic recevied during vport shutdown. */ + /* Ignore traffic received during vport shutdown. */ if (vport->load_flag & FC_UNLOADING) goto dropit; @@ -5618,6 +5659,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (newnode) lpfc_nlp_put(ndlp); break; + case ELS_CMD_RRQ: + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, + "RCV RRQ: did:x%x/ste:x%x flg:x%x", + did, vport->port_state, ndlp->nlp_flag); + + phba->fc_stat.elsRcvRRQ++; + lpfc_els_rcv_rrq(vport, elsiocb, ndlp); + if (newnode) + lpfc_nlp_put(ndlp); + break; default: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x", @@ -5670,7 +5721,7 @@ dropit: * NULL - No vport with the matching @vpi found * Otherwise - Address to the vport with the matching @vpi. **/ -static struct lpfc_vport * +struct lpfc_vport * lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) { struct lpfc_vport *vport; @@ -6024,11 +6075,6 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpStatus, irsp->un.ulpWord[4]); goto fdisc_failed; } - if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING) - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_nlp_put(ndlp); - /* giving up on FDISC. Cancel discovery timer */ - lpfc_can_disctmo(vport); spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_FABRIC; if (vport->phba->fc_topology == TOPOLOGY_LOOP) @@ -6107,6 +6153,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int did = ndlp->nlp_DID; int rc; + vport->port_state = LPFC_FDISC; cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did, ELS_CMD_FDISC); @@ -6172,7 +6219,6 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return 1; } lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING); - vport->port_state = LPFC_FDISC; return 0; } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index e6a47e25b21..3b942442765 100644..100755 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -525,8 +525,6 @@ lpfc_work_done(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); } - if (phba->hba_flag & HBA_RECEIVE_BUFFER) - lpfc_sli4_handle_received_buffer(phba); } vports = lpfc_create_vport_work_array(phba); @@ -568,8 +566,9 @@ lpfc_work_done(struct lpfc_hba *phba) pring = &phba->sli.ring[LPFC_ELS_RING]; status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING))); status >>= (4*LPFC_ELS_RING); - if ((status & HA_RXMASK) - || (pring->flag & LPFC_DEFERRED_RING_EVENT)) { + if ((status & HA_RXMASK) || + (pring->flag & LPFC_DEFERRED_RING_EVENT) || + (phba->hba_flag & HBA_SP_QUEUE_EVT)) { if (pring->flag & LPFC_STOP_IOCB_EVENT) { pring->flag |= LPFC_DEFERRED_RING_EVENT; /* Set the lpfc data pending flag */ @@ -688,7 +687,8 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) lpfc_unreg_rpi(vport, ndlp); /* Leave Fabric nodes alone on link down */ - if (!remove && ndlp->nlp_type & NLP_FABRIC) + if ((phba->sli_rev < LPFC_SLI_REV4) && + (!remove && ndlp->nlp_type & NLP_FABRIC)) continue; rc = lpfc_disc_state_machine(vport, ndlp, NULL, remove @@ -706,6 +706,9 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) void lpfc_port_link_failure(struct lpfc_vport *vport) { + /* Cleanup any outstanding received buffers */ + lpfc_cleanup_rcv_buffers(vport); + /* Cleanup any outstanding RSCN activity */ lpfc_els_flush_rscn(vport); @@ -1015,13 +1018,12 @@ lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) mempool_free(mboxq, phba->mbox_mem_pool); return; } - if (vport->port_state != LPFC_FLOGI) { - spin_lock_irqsave(&phba->hbalock, flags); - phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE); - phba->hba_flag &= ~FCF_DISC_INPROGRESS; - spin_unlock_irqrestore(&phba->hbalock, flags); + spin_lock_irqsave(&phba->hbalock, flags); + phba->fcf.fcf_flag |= (FCF_DISCOVERED | FCF_IN_USE); + phba->hba_flag &= ~FCF_DISC_INPROGRESS; + spin_unlock_irqrestore(&phba->hbalock, flags); + if (vport->port_state != LPFC_FLOGI) lpfc_initial_flogi(vport); - } mempool_free(mboxq, phba->mbox_mem_pool); return; @@ -1199,6 +1201,7 @@ lpfc_register_fcf(struct lpfc_hba *phba) /* If the FCF is not availabe do nothing. */ if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) { + phba->hba_flag &= ~FCF_DISC_INPROGRESS; spin_unlock_irqrestore(&phba->hbalock, flags); return; } @@ -1216,15 +1219,23 @@ lpfc_register_fcf(struct lpfc_hba *phba) fcf_mbxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!fcf_mbxq) + if (!fcf_mbxq) { + spin_lock_irqsave(&phba->hbalock, flags); + phba->hba_flag &= ~FCF_DISC_INPROGRESS; + spin_unlock_irqrestore(&phba->hbalock, flags); return; + } lpfc_reg_fcfi(phba, fcf_mbxq); fcf_mbxq->vport = phba->pport; fcf_mbxq->mbox_cmpl = lpfc_mbx_cmpl_reg_fcfi; rc = lpfc_sli_issue_mbox(phba, fcf_mbxq, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) + if (rc == MBX_NOT_FINISHED) { + spin_lock_irqsave(&phba->hbalock, flags); + phba->hba_flag &= ~FCF_DISC_INPROGRESS; + spin_unlock_irqrestore(&phba->hbalock, flags); mempool_free(fcf_mbxq, phba->mbox_mem_pool); + } return; } @@ -1253,13 +1264,27 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, uint16_t *vlan_id) { struct lpfc_fcf_conn_entry *conn_entry; + int i, j, fcf_vlan_id = 0; + + /* Find the lowest VLAN id in the FCF record */ + for (i = 0; i < 512; i++) { + if (new_fcf_record->vlan_bitmap[i]) { + fcf_vlan_id = i * 8; + j = 0; + while (!((new_fcf_record->vlan_bitmap[i] >> j) & 1)) { + j++; + fcf_vlan_id++; + } + break; + } + } /* If FCF not available return 0 */ if (!bf_get(lpfc_fcf_record_fcf_avail, new_fcf_record) || !bf_get(lpfc_fcf_record_fcf_valid, new_fcf_record)) return 0; - if (!phba->cfg_enable_fip) { + if (!(phba->hba_flag & HBA_FIP_SUPPORT)) { *boot_flag = 0; *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, new_fcf_record); @@ -1286,7 +1311,11 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, if (*addr_mode & LPFC_FCF_FPMA) *addr_mode = LPFC_FCF_FPMA; - *vlan_id = 0xFFFF; + /* If FCF record report a vlan id use that vlan id */ + if (fcf_vlan_id) + *vlan_id = fcf_vlan_id; + else + *vlan_id = 0xFFFF; return 1; } @@ -1384,8 +1413,15 @@ lpfc_match_fcf_conn_list(struct lpfc_hba *phba, (*addr_mode & LPFC_FCF_FPMA)) *addr_mode = LPFC_FCF_FPMA; + /* If matching connect list has a vlan id, use it */ if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) *vlan_id = conn_entry->conn_rec.vlan_tag; + /* + * If no vlan id is specified in connect list, use the vlan id + * in the FCF record + */ + else if (fcf_vlan_id) + *vlan_id = fcf_vlan_id; else *vlan_id = 0xFFFF; @@ -1423,6 +1459,15 @@ lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf) if (phba->link_state >= LPFC_LINK_UP) lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST); + else { + /* + * Do not continue FCF discovery and clear FCF_DISC_INPROGRESS + * flag + */ + spin_lock_irq(&phba->hbalock); + phba->hba_flag &= ~FCF_DISC_INPROGRESS; + spin_unlock_irq(&phba->hbalock); + } if (unreg_fcf) { spin_lock_irq(&phba->hbalock); @@ -1659,9 +1704,8 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) lpfc_initial_fdisc(vport); else { lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); - lpfc_printf_vlog(vport, KERN_ERR, - LOG_ELS, - "2606 No NPIV Fabric support\n"); + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "2606 No NPIV Fabric support\n"); } return; } @@ -1756,8 +1800,8 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) lpfc_vport_set_state(vport, FC_VPORT_FAILED); goto fail_free_mem; } - /* Mark the vport has registered with its VFI */ - vport->vfi_state |= LPFC_VFI_REGISTERED; + /* The VPI is implicitly registered when the VFI is registered */ + vport->vpi_state |= LPFC_VPI_REGISTERED; if (vport->port_state == LPFC_FABRIC_CFG_LINK) { lpfc_start_fdiscs(phba); @@ -1861,7 +1905,10 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) if (phba->fc_topology == TOPOLOGY_LOOP) { phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; - if (phba->cfg_enable_npiv) + /* if npiv is enabled and this adapter supports npiv log + * a message that npiv is not supported in this topology + */ + if (phba->cfg_enable_npiv && phba->max_vpi) lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1309 Link Up Event npiv not supported in loop " "topology\n"); @@ -1955,7 +2002,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) * is phase 1 implementation that support FCF index 0 and driver * defaults. */ - if (phba->cfg_enable_fip == 0) { + if (!(phba->hba_flag & HBA_FIP_SUPPORT)) { fcf_record = kzalloc(sizeof(struct fcf_record), GFP_KERNEL); if (unlikely(!fcf_record)) { @@ -2085,6 +2132,7 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) else phba->sli.sli_flag &= ~LPFC_MENLO_MAINT; + phba->link_events++; if (la->attType == AT_LINK_UP && (!la->mm)) { phba->fc_stat.LinkUp++; if (phba->link_flag & LS_LOOPBACK_MODE) { @@ -2211,13 +2259,14 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) mb->mbxStatus); break; } + vport->vpi_state &= ~LPFC_VPI_REGISTERED; vport->unreg_vpi_cmpl = VPORT_OK; mempool_free(pmb, phba->mbox_mem_pool); /* * This shost reference might have been taken at the beginning of * lpfc_vport_delete() */ - if (vport->load_flag & FC_UNLOADING) + if ((vport->load_flag & FC_UNLOADING) && (vport != phba->pport)) scsi_host_put(shost); } @@ -2268,6 +2317,7 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) goto out; } + vport->vpi_state |= LPFC_VPI_REGISTERED; vport->num_disc_nodes = 0; /* go thru NPR list and issue ELS PLOGIs */ if (vport->fc_npr_cnt) @@ -3077,7 +3127,7 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) struct lpfc_sli *psli; struct lpfc_sli_ring *pring; struct lpfc_iocbq *iocb, *next_iocb; - uint32_t rpi, i; + uint32_t i; lpfc_fabric_abort_nport(ndlp); @@ -3086,7 +3136,6 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) * by firmware with a no rpi error. */ psli = &phba->sli; - rpi = ndlp->nlp_rpi; if (ndlp->nlp_flag & NLP_RPI_VALID) { /* Now process each ring */ for (i = 0; i < psli->num_rings; i++) { @@ -4322,6 +4371,14 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) ret = 1; spin_unlock_irq(shost->host_lock); goto out; + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "2624 RPI %x DID %x flg %x still " + "logged in\n", + ndlp->nlp_rpi, ndlp->nlp_DID, + ndlp->nlp_flag); + if (ndlp->nlp_flag & NLP_RPI_VALID) + ret = 1; } } spin_unlock_irq(shost->host_lock); @@ -4400,7 +4457,7 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba) */ if (!(phba->hba_flag & HBA_FCOE_SUPPORT) || !(phba->fcf.fcf_flag & FCF_REGISTERED) || - (phba->cfg_enable_fip == 0)) { + (!(phba->hba_flag & HBA_FIP_SUPPORT))) { spin_unlock_irq(&phba->hbalock); return; } @@ -4409,6 +4466,8 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba) if (lpfc_fcf_inuse(phba)) return; + /* At this point, all discovery is aborted */ + phba->pport->port_state = LPFC_VPORT_UNKNOWN; /* Unregister VPIs */ vports = lpfc_create_vport_work_array(phba); @@ -4416,8 +4475,8 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba) (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { lpfc_mbx_unreg_vpi(vports[i]); - vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - vports[i]->vfi_state &= ~LPFC_VFI_REGISTERED; + vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; + vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED; } lpfc_destroy_vport_work_array(phba, vports); @@ -4431,7 +4490,7 @@ lpfc_unregister_unused_fcf(struct lpfc_hba *phba) return; } - lpfc_unreg_vfi(mbox, phba->pport->vfi); + lpfc_unreg_vfi(mbox, phba->pport); mbox->vport = phba->pport; mbox->mbox_cmpl = lpfc_unregister_vfi_cmpl; @@ -4512,8 +4571,10 @@ lpfc_read_fcf_conn_tbl(struct lpfc_hba *phba, /* Free the current connect table */ list_for_each_entry_safe(conn_entry, next_conn_entry, - &phba->fcf_conn_rec_list, list) + &phba->fcf_conn_rec_list, list) { + list_del_init(&conn_entry->list); kfree(conn_entry); + } conn_hdr = (struct lpfc_fcf_conn_hdr *) buff; record_count = conn_hdr->length * sizeof(uint32_t)/ @@ -4569,14 +4630,6 @@ lpfc_read_fcoe_param(struct lpfc_hba *phba, (fcoe_param_hdr->length != FCOE_PARAM_LENGTH)) return; - if (bf_get(lpfc_fip_param_hdr_fipp_mode, fcoe_param_hdr) == - FIPP_MODE_ON) - phba->cfg_enable_fip = 1; - - if (bf_get(lpfc_fip_param_hdr_fipp_mode, fcoe_param_hdr) == - FIPP_MODE_OFF) - phba->cfg_enable_fip = 0; - if (fcoe_param_hdr->parm_flags & FIPP_VLAN_VALID) { phba->valid_vlan = 1; phba->vlan_id = le16_to_cpu(fcoe_param->vlan_tag) & diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index ccb26724dc5..c9faa1d8c3c 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1124,21 +1124,6 @@ typedef struct { /* Number of 4-byte words in an IOCB. */ #define IOCB_WORD_SZ 8 -/* defines for type field in fc header */ -#define FC_ELS_DATA 0x1 -#define FC_LLC_SNAP 0x5 -#define FC_FCP_DATA 0x8 -#define FC_COMMON_TRANSPORT_ULP 0x20 - -/* defines for rctl field in fc header */ -#define FC_DEV_DATA 0x0 -#define FC_UNSOL_CTL 0x2 -#define FC_SOL_CTL 0x3 -#define FC_UNSOL_DATA 0x4 -#define FC_FCP_CMND 0x6 -#define FC_ELS_REQ 0x22 -#define FC_ELS_RSP 0x23 - /* network headers for Dfctl field */ #define FC_NET_HDR 0x20 @@ -1183,6 +1168,8 @@ typedef struct { #define PCI_DEVICE_ID_ZEPHYR_DCSP 0xfe12 #define PCI_VENDOR_ID_SERVERENGINE 0x19a2 #define PCI_DEVICE_ID_TIGERSHARK 0x0704 +#define PCI_DEVICE_ID_TOMCAT 0x0714 +#define PCI_DEVICE_ID_FALCON 0xf180 #define JEDEC_ID_ADDRESS 0x0080001c #define FIREFLY_JEDEC_ID 0x1ACC @@ -1444,6 +1431,7 @@ typedef struct { /* FireFly BIU registers */ #define CMD_ABORT_MXRI64_CN 0x8C #define CMD_RCV_ELS_REQ64_CX 0x8D #define CMD_XMIT_ELS_RSP64_CX 0x95 +#define CMD_XMIT_BLS_RSP64_CX 0x97 #define CMD_FCP_IWRITE64_CR 0x98 #define CMD_FCP_IWRITE64_CX 0x99 #define CMD_FCP_IREAD64_CR 0x9A @@ -2306,8 +2294,7 @@ typedef struct { uint32_t rsvd1; uint32_t rsvd2:8; uint32_t sid:24; - uint32_t rsvd3; - uint32_t rsvd4; + uint32_t wwn[2]; uint32_t rsvd5; uint16_t vfi; uint16_t vpi; @@ -2315,8 +2302,7 @@ typedef struct { uint32_t rsvd1; uint32_t sid:24; uint32_t rsvd2:8; - uint32_t rsvd3; - uint32_t rsvd4; + uint32_t wwn[2]; uint32_t rsvd5; uint16_t vpi; uint16_t vfi; @@ -2326,7 +2312,13 @@ typedef struct { /* Structure for MB Command UNREG_VPI (0x97) */ typedef struct { uint32_t rsvd1; - uint32_t rsvd2; +#ifdef __BIG_ENDIAN_BITFIELD + uint16_t rsvd2; + uint16_t sli4_vpi; +#else /* __LITTLE_ENDIAN */ + uint16_t sli4_vpi; + uint16_t rsvd2; +#endif uint32_t rsvd3; uint32_t rsvd4; uint32_t rsvd5; @@ -3547,7 +3539,7 @@ typedef struct _IOCB { /* IOCB structure */ ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */ QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */ struct rcv_seq64 rcvseq64; /* RCV_SEQ64 and RCV_CONT64 */ - + struct sli4_bls_acc bls_acc; /* UNSOL ABTS BLS_ACC params */ uint32_t ulpWord[IOCB_WORD_SZ - 2]; /* generic 6 'words' */ } un; union { diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 3689eee0453..1585148a17e 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -194,6 +194,26 @@ struct lpfc_sli4_flags { #define lpfc_fip_flag_WORD word0 }; +struct sli4_bls_acc { + uint32_t word0_rsvd; /* Word0 must be reserved */ + uint32_t word1; +#define lpfc_abts_orig_SHIFT 0 +#define lpfc_abts_orig_MASK 0x00000001 +#define lpfc_abts_orig_WORD word1 +#define LPFC_ABTS_UNSOL_RSP 1 +#define LPFC_ABTS_UNSOL_INT 0 + uint32_t word2; +#define lpfc_abts_rxid_SHIFT 0 +#define lpfc_abts_rxid_MASK 0x0000FFFF +#define lpfc_abts_rxid_WORD word2 +#define lpfc_abts_oxid_SHIFT 16 +#define lpfc_abts_oxid_MASK 0x0000FFFF +#define lpfc_abts_oxid_WORD word2 + uint32_t word3; + uint32_t word4; + uint32_t word5_rsvd; /* Word5 must be reserved */ +}; + /* event queue entry structure */ struct lpfc_eqe { uint32_t word0; @@ -425,7 +445,7 @@ struct lpfc_wqe_generic{ #define lpfc_wqe_gen_status_MASK 0x0000000F #define lpfc_wqe_gen_status_WORD word7 #define lpfc_wqe_gen_ct_SHIFT 2 -#define lpfc_wqe_gen_ct_MASK 0x00000007 +#define lpfc_wqe_gen_ct_MASK 0x00000003 #define lpfc_wqe_gen_ct_WORD word7 uint32_t abort_tag; uint32_t word9; @@ -453,6 +473,13 @@ struct lpfc_wqe_generic{ #define lpfc_wqe_gen_wqec_SHIFT 7 #define lpfc_wqe_gen_wqec_MASK 0x00000001 #define lpfc_wqe_gen_wqec_WORD word11 +#define ELS_ID_FLOGI 3 +#define ELS_ID_FDISC 2 +#define ELS_ID_LOGO 1 +#define ELS_ID_DEFAULT 0 +#define lpfc_wqe_gen_els_id_SHIFT 4 +#define lpfc_wqe_gen_els_id_MASK 0x00000003 +#define lpfc_wqe_gen_els_id_WORD word11 #define lpfc_wqe_gen_cmd_type_SHIFT 0 #define lpfc_wqe_gen_cmd_type_MASK 0x0000000F #define lpfc_wqe_gen_cmd_type_WORD word11 @@ -487,8 +514,8 @@ struct lpfc_register { #define LPFC_UERR_STATUS_HI 0x00A4 #define LPFC_UERR_STATUS_LO 0x00A0 -#define LPFC_ONLINE0 0x00B0 -#define LPFC_ONLINE1 0x00B4 +#define LPFC_UE_MASK_HI 0x00AC +#define LPFC_UE_MASK_LO 0x00A8 #define LPFC_SCRATCHPAD 0x0058 /* BAR0 Registers */ @@ -760,6 +787,7 @@ struct mbox_header { #define LPFC_MBOX_OPCODE_MQ_DESTROY 0x35 #define LPFC_MBOX_OPCODE_CQ_DESTROY 0x36 #define LPFC_MBOX_OPCODE_EQ_DESTROY 0x37 +#define LPFC_MBOX_OPCODE_QUERY_FW_CFG 0x3A #define LPFC_MBOX_OPCODE_FUNCTION_RESET 0x3D /* FCoE Opcodes */ @@ -1273,6 +1301,51 @@ struct lpfc_mbx_del_fcf_tbl_entry { #define lpfc_mbx_del_fcf_tbl_index_WORD word10 }; +struct lpfc_mbx_query_fw_cfg { + struct mbox_header header; + uint32_t config_number; + uint32_t asic_rev; + uint32_t phys_port; + uint32_t function_mode; +/* firmware Function Mode */ +#define lpfc_function_mode_toe_SHIFT 0 +#define lpfc_function_mode_toe_MASK 0x00000001 +#define lpfc_function_mode_toe_WORD function_mode +#define lpfc_function_mode_nic_SHIFT 1 +#define lpfc_function_mode_nic_MASK 0x00000001 +#define lpfc_function_mode_nic_WORD function_mode +#define lpfc_function_mode_rdma_SHIFT 2 +#define lpfc_function_mode_rdma_MASK 0x00000001 +#define lpfc_function_mode_rdma_WORD function_mode +#define lpfc_function_mode_vm_SHIFT 3 +#define lpfc_function_mode_vm_MASK 0x00000001 +#define lpfc_function_mode_vm_WORD function_mode +#define lpfc_function_mode_iscsi_i_SHIFT 4 +#define lpfc_function_mode_iscsi_i_MASK 0x00000001 +#define lpfc_function_mode_iscsi_i_WORD function_mode +#define lpfc_function_mode_iscsi_t_SHIFT 5 +#define lpfc_function_mode_iscsi_t_MASK 0x00000001 +#define lpfc_function_mode_iscsi_t_WORD function_mode +#define lpfc_function_mode_fcoe_i_SHIFT 6 +#define lpfc_function_mode_fcoe_i_MASK 0x00000001 +#define lpfc_function_mode_fcoe_i_WORD function_mode +#define lpfc_function_mode_fcoe_t_SHIFT 7 +#define lpfc_function_mode_fcoe_t_MASK 0x00000001 +#define lpfc_function_mode_fcoe_t_WORD function_mode +#define lpfc_function_mode_dal_SHIFT 8 +#define lpfc_function_mode_dal_MASK 0x00000001 +#define lpfc_function_mode_dal_WORD function_mode +#define lpfc_function_mode_lro_SHIFT 9 +#define lpfc_function_mode_lro_MASK 0x00000001 +#define lpfc_function_mode_lro_WORD function_mode9 +#define lpfc_function_mode_flex10_SHIFT 10 +#define lpfc_function_mode_flex10_MASK 0x00000001 +#define lpfc_function_mode_flex10_WORD function_mode +#define lpfc_function_mode_ncsi_SHIFT 11 +#define lpfc_function_mode_ncsi_MASK 0x00000001 +#define lpfc_function_mode_ncsi_WORD function_mode +}; + /* Status field for embedded SLI_CONFIG mailbox command */ #define STATUS_SUCCESS 0x0 #define STATUS_FAILED 0x1 @@ -1349,8 +1422,7 @@ struct lpfc_mbx_reg_vfi { #define lpfc_reg_vfi_fcfi_SHIFT 0 #define lpfc_reg_vfi_fcfi_MASK 0x0000FFFF #define lpfc_reg_vfi_fcfi_WORD word2 - uint32_t word3_rsvd; - uint32_t word4_rsvd; + uint32_t wwn[2]; struct ulp_bde64 bde; uint32_t word8_rsvd; uint32_t word9_rsvd; @@ -1555,6 +1627,11 @@ struct lpfc_mbx_read_rev { #define lpfc_mbx_rd_rev_fcoe_SHIFT 20 #define lpfc_mbx_rd_rev_fcoe_MASK 0x00000001 #define lpfc_mbx_rd_rev_fcoe_WORD word1 +#define lpfc_mbx_rd_rev_cee_ver_SHIFT 21 +#define lpfc_mbx_rd_rev_cee_ver_MASK 0x00000003 +#define lpfc_mbx_rd_rev_cee_ver_WORD word1 +#define LPFC_PREDCBX_CEE_MODE 0 +#define LPFC_DCBX_CEE_MODE 1 #define lpfc_mbx_rd_rev_vpd_SHIFT 29 #define lpfc_mbx_rd_rev_vpd_MASK 0x00000001 #define lpfc_mbx_rd_rev_vpd_WORD word1 @@ -1804,6 +1881,7 @@ struct lpfc_mqe { struct lpfc_mbx_read_config rd_config; struct lpfc_mbx_request_features req_ftrs; struct lpfc_mbx_post_hdr_tmpl hdr_tmpl; + struct lpfc_mbx_query_fw_cfg query_fw_cfg; struct lpfc_mbx_nop nop; } un; }; @@ -1885,7 +1963,7 @@ struct lpfc_acqe_link { }; struct lpfc_acqe_fcoe { - uint32_t fcf_index; + uint32_t index; uint32_t word1; #define lpfc_acqe_fcoe_fcf_count_SHIFT 0 #define lpfc_acqe_fcoe_fcf_count_MASK 0x0000FFFF @@ -1896,6 +1974,7 @@ struct lpfc_acqe_fcoe { #define LPFC_FCOE_EVENT_TYPE_NEW_FCF 0x1 #define LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL 0x2 #define LPFC_FCOE_EVENT_TYPE_FCF_DEAD 0x3 +#define LPFC_FCOE_EVENT_TYPE_CVL 0x4 uint32_t event_tag; uint32_t trailer; }; @@ -1921,12 +2000,13 @@ struct lpfc_bmbx_create { #define SGL_ALIGN_SZ 64 #define SGL_PAGE_SIZE 4096 /* align SGL addr on a size boundary - adjust address up */ -#define NO_XRI ((uint16_t)-1) +#define NO_XRI ((uint16_t)-1) + struct wqe_common { uint32_t word6; -#define wqe_xri_SHIFT 0 -#define wqe_xri_MASK 0x0000FFFF -#define wqe_xri_WORD word6 +#define wqe_xri_tag_SHIFT 0 +#define wqe_xri_tag_MASK 0x0000FFFF +#define wqe_xri_tag_WORD word6 #define wqe_ctxt_tag_SHIFT 16 #define wqe_ctxt_tag_MASK 0x0000FFFF #define wqe_ctxt_tag_WORD word6 @@ -1987,7 +2067,7 @@ struct wqe_common { #define wqe_wqec_MASK 0x00000001 #define wqe_wqec_WORD word11 #define wqe_cqid_SHIFT 16 -#define wqe_cqid_MASK 0x000003ff +#define wqe_cqid_MASK 0x0000ffff #define wqe_cqid_WORD word11 }; @@ -1996,6 +2076,9 @@ struct wqe_did { #define wqe_els_did_SHIFT 0 #define wqe_els_did_MASK 0x00FFFFFF #define wqe_els_did_WORD word5 +#define wqe_xmit_bls_pt_SHIFT 28 +#define wqe_xmit_bls_pt_MASK 0x00000003 +#define wqe_xmit_bls_pt_WORD word5 #define wqe_xmit_bls_ar_SHIFT 30 #define wqe_xmit_bls_ar_MASK 0x00000001 #define wqe_xmit_bls_ar_WORD word5 @@ -2044,6 +2127,23 @@ struct xmit_els_rsp64_wqe { struct xmit_bls_rsp64_wqe { uint32_t payload0; +/* Payload0 for BA_ACC */ +#define xmit_bls_rsp64_acc_seq_id_SHIFT 16 +#define xmit_bls_rsp64_acc_seq_id_MASK 0x000000ff +#define xmit_bls_rsp64_acc_seq_id_WORD payload0 +#define xmit_bls_rsp64_acc_seq_id_vald_SHIFT 24 +#define xmit_bls_rsp64_acc_seq_id_vald_MASK 0x000000ff +#define xmit_bls_rsp64_acc_seq_id_vald_WORD payload0 +/* Payload0 for BA_RJT */ +#define xmit_bls_rsp64_rjt_vspec_SHIFT 0 +#define xmit_bls_rsp64_rjt_vspec_MASK 0x000000ff +#define xmit_bls_rsp64_rjt_vspec_WORD payload0 +#define xmit_bls_rsp64_rjt_expc_SHIFT 8 +#define xmit_bls_rsp64_rjt_expc_MASK 0x000000ff +#define xmit_bls_rsp64_rjt_expc_WORD payload0 +#define xmit_bls_rsp64_rjt_rsnc_SHIFT 16 +#define xmit_bls_rsp64_rjt_rsnc_MASK 0x000000ff +#define xmit_bls_rsp64_rjt_rsnc_WORD payload0 uint32_t word1; #define xmit_bls_rsp64_rxid_SHIFT 0 #define xmit_bls_rsp64_rxid_MASK 0x0000ffff @@ -2052,18 +2152,19 @@ struct xmit_bls_rsp64_wqe { #define xmit_bls_rsp64_oxid_MASK 0x0000ffff #define xmit_bls_rsp64_oxid_WORD word1 uint32_t word2; -#define xmit_bls_rsp64_seqcntlo_SHIFT 0 -#define xmit_bls_rsp64_seqcntlo_MASK 0x0000ffff -#define xmit_bls_rsp64_seqcntlo_WORD word2 -#define xmit_bls_rsp64_seqcnthi_SHIFT 16 +#define xmit_bls_rsp64_seqcnthi_SHIFT 0 #define xmit_bls_rsp64_seqcnthi_MASK 0x0000ffff #define xmit_bls_rsp64_seqcnthi_WORD word2 +#define xmit_bls_rsp64_seqcntlo_SHIFT 16 +#define xmit_bls_rsp64_seqcntlo_MASK 0x0000ffff +#define xmit_bls_rsp64_seqcntlo_WORD word2 uint32_t rsrvd3; uint32_t rsrvd4; struct wqe_did wqe_dest; struct wqe_common wqe_com; /* words 6-11 */ uint32_t rsvd_12_15[4]; }; + struct wqe_rctl_dfctl { uint32_t word5; #define wqe_si_SHIFT 2 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 562d8cee874..0ba35a9a5c5 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -28,6 +28,7 @@ #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/ctype.h> +#include <linux/aer.h> #include <scsi/scsi.h> #include <scsi/scsi_device.h> @@ -852,12 +853,19 @@ lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) void lpfc_hb_timeout_handler(struct lpfc_hba *phba) { + struct lpfc_vport **vports; LPFC_MBOXQ_t *pmboxq; struct lpfc_dmabuf *buf_ptr; - int retval; + int retval, i; struct lpfc_sli *psli = &phba->sli; LIST_HEAD(completions); + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) + lpfc_rcv_seq_check_edtov(vports[i]); + lpfc_destroy_vport_work_array(phba, vports); + if ((phba->link_state == LPFC_HBA_ERROR) || (phba->pport->load_flag & FC_UNLOADING) || (phba->pport->fc_flag & FC_OFFLINE_MODE)) @@ -1521,10 +1529,10 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) int GE = 0; int oneConnect = 0; /* default is not a oneConnect */ struct { - char * name; - int max_speed; - char * bus; - } m = {"<Unknown>", 0, ""}; + char *name; + char *bus; + char *function; + } m = {"<Unknown>", "", ""}; if (mdp && mdp[0] != '\0' && descp && descp[0] != '\0') @@ -1545,132 +1553,155 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) switch (dev_id) { case PCI_DEVICE_ID_FIREFLY: - m = (typeof(m)){"LP6000", max_speed, "PCI"}; + m = (typeof(m)){"LP6000", "PCI", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SUPERFLY: if (vp->rev.biuRev >= 1 && vp->rev.biuRev <= 3) - m = (typeof(m)){"LP7000", max_speed, "PCI"}; + m = (typeof(m)){"LP7000", "PCI", + "Fibre Channel Adapter"}; else - m = (typeof(m)){"LP7000E", max_speed, "PCI"}; + m = (typeof(m)){"LP7000E", "PCI", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_DRAGONFLY: - m = (typeof(m)){"LP8000", max_speed, "PCI"}; + m = (typeof(m)){"LP8000", "PCI", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_CENTAUR: if (FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID) - m = (typeof(m)){"LP9002", max_speed, "PCI"}; + m = (typeof(m)){"LP9002", "PCI", + "Fibre Channel Adapter"}; else - m = (typeof(m)){"LP9000", max_speed, "PCI"}; + m = (typeof(m)){"LP9000", "PCI", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_RFLY: - m = (typeof(m)){"LP952", max_speed, "PCI"}; + m = (typeof(m)){"LP952", "PCI", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_PEGASUS: - m = (typeof(m)){"LP9802", max_speed, "PCI-X"}; + m = (typeof(m)){"LP9802", "PCI-X", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_THOR: - m = (typeof(m)){"LP10000", max_speed, "PCI-X"}; + m = (typeof(m)){"LP10000", "PCI-X", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_VIPER: - m = (typeof(m)){"LPX1000", max_speed, "PCI-X"}; + m = (typeof(m)){"LPX1000", "PCI-X", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_PFLY: - m = (typeof(m)){"LP982", max_speed, "PCI-X"}; + m = (typeof(m)){"LP982", "PCI-X", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_TFLY: - m = (typeof(m)){"LP1050", max_speed, "PCI-X"}; + m = (typeof(m)){"LP1050", "PCI-X", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_HELIOS: - m = (typeof(m)){"LP11000", max_speed, "PCI-X2"}; + m = (typeof(m)){"LP11000", "PCI-X2", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_HELIOS_SCSP: - m = (typeof(m)){"LP11000-SP", max_speed, "PCI-X2"}; + m = (typeof(m)){"LP11000-SP", "PCI-X2", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_HELIOS_DCSP: - m = (typeof(m)){"LP11002-SP", max_speed, "PCI-X2"}; + m = (typeof(m)){"LP11002-SP", "PCI-X2", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_NEPTUNE: - m = (typeof(m)){"LPe1000", max_speed, "PCIe"}; + m = (typeof(m)){"LPe1000", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_NEPTUNE_SCSP: - m = (typeof(m)){"LPe1000-SP", max_speed, "PCIe"}; + m = (typeof(m)){"LPe1000-SP", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_NEPTUNE_DCSP: - m = (typeof(m)){"LPe1002-SP", max_speed, "PCIe"}; + m = (typeof(m)){"LPe1002-SP", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_BMID: - m = (typeof(m)){"LP1150", max_speed, "PCI-X2"}; + m = (typeof(m)){"LP1150", "PCI-X2", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_BSMB: - m = (typeof(m)){"LP111", max_speed, "PCI-X2"}; + m = (typeof(m)){"LP111", "PCI-X2", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_ZEPHYR: - m = (typeof(m)){"LPe11000", max_speed, "PCIe"}; + m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_ZEPHYR_SCSP: - m = (typeof(m)){"LPe11000", max_speed, "PCIe"}; + m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_ZEPHYR_DCSP: - m = (typeof(m)){"LP2105", max_speed, "PCIe"}; + m = (typeof(m)){"LP2105", "PCIe", "FCoE Adapter"}; GE = 1; break; case PCI_DEVICE_ID_ZMID: - m = (typeof(m)){"LPe1150", max_speed, "PCIe"}; + m = (typeof(m)){"LPe1150", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_ZSMB: - m = (typeof(m)){"LPe111", max_speed, "PCIe"}; + m = (typeof(m)){"LPe111", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LP101: - m = (typeof(m)){"LP101", max_speed, "PCI-X"}; + m = (typeof(m)){"LP101", "PCI-X", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LP10000S: - m = (typeof(m)){"LP10000-S", max_speed, "PCI"}; + m = (typeof(m)){"LP10000-S", "PCI", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LP11000S: - m = (typeof(m)){"LP11000-S", max_speed, - "PCI-X2"}; + m = (typeof(m)){"LP11000-S", "PCI-X2", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LPE11000S: - m = (typeof(m)){"LPe11000-S", max_speed, - "PCIe"}; + m = (typeof(m)){"LPe11000-S", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT: - m = (typeof(m)){"LPe12000", max_speed, "PCIe"}; + m = (typeof(m)){"LPe12000", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_MID: - m = (typeof(m)){"LPe1250", max_speed, "PCIe"}; + m = (typeof(m)){"LPe1250", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_SMB: - m = (typeof(m)){"LPe121", max_speed, "PCIe"}; + m = (typeof(m)){"LPe121", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_DCSP: - m = (typeof(m)){"LPe12002-SP", max_speed, "PCIe"}; + m = (typeof(m)){"LPe12002-SP", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_SCSP: - m = (typeof(m)){"LPe12000-SP", max_speed, "PCIe"}; + m = (typeof(m)){"LPe12000-SP", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_S: - m = (typeof(m)){"LPe12000-S", max_speed, "PCIe"}; + m = (typeof(m)){"LPe12000-S", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_HORNET: - m = (typeof(m)){"LP21000", max_speed, "PCIe"}; + m = (typeof(m)){"LP21000", "PCIe", "FCoE Adapter"}; GE = 1; break; case PCI_DEVICE_ID_PROTEUS_VF: - m = (typeof(m)) {"LPev12000", max_speed, "PCIe IOV"}; + m = (typeof(m)){"LPev12000", "PCIe IOV", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_PROTEUS_PF: - m = (typeof(m)) {"LPev12000", max_speed, "PCIe IOV"}; + m = (typeof(m)){"LPev12000", "PCIe IOV", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_PROTEUS_S: - m = (typeof(m)) {"LPemv12002-S", max_speed, "PCIe IOV"}; + m = (typeof(m)){"LPemv12002-S", "PCIe IOV", + "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_TIGERSHARK: oneConnect = 1; - m = (typeof(m)) {"OCe10100-F", max_speed, "PCIe"}; + m = (typeof(m)){"OCe10100", "PCIe", "FCoE"}; + break; + case PCI_DEVICE_ID_TOMCAT: + oneConnect = 1; + m = (typeof(m)){"OCe11100", "PCIe", "FCoE"}; + break; + case PCI_DEVICE_ID_FALCON: + m = (typeof(m)){"LPSe12002-ML1-E", "PCIe", + "EmulexSecure Fibre"}; break; default: - m = (typeof(m)){ NULL }; + m = (typeof(m)){"Unknown", "", ""}; break; } @@ -1682,17 +1713,14 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) if (descp && descp[0] == '\0') { if (oneConnect) snprintf(descp, 255, - "Emulex OneConnect %s, FCoE Initiator, Port %s", - m.name, + "Emulex OneConnect %s, %s Initiator, Port %s", + m.name, m.function, phba->Port); else snprintf(descp, 255, "Emulex %s %d%s %s %s", - m.name, m.max_speed, - (GE) ? "GE" : "Gb", - m.bus, - (GE) ? "FCoE Adapter" : - "Fibre Channel Adapter"); + m.name, max_speed, (GE) ? "GE" : "Gb", + m.bus, m.function); } } @@ -2217,7 +2245,7 @@ lpfc_offline_prep(struct lpfc_hba * phba) if (vports[i]->load_flag & FC_UNLOADING) continue; - vports[i]->vfi_state &= ~LPFC_VFI_REGISTERED; + vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED; shost = lpfc_shost_from_vport(vports[i]); list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, @@ -2308,6 +2336,7 @@ lpfc_scsi_free(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); /* Release all the lpfc_scsi_bufs maintained by this host. */ + spin_lock(&phba->scsi_buf_list_lock); list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) { list_del(&sb->list); pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data, @@ -2315,6 +2344,7 @@ lpfc_scsi_free(struct lpfc_hba *phba) kfree(sb); phba->total_scsi_bufs--; } + spin_unlock(&phba->scsi_buf_list_lock); /* Release all the lpfc_iocbq entries maintained by this host. */ list_for_each_entry_safe(io, io_next, &phba->lpfc_iocb_list, list) { @@ -2322,9 +2352,7 @@ lpfc_scsi_free(struct lpfc_hba *phba) kfree(io); phba->total_iocbq_bufs--; } - spin_unlock_irq(&phba->hbalock); - return 0; } @@ -2408,7 +2436,7 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) vport->els_tmofunc.function = lpfc_els_timeout; vport->els_tmofunc.data = (unsigned long)vport; - error = scsi_add_host(shost, dev); + error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev); if (error) goto out_put_shost; @@ -2699,6 +2727,63 @@ lpfc_sli_remove_dflt_fcf(struct lpfc_hba *phba) } /** + * lpfc_sli4_fw_cfg_check - Read the firmware config and verify FCoE support + * @phba: pointer to lpfc hba data structure. + * + * This function uses the QUERY_FW_CFG mailbox command to determine if the + * firmware loaded supports FCoE. A return of zero indicates that the mailbox + * was successful and the firmware supports FCoE. Any other return indicates + * a error. It is assumed that this function will be called before interrupts + * are enabled. + **/ +static int +lpfc_sli4_fw_cfg_check(struct lpfc_hba *phba) +{ + int rc = 0; + LPFC_MBOXQ_t *mboxq; + struct lpfc_mbx_query_fw_cfg *query_fw_cfg; + uint32_t length; + uint32_t shdr_status, shdr_add_status; + + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2621 Failed to allocate mbox for " + "query firmware config cmd\n"); + return -ENOMEM; + } + query_fw_cfg = &mboxq->u.mqe.un.query_fw_cfg; + length = (sizeof(struct lpfc_mbx_query_fw_cfg) - + sizeof(struct lpfc_sli4_cfg_mhdr)); + lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, + LPFC_MBOX_OPCODE_QUERY_FW_CFG, + length, LPFC_SLI4_MBX_EMBED); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + /* The IOCTL status is embedded in the mailbox subheader. */ + shdr_status = bf_get(lpfc_mbox_hdr_status, + &query_fw_cfg->header.cfg_shdr.response); + shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, + &query_fw_cfg->header.cfg_shdr.response); + if (shdr_status || shdr_add_status || rc != MBX_SUCCESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2622 Query Firmware Config failed " + "mbx status x%x, status x%x add_status x%x\n", + rc, shdr_status, shdr_add_status); + return -EINVAL; + } + if (!bf_get(lpfc_function_mode_fcoe_i, query_fw_cfg)) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2623 FCoE Function not supported by firmware. " + "Function mode = %08x\n", + query_fw_cfg->function_mode); + return -EINVAL; + } + if (rc != MBX_TIMEOUT) + mempool_free(mboxq, phba->mbox_mem_pool); + return 0; +} + +/** * lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code * @phba: pointer to lpfc hba data structure. * @acqe_link: pointer to the async link completion queue entry. @@ -2918,13 +3003,17 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, { uint8_t event_type = bf_get(lpfc_acqe_fcoe_event_type, acqe_fcoe); int rc; + struct lpfc_vport *vport; + struct lpfc_nodelist *ndlp; + struct Scsi_Host *shost; + phba->fc_eventTag = acqe_fcoe->event_tag; phba->fcoe_eventtag = acqe_fcoe->event_tag; switch (event_type) { case LPFC_FCOE_EVENT_TYPE_NEW_FCF: lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "2546 New FCF found index 0x%x tag 0x%x\n", - acqe_fcoe->fcf_index, + acqe_fcoe->index, acqe_fcoe->event_tag); /* * If the current FCF is in discovered state, or @@ -2939,12 +3028,11 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, spin_unlock_irq(&phba->hbalock); /* Read the FCF table and re-discover SAN. */ - rc = lpfc_sli4_read_fcf_record(phba, - LPFC_FCOE_FCF_GET_FIRST); + rc = lpfc_sli4_read_fcf_record(phba, LPFC_FCOE_FCF_GET_FIRST); if (rc) lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "2547 Read FCF record failed 0x%x\n", - rc); + "2547 Read FCF record failed 0x%x\n", + rc); break; case LPFC_FCOE_EVENT_TYPE_FCF_TABLE_FULL: @@ -2956,11 +3044,11 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, case LPFC_FCOE_EVENT_TYPE_FCF_DEAD: lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "2549 FCF disconnected fron network index 0x%x" - " tag 0x%x\n", acqe_fcoe->fcf_index, + "2549 FCF disconnected from network index 0x%x" + " tag 0x%x\n", acqe_fcoe->index, acqe_fcoe->event_tag); /* If the event is not for currently used fcf do nothing */ - if (phba->fcf.fcf_indx != acqe_fcoe->fcf_index) + if (phba->fcf.fcf_indx != acqe_fcoe->index) break; /* * Currently, driver support only one FCF - so treat this as @@ -2970,7 +3058,28 @@ lpfc_sli4_async_fcoe_evt(struct lpfc_hba *phba, /* Unregister FCF if no devices connected to it */ lpfc_unregister_unused_fcf(phba); break; - + case LPFC_FCOE_EVENT_TYPE_CVL: + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + "2718 Clear Virtual Link Received for VPI 0x%x" + " tag 0x%x\n", acqe_fcoe->index, acqe_fcoe->event_tag); + vport = lpfc_find_vport_by_vpid(phba, + acqe_fcoe->index - phba->vpi_base); + if (!vport) + break; + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp) + break; + shost = lpfc_shost_from_vport(vport); + lpfc_linkdown_port(vport); + if (vport->port_type != LPFC_NPIV_PORT) { + mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_DELAY_TMO; + spin_unlock_irq(shost->host_lock); + ndlp->nlp_last_elscmd = ELS_CMD_FLOGI; + vport->port_state = LPFC_FLOGI; + } + break; default: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0288 Unknown FCoE event type 0x%x event tag " @@ -2990,6 +3099,7 @@ static void lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba, struct lpfc_acqe_dcbx *acqe_dcbx) { + phba->fc_eventTag = acqe_dcbx->event_tag; lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0290 The SLI4 DCBX asynchronous event is not " "handled yet\n"); @@ -3432,7 +3542,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) /* Driver internel slow-path CQ Event pool */ INIT_LIST_HEAD(&phba->sli4_hba.sp_cqe_event_pool); /* Response IOCB work queue list */ - INIT_LIST_HEAD(&phba->sli4_hba.sp_rspiocb_work_queue); + INIT_LIST_HEAD(&phba->sli4_hba.sp_queue_event); /* Asynchronous event CQ Event work queue list */ INIT_LIST_HEAD(&phba->sli4_hba.sp_asynce_work_queue); /* Fast-path XRI aborted CQ Event work queue list */ @@ -3461,6 +3571,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) if (unlikely(rc)) goto out_free_bsmbx; + rc = lpfc_sli4_fw_cfg_check(phba); + if (unlikely(rc)) + goto out_free_bsmbx; + /* Set up the hba's configuration parameters. */ rc = lpfc_sli4_read_config(phba); if (unlikely(rc)) @@ -3594,8 +3708,10 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) /* Free the current connect table */ list_for_each_entry_safe(conn_entry, next_conn_entry, - &phba->fcf_conn_rec_list, list) + &phba->fcf_conn_rec_list, list) { + list_del_init(&conn_entry->list); kfree(conn_entry); + } return; } @@ -3824,7 +3940,7 @@ lpfc_free_sgl_list(struct lpfc_hba *phba) rc = lpfc_sli4_remove_all_sgl_pages(phba); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2005 Unable to deregister pages from HBA: %x", rc); + "2005 Unable to deregister pages from HBA: %x\n", rc); } kfree(phba->sli4_hba.lpfc_els_sgl_array); } @@ -4273,7 +4389,8 @@ lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost) _dump_buf_data = (char *) __get_free_pages(GFP_KERNEL, pagecnt); if (_dump_buf_data) { - printk(KERN_ERR "BLKGRD allocated %d pages for " + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9043 BLKGRD: allocated %d pages for " "_dump_buf_data at 0x%p\n", (1 << pagecnt), _dump_buf_data); _dump_buf_data_order = pagecnt; @@ -4284,17 +4401,20 @@ lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost) --pagecnt; } if (!_dump_buf_data_order) - printk(KERN_ERR "BLKGRD ERROR unable to allocate " + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9044 BLKGRD: ERROR unable to allocate " "memory for hexdump\n"); } else - printk(KERN_ERR "BLKGRD already allocated _dump_buf_data=0x%p" + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9045 BLKGRD: already allocated _dump_buf_data=0x%p" "\n", _dump_buf_data); if (!_dump_buf_dif) { while (pagecnt) { _dump_buf_dif = (char *) __get_free_pages(GFP_KERNEL, pagecnt); if (_dump_buf_dif) { - printk(KERN_ERR "BLKGRD allocated %d pages for " + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9046 BLKGRD: allocated %d pages for " "_dump_buf_dif at 0x%p\n", (1 << pagecnt), _dump_buf_dif); _dump_buf_dif_order = pagecnt; @@ -4305,10 +4425,12 @@ lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost) --pagecnt; } if (!_dump_buf_dif_order) - printk(KERN_ERR "BLKGRD ERROR unable to allocate " + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9047 BLKGRD: ERROR unable to allocate " "memory for hexdump\n"); } else - printk(KERN_ERR "BLKGRD already allocated _dump_buf_dif=0x%p\n", + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9048 BLKGRD: already allocated _dump_buf_dif=0x%p\n", _dump_buf_dif); } @@ -4512,7 +4634,6 @@ int lpfc_sli4_post_status_check(struct lpfc_hba *phba) { struct lpfc_register sta_reg, uerrlo_reg, uerrhi_reg, scratchpad; - uint32_t onlnreg0, onlnreg1; int i, port_error = -ENODEV; if (!phba->sli4_hba.STAregaddr) @@ -4556,21 +4677,20 @@ lpfc_sli4_post_status_check(struct lpfc_hba *phba) bf_get(lpfc_scratchpad_slirev, &scratchpad), bf_get(lpfc_scratchpad_featurelevel1, &scratchpad), bf_get(lpfc_scratchpad_featurelevel2, &scratchpad)); - + phba->sli4_hba.ue_mask_lo = readl(phba->sli4_hba.UEMASKLOregaddr); + phba->sli4_hba.ue_mask_hi = readl(phba->sli4_hba.UEMASKHIregaddr); /* With uncoverable error, log the error message and return error */ - onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr); - onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr); - if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) { - uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr); - uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr); - if (uerrlo_reg.word0 || uerrhi_reg.word0) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1422 HBA Unrecoverable error: " - "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, " - "online0_reg=0x%x, online1_reg=0x%x\n", - uerrlo_reg.word0, uerrhi_reg.word0, - onlnreg0, onlnreg1); - } + uerrlo_reg.word0 = readl(phba->sli4_hba.UERRLOregaddr); + uerrhi_reg.word0 = readl(phba->sli4_hba.UERRHIregaddr); + if ((~phba->sli4_hba.ue_mask_lo & uerrlo_reg.word0) || + (~phba->sli4_hba.ue_mask_hi & uerrhi_reg.word0)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1422 HBA Unrecoverable error: " + "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, " + "ue_mask_lo_reg=0x%x, ue_mask_hi_reg=0x%x\n", + uerrlo_reg.word0, uerrhi_reg.word0, + phba->sli4_hba.ue_mask_lo, + phba->sli4_hba.ue_mask_hi); return -ENODEV; } @@ -4591,10 +4711,10 @@ lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba) LPFC_UERR_STATUS_LO; phba->sli4_hba.UERRHIregaddr = phba->sli4_hba.conf_regs_memmap_p + LPFC_UERR_STATUS_HI; - phba->sli4_hba.ONLINE0regaddr = phba->sli4_hba.conf_regs_memmap_p + - LPFC_ONLINE0; - phba->sli4_hba.ONLINE1regaddr = phba->sli4_hba.conf_regs_memmap_p + - LPFC_ONLINE1; + phba->sli4_hba.UEMASKLOregaddr = phba->sli4_hba.conf_regs_memmap_p + + LPFC_UE_MASK_LO; + phba->sli4_hba.UEMASKHIregaddr = phba->sli4_hba.conf_regs_memmap_p + + LPFC_UE_MASK_HI; phba->sli4_hba.SCRATCHPADregaddr = phba->sli4_hba.conf_regs_memmap_p + LPFC_SCRATCHPAD; } @@ -4825,7 +4945,8 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) phba->vpi_base = phba->sli4_hba.max_cfg_param.vpi_base; phba->vfi_base = phba->sli4_hba.max_cfg_param.vfi_base; phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.rpi_base; - phba->max_vpi = phba->sli4_hba.max_cfg_param.max_vpi; + phba->max_vpi = (phba->sli4_hba.max_cfg_param.max_vpi > 0) ? + (phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0; phba->max_vports = phba->max_vpi; lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "2003 cfg params XRI(B:%d M:%d), " @@ -4979,10 +5100,9 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) /* It does not make sense to have more EQs than WQs */ if (cfg_fcp_eq_count > phba->cfg_fcp_wq_count) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2593 The number of FCP EQs (%d) is more " - "than the number of FCP WQs (%d), take " - "the number of FCP EQs same as than of " - "WQs (%d)\n", cfg_fcp_eq_count, + "2593 The FCP EQ count(%d) cannot be greater " + "than the FCP WQ count(%d), limiting the " + "FCP EQ count to %d\n", cfg_fcp_eq_count, phba->cfg_fcp_wq_count, phba->cfg_fcp_wq_count); cfg_fcp_eq_count = phba->cfg_fcp_wq_count; @@ -5058,15 +5178,6 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) } phba->sli4_hba.els_cq = qdesc; - /* Create slow-path Unsolicited Receive Complete Queue */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, - phba->sli4_hba.cq_ecount); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0502 Failed allocate slow-path USOL RX CQ\n"); - goto out_free_els_cq; - } - phba->sli4_hba.rxq_cq = qdesc; /* Create fast-path FCP Completion Queue(s), one-to-one with EQs */ phba->sli4_hba.fcp_cq = kzalloc((sizeof(struct lpfc_queue *) * @@ -5075,7 +5186,7 @@ lpfc_sli4_queue_create(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2577 Failed allocate memory for fast-path " "CQ record array\n"); - goto out_free_rxq_cq; + goto out_free_els_cq; } for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) { qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, @@ -5188,9 +5299,6 @@ out_free_fcp_cq: phba->sli4_hba.fcp_cq[fcp_cqidx] = NULL; } kfree(phba->sli4_hba.fcp_cq); -out_free_rxq_cq: - lpfc_sli4_queue_free(phba->sli4_hba.rxq_cq); - phba->sli4_hba.rxq_cq = NULL; out_free_els_cq: lpfc_sli4_queue_free(phba->sli4_hba.els_cq); phba->sli4_hba.els_cq = NULL; @@ -5247,10 +5355,6 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba) lpfc_sli4_queue_free(phba->sli4_hba.dat_rq); phba->sli4_hba.dat_rq = NULL; - /* Release unsolicited receive complete queue */ - lpfc_sli4_queue_free(phba->sli4_hba.rxq_cq); - phba->sli4_hba.rxq_cq = NULL; - /* Release ELS complete queue */ lpfc_sli4_queue_free(phba->sli4_hba.els_cq); phba->sli4_hba.els_cq = NULL; @@ -5383,25 +5487,6 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) phba->sli4_hba.els_cq->queue_id, phba->sli4_hba.sp_eq->queue_id); - /* Set up slow-path Unsolicited Receive Complete Queue */ - if (!phba->sli4_hba.rxq_cq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0532 USOL RX CQ not allocated\n"); - goto out_destroy_els_cq; - } - rc = lpfc_cq_create(phba, phba->sli4_hba.rxq_cq, phba->sli4_hba.sp_eq, - LPFC_RCQ, LPFC_USOL); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0533 Failed setup of slow-path USOL RX CQ: " - "rc = 0x%x\n", rc); - goto out_destroy_els_cq; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2587 USL CQ setup: cq-id=%d, parent eq-id=%d\n", - phba->sli4_hba.rxq_cq->queue_id, - phba->sli4_hba.sp_eq->queue_id); - /* Set up fast-path FCP Response Complete Queue */ for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) { if (!phba->sli4_hba.fcp_cq[fcp_cqidx]) { @@ -5507,7 +5592,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) goto out_destroy_fcp_wq; } rc = lpfc_rq_create(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq, - phba->sli4_hba.rxq_cq, LPFC_USOL); + phba->sli4_hba.els_cq, LPFC_USOL); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0541 Failed setup of Receive Queue: " @@ -5519,7 +5604,7 @@ lpfc_sli4_queue_setup(struct lpfc_hba *phba) "parent cq-id=%d\n", phba->sli4_hba.hdr_rq->queue_id, phba->sli4_hba.dat_rq->queue_id, - phba->sli4_hba.rxq_cq->queue_id); + phba->sli4_hba.els_cq->queue_id); return 0; out_destroy_fcp_wq: @@ -5531,8 +5616,6 @@ out_destroy_mbx_wq: out_destroy_fcp_cq: for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--) lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_cqidx]); - lpfc_cq_destroy(phba, phba->sli4_hba.rxq_cq); -out_destroy_els_cq: lpfc_cq_destroy(phba, phba->sli4_hba.els_cq); out_destroy_mbx_cq: lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq); @@ -5574,8 +5657,6 @@ lpfc_sli4_queue_unset(struct lpfc_hba *phba) lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq); /* Unset ELS complete queue */ lpfc_cq_destroy(phba, phba->sli4_hba.els_cq); - /* Unset unsolicited receive complete queue */ - lpfc_cq_destroy(phba, phba->sli4_hba.rxq_cq); /* Unset FCP response complete queue */ for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; fcp_qidx++) lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_qidx]); @@ -6722,6 +6803,7 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid) { struct lpfc_hba *phba; struct lpfc_vport *vport = NULL; + struct Scsi_Host *shost = NULL; int error; uint32_t cfg_mode, intr_mode; @@ -6800,6 +6882,7 @@ lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid) goto out_destroy_shost; } + shost = lpfc_shost_from_vport(vport); /* save shost for error cleanup */ /* Now, trying to enable interrupt and bring up the device */ cfg_mode = phba->cfg_use_msi; while (true) { @@ -6866,6 +6949,8 @@ out_unset_pci_mem_s3: lpfc_sli_pci_mem_unset(phba); out_disable_pci_dev: lpfc_disable_pci_dev(phba); + if (shost) + scsi_host_put(shost); out_free_phba: lpfc_hba_free(phba); return error; @@ -7036,6 +7121,7 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev) /* Restore device state from PCI config space */ pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); + if (pdev->is_busmaster) pci_set_master(pdev); @@ -7070,6 +7156,75 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev) } /** + * lpfc_sli_prep_dev_for_recover - Prepare SLI3 device for pci slot recover + * @phba: pointer to lpfc hba data structure. + * + * This routine is called to prepare the SLI3 device for PCI slot recover. It + * aborts and stops all the on-going I/Os on the pci device. + **/ +static void +lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba) +{ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2723 PCI channel I/O abort preparing for recovery\n"); + /* Prepare for bringing HBA offline */ + lpfc_offline_prep(phba); + /* Clear sli active flag to prevent sysfs access to HBA */ + spin_lock_irq(&phba->hbalock); + phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE; + spin_unlock_irq(&phba->hbalock); + /* Stop and flush all I/Os and bring HBA offline */ + lpfc_offline(phba); +} + +/** + * lpfc_sli_prep_dev_for_reset - Prepare SLI3 device for pci slot reset + * @phba: pointer to lpfc hba data structure. + * + * This routine is called to prepare the SLI3 device for PCI slot reset. It + * disables the device interrupt and pci device, and aborts the internal FCP + * pending I/Os. + **/ +static void +lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *pring; + + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2710 PCI channel disable preparing for reset\n"); + /* Disable interrupt and pci device */ + lpfc_sli_disable_intr(phba); + pci_disable_device(phba->pcidev); + /* + * There may be I/Os dropped by the firmware. + * Error iocb (I/O) on txcmplq and let the SCSI layer + * retry it after re-establishing link. + */ + pring = &psli->ring[psli->fcp_ring]; + lpfc_sli_abort_iocb_ring(phba, pring); +} + +/** + * lpfc_sli_prep_dev_for_perm_failure - Prepare SLI3 dev for pci slot disable + * @phba: pointer to lpfc hba data structure. + * + * This routine is called to prepare the SLI3 device for PCI slot permanently + * disabling. It blocks the SCSI transport layer traffic and flushes the FCP + * pending I/Os. + **/ +static void +lpfc_prep_dev_for_perm_failure(struct lpfc_hba *phba) +{ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "2711 PCI channel permanent disable for failure\n"); + /* Block all SCSI devices' I/Os on the host */ + lpfc_scsi_dev_block(phba); + /* Clean up all driver's outstanding SCSI I/Os */ + lpfc_sli_flush_fcp_rings(phba); +} + +/** * lpfc_io_error_detected_s3 - Method for handling SLI-3 device PCI I/O error * @pdev: pointer to PCI device. * @state: the current PCI connection state. @@ -7083,6 +7238,7 @@ lpfc_pci_resume_one_s3(struct pci_dev *pdev) * as desired. * * Return codes + * PCI_ERS_RESULT_CAN_RECOVER - can be recovered with reset_link * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery * PCI_ERS_RESULT_DISCONNECT - device could not be recovered **/ @@ -7091,33 +7247,27 @@ lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state) { struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - if (state == pci_channel_io_perm_failure) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0472 PCI channel I/O permanent failure\n"); - /* Block all SCSI devices' I/Os on the host */ - lpfc_scsi_dev_block(phba); - /* Clean up all driver's outstanding SCSI I/Os */ - lpfc_sli_flush_fcp_rings(phba); + switch (state) { + case pci_channel_io_normal: + /* Non-fatal error, prepare for recovery */ + lpfc_sli_prep_dev_for_recover(phba); + return PCI_ERS_RESULT_CAN_RECOVER; + case pci_channel_io_frozen: + /* Fatal error, prepare for slot reset */ + lpfc_sli_prep_dev_for_reset(phba); + return PCI_ERS_RESULT_NEED_RESET; + case pci_channel_io_perm_failure: + /* Permanent failure, prepare for device down */ + lpfc_prep_dev_for_perm_failure(phba); return PCI_ERS_RESULT_DISCONNECT; + default: + /* Unknown state, prepare and request slot reset */ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0472 Unknown PCI error state: x%x\n", state); + lpfc_sli_prep_dev_for_reset(phba); + return PCI_ERS_RESULT_NEED_RESET; } - - pci_disable_device(pdev); - /* - * There may be I/Os dropped by the firmware. - * Error iocb (I/O) on txcmplq and let the SCSI layer - * retry it after re-establishing link. - */ - pring = &psli->ring[psli->fcp_ring]; - lpfc_sli_abort_iocb_ring(phba, pring); - - /* Disable interrupt */ - lpfc_sli_disable_intr(phba); - - /* Request a slot reset. */ - return PCI_ERS_RESULT_NEED_RESET; } /** @@ -7197,7 +7347,12 @@ lpfc_io_resume_s3(struct pci_dev *pdev) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + /* Bring the device online */ lpfc_online(phba); + + /* Clean up Advanced Error Reporting (AER) if needed */ + if (phba->hba_flag & HBA_AER_ENABLED) + pci_cleanup_aer_uncorrect_error_status(pdev); } /** @@ -7213,15 +7368,15 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba) if (phba->sli_rev == LPFC_SLI_REV4) { if (max_xri <= 100) - return 4; + return 10; else if (max_xri <= 256) - return 8; + return 25; else if (max_xri <= 512) - return 16; + return 50; else if (max_xri <= 1024) - return 32; + return 100; else - return 48; + return 150; } else return 0; } @@ -7249,6 +7404,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) { struct lpfc_hba *phba; struct lpfc_vport *vport = NULL; + struct Scsi_Host *shost = NULL; int error; uint32_t cfg_mode, intr_mode; int mcnt; @@ -7329,6 +7485,7 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) goto out_destroy_shost; } + shost = lpfc_shost_from_vport(vport); /* save shost for error cleanup */ /* Now, trying to enable interrupt and bring up the device */ cfg_mode = phba->cfg_use_msi; while (true) { @@ -7397,6 +7554,8 @@ out_unset_pci_mem_s4: lpfc_sli4_pci_mem_unset(phba); out_disable_pci_dev: lpfc_disable_pci_dev(phba); + if (shost) + scsi_host_put(shost); out_free_phba: lpfc_hba_free(phba); return error; @@ -7971,6 +8130,10 @@ static struct pci_device_id lpfc_id_table[] = { PCI_ANY_ID, PCI_ANY_ID, }, {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK, PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TOMCAT, + PCI_ANY_ID, PCI_ANY_ID, }, + {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON, + PCI_ANY_ID, PCI_ANY_ID, }, { 0 } }; @@ -8053,15 +8216,15 @@ lpfc_exit(void) if (lpfc_enable_npiv) fc_release_transport(lpfc_vport_transport_template); if (_dump_buf_data) { - printk(KERN_ERR "BLKGRD freeing %lu pages for _dump_buf_data " - "at 0x%p\n", + printk(KERN_ERR "9062 BLKGRD: freeing %lu pages for " + "_dump_buf_data at 0x%p\n", (1L << _dump_buf_data_order), _dump_buf_data); free_pages((unsigned long)_dump_buf_data, _dump_buf_data_order); } if (_dump_buf_dif) { - printk(KERN_ERR "BLKGRD freeing %lu pages for _dump_buf_dif " - "at 0x%p\n", + printk(KERN_ERR "9049 BLKGRD: freeing %lu pages for " + "_dump_buf_dif at 0x%p\n", (1L << _dump_buf_dif_order), _dump_buf_dif); free_pages((unsigned long)_dump_buf_dif, _dump_buf_dif_order); } diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 1ab405902a1..a9afd8b94b6 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -25,8 +25,8 @@ #include <scsi/scsi_device.h> #include <scsi/scsi_transport_fc.h> - #include <scsi/scsi.h> +#include <scsi/fc/fc_fs.h> #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -820,6 +820,10 @@ lpfc_reg_vpi(struct lpfc_vport *vport, LPFC_MBOXQ_t *pmb) mb->un.varRegVpi.vpi = vport->vpi + vport->phba->vpi_base; mb->un.varRegVpi.sid = vport->fc_myDID; mb->un.varRegVpi.vfi = vport->vfi + vport->phba->vfi_base; + memcpy(mb->un.varRegVpi.wwn, &vport->fc_portname, + sizeof(struct lpfc_name)); + mb->un.varRegVpi.wwn[0] = cpu_to_le32(mb->un.varRegVpi.wwn[0]); + mb->un.varRegVpi.wwn[1] = cpu_to_le32(mb->un.varRegVpi.wwn[1]); mb->mbxCommand = MBX_REG_VPI; mb->mbxOwner = OWN_HOST; @@ -849,7 +853,10 @@ lpfc_unreg_vpi(struct lpfc_hba *phba, uint16_t vpi, LPFC_MBOXQ_t *pmb) MAILBOX_t *mb = &pmb->u.mb; memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - mb->un.varUnregVpi.vpi = vpi + phba->vpi_base; + if (phba->sli_rev < LPFC_SLI_REV4) + mb->un.varUnregVpi.vpi = vpi + phba->vpi_base; + else + mb->un.varUnregVpi.sli4_vpi = vpi + phba->vpi_base; mb->mbxCommand = MBX_UNREG_VPI; mb->mbxOwner = OWN_HOST; @@ -1132,7 +1139,7 @@ lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb) /* Otherwise we setup specific rctl / type masks for this ring */ for (i = 0; i < pring->num_mask; i++) { mb->un.varCfgRing.rrRegs[i].rval = pring->prt[i].rctl; - if (mb->un.varCfgRing.rrRegs[i].rval != FC_ELS_REQ) + if (mb->un.varCfgRing.rrRegs[i].rval != FC_RCTL_ELS_REQ) mb->un.varCfgRing.rrRegs[i].rmask = 0xff; else mb->un.varCfgRing.rrRegs[i].rmask = 0xfe; @@ -1654,9 +1661,12 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox, /* Allocate record for keeping SGE virtual addresses */ mbox->sge_array = kmalloc(sizeof(struct lpfc_mbx_nembed_sge_virt), GFP_KERNEL); - if (!mbox->sge_array) + if (!mbox->sge_array) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "2527 Failed to allocate non-embedded SGE " + "array.\n"); return 0; - + } for (pagen = 0, alloc_len = 0; pagen < pcount; pagen++) { /* The DMA memory is always allocated in the length of a * page even though the last SGE might not fill up to a @@ -1753,11 +1763,6 @@ lpfc_request_features(struct lpfc_hba *phba, struct lpfcMboxq *mboxq) /* Set up host requested features. */ bf_set(lpfc_mbx_rq_ftr_rq_fcpi, &mboxq->u.mqe.un.req_ftrs, 1); - if (phba->cfg_enable_fip) - bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 0); - else - bf_set(lpfc_mbx_rq_ftr_rq_ifip, &mboxq->u.mqe.un.req_ftrs, 1); - /* Enable DIF (block guard) only if configured to do so. */ if (phba->cfg_enable_bg) bf_set(lpfc_mbx_rq_ftr_rq_dif, &mboxq->u.mqe.un.req_ftrs, 1); @@ -1817,6 +1822,9 @@ lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys) bf_set(lpfc_reg_vfi_vfi, reg_vfi, vport->vfi + vport->phba->vfi_base); bf_set(lpfc_reg_vfi_fcfi, reg_vfi, vport->phba->fcf.fcfi); bf_set(lpfc_reg_vfi_vpi, reg_vfi, vport->vpi + vport->phba->vpi_base); + memcpy(reg_vfi->wwn, &vport->fc_portname, sizeof(struct lpfc_name)); + reg_vfi->wwn[0] = cpu_to_le32(reg_vfi->wwn[0]); + reg_vfi->wwn[1] = cpu_to_le32(reg_vfi->wwn[1]); reg_vfi->bde.addrHigh = putPaddrHigh(phys); reg_vfi->bde.addrLow = putPaddrLow(phys); reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam); @@ -1850,7 +1858,7 @@ lpfc_init_vpi(struct lpfc_hba *phba, struct lpfcMboxq *mbox, uint16_t vpi) /** * lpfc_unreg_vfi - Initialize the UNREG_VFI mailbox command * @mbox: pointer to lpfc mbox command to initialize. - * @vfi: VFI to be unregistered. + * @vport: vport associated with the VF. * * The UNREG_VFI mailbox command causes the SLI Host to put a virtual fabric * (logical NPort) into the inactive state. The SLI Host must have logged out @@ -1859,11 +1867,12 @@ lpfc_init_vpi(struct lpfc_hba *phba, struct lpfcMboxq *mbox, uint16_t vpi) * fabric inactive. **/ void -lpfc_unreg_vfi(struct lpfcMboxq *mbox, uint16_t vfi) +lpfc_unreg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport) { memset(mbox, 0, sizeof(*mbox)); bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_UNREG_VFI); - bf_set(lpfc_unreg_vfi_vfi, &mbox->u.mqe.un.unreg_vfi, vfi); + bf_set(lpfc_unreg_vfi_vfi, &mbox->u.mqe.un.unreg_vfi, + vport->vfi + vport->phba->vfi_base); } /** diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 3e74136f1ed..2ed6af19493 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1223,6 +1223,12 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && (ndlp == (struct lpfc_nodelist *) mb->context2)) { + if (phba->sli_rev == LPFC_SLI_REV4) { + spin_unlock_irq(&phba->hbalock); + lpfc_sli4_free_rpi(phba, + mb->u.mb.un.varRegLogin.rpi); + spin_lock_irq(&phba->hbalock); + } mp = (struct lpfc_dmabuf *) (mb->context1); if (mp) { __lpfc_mbuf_free(phba, mp->virt, mp->phys); @@ -1230,6 +1236,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, } lpfc_nlp_put(ndlp); list_del(&mb->list); + phba->sli.mboxq_cnt--; mempool_free(mb, phba->mbox_mem_pool); } } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index c88f59f0ce3..a246410ce9d 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -59,22 +59,26 @@ static char *dif_op_str[] = { }; static void lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb); +static void +lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb); static void -lpfc_debug_save_data(struct scsi_cmnd *cmnd) +lpfc_debug_save_data(struct lpfc_hba *phba, struct scsi_cmnd *cmnd) { void *src, *dst; struct scatterlist *sgde = scsi_sglist(cmnd); if (!_dump_buf_data) { - printk(KERN_ERR "BLKGRD ERROR %s _dump_buf_data is NULL\n", + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9050 BLKGRD: ERROR %s _dump_buf_data is NULL\n", __func__); return; } if (!sgde) { - printk(KERN_ERR "BLKGRD ERROR: data scatterlist is null\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9051 BLKGRD: ERROR: data scatterlist is null\n"); return; } @@ -88,19 +92,21 @@ lpfc_debug_save_data(struct scsi_cmnd *cmnd) } static void -lpfc_debug_save_dif(struct scsi_cmnd *cmnd) +lpfc_debug_save_dif(struct lpfc_hba *phba, struct scsi_cmnd *cmnd) { void *src, *dst; struct scatterlist *sgde = scsi_prot_sglist(cmnd); if (!_dump_buf_dif) { - printk(KERN_ERR "BLKGRD ERROR %s _dump_buf_data is NULL\n", + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9052 BLKGRD: ERROR %s _dump_buf_data is NULL\n", __func__); return; } if (!sgde) { - printk(KERN_ERR "BLKGRD ERROR: prot scatterlist is null\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9053 BLKGRD: ERROR: prot scatterlist is null\n"); return; } @@ -242,6 +248,36 @@ lpfc_send_sdev_queuedepth_change_event(struct lpfc_hba *phba, } /** + * lpfc_change_queue_depth - Alter scsi device queue depth + * @sdev: Pointer the scsi device on which to change the queue depth. + * @qdepth: New queue depth to set the sdev to. + * @reason: The reason for the queue depth change. + * + * This function is called by the midlayer and the LLD to alter the queue + * depth for a scsi device. This function sets the queue depth to the new + * value and sends an event out to log the queue depth change. + **/ +int +lpfc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) +{ + struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_rport_data *rdata; + unsigned long new_queue_depth, old_queue_depth; + + old_queue_depth = sdev->queue_depth; + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + new_queue_depth = sdev->queue_depth; + rdata = sdev->hostdata; + if (rdata) + lpfc_send_sdev_queuedepth_change_event(phba, vport, + rdata->pnode, sdev->lun, + old_queue_depth, + new_queue_depth); + return sdev->queue_depth; +} + +/** * lpfc_rampdown_queue_depth - Post RAMP_DOWN_QUEUE event to worker thread * @phba: The Hba for which this call is being executed. * @@ -305,8 +341,10 @@ lpfc_rampup_queue_depth(struct lpfc_vport *vport, if (vport->cfg_lun_queue_depth <= queue_depth) return; spin_lock_irqsave(&phba->hbalock, flags); - if (((phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) > jiffies) || - ((phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL ) > jiffies)) { + if (time_before(jiffies, + phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) || + time_before(jiffies, + phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL)) { spin_unlock_irqrestore(&phba->hbalock, flags); return; } @@ -338,10 +376,9 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) struct lpfc_vport **vports; struct Scsi_Host *shost; struct scsi_device *sdev; - unsigned long new_queue_depth, old_queue_depth; + unsigned long new_queue_depth; unsigned long num_rsrc_err, num_cmd_success; int i; - struct lpfc_rport_data *rdata; num_rsrc_err = atomic_read(&phba->num_rsrc_err); num_cmd_success = atomic_read(&phba->num_cmd_success); @@ -359,22 +396,8 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) else new_queue_depth = sdev->queue_depth - new_queue_depth; - old_queue_depth = sdev->queue_depth; - if (sdev->ordered_tags) - scsi_adjust_queue_depth(sdev, - MSG_ORDERED_TAG, - new_queue_depth); - else - scsi_adjust_queue_depth(sdev, - MSG_SIMPLE_TAG, - new_queue_depth); - rdata = sdev->hostdata; - if (rdata) - lpfc_send_sdev_queuedepth_change_event( - phba, vports[i], - rdata->pnode, - sdev->lun, old_queue_depth, - new_queue_depth); + lpfc_change_queue_depth(sdev, new_queue_depth, + SCSI_QDEPTH_DEFAULT); } } lpfc_destroy_vport_work_array(phba, vports); @@ -398,7 +421,6 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) struct Scsi_Host *shost; struct scsi_device *sdev; int i; - struct lpfc_rport_data *rdata; vports = lpfc_create_vport_work_array(phba); if (vports != NULL) @@ -408,22 +430,9 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) if (vports[i]->cfg_lun_queue_depth <= sdev->queue_depth) continue; - if (sdev->ordered_tags) - scsi_adjust_queue_depth(sdev, - MSG_ORDERED_TAG, - sdev->queue_depth+1); - else - scsi_adjust_queue_depth(sdev, - MSG_SIMPLE_TAG, - sdev->queue_depth+1); - rdata = sdev->hostdata; - if (rdata) - lpfc_send_sdev_queuedepth_change_event( - phba, vports[i], - rdata->pnode, - sdev->lun, - sdev->queue_depth - 1, - sdev->queue_depth); + lpfc_change_queue_depth(sdev, + sdev->queue_depth+1, + SCSI_QDEPTH_RAMP_UP); } } lpfc_destroy_vport_work_array(phba, vports); @@ -589,7 +598,7 @@ lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc) iocb->ulpClass = CLASS3; psb->status = IOSTAT_SUCCESS; /* Put it back into the SCSI buffer list */ - lpfc_release_scsi_buf_s4(phba, psb); + lpfc_release_scsi_buf_s3(phba, psb); } @@ -1024,7 +1033,8 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) lpfc_cmd->seg_cnt = nseg; if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { - printk(KERN_ERR "%s: Too many sg segments from " + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9064 BLKGRD: %s: Too many sg segments from " "dma_map_sg. Config %d, seg_cnt %d\n", __func__, phba->cfg_sg_seg_cnt, lpfc_cmd->seg_cnt); @@ -1112,7 +1122,7 @@ lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) * with the cmd */ static int -lpfc_sc_to_sli_prof(struct scsi_cmnd *sc) +lpfc_sc_to_sli_prof(struct lpfc_hba *phba, struct scsi_cmnd *sc) { uint8_t guard_type = scsi_host_get_guard(sc->device->host); uint8_t ret_prof = LPFC_PROF_INVALID; @@ -1136,7 +1146,8 @@ lpfc_sc_to_sli_prof(struct scsi_cmnd *sc) case SCSI_PROT_NORMAL: default: - printk(KERN_ERR "Bad op/guard:%d/%d combination\n", + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9063 BLKGRD:Bad op/guard:%d/%d combination\n", scsi_get_prot_op(sc), guard_type); break; @@ -1157,7 +1168,8 @@ lpfc_sc_to_sli_prof(struct scsi_cmnd *sc) case SCSI_PROT_WRITE_STRIP: case SCSI_PROT_NORMAL: default: - printk(KERN_ERR "Bad op/guard:%d/%d combination\n", + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9075 BLKGRD: Bad op/guard:%d/%d combination\n", scsi_get_prot_op(sc), guard_type); break; } @@ -1259,7 +1271,7 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint16_t apptagmask, apptagval; pde1 = (struct lpfc_pde *) bpl; - prof = lpfc_sc_to_sli_prof(sc); + prof = lpfc_sc_to_sli_prof(phba, sc); if (prof == LPFC_PROF_INVALID) goto out; @@ -1359,7 +1371,7 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, return 0; } - prof = lpfc_sc_to_sli_prof(sc); + prof = lpfc_sc_to_sli_prof(phba, sc); if (prof == LPFC_PROF_INVALID) goto out; @@ -1408,7 +1420,8 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, subtotal = 0; /* total bytes processed for current prot grp */ while (!pgdone) { if (!sgde) { - printk(KERN_ERR "%s Invalid data segment\n", + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9065 BLKGRD:%s Invalid data segment\n", __func__); return 0; } @@ -1462,7 +1475,8 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, reftag += protgrp_blks; } else { /* if we're here, we have a bug */ - printk(KERN_ERR "BLKGRD: bug in %s\n", __func__); + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9054 BLKGRD: bug in %s\n", __func__); } } while (!alldone); @@ -1544,8 +1558,10 @@ lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba, lpfc_cmd->seg_cnt = datasegcnt; if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { - printk(KERN_ERR "%s: Too many sg segments from " - "dma_map_sg. Config %d, seg_cnt %d\n", + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9067 BLKGRD: %s: Too many sg segments" + " from dma_map_sg. Config %d, seg_cnt" + " %d\n", __func__, phba->cfg_sg_seg_cnt, lpfc_cmd->seg_cnt); scsi_dma_unmap(scsi_cmnd); @@ -1579,8 +1595,9 @@ lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba, lpfc_cmd->prot_seg_cnt = protsegcnt; if (lpfc_cmd->prot_seg_cnt > phba->cfg_prot_sg_seg_cnt) { - printk(KERN_ERR "%s: Too many prot sg segments " - "from dma_map_sg. Config %d," + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9068 BLKGRD: %s: Too many prot sg " + "segments from dma_map_sg. Config %d," "prot_seg_cnt %d\n", __func__, phba->cfg_prot_sg_seg_cnt, lpfc_cmd->prot_seg_cnt); @@ -1671,23 +1688,26 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, uint32_t bgstat = bgf->bgstat; uint64_t failing_sector = 0; - printk(KERN_ERR "BG ERROR in cmd 0x%x lba 0x%llx blk cnt 0x%x " + lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9069 BLKGRD: BG ERROR in cmd" + " 0x%x lba 0x%llx blk cnt 0x%x " "bgstat=0x%x bghm=0x%x\n", cmd->cmnd[0], (unsigned long long)scsi_get_lba(cmd), blk_rq_sectors(cmd->request), bgstat, bghm); spin_lock(&_dump_buf_lock); if (!_dump_buf_done) { - printk(KERN_ERR "Saving Data for %u blocks to debugfs\n", + lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9070 BLKGRD: Saving" + " Data for %u blocks to debugfs\n", (cmd->cmnd[7] << 8 | cmd->cmnd[8])); - lpfc_debug_save_data(cmd); + lpfc_debug_save_data(phba, cmd); /* If we have a prot sgl, save the DIF buffer */ if (lpfc_prot_group_type(phba, cmd) == LPFC_PG_TYPE_DIF_BUF) { - printk(KERN_ERR "Saving DIF for %u blocks to debugfs\n", - (cmd->cmnd[7] << 8 | cmd->cmnd[8])); - lpfc_debug_save_dif(cmd); + lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9071 BLKGRD: " + "Saving DIF for %u blocks to debugfs\n", + (cmd->cmnd[7] << 8 | cmd->cmnd[8])); + lpfc_debug_save_dif(phba, cmd); } _dump_buf_done = 1; @@ -1696,15 +1716,17 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, if (lpfc_bgs_get_invalid_prof(bgstat)) { cmd->result = ScsiResult(DID_ERROR, 0); - printk(KERN_ERR "Invalid BlockGuard profile. bgstat:0x%x\n", - bgstat); + lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9072 BLKGRD: Invalid" + " BlockGuard profile. bgstat:0x%x\n", + bgstat); ret = (-1); goto out; } if (lpfc_bgs_get_uninit_dif_block(bgstat)) { cmd->result = ScsiResult(DID_ERROR, 0); - printk(KERN_ERR "Invalid BlockGuard DIF Block. bgstat:0x%x\n", + lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9073 BLKGRD: " + "Invalid BlockGuard DIF Block. bgstat:0x%x\n", bgstat); ret = (-1); goto out; @@ -1718,7 +1740,8 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, cmd->result = DRIVER_SENSE << 24 | ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION); phba->bg_guard_err_cnt++; - printk(KERN_ERR "BLKGRD: guard_tag error\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9055 BLKGRD: guard_tag error\n"); } if (lpfc_bgs_get_reftag_err(bgstat)) { @@ -1730,7 +1753,8 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, | ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION); phba->bg_reftag_err_cnt++; - printk(KERN_ERR "BLKGRD: ref_tag error\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9056 BLKGRD: ref_tag error\n"); } if (lpfc_bgs_get_apptag_err(bgstat)) { @@ -1742,7 +1766,8 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, | ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION); phba->bg_apptag_err_cnt++; - printk(KERN_ERR "BLKGRD: app_tag error\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9061 BLKGRD: app_tag error\n"); } if (lpfc_bgs_get_hi_water_mark_present(bgstat)) { @@ -1763,7 +1788,8 @@ lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, if (!ret) { /* No error was reported - problem in FW? */ cmd->result = ScsiResult(DID_ERROR, 0); - printk(KERN_ERR "BLKGRD: no errors reported!\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9057 BLKGRD: no errors reported!\n"); } out: @@ -1822,9 +1848,10 @@ lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) lpfc_cmd->seg_cnt = nseg; if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { - printk(KERN_ERR "%s: Too many sg segments from " - "dma_map_sg. Config %d, seg_cnt %d\n", - __func__, phba->cfg_sg_seg_cnt, + lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9074 BLKGRD:" + " %s: Too many sg segments from " + "dma_map_sg. Config %d, seg_cnt %d\n", + __func__, phba->cfg_sg_seg_cnt, lpfc_cmd->seg_cnt); scsi_dma_unmap(scsi_cmnd); return 1; @@ -2050,6 +2077,21 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, goto out; } + if (resp_info & RSP_LEN_VALID) { + rsplen = be32_to_cpu(fcprsp->rspRspLen); + if ((rsplen != 0 && rsplen != 4 && rsplen != 8) || + (fcprsp->rspInfo3 != RSP_NO_FAILURE)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "2719 Invalid response length: " + "tgt x%x lun x%x cmnd x%x rsplen x%x\n", + cmnd->device->id, + cmnd->device->lun, cmnd->cmnd[0], + rsplen); + host_status = DID_ERROR; + goto out; + } + } + if ((resp_info & SNS_LEN_VALID) && fcprsp->rspSnsLen) { uint32_t snslen = be32_to_cpu(fcprsp->rspSnsLen); if (snslen > SCSI_SENSE_BUFFERSIZE) @@ -2074,15 +2116,6 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, be32_to_cpu(fcprsp->rspRspLen), fcprsp->rspInfo3); - if (resp_info & RSP_LEN_VALID) { - rsplen = be32_to_cpu(fcprsp->rspRspLen); - if ((rsplen != 0 && rsplen != 4 && rsplen != 8) || - (fcprsp->rspInfo3 != RSP_NO_FAILURE)) { - host_status = DID_ERROR; - goto out; - } - } - scsi_set_resid(cmnd, 0); if (resp_info & RESID_UNDER) { scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId)); @@ -2180,7 +2213,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, struct scsi_cmnd *cmd = lpfc_cmd->pCmd; int result; struct scsi_device *tmp_sdev; - int depth = 0; + int depth; unsigned long flags; struct lpfc_fast_path_event *fast_path_evt; struct Scsi_Host *shost = cmd->device->host; @@ -2264,7 +2297,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9031 non-zero BGSTAT " - "on unprotected cmd"); + "on unprotected cmd\n"); } } @@ -2347,67 +2380,29 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, return; } - if (!result) lpfc_rampup_queue_depth(vport, queue_depth); - if (!result && pnode && NLP_CHK_NODE_ACT(pnode) && - ((jiffies - pnode->last_ramp_up_time) > - LPFC_Q_RAMP_UP_INTERVAL * HZ) && - ((jiffies - pnode->last_q_full_time) > - LPFC_Q_RAMP_UP_INTERVAL * HZ) && - (vport->cfg_lun_queue_depth > queue_depth)) { - shost_for_each_device(tmp_sdev, shost) { - if (vport->cfg_lun_queue_depth > tmp_sdev->queue_depth){ - if (tmp_sdev->id != scsi_id) - continue; - if (tmp_sdev->ordered_tags) - scsi_adjust_queue_depth(tmp_sdev, - MSG_ORDERED_TAG, - tmp_sdev->queue_depth+1); - else - scsi_adjust_queue_depth(tmp_sdev, - MSG_SIMPLE_TAG, - tmp_sdev->queue_depth+1); - - pnode->last_ramp_up_time = jiffies; - } - } - lpfc_send_sdev_queuedepth_change_event(phba, vport, pnode, - 0xFFFFFFFF, - queue_depth , queue_depth + 1); - } - /* * Check for queue full. If the lun is reporting queue full, then * back off the lun queue depth to prevent target overloads. */ if (result == SAM_STAT_TASK_SET_FULL && pnode && NLP_CHK_NODE_ACT(pnode)) { - pnode->last_q_full_time = jiffies; - shost_for_each_device(tmp_sdev, shost) { if (tmp_sdev->id != scsi_id) continue; depth = scsi_track_queue_full(tmp_sdev, - tmp_sdev->queue_depth - 1); - } - /* - * The queue depth cannot be lowered any more. - * Modify the returned error code to store - * the final depth value set by - * scsi_track_queue_full. - */ - if (depth == -1) - depth = shost->cmd_per_lun; - - if (depth) { + tmp_sdev->queue_depth-1); + if (depth <= 0) + continue; lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "0711 detected queue full - lun queue " "depth adjusted to %d.\n", depth); lpfc_send_sdev_queuedepth_change_event(phba, vport, - pnode, 0xFFFFFFFF, - depth+1, depth); + pnode, + tmp_sdev->lun, + depth+1, depth); } } @@ -2745,7 +2740,9 @@ void lpfc_poll_timeout(unsigned long ptr) struct lpfc_hba *phba = (struct lpfc_hba *) ptr; if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - lpfc_sli_poll_fcp_ring (phba); + lpfc_sli_handle_fast_ring_event(phba, + &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); + if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_poll_rearm_timer(phba); } @@ -2771,7 +2768,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; struct lpfc_rport_data *rdata = cmnd->device->hostdata; - struct lpfc_nodelist *ndlp = rdata->pnode; + struct lpfc_nodelist *ndlp; struct lpfc_scsi_buf *lpfc_cmd; struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); int err; @@ -2781,13 +2778,15 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) cmnd->result = err; goto out_fail_command; } + ndlp = rdata->pnode; if (!(phba->sli3_options & LPFC_SLI3_BG_ENABLED) && scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) { - printk(KERN_ERR "BLKGRD ERROR: rcvd protected cmd:%02x op:%02x " - "str=%s without registering for BlockGuard - " - "Rejecting command\n", + lpfc_printf_log(phba, KERN_ERR, LOG_BG, + "9058 BLKGRD: ERROR: rcvd protected cmd:%02x" + " op:%02x str=%s without registering for" + " BlockGuard - Rejecting command\n", cmnd->cmnd[0], scsi_get_prot_op(cmnd), dif_op_str[scsi_get_prot_op(cmnd)]); goto out_fail_command; @@ -2827,61 +2826,66 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) cmnd->scsi_done = done; if (scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, + if (vport->phba->cfg_enable_bg) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9033 BLKGRD: rcvd protected cmd:%02x op:%02x " "str=%s\n", cmnd->cmnd[0], scsi_get_prot_op(cmnd), dif_op_str[scsi_get_prot_op(cmnd)]); - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, + lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9034 BLKGRD: CDB: %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x\n", cmnd->cmnd[0], cmnd->cmnd[1], cmnd->cmnd[2], cmnd->cmnd[3], cmnd->cmnd[4], cmnd->cmnd[5], cmnd->cmnd[6], cmnd->cmnd[7], cmnd->cmnd[8], cmnd->cmnd[9]); - if (cmnd->cmnd[0] == READ_10) - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, + if (cmnd->cmnd[0] == READ_10) + lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9035 BLKGRD: READ @ sector %llu, " "count %u\n", (unsigned long long)scsi_get_lba(cmnd), blk_rq_sectors(cmnd->request)); - else if (cmnd->cmnd[0] == WRITE_10) - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, + else if (cmnd->cmnd[0] == WRITE_10) + lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9036 BLKGRD: WRITE @ sector %llu, " "count %u cmd=%p\n", (unsigned long long)scsi_get_lba(cmnd), blk_rq_sectors(cmnd->request), cmnd); + } err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd); } else { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9038 BLKGRD: rcvd unprotected cmd:%02x op:%02x" - " str=%s\n", - cmnd->cmnd[0], scsi_get_prot_op(cmnd), - dif_op_str[scsi_get_prot_op(cmnd)]); - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9039 BLKGRD: CDB: %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x\n", - cmnd->cmnd[0], cmnd->cmnd[1], cmnd->cmnd[2], - cmnd->cmnd[3], cmnd->cmnd[4], cmnd->cmnd[5], - cmnd->cmnd[6], cmnd->cmnd[7], cmnd->cmnd[8], - cmnd->cmnd[9]); - if (cmnd->cmnd[0] == READ_10) + if (vport->phba->cfg_enable_bg) { lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9040 dbg: READ @ sector %llu, " - "count %u\n", - (unsigned long long)scsi_get_lba(cmnd), + "9038 BLKGRD: rcvd unprotected cmd:" + "%02x op:%02x str=%s\n", + cmnd->cmnd[0], scsi_get_prot_op(cmnd), + dif_op_str[scsi_get_prot_op(cmnd)]); + lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, + "9039 BLKGRD: CDB: %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x\n", + cmnd->cmnd[0], cmnd->cmnd[1], + cmnd->cmnd[2], cmnd->cmnd[3], + cmnd->cmnd[4], cmnd->cmnd[5], + cmnd->cmnd[6], cmnd->cmnd[7], + cmnd->cmnd[8], cmnd->cmnd[9]); + if (cmnd->cmnd[0] == READ_10) + lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, + "9040 dbg: READ @ sector %llu, " + "count %u\n", + (unsigned long long)scsi_get_lba(cmnd), blk_rq_sectors(cmnd->request)); - else if (cmnd->cmnd[0] == WRITE_10) - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, + else if (cmnd->cmnd[0] == WRITE_10) + lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9041 dbg: WRITE @ sector %llu, " "count %u cmd=%p\n", (unsigned long long)scsi_get_lba(cmnd), blk_rq_sectors(cmnd->request), cmnd); - else - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, + else + lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, "9042 dbg: parser not implemented\n"); + } err = lpfc_scsi_prep_dma_buf(phba, lpfc_cmd); } @@ -2898,7 +2902,11 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) goto out_host_busy_free_buf; } if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - lpfc_sli_poll_fcp_ring(phba); + spin_unlock(shost->host_lock); + lpfc_sli_handle_fast_ring_event(phba, + &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); + + spin_lock(shost->host_lock); if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_poll_rearm_timer(phba); } @@ -2917,28 +2925,6 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) } /** - * lpfc_block_error_handler - Routine to block error handler - * @cmnd: Pointer to scsi_cmnd data structure. - * - * This routine blocks execution till fc_rport state is not FC_PORSTAT_BLCOEKD. - **/ -static void -lpfc_block_error_handler(struct scsi_cmnd *cmnd) -{ - struct Scsi_Host *shost = cmnd->device->host; - struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); - - spin_lock_irq(shost->host_lock); - while (rport->port_state == FC_PORTSTATE_BLOCKED) { - spin_unlock_irq(shost->host_lock); - msleep(1000); - spin_lock_irq(shost->host_lock); - } - spin_unlock_irq(shost->host_lock); - return; -} - -/** * lpfc_abort_handler - scsi_host_template eh_abort_handler entry point * @cmnd: Pointer to scsi_cmnd data structure. * @@ -2961,7 +2947,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) int ret = SUCCESS; DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); - lpfc_block_error_handler(cmnd); + fc_block_scsi_eh(cmnd); lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; BUG_ON(!lpfc_cmd); @@ -3001,6 +2987,10 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) icmd->ulpLe = 1; icmd->ulpClass = cmd->ulpClass; + + /* ABTS WQE must go to the same WQ as the WQE to be aborted */ + abtsiocb->fcp_wqidx = iocb->fcp_wqidx; + if (lpfc_is_link_up(phba)) icmd->ulpCommand = CMD_ABORT_XRI_CN; else @@ -3016,7 +3006,8 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) } if (phba->cfg_poll & DISABLE_FCP_RING_INT) - lpfc_sli_poll_fcp_ring (phba); + lpfc_sli_handle_fast_ring_event(phba, + &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); lpfc_cmd->waitq = &waitq; /* Wait for abort to complete */ @@ -3166,9 +3157,15 @@ static int lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd) { struct lpfc_rport_data *rdata = cmnd->device->hostdata; - struct lpfc_nodelist *pnode = rdata->pnode; + struct lpfc_nodelist *pnode; unsigned long later; + if (!rdata) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, + "0797 Tgt Map rport failure: rdata x%p\n", rdata); + return FAILED; + } + pnode = rdata->pnode; /* * If target is not in a MAPPED state, delay until * target is rediscovered or devloss timeout expires. @@ -3253,13 +3250,19 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) struct Scsi_Host *shost = cmnd->device->host; struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_rport_data *rdata = cmnd->device->hostdata; - struct lpfc_nodelist *pnode = rdata->pnode; + struct lpfc_nodelist *pnode; unsigned tgt_id = cmnd->device->id; unsigned int lun_id = cmnd->device->lun; struct lpfc_scsi_event_header scsi_event; int status; - lpfc_block_error_handler(cmnd); + if (!rdata) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0798 Device Reset rport failure: rdata x%p\n", rdata); + return FAILED; + } + pnode = rdata->pnode; + fc_block_scsi_eh(cmnd); status = lpfc_chk_tgt_mapped(vport, cmnd); if (status == FAILED) { @@ -3312,13 +3315,19 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) struct Scsi_Host *shost = cmnd->device->host; struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_rport_data *rdata = cmnd->device->hostdata; - struct lpfc_nodelist *pnode = rdata->pnode; + struct lpfc_nodelist *pnode; unsigned tgt_id = cmnd->device->id; unsigned int lun_id = cmnd->device->lun; struct lpfc_scsi_event_header scsi_event; int status; - lpfc_block_error_handler(cmnd); + if (!rdata) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, + "0799 Target Reset rport failure: rdata x%p\n", rdata); + return FAILED; + } + pnode = rdata->pnode; + fc_block_scsi_eh(cmnd); status = lpfc_chk_tgt_mapped(vport, cmnd); if (status == FAILED) { @@ -3384,7 +3393,7 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) fc_host_post_vendor_event(shost, fc_get_event_number(), sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); - lpfc_block_error_handler(cmnd); + fc_block_scsi_eh(cmnd); /* * Since the driver manages a single bus device, reset all @@ -3498,6 +3507,8 @@ lpfc_slave_alloc(struct scsi_device *sdev) "Allocated %d buffers.\n", num_to_alloc, num_allocated); } + if (num_allocated > 0) + phba->total_scsi_bufs += num_allocated; return 0; } @@ -3534,7 +3545,8 @@ lpfc_slave_configure(struct scsi_device *sdev) rport->dev_loss_tmo = vport->cfg_devloss_tmo; if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - lpfc_sli_poll_fcp_ring(phba); + lpfc_sli_handle_fast_ring_event(phba, + &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_poll_rearm_timer(phba); } @@ -3576,6 +3588,7 @@ struct scsi_host_template lpfc_template = { .shost_attrs = lpfc_hba_attrs, .max_sectors = 0xFFFF, .vendor_id = LPFC_NL_VENDOR_ID, + .change_queue_depth = lpfc_change_queue_depth, }; struct scsi_host_template lpfc_vport_template = { @@ -3597,4 +3610,5 @@ struct scsi_host_template lpfc_vport_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = lpfc_vport_attrs, .max_sectors = 0xFFFF, + .change_queue_depth = lpfc_change_queue_depth, }; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 43cbe336f1f..b3a69f984d9 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -30,6 +30,7 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_transport_fc.h> #include <scsi/fc/fc_fs.h> +#include <linux/aer.h> #include "lpfc_hw4.h" #include "lpfc_hw.h" @@ -58,8 +59,11 @@ typedef enum _lpfc_iocb_type { static int lpfc_sli_issue_mbox_s4(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); static int lpfc_sli4_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *, - uint8_t *, uint32_t *); - + uint8_t *, uint32_t *); +static struct lpfc_iocbq *lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *, + struct lpfc_iocbq *); +static void lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *, + struct hbq_dmabuf *); static IOCB_t * lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) { @@ -259,6 +263,9 @@ lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm) bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT); bf_set(lpfc_eqcq_doorbell_eqid, &doorbell, q->queue_id); writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr); + /* PCI read to flush PCI pipeline on re-arming for INTx mode */ + if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM)) + readl(q->phba->sli4_hba.EQCQDBregaddr); return released; } @@ -515,6 +522,8 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba) struct lpfc_sglq *sglq = NULL; uint16_t adj_xri; list_remove_head(lpfc_sgl_list, sglq, struct lpfc_sglq, list); + if (!sglq) + return NULL; adj_xri = sglq->sli4_xritag - phba->sli4_hba.max_cfg_param.xri_base; phba->sli4_hba.lpfc_sglq_active_list[adj_xri] = sglq; return sglq; @@ -572,9 +581,9 @@ __lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_xritag); if (sglq) { if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED - || ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT) + && ((iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT) && (iocbq->iocb.un.ulpWord[4] - == IOERR_SLI_ABORTED))) { + == IOERR_ABORT_REQUESTED))) { spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, iflag); list_add(&sglq->list, @@ -767,6 +776,7 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) case CMD_CLOSE_XRI_CX: case CMD_XRI_ABORTED_CX: case CMD_ABORT_MXRI64_CN: + case CMD_XMIT_BLS_RSP64_CX: type = LPFC_ABORT_IOCB; break; case CMD_RCV_SEQUENCE_CX: @@ -2068,8 +2078,8 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)) { - Rctl = FC_ELS_REQ; - Type = FC_ELS_DATA; + Rctl = FC_RCTL_ELS_REQ; + Type = FC_TYPE_ELS; } else { w5p = (WORD5 *)&(saveq->iocb.un.ulpWord[5]); Rctl = w5p->hcsw.Rctl; @@ -2079,8 +2089,8 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if ((Rctl == 0) && (pring->ringno == LPFC_ELS_RING) && (irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX || irsp->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) { - Rctl = FC_ELS_REQ; - Type = FC_ELS_DATA; + Rctl = FC_RCTL_ELS_REQ; + Type = FC_TYPE_ELS; w5p->hcsw.Rctl = Rctl; w5p->hcsw.Type = Type; } @@ -2324,168 +2334,6 @@ void lpfc_poll_eratt(unsigned long ptr) return; } -/** - * lpfc_sli_poll_fcp_ring - Handle FCP ring completion in polling mode - * @phba: Pointer to HBA context object. - * - * This function is called from lpfc_queuecommand, lpfc_poll_timeout, - * lpfc_abort_handler and lpfc_slave_configure when FCP_RING_POLLING - * is enabled. - * - * The caller does not hold any lock. - * The function processes each response iocb in the response ring until it - * finds an iocb with LE bit set and chains all the iocbs upto the iocb with - * LE bit set. The function will call the completion handler of the command iocb - * if the response iocb indicates a completion for a command iocb or it is - * an abort completion. - **/ -void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING]; - IOCB_t *irsp = NULL; - IOCB_t *entry = NULL; - struct lpfc_iocbq *cmdiocbq = NULL; - struct lpfc_iocbq rspiocbq; - struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno]; - uint32_t status; - uint32_t portRspPut, portRspMax; - int type; - uint32_t rsp_cmpl = 0; - uint32_t ha_copy; - unsigned long iflags; - - pring->stats.iocb_event++; - - /* - * The next available response entry should never exceed the maximum - * entries. If it does, treat it as an adapter hardware error. - */ - portRspMax = pring->numRiocb; - portRspPut = le32_to_cpu(pgp->rspPutInx); - if (unlikely(portRspPut >= portRspMax)) { - lpfc_sli_rsp_pointers_error(phba, pring); - return; - } - - rmb(); - while (pring->rspidx != portRspPut) { - entry = lpfc_resp_iocb(phba, pring); - if (++pring->rspidx >= portRspMax) - pring->rspidx = 0; - - lpfc_sli_pcimem_bcopy((uint32_t *) entry, - (uint32_t *) &rspiocbq.iocb, - phba->iocb_rsp_size); - irsp = &rspiocbq.iocb; - type = lpfc_sli_iocb_cmd_type(irsp->ulpCommand & CMD_IOCB_MASK); - pring->stats.iocb_rsp++; - rsp_cmpl++; - - if (unlikely(irsp->ulpStatus)) { - /* Rsp ring <ringno> error: IOCB */ - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0326 Rsp Ring %d error: IOCB Data: " - "x%x x%x x%x x%x x%x x%x x%x x%x\n", - pring->ringno, - irsp->un.ulpWord[0], - irsp->un.ulpWord[1], - irsp->un.ulpWord[2], - irsp->un.ulpWord[3], - irsp->un.ulpWord[4], - irsp->un.ulpWord[5], - *(uint32_t *)&irsp->un1, - *((uint32_t *)&irsp->un1 + 1)); - } - - switch (type) { - case LPFC_ABORT_IOCB: - case LPFC_SOL_IOCB: - /* - * Idle exchange closed via ABTS from port. No iocb - * resources need to be recovered. - */ - if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) { - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0314 IOCB cmd 0x%x " - "processed. Skipping " - "completion", - irsp->ulpCommand); - break; - } - - spin_lock_irqsave(&phba->hbalock, iflags); - cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring, - &rspiocbq); - spin_unlock_irqrestore(&phba->hbalock, iflags); - if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) { - (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, - &rspiocbq); - } - break; - default: - if (irsp->ulpCommand == CMD_ADAPTER_MSG) { - char adaptermsg[LPFC_MAX_ADPTMSG]; - memset(adaptermsg, 0, LPFC_MAX_ADPTMSG); - memcpy(&adaptermsg[0], (uint8_t *) irsp, - MAX_MSG_DATA); - dev_warn(&((phba->pcidev)->dev), - "lpfc%d: %s\n", - phba->brd_no, adaptermsg); - } else { - /* Unknown IOCB command */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0321 Unknown IOCB command " - "Data: x%x, x%x x%x x%x x%x\n", - type, irsp->ulpCommand, - irsp->ulpStatus, - irsp->ulpIoTag, - irsp->ulpContext); - } - break; - } - - /* - * The response IOCB has been processed. Update the ring - * pointer in SLIM. If the port response put pointer has not - * been updated, sync the pgp->rspPutInx and fetch the new port - * response put pointer. - */ - writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); - - if (pring->rspidx == portRspPut) - portRspPut = le32_to_cpu(pgp->rspPutInx); - } - - ha_copy = readl(phba->HAregaddr); - ha_copy >>= (LPFC_FCP_RING * 4); - - if ((rsp_cmpl > 0) && (ha_copy & HA_R0RE_REQ)) { - spin_lock_irqsave(&phba->hbalock, iflags); - pring->stats.iocb_rsp_full++; - status = ((CA_R0ATT | CA_R0RE_RSP) << (LPFC_FCP_RING * 4)); - writel(status, phba->CAregaddr); - readl(phba->CAregaddr); - spin_unlock_irqrestore(&phba->hbalock, iflags); - } - if ((ha_copy & HA_R0CE_RSP) && - (pring->flag & LPFC_CALL_RING_AVAILABLE)) { - spin_lock_irqsave(&phba->hbalock, iflags); - pring->flag &= ~LPFC_CALL_RING_AVAILABLE; - pring->stats.iocb_cmd_empty++; - - /* Force update of the local copy of cmdGetInx */ - pring->local_getidx = le32_to_cpu(pgp->cmdGetInx); - lpfc_sli_resume_iocb(phba, pring); - - if ((pring->lpfc_sli_cmd_available)) - (pring->lpfc_sli_cmd_available) (phba, pring); - - spin_unlock_irqrestore(&phba->hbalock, iflags); - } - - return; -} /** * lpfc_sli_handle_fast_ring_event - Handle ring events on FCP ring @@ -2502,9 +2350,9 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba) * an abort completion. The function will call lpfc_sli_process_unsol_iocb * function if this is an unsolicited iocb. * This routine presumes LPFC_FCP_RING handling and doesn't bother - * to check it explicitly. This function always returns 1. - **/ -static int + * to check it explicitly. + */ +int lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint32_t mask) { @@ -2534,6 +2382,11 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, spin_unlock_irqrestore(&phba->hbalock, iflag); return 1; } + if (phba->fcp_ring_in_use) { + spin_unlock_irqrestore(&phba->hbalock, iflag); + return 1; + } else + phba->fcp_ring_in_use = 1; rmb(); while (pring->rspidx != portRspPut) { @@ -2604,10 +2457,6 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring, &rspiocbq); if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) { - if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, - &rspiocbq); - } else { spin_unlock_irqrestore(&phba->hbalock, iflag); (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, @@ -2615,7 +2464,6 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, spin_lock_irqsave(&phba->hbalock, iflag); } - } break; case LPFC_UNSOL_IOCB: spin_unlock_irqrestore(&phba->hbalock, iflag); @@ -2675,6 +2523,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, } + phba->fcp_ring_in_use = 0; spin_unlock_irqrestore(&phba->hbalock, iflag); return rc; } @@ -3018,16 +2867,39 @@ lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint32_t mask) { struct lpfc_iocbq *irspiocbq; + struct hbq_dmabuf *dmabuf; + struct lpfc_cq_event *cq_event; unsigned long iflag; - while (!list_empty(&phba->sli4_hba.sp_rspiocb_work_queue)) { + spin_lock_irqsave(&phba->hbalock, iflag); + phba->hba_flag &= ~HBA_SP_QUEUE_EVT; + spin_unlock_irqrestore(&phba->hbalock, iflag); + while (!list_empty(&phba->sli4_hba.sp_queue_event)) { /* Get the response iocb from the head of work queue */ spin_lock_irqsave(&phba->hbalock, iflag); - list_remove_head(&phba->sli4_hba.sp_rspiocb_work_queue, - irspiocbq, struct lpfc_iocbq, list); + list_remove_head(&phba->sli4_hba.sp_queue_event, + cq_event, struct lpfc_cq_event, list); spin_unlock_irqrestore(&phba->hbalock, iflag); - /* Process the response iocb */ - lpfc_sli_sp_handle_rspiocb(phba, pring, irspiocbq); + + switch (bf_get(lpfc_wcqe_c_code, &cq_event->cqe.wcqe_cmpl)) { + case CQE_CODE_COMPL_WQE: + irspiocbq = container_of(cq_event, struct lpfc_iocbq, + cq_event); + /* Translate ELS WCQE to response IOCBQ */ + irspiocbq = lpfc_sli4_els_wcqe_to_rspiocbq(phba, + irspiocbq); + if (irspiocbq) + lpfc_sli_sp_handle_rspiocb(phba, pring, + irspiocbq); + break; + case CQE_CODE_RECEIVE: + dmabuf = container_of(cq_event, struct hbq_dmabuf, + cq_event); + lpfc_sli4_handle_received_buffer(phba, dmabuf); + break; + default: + break; + } } } @@ -3416,6 +3288,7 @@ lpfc_sli_brdreset(struct lpfc_hba *phba) /* perform board reset */ phba->fc_eventTag = 0; + phba->link_events = 0; phba->pport->fc_myDID = 0; phba->pport->fc_prevDID = 0; @@ -3476,6 +3349,7 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) /* perform board reset */ phba->fc_eventTag = 0; + phba->link_events = 0; phba->pport->fc_myDID = 0; phba->pport->fc_prevDID = 0; @@ -3495,7 +3369,6 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) list_del_init(&phba->sli4_hba.dat_rq->list); list_del_init(&phba->sli4_hba.mbx_cq->list); list_del_init(&phba->sli4_hba.els_cq->list); - list_del_init(&phba->sli4_hba.rxq_cq->list); for (qindx = 0; qindx < phba->cfg_fcp_wq_count; qindx++) list_del_init(&phba->sli4_hba.fcp_wq[qindx]->list); for (qindx = 0; qindx < phba->cfg_fcp_eq_count; qindx++) @@ -3531,9 +3404,13 @@ lpfc_sli_brdrestart_s3(struct lpfc_hba *phba) struct lpfc_sli *psli; volatile uint32_t word0; void __iomem *to_slim; + uint32_t hba_aer_enabled; spin_lock_irq(&phba->hbalock); + /* Take PCIe device Advanced Error Reporting (AER) state */ + hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED; + psli = &phba->sli; /* Restart HBA */ @@ -3573,6 +3450,10 @@ lpfc_sli_brdrestart_s3(struct lpfc_hba *phba) /* Give the INITFF and Post time to settle. */ mdelay(100); + /* Reset HBA AER if it was enabled, note hba_flag was reset above */ + if (hba_aer_enabled) + pci_disable_pcie_error_reporting(phba->pcidev); + lpfc_hba_down_post(phba); return 0; @@ -4042,6 +3923,24 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) if (rc) goto lpfc_sli_hba_setup_error; + /* Enable PCIe device Advanced Error Reporting (AER) if configured */ + if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) { + rc = pci_enable_pcie_error_reporting(phba->pcidev); + if (!rc) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2709 This device supports " + "Advanced Error Reporting (AER)\n"); + spin_lock_irq(&phba->hbalock); + phba->hba_flag |= HBA_AER_ENABLED; + spin_unlock_irq(&phba->hbalock); + } else { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "2708 This device does not support " + "Advanced Error Reporting (AER)\n"); + phba->cfg_aer_support = 0; + } + } + if (phba->sli_rev == 3) { phba->iocb_cmd_size = SLI3_IOCB_CMD_SIZE; phba->iocb_rsp_size = SLI3_IOCB_RSP_SIZE; @@ -4243,7 +4142,6 @@ lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM); lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM); - lpfc_sli4_cq_release(phba->sli4_hba.rxq_cq, LPFC_QUEUE_REARM); for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[fcp_eqidx], LPFC_QUEUE_REARM); @@ -4322,6 +4220,13 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev); if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev)) phba->hba_flag |= HBA_FCOE_SUPPORT; + + if (bf_get(lpfc_mbx_rd_rev_cee_ver, &mqe->un.read_rev) == + LPFC_DCBX_CEE_MODE) + phba->hba_flag |= HBA_FIP_SUPPORT; + else + phba->hba_flag &= ~HBA_FIP_SUPPORT; + if (phba->sli_rev != LPFC_SLI_REV4 || !(phba->hba_flag & HBA_FCOE_SUPPORT)) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, @@ -4468,7 +4373,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = lpfc_sli4_post_sgl_list(phba); if (unlikely(rc)) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0582 Error %d during sgl post operation", rc); + "0582 Error %d during sgl post operation\n", + rc); rc = -ENODEV; goto out_free_vpd; } @@ -4477,8 +4383,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = lpfc_sli4_repost_scsi_sgl_list(phba); if (unlikely(rc)) { lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, - "0383 Error %d during scsi sgl post opeation", - rc); + "0383 Error %d during scsi sgl post " + "operation\n", rc); /* Some Scsi buffers were moved to the abort scsi list */ /* A pci function reset will repost them */ rc = -ENODEV; @@ -4494,10 +4400,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = -ENODEV; goto out_free_vpd; } - if (phba->cfg_enable_fip) - bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 1); - else - bf_set(lpfc_fip_flag, &phba->sli4_hba.sli4_flags, 0); /* Set up all the queues to the device */ rc = lpfc_sli4_queue_setup(phba); @@ -5669,7 +5571,7 @@ __lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number, case CMD_GEN_REQUEST64_CX: if (!(phba->sli.sli_flag & LPFC_MENLO_MAINT) || (piocb->iocb.un.genreq64.w5.hcsw.Rctl != - FC_FCP_CMND) || + FC_RCTL_DD_UNSOL_CMD) || (piocb->iocb.un.genreq64.w5.hcsw.Type != MENLO_TRANSPORT_TYPE)) @@ -5849,7 +5751,7 @@ static int lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, union lpfc_wqe *wqe) { - uint32_t payload_len = 0; + uint32_t xmit_len = 0, total_len = 0; uint8_t ct = 0; uint32_t fip; uint32_t abort_tag; @@ -5857,12 +5759,15 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, uint8_t cmnd; uint16_t xritag; struct ulp_bde64 *bpl = NULL; + uint32_t els_id = ELS_ID_DEFAULT; + int numBdes, i; + struct ulp_bde64 bde; - fip = bf_get(lpfc_fip_flag, &phba->sli4_hba.sli4_flags); + fip = phba->hba_flag & HBA_FIP_SUPPORT; /* The fcp commands will set command type */ if (iocbq->iocb_flag & LPFC_IO_FCP) command_type = FCP_COMMAND; - else if (fip && (iocbq->iocb_flag & LPFC_FIP_ELS)) + else if (fip && (iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK)) command_type = ELS_COMMAND_FIP; else command_type = ELS_COMMAND_NON_FIP; @@ -5874,6 +5779,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, wqe->words[7] = 0; /* The ct field has moved so reset */ /* words0-2 bpl convert bde */ if (iocbq->iocb.un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) { + numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize / + sizeof(struct ulp_bde64); bpl = (struct ulp_bde64 *) ((struct lpfc_dmabuf *)iocbq->context3)->virt; if (!bpl) @@ -5886,9 +5793,14 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, * can assign it to the sgl. */ wqe->generic.bde.tus.w = le32_to_cpu(bpl->tus.w); - payload_len = wqe->generic.bde.tus.f.bdeSize; + xmit_len = wqe->generic.bde.tus.f.bdeSize; + total_len = 0; + for (i = 0; i < numBdes; i++) { + bde.tus.w = le32_to_cpu(bpl[i].tus.w); + total_len += bde.tus.f.bdeSize; + } } else - payload_len = iocbq->iocb.un.fcpi64.bdl.bdeSize; + xmit_len = iocbq->iocb.un.fcpi64.bdl.bdeSize; iocbq->iocb.ulpIoTag = iocbq->iotag; cmnd = iocbq->iocb.ulpCommand; @@ -5902,7 +5814,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, iocbq->iocb.ulpCommand); return IOCB_ERROR; } - wqe->els_req.payload_len = payload_len; + wqe->els_req.payload_len = xmit_len; /* Els_reguest64 has a TMO */ bf_set(wqe_tmo, &wqe->els_req.wqe_com, iocbq->iocb.ulpTimeout); @@ -5923,7 +5835,23 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(lpfc_wqe_gen_ct, &wqe->generic, ct); bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0); /* CCP CCPE PV PRI in word10 were set in the memcpy */ + + if (command_type == ELS_COMMAND_FIP) { + els_id = ((iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK) + >> LPFC_FIP_ELS_ID_SHIFT); + } + bf_set(lpfc_wqe_gen_els_id, &wqe->generic, els_id); + break; + case CMD_XMIT_SEQUENCE64_CX: + bf_set(lpfc_wqe_gen_context, &wqe->generic, + iocbq->iocb.un.ulpWord[3]); + wqe->generic.word3 = 0; + bf_set(wqe_rcvoxid, &wqe->generic, iocbq->iocb.ulpContext); + bf_set(wqe_xc, &wqe->generic, 1); + /* The entire sequence is transmitted for this IOCB */ + xmit_len = total_len; + cmnd = CMD_XMIT_SEQUENCE64_CR; case CMD_XMIT_SEQUENCE64_CR: /* word3 iocb=io_tag32 wqe=payload_offset */ /* payload offset used for multilpe outstanding @@ -5933,7 +5861,8 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, /* word4 relative_offset memcpy */ /* word5 r_ctl/df_ctl memcpy */ bf_set(lpfc_wqe_gen_pu, &wqe->generic, 0); - wqe->xmit_sequence.xmit_len = payload_len; + wqe->xmit_sequence.xmit_len = xmit_len; + command_type = OTHER_COMMAND; break; case CMD_XMIT_BCAST64_CN: /* word3 iocb=iotag32 wqe=payload_len */ @@ -5962,7 +5891,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, case CMD_FCP_IREAD64_CR: /* FCP_CMD is always the 1st sgl entry */ wqe->fcp_iread.payload_len = - payload_len + sizeof(struct fcp_rsp); + xmit_len + sizeof(struct fcp_rsp); /* word 4 (xfer length) should have been set on the memcpy */ @@ -5999,7 +5928,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, * sgl[1] = rsp. * */ - wqe->gen_req.command_len = payload_len; + wqe->gen_req.command_len = xmit_len; /* Word4 parameter copied in the memcpy */ /* Word5 [rctl, type, df_ctl, la] copied in memcpy */ /* word6 context tag copied in memcpy */ @@ -6066,6 +5995,38 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, command_type = OTHER_COMMAND; xritag = 0; break; + case CMD_XMIT_BLS_RSP64_CX: + /* As BLS ABTS-ACC WQE is very different from other WQEs, + * we re-construct this WQE here based on information in + * iocbq from scratch. + */ + memset(wqe, 0, sizeof(union lpfc_wqe)); + /* OX_ID is invariable to who sent ABTS to CT exchange */ + bf_set(xmit_bls_rsp64_oxid, &wqe->xmit_bls_rsp, + bf_get(lpfc_abts_oxid, &iocbq->iocb.un.bls_acc)); + if (bf_get(lpfc_abts_orig, &iocbq->iocb.un.bls_acc) == + LPFC_ABTS_UNSOL_INT) { + /* ABTS sent by initiator to CT exchange, the + * RX_ID field will be filled with the newly + * allocated responder XRI. + */ + bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp, + iocbq->sli4_xritag); + } else { + /* ABTS sent by responder to CT exchange, the + * RX_ID field will be filled with the responder + * RX_ID from ABTS. + */ + bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp, + bf_get(lpfc_abts_rxid, &iocbq->iocb.un.bls_acc)); + } + bf_set(xmit_bls_rsp64_seqcnthi, &wqe->xmit_bls_rsp, 0xffff); + bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1); + bf_set(wqe_ctxt_tag, &wqe->xmit_bls_rsp.wqe_com, + iocbq->iocb.ulpContext); + /* Overwrite the pre-set comnd type with OTHER_COMMAND */ + command_type = OTHER_COMMAND; + break; case CMD_XRI_ABORTED_CX: case CMD_CREATE_XRI_CR: /* Do we expect to use this? */ /* words0-2 are all 0's no bde */ @@ -6120,11 +6081,10 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, uint16_t xritag; union lpfc_wqe wqe; struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number]; - uint32_t fcp_wqidx; if (piocb->sli4_xritag == NO_XRI) { if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN || - piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN) + piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN) sglq = NULL; else { sglq = __lpfc_sli_get_sglq(phba); @@ -6155,8 +6115,17 @@ __lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, return IOCB_ERROR; if (piocb->iocb_flag & LPFC_IO_FCP) { - fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba); - if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[fcp_wqidx], &wqe)) + /* + * For FCP command IOCB, get a new WQ index to distribute + * WQE across the WQsr. On the other hand, for abort IOCB, + * it carries the same WQ index to the original command + * IOCB. + */ + if ((piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && + (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) + piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba); + if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx], + &wqe)) return IOCB_ERROR; } else { if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe)) @@ -6449,31 +6418,37 @@ lpfc_sli_setup(struct lpfc_hba *phba) pring->iotag_max = 4096; pring->lpfc_sli_rcv_async_status = lpfc_sli_async_event_handler; - pring->num_mask = 4; + pring->num_mask = LPFC_MAX_RING_MASK; pring->prt[0].profile = 0; /* Mask 0 */ - pring->prt[0].rctl = FC_ELS_REQ; - pring->prt[0].type = FC_ELS_DATA; + pring->prt[0].rctl = FC_RCTL_ELS_REQ; + pring->prt[0].type = FC_TYPE_ELS; pring->prt[0].lpfc_sli_rcv_unsol_event = lpfc_els_unsol_event; pring->prt[1].profile = 0; /* Mask 1 */ - pring->prt[1].rctl = FC_ELS_RSP; - pring->prt[1].type = FC_ELS_DATA; + pring->prt[1].rctl = FC_RCTL_ELS_REP; + pring->prt[1].type = FC_TYPE_ELS; pring->prt[1].lpfc_sli_rcv_unsol_event = lpfc_els_unsol_event; pring->prt[2].profile = 0; /* Mask 2 */ /* NameServer Inquiry */ - pring->prt[2].rctl = FC_UNSOL_CTL; + pring->prt[2].rctl = FC_RCTL_DD_UNSOL_CTL; /* NameServer */ - pring->prt[2].type = FC_COMMON_TRANSPORT_ULP; + pring->prt[2].type = FC_TYPE_CT; pring->prt[2].lpfc_sli_rcv_unsol_event = lpfc_ct_unsol_event; pring->prt[3].profile = 0; /* Mask 3 */ /* NameServer response */ - pring->prt[3].rctl = FC_SOL_CTL; + pring->prt[3].rctl = FC_RCTL_DD_SOL_CTL; /* NameServer */ - pring->prt[3].type = FC_COMMON_TRANSPORT_ULP; + pring->prt[3].type = FC_TYPE_CT; pring->prt[3].lpfc_sli_rcv_unsol_event = lpfc_ct_unsol_event; + /* abort unsolicited sequence */ + pring->prt[4].profile = 0; /* Mask 4 */ + pring->prt[4].rctl = FC_RCTL_BA_ABTS; + pring->prt[4].type = FC_TYPE_BLS; + pring->prt[4].lpfc_sli_rcv_unsol_event = + lpfc_sli4_ct_abort_unsol_event; break; } totiocbsize += (pring->numCiocb * pring->sizeCiocb) + @@ -6976,8 +6951,18 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag; spin_lock_irq(&phba->hbalock); - if (abort_iotag != 0 && abort_iotag <= phba->sli.last_iotag) - abort_iocb = phba->sli.iocbq_lookup[abort_iotag]; + if (phba->sli_rev < LPFC_SLI_REV4) { + if (abort_iotag != 0 && + abort_iotag <= phba->sli.last_iotag) + abort_iocb = + phba->sli.iocbq_lookup[abort_iotag]; + } else + /* For sli4 the abort_tag is the XRI, + * so the abort routine puts the iotag of the iocb + * being aborted in the context field of the abort + * IOCB. + */ + abort_iocb = phba->sli.iocbq_lookup[abort_context]; lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI, "0327 Cannot abort els iocb %p " @@ -6991,9 +6976,18 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * might have completed already. Do not free it again. */ if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - spin_unlock_irq(&phba->hbalock); - lpfc_sli_release_iocbq(phba, cmdiocb); - return; + if (irsp->un.ulpWord[4] != IOERR_NO_XRI) { + spin_unlock_irq(&phba->hbalock); + lpfc_sli_release_iocbq(phba, cmdiocb); + return; + } + /* For SLI4 the ulpContext field for abort IOCB + * holds the iotag of the IOCB being aborted so + * the local abort_context needs to be reset to + * match the aborted IOCBs ulpContext. + */ + if (abort_iocb && phba->sli_rev == LPFC_SLI_REV4) + abort_context = abort_iocb->iocb.ulpContext; } /* * make sure we have the right iocbq before taking it @@ -7112,13 +7106,18 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, iabt = &abtsiocbp->iocb; iabt->un.acxri.abortType = ABORT_TYPE_ABTS; iabt->un.acxri.abortContextTag = icmd->ulpContext; - if (phba->sli_rev == LPFC_SLI_REV4) + if (phba->sli_rev == LPFC_SLI_REV4) { iabt->un.acxri.abortIoTag = cmdiocb->sli4_xritag; + iabt->un.acxri.abortContextTag = cmdiocb->iotag; + } else iabt->un.acxri.abortIoTag = icmd->ulpIoTag; iabt->ulpLe = 1; iabt->ulpClass = icmd->ulpClass; + /* ABTS WQE must go to the same WQ as the WQE to be aborted */ + abtsiocbp->fcp_wqidx = cmdiocb->fcp_wqidx; + if (phba->link_state >= LPFC_LINK_UP) iabt->ulpCommand = CMD_ABORT_XRI_CN; else @@ -7322,6 +7321,9 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, abtsiocb->iocb.ulpClass = cmd->ulpClass; abtsiocb->vport = phba->pport; + /* ABTS WQE must go to the same WQ as the WQE to be aborted */ + abtsiocb->fcp_wqidx = iocbq->fcp_wqidx; + if (lpfc_is_link_up(phba)) abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN; else @@ -7687,31 +7689,28 @@ static int lpfc_sli4_eratt_read(struct lpfc_hba *phba) { uint32_t uerr_sta_hi, uerr_sta_lo; - uint32_t onlnreg0, onlnreg1; /* For now, use the SLI4 device internal unrecoverable error * registers for error attention. This can be changed later. */ - onlnreg0 = readl(phba->sli4_hba.ONLINE0regaddr); - onlnreg1 = readl(phba->sli4_hba.ONLINE1regaddr); - if ((onlnreg0 != LPFC_ONLINE_NERR) || (onlnreg1 != LPFC_ONLINE_NERR)) { - uerr_sta_lo = readl(phba->sli4_hba.UERRLOregaddr); - uerr_sta_hi = readl(phba->sli4_hba.UERRHIregaddr); - if (uerr_sta_lo || uerr_sta_hi) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1423 HBA Unrecoverable error: " - "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, " - "online0_reg=0x%x, online1_reg=0x%x\n", - uerr_sta_lo, uerr_sta_hi, - onlnreg0, onlnreg1); - phba->work_status[0] = uerr_sta_lo; - phba->work_status[1] = uerr_sta_hi; - /* Set the driver HA work bitmap */ - phba->work_ha |= HA_ERATT; - /* Indicate polling handles this ERATT */ - phba->hba_flag |= HBA_ERATT_HANDLED; - return 1; - } + uerr_sta_lo = readl(phba->sli4_hba.UERRLOregaddr); + uerr_sta_hi = readl(phba->sli4_hba.UERRHIregaddr); + if ((~phba->sli4_hba.ue_mask_lo & uerr_sta_lo) || + (~phba->sli4_hba.ue_mask_hi & uerr_sta_hi)) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "1423 HBA Unrecoverable error: " + "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, " + "ue_mask_lo_reg=0x%x, ue_mask_hi_reg=0x%x\n", + uerr_sta_lo, uerr_sta_hi, + phba->sli4_hba.ue_mask_lo, + phba->sli4_hba.ue_mask_hi); + phba->work_status[0] = uerr_sta_lo; + phba->work_status[1] = uerr_sta_hi; + /* Set the driver HA work bitmap */ + phba->work_ha |= HA_ERATT; + /* Indicate polling handles this ERATT */ + phba->hba_flag |= HBA_ERATT_HANDLED; + return 1; } return 0; } @@ -7834,7 +7833,7 @@ irqreturn_t lpfc_sli_sp_intr_handler(int irq, void *dev_id) { struct lpfc_hba *phba; - uint32_t ha_copy; + uint32_t ha_copy, hc_copy; uint32_t work_ha_copy; unsigned long status; unsigned long iflag; @@ -7892,8 +7891,13 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) } /* Clear up only attention source related to slow-path */ + hc_copy = readl(phba->HCregaddr); + writel(hc_copy & ~(HC_MBINT_ENA | HC_R2INT_ENA | + HC_LAINT_ENA | HC_ERINT_ENA), + phba->HCregaddr); writel((ha_copy & (HA_MBATT | HA_R2_CLR_MSK)), phba->HAregaddr); + writel(hc_copy, phba->HCregaddr); readl(phba->HAregaddr); /* flush */ spin_unlock_irqrestore(&phba->hbalock, iflag); } else @@ -8049,7 +8053,7 @@ lpfc_sli_sp_intr_handler(int irq, void *dev_id) KERN_ERR, LOG_MBOX | LOG_SLI, "0350 rc should have" - "been MBX_BUSY"); + "been MBX_BUSY\n"); if (rc != MBX_NOT_FINISHED) goto send_current_mbox; } @@ -8078,7 +8082,7 @@ send_current_mbox: if (rc != MBX_SUCCESS) lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "0349 rc should be " - "MBX_SUCCESS"); + "MBX_SUCCESS\n"); } spin_lock_irqsave(&phba->hbalock, iflag); @@ -8203,6 +8207,7 @@ lpfc_sli_intr_handler(int irq, void *dev_id) struct lpfc_hba *phba; irqreturn_t sp_irq_rc, fp_irq_rc; unsigned long status1, status2; + uint32_t hc_copy; /* * Get the driver's phba structure from the dev_id and @@ -8240,7 +8245,12 @@ lpfc_sli_intr_handler(int irq, void *dev_id) } /* Clear attention sources except link and error attentions */ + hc_copy = readl(phba->HCregaddr); + writel(hc_copy & ~(HC_MBINT_ENA | HC_R0INT_ENA | HC_R1INT_ENA + | HC_R2INT_ENA | HC_LAINT_ENA | HC_ERINT_ENA), + phba->HCregaddr); writel((phba->ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr); + writel(hc_copy, phba->HCregaddr); readl(phba->HAregaddr); /* flush */ spin_unlock(&phba->hbalock); @@ -8351,8 +8361,6 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn, memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset, sizeof(struct lpfc_iocbq) - offset); - memset(&pIocbIn->sli4_info, 0, - sizeof(struct lpfc_sli4_rspiocb_info)); /* Map WCQE parameters into irspiocb parameters */ pIocbIn->iocb.ulpStatus = bf_get(lpfc_wcqe_c_status, wcqe); if (pIocbOut->iocb_flag & LPFC_IO_FCP) @@ -8364,16 +8372,49 @@ lpfc_sli4_iocb_param_transfer(struct lpfc_iocbq *pIocbIn, pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; else pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; - /* Load in additional WCQE parameters */ - pIocbIn->sli4_info.hw_status = bf_get(lpfc_wcqe_c_hw_status, wcqe); - pIocbIn->sli4_info.bfield = 0; - if (bf_get(lpfc_wcqe_c_xb, wcqe)) - pIocbIn->sli4_info.bfield |= LPFC_XB; - if (bf_get(lpfc_wcqe_c_pv, wcqe)) { - pIocbIn->sli4_info.bfield |= LPFC_PV; - pIocbIn->sli4_info.priority = - bf_get(lpfc_wcqe_c_priority, wcqe); +} + +/** + * lpfc_sli4_els_wcqe_to_rspiocbq - Get response iocbq from els wcqe + * @phba: Pointer to HBA context object. + * @wcqe: Pointer to work-queue completion queue entry. + * + * This routine handles an ELS work-queue completion event and construct + * a pseudo response ELS IODBQ from the SLI4 ELS WCQE for the common + * discovery engine to handle. + * + * Return: Pointer to the receive IOCBQ, NULL otherwise. + **/ +static struct lpfc_iocbq * +lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, + struct lpfc_iocbq *irspiocbq) +{ + struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; + struct lpfc_iocbq *cmdiocbq; + struct lpfc_wcqe_complete *wcqe; + unsigned long iflags; + + wcqe = &irspiocbq->cq_event.cqe.wcqe_cmpl; + spin_lock_irqsave(&phba->hbalock, iflags); + pring->stats.iocb_event++; + /* Look up the ELS command IOCB and create pseudo response IOCB */ + cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, + bf_get(lpfc_wcqe_c_request_tag, wcqe)); + spin_unlock_irqrestore(&phba->hbalock, iflags); + + if (unlikely(!cmdiocbq)) { + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "0386 ELS complete with no corresponding " + "cmdiocb: iotag (%d)\n", + bf_get(lpfc_wcqe_c_request_tag, wcqe)); + lpfc_sli_release_iocbq(phba, irspiocbq); + return NULL; } + + /* Fake the irspiocbq and copy necessary response information */ + lpfc_sli4_iocb_param_transfer(irspiocbq, cmdiocbq, wcqe); + + return irspiocbq; } /** @@ -8566,45 +8607,26 @@ static bool lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, struct lpfc_wcqe_complete *wcqe) { - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - struct lpfc_iocbq *cmdiocbq; struct lpfc_iocbq *irspiocbq; unsigned long iflags; - bool workposted = false; - - spin_lock_irqsave(&phba->hbalock, iflags); - pring->stats.iocb_event++; - /* Look up the ELS command IOCB and create pseudo response IOCB */ - cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, - bf_get(lpfc_wcqe_c_request_tag, wcqe)); - spin_unlock_irqrestore(&phba->hbalock, iflags); - if (unlikely(!cmdiocbq)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0386 ELS complete with no corresponding " - "cmdiocb: iotag (%d)\n", - bf_get(lpfc_wcqe_c_request_tag, wcqe)); - return workposted; - } - - /* Fake the irspiocbq and copy necessary response information */ + /* Get an irspiocbq for later ELS response processing use */ irspiocbq = lpfc_sli_get_iocbq(phba); if (!irspiocbq) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0387 Failed to allocate an iocbq\n"); - return workposted; + return false; } - lpfc_sli4_iocb_param_transfer(irspiocbq, cmdiocbq, wcqe); - /* Add the irspiocb to the response IOCB work list */ + /* Save off the slow-path queue event for work thread to process */ + memcpy(&irspiocbq->cq_event.cqe.wcqe_cmpl, wcqe, sizeof(*wcqe)); spin_lock_irqsave(&phba->hbalock, iflags); - list_add_tail(&irspiocbq->list, &phba->sli4_hba.sp_rspiocb_work_queue); - /* Indicate ELS ring attention */ - phba->work_ha |= (HA_R0ATT << (4*LPFC_ELS_RING)); + list_add_tail(&irspiocbq->cq_event.list, + &phba->sli4_hba.sp_queue_event); + phba->hba_flag |= HBA_SP_QUEUE_EVT; spin_unlock_irqrestore(&phba->hbalock, iflags); - workposted = true; - return workposted; + return true; } /** @@ -8690,52 +8712,6 @@ lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, } /** - * lpfc_sli4_sp_handle_wcqe - Process a work-queue completion queue entry - * @phba: Pointer to HBA context object. - * @cq: Pointer to the completion queue. - * @wcqe: Pointer to a completion queue entry. - * - * This routine process a slow-path work-queue completion queue entry. - * - * Return: true if work posted to worker thread, otherwise false. - **/ -static bool -lpfc_sli4_sp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, - struct lpfc_cqe *cqe) -{ - struct lpfc_wcqe_complete wcqe; - bool workposted = false; - - /* Copy the work queue CQE and convert endian order if needed */ - lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe)); - - /* Check and process for different type of WCQE and dispatch */ - switch (bf_get(lpfc_wcqe_c_code, &wcqe)) { - case CQE_CODE_COMPL_WQE: - /* Process the WQ complete event */ - workposted = lpfc_sli4_sp_handle_els_wcqe(phba, - (struct lpfc_wcqe_complete *)&wcqe); - break; - case CQE_CODE_RELEASE_WQE: - /* Process the WQ release event */ - lpfc_sli4_sp_handle_rel_wcqe(phba, - (struct lpfc_wcqe_release *)&wcqe); - break; - case CQE_CODE_XRI_ABORTED: - /* Process the WQ XRI abort event */ - workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq, - (struct sli4_wcqe_xri_aborted *)&wcqe); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0388 Not a valid WCQE code: x%x\n", - bf_get(lpfc_wcqe_c_code, &wcqe)); - break; - } - return workposted; -} - -/** * lpfc_sli4_sp_handle_rcqe - Process a receive-queue completion queue entry * @phba: Pointer to HBA context object. * @rcqe: Pointer to receive-queue completion queue entry. @@ -8745,9 +8721,8 @@ lpfc_sli4_sp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, * Return: true if work posted to worker thread, otherwise false. **/ static bool -lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe) +lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) { - struct lpfc_rcqe rcqe; bool workposted = false; struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq; struct lpfc_queue *drq = phba->sli4_hba.dat_rq; @@ -8755,31 +8730,28 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe) uint32_t status; unsigned long iflags; - /* Copy the receive queue CQE and convert endian order if needed */ - lpfc_sli_pcimem_bcopy(cqe, &rcqe, sizeof(struct lpfc_rcqe)); - lpfc_sli4_rq_release(hrq, drq); - if (bf_get(lpfc_rcqe_code, &rcqe) != CQE_CODE_RECEIVE) - goto out; - if (bf_get(lpfc_rcqe_rq_id, &rcqe) != hrq->queue_id) + if (bf_get(lpfc_rcqe_rq_id, rcqe) != hrq->queue_id) goto out; - status = bf_get(lpfc_rcqe_status, &rcqe); + status = bf_get(lpfc_rcqe_status, rcqe); switch (status) { case FC_STATUS_RQ_BUF_LEN_EXCEEDED: lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2537 Receive Frame Truncated!!\n"); case FC_STATUS_RQ_SUCCESS: + lpfc_sli4_rq_release(hrq, drq); spin_lock_irqsave(&phba->hbalock, iflags); dma_buf = lpfc_sli_hbqbuf_get(&phba->hbqs[0].hbq_buffer_list); if (!dma_buf) { spin_unlock_irqrestore(&phba->hbalock, iflags); goto out; } - memcpy(&dma_buf->rcqe, &rcqe, sizeof(rcqe)); + memcpy(&dma_buf->cq_event.cqe.rcqe_cmpl, rcqe, sizeof(*rcqe)); /* save off the frame for the word thread to process */ - list_add_tail(&dma_buf->dbuf.list, &phba->rb_pend_list); + list_add_tail(&dma_buf->cq_event.list, + &phba->sli4_hba.sp_queue_event); /* Frame received */ - phba->hba_flag |= HBA_RECEIVE_BUFFER; + phba->hba_flag |= HBA_SP_QUEUE_EVT; spin_unlock_irqrestore(&phba->hbalock, iflags); workposted = true; break; @@ -8794,7 +8766,58 @@ lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe) } out: return workposted; +} + +/** + * lpfc_sli4_sp_handle_cqe - Process a slow path completion queue entry + * @phba: Pointer to HBA context object. + * @cq: Pointer to the completion queue. + * @wcqe: Pointer to a completion queue entry. + * + * This routine process a slow-path work-queue or recieve queue completion queue + * entry. + * + * Return: true if work posted to worker thread, otherwise false. + **/ +static bool +lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, + struct lpfc_cqe *cqe) +{ + struct lpfc_cqe cqevt; + bool workposted = false; + + /* Copy the work queue CQE and convert endian order if needed */ + lpfc_sli_pcimem_bcopy(cqe, &cqevt, sizeof(struct lpfc_cqe)); + /* Check and process for different type of WCQE and dispatch */ + switch (bf_get(lpfc_cqe_code, &cqevt)) { + case CQE_CODE_COMPL_WQE: + /* Process the WQ/RQ complete event */ + workposted = lpfc_sli4_sp_handle_els_wcqe(phba, + (struct lpfc_wcqe_complete *)&cqevt); + break; + case CQE_CODE_RELEASE_WQE: + /* Process the WQ release event */ + lpfc_sli4_sp_handle_rel_wcqe(phba, + (struct lpfc_wcqe_release *)&cqevt); + break; + case CQE_CODE_XRI_ABORTED: + /* Process the WQ XRI abort event */ + workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq, + (struct sli4_wcqe_xri_aborted *)&cqevt); + break; + case CQE_CODE_RECEIVE: + /* Process the RQ event */ + workposted = lpfc_sli4_sp_handle_rcqe(phba, + (struct lpfc_rcqe *)&cqevt); + break; + default: + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "0388 Not a valid WCQE code: x%x\n", + bf_get(lpfc_cqe_code, &cqevt)); + break; + } + return workposted; } /** @@ -8858,14 +8881,7 @@ lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) break; case LPFC_WCQ: while ((cqe = lpfc_sli4_cq_get(cq))) { - workposted |= lpfc_sli4_sp_handle_wcqe(phba, cq, cqe); - if (!(++ecount % LPFC_GET_QE_REL_INT)) - lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); - } - break; - case LPFC_RCQ: - while ((cqe = lpfc_sli4_cq_get(cq))) { - workposted |= lpfc_sli4_sp_handle_rcqe(phba, cqe); + workposted |= lpfc_sli4_sp_handle_cqe(phba, cq, cqe); if (!(++ecount % LPFC_GET_QE_REL_INT)) lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); } @@ -10427,8 +10443,7 @@ lpfc_sli4_next_xritag(struct lpfc_hba *phba) return xritag; } spin_unlock_irq(&phba->hbalock); - - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, "2004 Failed to allocate XRI.last XRITAG is %d" " Max XRI is %d, Used XRI is %d\n", phba->sli4_hba.next_xri, @@ -10492,15 +10507,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba) lpfc_sli4_mbox_cmd_free(phba, mbox); return -ENOMEM; } - /* Get the first SGE entry from the non-embedded DMA memory */ - if (unlikely(!mbox->sge_array)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "2525 Failed to get the non-embedded SGE " - "virtual address\n"); - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } viraddr = mbox->sge_array->addr[0]; /* Set up the SGL pages in the non-embedded DMA pages */ @@ -10524,8 +10531,7 @@ lpfc_sli4_post_sgl_list(struct lpfc_hba *phba) sgl_pg_pairs++; } bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start); - pg_pairs = (pg_pairs > 0) ? (pg_pairs - 1) : pg_pairs; - bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs); + bf_set(lpfc_post_sgl_pages_xricnt, sgl, els_xri_cnt); /* Perform endian conversion if necessary */ sgl->word0 = cpu_to_le32(sgl->word0); @@ -10607,15 +10613,7 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist, lpfc_sli4_mbox_cmd_free(phba, mbox); return -ENOMEM; } - /* Get the first SGE entry from the non-embedded DMA memory */ - if (unlikely(!mbox->sge_array)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "2565 Failed to get the non-embedded SGE " - "virtual address\n"); - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } viraddr = mbox->sge_array->addr[0]; /* Set up the SGL pages in the non-embedded DMA pages */ @@ -10802,6 +10800,105 @@ lpfc_fc_frame_to_vport(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr, } /** + * lpfc_update_rcv_time_stamp - Update vport's rcv seq time stamp + * @vport: The vport to work on. + * + * This function updates the receive sequence time stamp for this vport. The + * receive sequence time stamp indicates the time that the last frame of the + * the sequence that has been idle for the longest amount of time was received. + * the driver uses this time stamp to indicate if any received sequences have + * timed out. + **/ +void +lpfc_update_rcv_time_stamp(struct lpfc_vport *vport) +{ + struct lpfc_dmabuf *h_buf; + struct hbq_dmabuf *dmabuf = NULL; + + /* get the oldest sequence on the rcv list */ + h_buf = list_get_first(&vport->rcv_buffer_list, + struct lpfc_dmabuf, list); + if (!h_buf) + return; + dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf); + vport->rcv_buffer_time_stamp = dmabuf->time_stamp; +} + +/** + * lpfc_cleanup_rcv_buffers - Cleans up all outstanding receive sequences. + * @vport: The vport that the received sequences were sent to. + * + * This function cleans up all outstanding received sequences. This is called + * by the driver when a link event or user action invalidates all the received + * sequences. + **/ +void +lpfc_cleanup_rcv_buffers(struct lpfc_vport *vport) +{ + struct lpfc_dmabuf *h_buf, *hnext; + struct lpfc_dmabuf *d_buf, *dnext; + struct hbq_dmabuf *dmabuf = NULL; + + /* start with the oldest sequence on the rcv list */ + list_for_each_entry_safe(h_buf, hnext, &vport->rcv_buffer_list, list) { + dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf); + list_del_init(&dmabuf->hbuf.list); + list_for_each_entry_safe(d_buf, dnext, + &dmabuf->dbuf.list, list) { + list_del_init(&d_buf->list); + lpfc_in_buf_free(vport->phba, d_buf); + } + lpfc_in_buf_free(vport->phba, &dmabuf->dbuf); + } +} + +/** + * lpfc_rcv_seq_check_edtov - Cleans up timed out receive sequences. + * @vport: The vport that the received sequences were sent to. + * + * This function determines whether any received sequences have timed out by + * first checking the vport's rcv_buffer_time_stamp. If this time_stamp + * indicates that there is at least one timed out sequence this routine will + * go through the received sequences one at a time from most inactive to most + * active to determine which ones need to be cleaned up. Once it has determined + * that a sequence needs to be cleaned up it will simply free up the resources + * without sending an abort. + **/ +void +lpfc_rcv_seq_check_edtov(struct lpfc_vport *vport) +{ + struct lpfc_dmabuf *h_buf, *hnext; + struct lpfc_dmabuf *d_buf, *dnext; + struct hbq_dmabuf *dmabuf = NULL; + unsigned long timeout; + int abort_count = 0; + + timeout = (msecs_to_jiffies(vport->phba->fc_edtov) + + vport->rcv_buffer_time_stamp); + if (list_empty(&vport->rcv_buffer_list) || + time_before(jiffies, timeout)) + return; + /* start with the oldest sequence on the rcv list */ + list_for_each_entry_safe(h_buf, hnext, &vport->rcv_buffer_list, list) { + dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf); + timeout = (msecs_to_jiffies(vport->phba->fc_edtov) + + dmabuf->time_stamp); + if (time_before(jiffies, timeout)) + break; + abort_count++; + list_del_init(&dmabuf->hbuf.list); + list_for_each_entry_safe(d_buf, dnext, + &dmabuf->dbuf.list, list) { + list_del_init(&d_buf->list); + lpfc_in_buf_free(vport->phba, d_buf); + } + lpfc_in_buf_free(vport->phba, &dmabuf->dbuf); + } + if (abort_count) + lpfc_update_rcv_time_stamp(vport); +} + +/** * lpfc_fc_frame_add - Adds a frame to the vport's list of received sequences * @dmabuf: pointer to a dmabuf that describes the hdr and data of the FC frame * @@ -10823,6 +10920,8 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf) struct hbq_dmabuf *seq_dmabuf = NULL; struct hbq_dmabuf *temp_dmabuf = NULL; + INIT_LIST_HEAD(&dmabuf->dbuf.list); + dmabuf->time_stamp = jiffies; new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; /* Use the hdr_buf to find the sequence that this frame belongs to */ list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) { @@ -10841,13 +10940,21 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf) * Queue the buffer on the vport's rcv_buffer_list. */ list_add_tail(&dmabuf->hbuf.list, &vport->rcv_buffer_list); + lpfc_update_rcv_time_stamp(vport); return dmabuf; } temp_hdr = seq_dmabuf->hbuf.virt; if (new_hdr->fh_seq_cnt < temp_hdr->fh_seq_cnt) { - list_add(&seq_dmabuf->dbuf.list, &dmabuf->dbuf.list); + list_del_init(&seq_dmabuf->hbuf.list); + list_add_tail(&dmabuf->hbuf.list, &vport->rcv_buffer_list); + list_add_tail(&dmabuf->dbuf.list, &seq_dmabuf->dbuf.list); + lpfc_update_rcv_time_stamp(vport); return dmabuf; } + /* move this sequence to the tail to indicate a young sequence */ + list_move_tail(&seq_dmabuf->hbuf.list, &vport->rcv_buffer_list); + seq_dmabuf->time_stamp = jiffies; + lpfc_update_rcv_time_stamp(vport); /* find the correct place in the sequence to insert this frame */ list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) { temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf); @@ -10865,6 +10972,210 @@ lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf) } /** + * lpfc_sli4_abort_partial_seq - Abort partially assembled unsol sequence + * @vport: pointer to a vitural port + * @dmabuf: pointer to a dmabuf that describes the FC sequence + * + * This function tries to abort from the partially assembed sequence, described + * by the information from basic abbort @dmabuf. It checks to see whether such + * partially assembled sequence held by the driver. If so, it shall free up all + * the frames from the partially assembled sequence. + * + * Return + * true -- if there is matching partially assembled sequence present and all + * the frames freed with the sequence; + * false -- if there is no matching partially assembled sequence present so + * nothing got aborted in the lower layer driver + **/ +static bool +lpfc_sli4_abort_partial_seq(struct lpfc_vport *vport, + struct hbq_dmabuf *dmabuf) +{ + struct fc_frame_header *new_hdr; + struct fc_frame_header *temp_hdr; + struct lpfc_dmabuf *d_buf, *n_buf, *h_buf; + struct hbq_dmabuf *seq_dmabuf = NULL; + + /* Use the hdr_buf to find the sequence that matches this frame */ + INIT_LIST_HEAD(&dmabuf->dbuf.list); + INIT_LIST_HEAD(&dmabuf->hbuf.list); + new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; + list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) { + temp_hdr = (struct fc_frame_header *)h_buf->virt; + if ((temp_hdr->fh_seq_id != new_hdr->fh_seq_id) || + (temp_hdr->fh_ox_id != new_hdr->fh_ox_id) || + (memcmp(&temp_hdr->fh_s_id, &new_hdr->fh_s_id, 3))) + continue; + /* found a pending sequence that matches this frame */ + seq_dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf); + break; + } + + /* Free up all the frames from the partially assembled sequence */ + if (seq_dmabuf) { + list_for_each_entry_safe(d_buf, n_buf, + &seq_dmabuf->dbuf.list, list) { + list_del_init(&d_buf->list); + lpfc_in_buf_free(vport->phba, d_buf); + } + return true; + } + return false; +} + +/** + * lpfc_sli4_seq_abort_acc_cmpl - Accept seq abort iocb complete handler + * @phba: Pointer to HBA context object. + * @cmd_iocbq: pointer to the command iocbq structure. + * @rsp_iocbq: pointer to the response iocbq structure. + * + * This function handles the sequence abort accept iocb command complete + * event. It properly releases the memory allocated to the sequence abort + * accept iocb. + **/ +static void +lpfc_sli4_seq_abort_acc_cmpl(struct lpfc_hba *phba, + struct lpfc_iocbq *cmd_iocbq, + struct lpfc_iocbq *rsp_iocbq) +{ + if (cmd_iocbq) + lpfc_sli_release_iocbq(phba, cmd_iocbq); +} + +/** + * lpfc_sli4_seq_abort_acc - Accept sequence abort + * @phba: Pointer to HBA context object. + * @fc_hdr: pointer to a FC frame header. + * + * This function sends a basic accept to a previous unsol sequence abort + * event after aborting the sequence handling. + **/ +static void +lpfc_sli4_seq_abort_acc(struct lpfc_hba *phba, + struct fc_frame_header *fc_hdr) +{ + struct lpfc_iocbq *ctiocb = NULL; + struct lpfc_nodelist *ndlp; + uint16_t oxid, rxid; + uint32_t sid, fctl; + IOCB_t *icmd; + + if (!lpfc_is_link_up(phba)) + return; + + sid = sli4_sid_from_fc_hdr(fc_hdr); + oxid = be16_to_cpu(fc_hdr->fh_ox_id); + rxid = be16_to_cpu(fc_hdr->fh_rx_id); + + ndlp = lpfc_findnode_did(phba->pport, sid); + if (!ndlp) { + lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, + "1268 Find ndlp returned NULL for oxid:x%x " + "SID:x%x\n", oxid, sid); + return; + } + + /* Allocate buffer for acc iocb */ + ctiocb = lpfc_sli_get_iocbq(phba); + if (!ctiocb) + return; + + /* Extract the F_CTL field from FC_HDR */ + fctl = sli4_fctl_from_fc_hdr(fc_hdr); + + icmd = &ctiocb->iocb; + icmd->un.xseq64.bdl.bdeSize = 0; + icmd->un.xseq64.bdl.ulpIoTag32 = 0; + icmd->un.xseq64.w5.hcsw.Dfctl = 0; + icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_ACC; + icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_BLS; + + /* Fill in the rest of iocb fields */ + icmd->ulpCommand = CMD_XMIT_BLS_RSP64_CX; + icmd->ulpBdeCount = 0; + icmd->ulpLe = 1; + icmd->ulpClass = CLASS3; + icmd->ulpContext = ndlp->nlp_rpi; + + ctiocb->iocb_cmpl = NULL; + ctiocb->vport = phba->pport; + ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_acc_cmpl; + + if (fctl & FC_FC_EX_CTX) { + /* ABTS sent by responder to CT exchange, construction + * of BA_ACC will use OX_ID from ABTS for the XRI_TAG + * field and RX_ID from ABTS for RX_ID field. + */ + bf_set(lpfc_abts_orig, &icmd->un.bls_acc, LPFC_ABTS_UNSOL_RSP); + bf_set(lpfc_abts_rxid, &icmd->un.bls_acc, rxid); + ctiocb->sli4_xritag = oxid; + } else { + /* ABTS sent by initiator to CT exchange, construction + * of BA_ACC will need to allocate a new XRI as for the + * XRI_TAG and RX_ID fields. + */ + bf_set(lpfc_abts_orig, &icmd->un.bls_acc, LPFC_ABTS_UNSOL_INT); + bf_set(lpfc_abts_rxid, &icmd->un.bls_acc, NO_XRI); + ctiocb->sli4_xritag = NO_XRI; + } + bf_set(lpfc_abts_oxid, &icmd->un.bls_acc, oxid); + + /* Xmit CT abts accept on exchange <xid> */ + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "1200 Xmit CT ABTS ACC on exchange x%x Data: x%x\n", + CMD_XMIT_BLS_RSP64_CX, phba->link_state); + lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); +} + +/** + * lpfc_sli4_handle_unsol_abort - Handle sli-4 unsolicited abort event + * @vport: Pointer to the vport on which this sequence was received + * @dmabuf: pointer to a dmabuf that describes the FC sequence + * + * This function handles an SLI-4 unsolicited abort event. If the unsolicited + * receive sequence is only partially assembed by the driver, it shall abort + * the partially assembled frames for the sequence. Otherwise, if the + * unsolicited receive sequence has been completely assembled and passed to + * the Upper Layer Protocol (UPL), it then mark the per oxid status for the + * unsolicited sequence has been aborted. After that, it will issue a basic + * accept to accept the abort. + **/ +void +lpfc_sli4_handle_unsol_abort(struct lpfc_vport *vport, + struct hbq_dmabuf *dmabuf) +{ + struct lpfc_hba *phba = vport->phba; + struct fc_frame_header fc_hdr; + uint32_t fctl; + bool abts_par; + + /* Make a copy of fc_hdr before the dmabuf being released */ + memcpy(&fc_hdr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header)); + fctl = sli4_fctl_from_fc_hdr(&fc_hdr); + + if (fctl & FC_FC_EX_CTX) { + /* + * ABTS sent by responder to exchange, just free the buffer + */ + lpfc_in_buf_free(phba, &dmabuf->dbuf); + } else { + /* + * ABTS sent by initiator to exchange, need to do cleanup + */ + /* Try to abort partially assembled seq */ + abts_par = lpfc_sli4_abort_partial_seq(vport, dmabuf); + + /* Send abort to ULP if partially seq abort failed */ + if (abts_par == false) + lpfc_sli4_send_seq_to_ulp(vport, dmabuf); + else + lpfc_in_buf_free(phba, &dmabuf->dbuf); + } + /* Send basic accept (BA_ACC) to the abort requester */ + lpfc_sli4_seq_abort_acc(phba, &fc_hdr); +} + +/** * lpfc_seq_complete - Indicates if a sequence is complete * @dmabuf: pointer to a dmabuf that describes the FC sequence * @@ -10935,10 +11246,9 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; /* remove from receive buffer list */ list_del_init(&seq_dmabuf->hbuf.list); + lpfc_update_rcv_time_stamp(vport); /* get the Remote Port's SID */ - sid = (fc_hdr->fh_s_id[0] << 16 | - fc_hdr->fh_s_id[1] << 8 | - fc_hdr->fh_s_id[2]); + sid = sli4_sid_from_fc_hdr(fc_hdr); /* Get an iocbq struct to fill in. */ first_iocbq = lpfc_sli_get_iocbq(vport->phba); if (first_iocbq) { @@ -10957,7 +11267,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) LPFC_DATA_BUF_SIZE; first_iocbq->iocb.un.rcvels.remoteID = sid; first_iocbq->iocb.unsli3.rcvsli3.acc_len += - bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe); + bf_get(lpfc_rcqe_length, + &seq_dmabuf->cq_event.cqe.rcqe_cmpl); } iocbq = first_iocbq; /* @@ -10975,7 +11286,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) iocbq->iocb.unsli3.rcvsli3.bde2.tus.f.bdeSize = LPFC_DATA_BUF_SIZE; first_iocbq->iocb.unsli3.rcvsli3.acc_len += - bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe); + bf_get(lpfc_rcqe_length, + &seq_dmabuf->cq_event.cqe.rcqe_cmpl); } else { iocbq = lpfc_sli_get_iocbq(vport->phba); if (!iocbq) { @@ -10994,7 +11306,8 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) iocbq->iocb.un.cont64[0].tus.f.bdeSize = LPFC_DATA_BUF_SIZE; first_iocbq->iocb.unsli3.rcvsli3.acc_len += - bf_get(lpfc_rcqe_length, &seq_dmabuf->rcqe); + bf_get(lpfc_rcqe_length, + &seq_dmabuf->cq_event.cqe.rcqe_cmpl); iocbq->iocb.un.rcvels.remoteID = sid; list_add_tail(&iocbq->list, &first_iocbq->list); } @@ -11002,6 +11315,43 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) return first_iocbq; } +static void +lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *vport, + struct hbq_dmabuf *seq_dmabuf) +{ + struct fc_frame_header *fc_hdr; + struct lpfc_iocbq *iocbq, *curr_iocb, *next_iocb; + struct lpfc_hba *phba = vport->phba; + + fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; + iocbq = lpfc_prep_seq(vport, seq_dmabuf); + if (!iocbq) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2707 Ring %d handler: Failed to allocate " + "iocb Rctl x%x Type x%x received\n", + LPFC_ELS_RING, + fc_hdr->fh_r_ctl, fc_hdr->fh_type); + return; + } + if (!lpfc_complete_unsol_iocb(phba, + &phba->sli.ring[LPFC_ELS_RING], + iocbq, fc_hdr->fh_r_ctl, + fc_hdr->fh_type)) + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "2540 Ring %d handler: unexpected Rctl " + "x%x Type x%x received\n", + LPFC_ELS_RING, + fc_hdr->fh_r_ctl, fc_hdr->fh_type); + + /* Free iocb created in lpfc_prep_seq */ + list_for_each_entry_safe(curr_iocb, next_iocb, + &iocbq->list, list) { + list_del_init(&curr_iocb->list); + lpfc_sli_release_iocbq(phba, curr_iocb); + } + lpfc_sli_release_iocbq(phba, iocbq); +} + /** * lpfc_sli4_handle_received_buffer - Handle received buffers from firmware * @phba: Pointer to HBA context object. @@ -11014,67 +11364,54 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) * Worker thread calls lpfc_sli4_handle_received_buffer, which will call the * appropriate receive function when the final frame in a sequence is received. **/ -int -lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba) +void +lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, + struct hbq_dmabuf *dmabuf) { - LIST_HEAD(cmplq); - struct hbq_dmabuf *dmabuf, *seq_dmabuf; + struct hbq_dmabuf *seq_dmabuf; struct fc_frame_header *fc_hdr; struct lpfc_vport *vport; uint32_t fcfi; - struct lpfc_iocbq *iocbq; - - /* Clear hba flag and get all received buffers into the cmplq */ - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~HBA_RECEIVE_BUFFER; - list_splice_init(&phba->rb_pend_list, &cmplq); - spin_unlock_irq(&phba->hbalock); /* Process each received buffer */ - while ((dmabuf = lpfc_sli_hbqbuf_get(&cmplq)) != NULL) { - fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; - /* check to see if this a valid type of frame */ - if (lpfc_fc_frame_check(phba, fc_hdr)) { - lpfc_in_buf_free(phba, &dmabuf->dbuf); - continue; - } - fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->rcqe); - vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi); - if (!vport) { - /* throw out the frame */ - lpfc_in_buf_free(phba, &dmabuf->dbuf); - continue; - } - /* Link this frame */ - seq_dmabuf = lpfc_fc_frame_add(vport, dmabuf); - if (!seq_dmabuf) { - /* unable to add frame to vport - throw it out */ - lpfc_in_buf_free(phba, &dmabuf->dbuf); - continue; - } - /* If not last frame in sequence continue processing frames. */ - if (!lpfc_seq_complete(seq_dmabuf)) { - /* - * When saving off frames post a new one and mark this - * frame to be freed when it is finished. - **/ - lpfc_sli_hbqbuf_fill_hbqs(phba, LPFC_ELS_HBQ, 1); - dmabuf->tag = -1; - continue; - } - fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; - iocbq = lpfc_prep_seq(vport, seq_dmabuf); - if (!lpfc_complete_unsol_iocb(phba, - &phba->sli.ring[LPFC_ELS_RING], - iocbq, fc_hdr->fh_r_ctl, - fc_hdr->fh_type)) - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "2540 Ring %d handler: unexpected Rctl " - "x%x Type x%x received\n", - LPFC_ELS_RING, - fc_hdr->fh_r_ctl, fc_hdr->fh_type); - }; - return 0; + fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; + /* check to see if this a valid type of frame */ + if (lpfc_fc_frame_check(phba, fc_hdr)) { + lpfc_in_buf_free(phba, &dmabuf->dbuf); + return; + } + fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->cq_event.cqe.rcqe_cmpl); + vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi); + if (!vport || !(vport->vpi_state & LPFC_VPI_REGISTERED)) { + /* throw out the frame */ + lpfc_in_buf_free(phba, &dmabuf->dbuf); + return; + } + /* Handle the basic abort sequence (BA_ABTS) event */ + if (fc_hdr->fh_r_ctl == FC_RCTL_BA_ABTS) { + lpfc_sli4_handle_unsol_abort(vport, dmabuf); + return; + } + + /* Link this frame */ + seq_dmabuf = lpfc_fc_frame_add(vport, dmabuf); + if (!seq_dmabuf) { + /* unable to add frame to vport - throw it out */ + lpfc_in_buf_free(phba, &dmabuf->dbuf); + return; + } + /* If not last frame in sequence continue processing frames. */ + if (!lpfc_seq_complete(seq_dmabuf)) { + /* + * When saving off frames post a new one and mark this + * frame to be freed when it is finished. + **/ + lpfc_sli_hbqbuf_fill_hbqs(phba, LPFC_ELS_HBQ, 1); + dmabuf->tag = -1; + return; + } + /* Send the complete sequence to the upper layer protocol */ + lpfc_sli4_send_seq_to_ulp(vport, seq_dmabuf); } /** @@ -11334,6 +11671,7 @@ lpfc_sli4_init_vpi(struct lpfc_hba *phba, uint16_t vpi) { LPFC_MBOXQ_t *mboxq; int rc = 0; + int retval = MBX_SUCCESS; uint32_t mbox_tmo; if (vpi == 0) @@ -11344,16 +11682,17 @@ lpfc_sli4_init_vpi(struct lpfc_hba *phba, uint16_t vpi) lpfc_init_vpi(phba, mboxq, vpi); mbox_tmo = lpfc_mbox_tmo_val(phba, MBX_INIT_VPI); rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, phba->mbox_mem_pool); if (rc != MBX_SUCCESS) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2022 INIT VPI Mailbox failed " "status %d, mbxStatus x%x\n", rc, bf_get(lpfc_mqe_status, &mboxq->u.mqe)); - rc = -EIO; + retval = -EIO; } - return rc; + if (rc != MBX_TIMEOUT) + mempool_free(mboxq, phba->mbox_mem_pool); + + return retval; } /** @@ -11438,13 +11777,6 @@ lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record) */ lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); - if (unlikely(!mboxq->sge_array)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "2526 Failed to get the non-embedded SGE " - "virtual address\n"); - lpfc_sli4_mbox_cmd_free(phba, mboxq); - return -ENOMEM; - } virt_addr = mboxq->sge_array->addr[0]; /* * Configure the FCF record for FCFI 0. This is the driver's @@ -11542,7 +11874,8 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index) lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2000 Failed to allocate mbox for " "READ_FCF cmd\n"); - return -ENOMEM; + error = -ENOMEM; + goto fail_fcfscan; } req_len = sizeof(struct fcf_record) + @@ -11558,8 +11891,8 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index) "0291 Allocated DMA memory size (x%x) is " "less than the requested DMA memory " "size (x%x)\n", alloc_len, req_len); - lpfc_sli4_mbox_cmd_free(phba, mboxq); - return -ENOMEM; + error = -ENOMEM; + goto fail_fcfscan; } /* Get the first SGE entry from the non-embedded DMA memory. This @@ -11567,13 +11900,6 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index) */ lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); - if (unlikely(!mboxq->sge_array)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "2527 Failed to get the non-embedded SGE " - "virtual address\n"); - lpfc_sli4_mbox_cmd_free(phba, mboxq); - return -ENOMEM; - } virt_addr = mboxq->sge_array->addr[0]; read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr; @@ -11586,7 +11912,6 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index) mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_fcf_record; rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { - lpfc_sli4_mbox_cmd_free(phba, mboxq); error = -EIO; } else { spin_lock_irq(&phba->hbalock); @@ -11594,6 +11919,15 @@ lpfc_sli4_read_fcf_record(struct lpfc_hba *phba, uint16_t fcf_index) spin_unlock_irq(&phba->hbalock); error = 0; } +fail_fcfscan: + if (error) { + if (mboxq) + lpfc_sli4_mbox_cmd_free(phba, mboxq); + /* FCF scan failed, clear FCF_DISC_INPROGRESS flag */ + spin_lock_irq(&phba->hbalock); + phba->hba_flag &= ~FCF_DISC_INPROGRESS; + spin_unlock_irq(&phba->hbalock); + } return error; } diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 3c53316cf6d..ba38de3c28f 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -29,14 +29,17 @@ typedef enum _lpfc_ctx_cmd { LPFC_CTX_HOST } lpfc_ctx_cmd; -/* This structure is used to carry the needed response IOCB states */ -struct lpfc_sli4_rspiocb_info { - uint8_t hw_status; - uint8_t bfield; -#define LPFC_XB 0x1 -#define LPFC_PV 0x2 - uint8_t priority; - uint8_t reserved; +struct lpfc_cq_event { + struct list_head list; + union { + struct lpfc_mcqe mcqe_cmpl; + struct lpfc_acqe_link acqe_link; + struct lpfc_acqe_fcoe acqe_fcoe; + struct lpfc_acqe_dcbx acqe_dcbx; + struct lpfc_rcqe rcqe_cmpl; + struct sli4_wcqe_xri_aborted wcqe_axri; + struct lpfc_wcqe_complete wcqe_cmpl; + } cqe; }; /* This structure is used to handle IOCB requests / responses */ @@ -46,6 +49,7 @@ struct lpfc_iocbq { struct list_head clist; uint16_t iotag; /* pre-assigned IO tag */ uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */ + struct lpfc_cq_event cq_event; IOCB_t iocb; /* IOCB cmd */ uint8_t retry; /* retry counter for IOCB cmd - if needed */ @@ -56,11 +60,13 @@ struct lpfc_iocbq { #define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ #define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */ #define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */ -#define LPFC_FIP_ELS 0x40 +#define LPFC_FIP_ELS_ID_MASK 0xc0 /* ELS_ID range 0-3 */ +#define LPFC_FIP_ELS_ID_SHIFT 6 uint8_t abort_count; uint8_t rsvd2; uint32_t drvrTimeout; /* driver timeout in seconds */ + uint32_t fcp_wqidx; /* index to FCP work queue */ struct lpfc_vport *vport;/* virtual port pointer */ void *context1; /* caller context information */ void *context2; /* caller context information */ @@ -76,7 +82,6 @@ struct lpfc_iocbq { struct lpfc_iocbq *); void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *); - struct lpfc_sli4_rspiocb_info sli4_info; }; #define SLI_IOCB_RET_IOCB 1 /* Return IOCB if cmd ring full */ @@ -110,7 +115,7 @@ typedef struct lpfcMboxq { return */ #define MBX_NOWAIT 2 /* issue command then return immediately */ -#define LPFC_MAX_RING_MASK 4 /* max num of rctl/type masks allowed per +#define LPFC_MAX_RING_MASK 5 /* max num of rctl/type masks allowed per ring */ #define LPFC_MAX_RING 4 /* max num of SLI rings used by driver */ diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index b5f4ba1a5c2..25d66d070cf 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -58,6 +58,16 @@ #define LPFC_FCOE_FKA_ADV_PER 0 #define LPFC_FCOE_FIP_PRIORITY 0x80 +#define sli4_sid_from_fc_hdr(fc_hdr) \ + ((fc_hdr)->fh_s_id[0] << 16 | \ + (fc_hdr)->fh_s_id[1] << 8 | \ + (fc_hdr)->fh_s_id[2]) + +#define sli4_fctl_from_fc_hdr(fc_hdr) \ + ((fc_hdr)->fh_f_ctl[0] << 16 | \ + (fc_hdr)->fh_f_ctl[1] << 8 | \ + (fc_hdr)->fh_f_ctl[2]) + enum lpfc_sli4_queue_type { LPFC_EQ, LPFC_GCQ, @@ -110,18 +120,6 @@ struct lpfc_queue { union sli4_qe qe[1]; /* array to index entries (must be last) */ }; -struct lpfc_cq_event { - struct list_head list; - union { - struct lpfc_mcqe mcqe_cmpl; - struct lpfc_acqe_link acqe_link; - struct lpfc_acqe_fcoe acqe_fcoe; - struct lpfc_acqe_dcbx acqe_dcbx; - struct lpfc_rcqe rcqe_cmpl; - struct sli4_wcqe_xri_aborted wcqe_axri; - } cqe; -}; - struct lpfc_sli4_link { uint8_t speed; uint8_t duplex; @@ -166,7 +164,7 @@ struct lpfc_fip_param_hdr { #define lpfc_fip_param_hdr_fipp_mode_SHIFT 6 #define lpfc_fip_param_hdr_fipp_mode_MASK 0x3 #define lpfc_fip_param_hdr_fipp_mode_WORD parm_flags -#define FIPP_MODE_ON 0x2 +#define FIPP_MODE_ON 0x1 #define FIPP_MODE_OFF 0x0 #define FIPP_VLAN_VALID 0x1 }; @@ -295,9 +293,8 @@ struct lpfc_sli4_hba { /* BAR0 PCI config space register memory map */ void __iomem *UERRLOregaddr; /* Address to UERR_STATUS_LO register */ void __iomem *UERRHIregaddr; /* Address to UERR_STATUS_HI register */ - void __iomem *ONLINE0regaddr; /* Address to components of internal UE */ - void __iomem *ONLINE1regaddr; /* Address to components of internal UE */ -#define LPFC_ONLINE_NERR 0xFFFFFFFF + void __iomem *UEMASKLOregaddr; /* Address to UE_MASK_LO register */ + void __iomem *UEMASKHIregaddr; /* Address to UE_MASK_HI register */ void __iomem *SCRATCHPADregaddr; /* Address to scratchpad register */ /* BAR1 FCoE function CSR register memory map */ void __iomem *STAregaddr; /* Address to HST_STATE register */ @@ -311,6 +308,8 @@ struct lpfc_sli4_hba { void __iomem *MQDBregaddr; /* Address to MQ_DOORBELL register */ void __iomem *BMBXregaddr; /* Address to BootStrap MBX register */ + uint32_t ue_mask_lo; + uint32_t ue_mask_hi; struct msix_entry *msix_entries; uint32_t cfg_eqn; struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */ @@ -325,7 +324,6 @@ struct lpfc_sli4_hba { struct lpfc_queue **fcp_cq;/* Fast-path FCP compl queue */ struct lpfc_queue *mbx_cq; /* Slow-path mailbox complete queue */ struct lpfc_queue *els_cq; /* Slow-path ELS response complete queue */ - struct lpfc_queue *rxq_cq; /* Slow-path unsolicited complete queue */ /* Setup information for various queue parameters */ int eq_esize; @@ -360,7 +358,7 @@ struct lpfc_sli4_hba { unsigned long *rpi_bmask; uint16_t rpi_count; struct lpfc_sli4_flags sli4_flags; - struct list_head sp_rspiocb_work_queue; + struct list_head sp_queue_event; struct list_head sp_cqe_event_pool; struct list_head sp_asynce_work_queue; struct list_head sp_fcp_xri_aborted_work_queue; diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 9ae20af4bdb..c7f3aed2aab 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,8 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.3.4" - +#define LPFC_DRIVER_VERSION "8.3.6" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 606efa76754..7d6dd83d359 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -389,7 +389,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) * by the port. */ if ((phba->sli_rev == LPFC_SLI_REV4) && - (pport->vfi_state & LPFC_VFI_REGISTERED)) { + (pport->vpi_state & LPFC_VPI_REGISTERED)) { rc = lpfc_sli4_init_vpi(phba, vpi); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, @@ -700,6 +700,8 @@ lpfc_vport_delete(struct fc_vport *fc_vport) } spin_unlock_irq(&phba->ndlp_lock); } + if (vport->vpi_state != LPFC_VPI_REGISTERED) + goto skip_logo; vport->unreg_vpi_cmpl = VPORT_INVAL; timeout = msecs_to_jiffies(phba->fc_ratov * 2000); if (!lpfc_issue_els_npiv_logo(vport, ndlp)) |