From: Chip Coldwell <coldwell@redhat.com> Date: Wed, 19 Dec 2007 17:32:10 -0500 Subject: [scsi] lpfc: update to version 8.2.0.13 Message-id: alpine.LFD.0.9999.0712191425160.6018@localhost.localdomain O-Subject: [RHEL-5.2 PATCH] bz426281 update lpfc (Emulex) driver to version 8.2.0.13 Bugzilla: 426281 Some serious deficiencies were discovered in the 8.2.0.8 lpfc driver (already integrated into the 5.2 kernel, see bz252989). * Changed version number to 8.2.0.13 * Enhance debugfs to dump HBA SLIM as well as Host SLIM * Fix driver to recover properly from FAN timeout (CR 27723) * Fix Unsolicited CT command handling (CR 27553) * Force NPIV off for pt2pt mode between 2 NPorts (CR 27543) * Fix up loopback ioctl to handle vports properly * Check void pointer type condition with proper type * Fix mbox race condition and a workaround on back-to-back mailbox commands (CR 27603) * Fix panic when HBA generates ERATT interupt (CR 27531) * Fix hbq initialization after HBA reset (CR 27581) * Changed version number to 8.2.0.12 * Allow vports to be created when no fabric present * Removed schedule call from the worker thread. (CR 27379, 27516, 27178, 27203, 27349) * Remove bogus message displayed when driver unloads (CR 27539) * Added module parameter and sysfs interface to restrict PCI DMA length. (CR 27634) * Perform target flush before releasing references with FC_UNLOADING (CR 27506) * Fix instances of beXX_to_cpu() should actually be cpu_to_beXX() (CR 25073) * Change del_timer_sync() in ISR to del_timer() * Fixed System crash deleting vports with traffic running (CR 27280) * Added support for direct download feature of offline utility. (CR 27546) * Fixed a panic while running PCI loopback test with old libdfc. (CR 27456) * Added code to report unknown link speed when link is down. (CR 27454) * Enable PCI Enhanced Error Handling for RHEL 5 and SLES 10 SP1 * Make scatter gather Segment Count into a module parameter. (CR 27269) * Added support for PCI loopback test. (CR 26350) * Fixed HBQ dma buffer leak at dma_pool_destroy when unloading driver (CR 27069) * Changed version number to 8.2.0.11 * Fix system panic'd when unloading the driver (CR 27275) * Fix "bad status back" when hitting "initiate authentication" button (CR 27287) * Fixed use after free of event buffers. (CR 26881) * Make lpfc legacy I/O port free. (CR 27197) * Log all temperature event messages. (CR 27228) * Fix reauthenticate periodically with time interval does not work (CR 26867) * Changed version number to 8.2.0.10 * Added support for SET_VARIABLE mailbox command in online mode. (CR 27125) * Remove unused netlink-related #defines * Fix incorrect queue tag handling. (CR 27032) * Made link speed and link topology modifiable. (CR 27112) * Fixed key calculation for low cost and MID range saturn HBAs. (CR 27111) * Devloss timeouts with swap cable test (CR 27009) * Add parameters to enable and disable heartbeat and hba resets (CR 27033) * Increase Max Vport limit from 100 to 0xFFFF (CR 27038) * Fixed error code returned from the driver when HBA is over heated. (CR 27029) * Added code for event based abort completion. (CR 26653) * Fix annoying messages that occur while executing fc swap test (CR 26960 26961) * Fixed external loopback test. (CR 26881) * Changed version number to 8.2.0.9 * Fixed a memory leak in an error path. * SCSI 0x10000 errors during dt with HBA reset (CR 26082) * Add retry mechanism for GFF_ID (CR 26728) * Reset the FCP recovery flag when the node is not a FCP2 device. * Fixed a discovery issue. (CR 26424) * ELS payload gets freed while firmware DMA is in progress (CR 26919) * Fix potential overflow of hbqs array * Clean up duplicate includes * kmalloc + memset conversion to kzalloc * Added support for extended mailbox commands for EFI boot manager. (CR 26707) * Initiate Authentication succeeds when auth mode is disabled. (CR 26889) * RSCN timeout messages displayed (CR 26826) * Fix for internal loopback test. (CR 26315) * Unable to get out of non-communicating mode. (CR 26869) * Clear Link attention after Authentication failure. (CR 26838) * The driver waits a long time for the authentication service. (CR 26798) * Illegal state transition messages displayed (CR 26826) So Emulex have asked us to incorporate the patch below. All-arches build at http://brewweb.devel.redhat.com/brew/taskinfo?taskID=1087211 diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 9b1306a..64504cc 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -29,7 +29,8 @@ struct lpfc_sli2_slim; #define LPFC_MAX_NS_RETRY 3 /* Number of retry attempts to contact the NameServer before giving up. */ #define LPFC_CMD_PER_LUN 3 /* max outstanding cmds per lun */ -#define LPFC_SG_SEG_CNT 64 /* sg element count per scsi cmnd */ +#define LPFC_DEFAULT_SG_SEG_CNT 64 /* sg element count per scsi cmnd */ +#define LPFC_MAX_SG_SEG_CNT 256 /* sg element count per scsi cmnd */ #define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ #define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */ @@ -68,6 +69,7 @@ struct lpfc_dmabuf { struct list_head list; void *virt; /* virtual address ptr */ dma_addr_t phys; /* mapped address */ + uint32_t buffer_tag; /* used for tagged queue ring */ }; struct lpfc_dma_pool { @@ -201,7 +203,10 @@ struct lpfc_stats { enum sysfs_mbox_state { SMBOX_IDLE, SMBOX_WRITING, - SMBOX_READING + SMBOX_WRITING_MBEXT, + SMBOX_READING, + SMBOX_WRITING_BUFF, + SMBOX_READING_BUFF }; struct lpfc_sysfs_mbox { @@ -211,6 +216,10 @@ struct lpfc_sysfs_mbox { /* process id of the mgmt application */ pid_t pid; struct list_head list; + uint8_t * mbext; + uint32_t extoff; + struct lpfc_dmabuf * txmit_buff; + struct lpfc_dmabuf * rcv_buff; }; struct lpfc_hba; @@ -294,6 +303,8 @@ struct lpfc_auth { uint32_t challenge_len; uint8_t *dh_pub_key; uint32_t dh_pub_key_len; + + unsigned long last_auth; }; struct lpfc_vport { @@ -477,8 +488,6 @@ struct lpfc_hba { uint16_t pci_cfg_value; - uint8_t work_found; -#define LPFC_MAX_WORKER_ITERATION 4 uint8_t fc_linkspeed; /* Link speed after last READ_LA */ @@ -532,7 +541,9 @@ struct lpfc_hba { uint64_t cfg_soft_wwnn; uint64_t cfg_soft_wwpn; uint32_t cfg_hba_queue_depth; - + uint32_t cfg_enable_hba_reset; + uint32_t cfg_enable_hba_heartbeat; + uint32_t cfg_pci_max_read; lpfc_vpd_t vpd; /* vital product data */ @@ -546,6 +557,8 @@ struct lpfc_hba { wait_queue_head_t *work_wait; struct task_struct *worker_thread; + uint32_t hbq_in_use; /* HBQs in use flag */ + struct list_head hbqbuf_in_list; /* in-fly hbq buffer list */ uint32_t hbq_count; /* Count of configured HBQs */ struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */ @@ -621,8 +634,7 @@ struct lpfc_hba { struct list_head port_list; struct lpfc_vport *pport; /* physical lpfc_vport pointer */ uint16_t max_vpi; /* Maximum virtual nports */ -#define LPFC_MAX_VPI 100 /* Max number of VPI supported */ -#define LPFC_MAX_VPORTS (LPFC_MAX_VPI+1)/* Max number of VPorts supported */ +#define LPFC_MAX_VPI 0xFFFF /* Max number of VPI supported */ unsigned long *vpi_bmask; /* vpi allocation table */ /* Data structure used by fabric iocb scheduler */ @@ -640,18 +652,30 @@ struct lpfc_hba { struct dentry *hba_debugfs_root; atomic_t debugfs_vport_count; struct dentry *debug_hbqinfo; - struct dentry *debug_dumpslim; + struct dentry *debug_dumpHostSlim; + struct dentry *debug_dumpHBASlim; struct dentry *debug_slow_ring_trc; struct lpfc_debugfs_trc *slow_ring_trc; atomic_t slow_ring_trc_cnt; #endif + /* Used for deferred freeing of ELS data buffers */ + struct list_head elsbuf; + int elsbuf_cnt; + int elsbuf_prev_cnt; + uint8_t temp_sensor_support; /* Fields used for heart beat. */ unsigned long last_completion_time; struct timer_list hb_tmofunc; uint8_t hb_outstanding; enum hba_temp_state over_temp_state; + /* + * Following bit will be set for all buffer tags which are not + * associated with any HBQ. + */ +#define QUE_BUFTAG_BIT (1<<31) + uint32_t buffer_tag_count; }; static inline struct Scsi_Host * diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 972705f..f934e2d 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -269,8 +269,7 @@ lpfc_issue_lip(struct Scsi_Host *shost) int mbxstatus = MBXERR_ERROR; if ((vport->fc_flag & FC_OFFLINE_MODE) || - (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) || - (vport->port_state != LPFC_VPORT_READY)) + (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)) return -EPERM; pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL); @@ -322,12 +321,14 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type) psli = &phba->sli; + /* Wait a little for things to settle down, but not + * long enough for dev loss timeout to expire. + */ for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; - /* The linkdown event takes 30 seconds to timeout. */ while (pring->txcmplq_cnt) { msleep(10); - if (cnt++ > 3000) { + if (cnt++ > 500) { /* 5 secs */ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0466 Outstanding IO when " @@ -347,20 +348,22 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type) return 0; } -static int +int lpfc_selective_reset(struct lpfc_hba *phba) { struct completion online_compl; int status = 0; + if (!phba->cfg_enable_hba_reset) + return -EIO; + status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); if (status != 0) return status; init_completion(&online_compl); - lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_ONLINE); + lpfc_workq_post_event(phba, &status, &online_compl, LPFC_EVT_ONLINE); wait_for_completion(&online_compl); if (status != 0) @@ -426,6 +429,8 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count) struct completion online_compl; int status=0; + if (!phba->cfg_enable_hba_reset) + return -EACCES; init_completion(&online_compl); if(strncmp(buf, "online", sizeof("online") - 1) == 0) { @@ -1101,10 +1106,12 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count) unsigned int i, j, cnt=count; u8 wwpn[8]; + if (!phba->cfg_enable_hba_reset) + return -EACCES; spin_lock_irq(&phba->hbalock); if (phba->over_temp_state == HBA_OVER_TEMP) { spin_unlock_irq(&phba->hbalock); - return -EPERM; + return -EACCES; } spin_unlock_irq(&phba->hbalock); /* count may include a LF at end of string */ @@ -1328,46 +1335,90 @@ lpfc_nodev_tmo_set(struct lpfc_vport *vport, int val) val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO); return -EINVAL; } - lpfc_vport_param_store(nodev_tmo) - static CLASS_DEVICE_ATTR(lpfc_nodev_tmo, S_IRUGO | S_IWUSR, lpfc_nodev_tmo_show, lpfc_nodev_tmo_store); - static ssize_t -lpfc_restart_auth (struct class_device *cdev, const char *buf, size_t count) +lpfc_authenticate (struct class_device *cdev, const char *buf, size_t count) { struct Scsi_Host *shost = class_to_shost(cdev); struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp; int status; + struct lpfc_name wwpn; + if (lpfc_parse_wwn(buf, wwpn.u.wwn)) + return -EINVAL; + + if (vport->port_state == LPFC_VPORT_FAILED) { + lpfc_issue_lip(shost); + return strlen(buf); + } if ((vport->fc_flag & FC_OFFLINE_MODE) || - (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) || - (!vport->cfg_enable_auth)) + (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) || + (!vport->cfg_enable_auth)) return -EPERM; /* If vport already in the middle of authentication do not restart */ if ((vport->auth.auth_msg_state == LPFC_AUTH_NEGOTIATE) || (vport->auth.auth_msg_state == LPFC_DHCHAP_CHALLENGE) || (vport->auth.auth_msg_state == LPFC_DHCHAP_REPLY)) - return -EPERM; + return -EAGAIN; - ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (wwn_to_u64(wwpn.u.wwn) == AUTH_FABRIC_WWN) + ndlp = lpfc_findnode_did(vport, Fabric_DID); + else + ndlp = lpfc_findnode_wwnn(vport, &wwpn); if (!ndlp) return -EPERM; status = lpfc_start_node_authentication(ndlp); if (status) return status; - return strlen(buf); - } +static CLASS_DEVICE_ATTR(lpfc_authenticate, S_IRUGO | S_IWUSR, + NULL, lpfc_authenticate); + +static ssize_t +lpfc_update_auth_config (struct class_device *cdev, const char *buf, + size_t count) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp; + struct lpfc_name wwpn; + int status; + + if (lpfc_parse_wwn(buf, wwpn.u.wwn)) + return -EINVAL; + + if ((vport->fc_flag & FC_OFFLINE_MODE) || + (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) || + (!vport->cfg_enable_auth)) + return -EPERM; -static CLASS_DEVICE_ATTR(lpfc_restart_auth, S_IRUGO | S_IWUSR, - NULL, lpfc_restart_auth); + /* If vport already in the middle of authentication do not restart */ + if ((vport->auth.auth_msg_state == LPFC_AUTH_NEGOTIATE) || + (vport->auth.auth_msg_state == LPFC_DHCHAP_CHALLENGE) || + (vport->auth.auth_msg_state == LPFC_DHCHAP_REPLY)) + return -EAGAIN; + + if (wwn_to_u64(wwpn.u.wwn) == AUTH_FABRIC_WWN) + ndlp = lpfc_findnode_did(vport, Fabric_DID); + else + ndlp = lpfc_findnode_wwnn(vport, &wwpn); + if (!ndlp) + return -EPERM; + status = lpfc_get_auth_config(ndlp); + if (status) + return -EPERM; + return strlen(buf); +} +static CLASS_DEVICE_ATTR(lpfc_update_auth_config, S_IRUGO | S_IWUSR, + NULL, lpfc_update_auth_config); /* # lpfc_devloss_tmo: If set, it will hold all I/O errors on devices that @@ -1553,7 +1604,33 @@ LPFC_VPORT_ATTR_R(scan_down, 1, 0, 1, # Set loop mode if you want to run as an NL_Port. Value range is [0,0x6]. # Default value is 0. */ -LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology"); +static int +lpfc_topology_set(struct lpfc_hba *phba, int val) +{ + int err; + uint32_t prev_val; + if (val >= 0 && val <= 6) { + prev_val = phba->cfg_topology; + phba->cfg_topology = val; + err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport)); + if (err) + phba->cfg_topology = prev_val; + return err; + } + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "%d:0467 lpfc_topology attribute cannot be set to %d, " + "allowed range is [0, 6]\n", + phba->brd_no, val); + return -EINVAL; +} +static int lpfc_topology = 0; +module_param(lpfc_topology, int, 0); +MODULE_PARM_DESC(lpfc_topology, "Select Fibre Channel topology"); +lpfc_param_show(topology) +lpfc_param_init(topology, 0, 0, 6) +lpfc_param_store(topology) +static CLASS_DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR, + lpfc_topology_show, lpfc_topology_store); /* # lpfc_link_speed: Link speed selection for initializing the Fibre Channel @@ -1565,6 +1642,36 @@ LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology"); # 8 = 8 Gigabaud # Value range is [0,8]. Default value is 0. */ +static int +lpfc_link_speed_set(struct lpfc_hba *phba, int val) +{ + int err; + uint32_t prev_val; + + if (((val == LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) || + ((val == LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) || + ((val == LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) || + ((val == LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) || + ((val == LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb))) + return -EINVAL; + + if ((val >= 0 && val <= 8) + && (LPFC_LINK_SPEED_BITMAP & (1 << val))) { + prev_val = phba->cfg_link_speed; + phba->cfg_link_speed = val; + err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport)); + if (err) + phba->cfg_link_speed = prev_val; + return err; + } + + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "%d:0469 lpfc_link_speed attribute cannot be set to %d, " + "allowed range is [0, 8]\n", + phba->brd_no, val); + return -EINVAL; +} + static int lpfc_link_speed = 0; module_param(lpfc_link_speed, int, 0); MODULE_PARM_DESC(lpfc_link_speed, "Select link speed"); @@ -1584,7 +1691,10 @@ lpfc_link_speed_init(struct lpfc_hba *phba, int val) phba->cfg_link_speed = 0; return -EINVAL; } -static CLASS_DEVICE_ATTR(lpfc_link_speed, S_IRUGO , lpfc_link_speed_show, NULL); + +lpfc_param_store(link_speed) +static CLASS_DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR, + lpfc_link_speed_show, lpfc_link_speed_store); /* # lpfc_fcp_class: Determines FC class to use for the FCP protocol. @@ -1725,6 +1835,80 @@ static CLASS_DEVICE_ATTR(lpfc_enable_auth, S_IRUGO | S_IWUSR, lpfc_enable_auth_show, lpfc_enable_auth_store); /* +# lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware. +# 0 = HBA resets disabled +# 1 = HBA resets enabled (default) +# Value range is [0,1]. Default value is 1. +*/ +LPFC_ATTR_R(enable_hba_reset, 1, 0, 1, "Enable HBA resets from the driver."); + +/* +# lpfc_enable_hba_heartbeat: Enable HBA heartbeat timer.. +# 0 = HBA Heartbeat disabled +# 1 = HBA Heartbeat enabled (default) +# Value range is [0,1]. Default value is 1. +*/ +LPFC_ATTR_R(enable_hba_heartbeat, 1, 0, 1, "Enable HBA Heartbeat."); + +/* + * lpfc_sg_seg_cnt: Initial Maximum DMA Segment Count + * This value can be set to values between 64 and 256. The default value is + * 64, but may be increased to allow for larger Max I/O sizes. The scsi layer + * will be allowed to request I/Os of sizes up to (MAX_SEG_COUNT * SEG_SIZE). + */ +LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT, + LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count"); + +/* +# lpfc_pci_max_read: Maximum DMA read byte count. This parameter can have +# values 512, 1024, 2048, 4096. Default value is 2048. +*/ +static int lpfc_pci_max_read = 2048; +module_param(lpfc_pci_max_read, int, 0); +MODULE_PARM_DESC(lpfc_pci_max_read, + "Maximum DMA read byte count. Allowed values:" + " 512,1024,2048,4096." ); +static ssize_t +lpfc_pci_max_read_show(struct class_device *cdev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba; + uint32_t val = 0; + val = phba->cfg_pci_max_read; + return snprintf(buf, PAGE_SIZE, "%d\n", val); +} + +static int +lpfc_pci_max_read_init(struct lpfc_hba *phba, int val) +{ + phba->cfg_pci_max_read = 2048; + if ((val == 512) || (val == 1024) || (val == 2048) + || (val == 4096)) + phba->cfg_pci_max_read = val; + return 0; +} + +static int +lpfc_pci_max_read_set(struct lpfc_hba *phba, int val) +{ + uint32_t prev_val; + int ret; + + prev_val = phba->cfg_pci_max_read; + phba->cfg_pci_max_read = val; + if ((ret = lpfc_sli_set_dma_length(phba, 0))) { + phba->cfg_pci_max_read = prev_val; + return ret; + } else + return 0; +} + +lpfc_param_store(pci_max_read) + +static CLASS_DEVICE_ATTR(lpfc_pci_max_read, S_IRUGO | S_IWUSR, + lpfc_pci_max_read_show, lpfc_pci_max_read_store); + +/* # lpfc_dev_loss_initiator: FC transport layer waits for dev_loss timer to # expire for FC Initiators before calling rport dev_loss callback routine # 0 = disabled (dev_loss callback called immediately after rport delete) @@ -1751,6 +1935,7 @@ struct class_device_attribute *lpfc_hba_attrs[] = { &class_device_attr_lpfc_log_verbose, &class_device_attr_lpfc_lun_queue_depth, &class_device_attr_lpfc_hba_queue_depth, + &class_device_attr_lpfc_pci_max_read, &class_device_attr_lpfc_peer_port_login, &class_device_attr_lpfc_nodev_tmo, &class_device_attr_lpfc_devloss_tmo, @@ -1783,7 +1968,8 @@ struct class_device_attribute *lpfc_hba_attrs[] = { &class_device_attr_lpfc_poll_tmo, &class_device_attr_lpfc_use_msi, &class_device_attr_lpfc_enable_auth, - &class_device_attr_lpfc_restart_auth, + &class_device_attr_lpfc_authenticate, + &class_device_attr_lpfc_update_auth_config, &class_device_attr_lpfc_dev_loss_initiator, &class_device_attr_npiv_vports_inuse, &class_device_attr_max_npiv_vports, @@ -1792,6 +1978,9 @@ struct class_device_attribute *lpfc_hba_attrs[] = { &class_device_attr_lpfc_soft_wwnn, &class_device_attr_lpfc_soft_wwpn, &class_device_attr_lpfc_soft_wwn_enable, + &class_device_attr_lpfc_enable_hba_reset, + &class_device_attr_lpfc_enable_hba_heartbeat, + &class_device_attr_lpfc_sg_seg_cnt, NULL, }; @@ -1812,6 +2001,7 @@ struct class_device_attribute *lpfc_hba_attrs_no_npiv[] = { &class_device_attr_lpfc_log_verbose, &class_device_attr_lpfc_lun_queue_depth, &class_device_attr_lpfc_hba_queue_depth, + &class_device_attr_lpfc_pci_max_read, &class_device_attr_lpfc_peer_port_login, &class_device_attr_lpfc_nodev_tmo, &class_device_attr_lpfc_devloss_tmo, @@ -1844,7 +2034,8 @@ struct class_device_attribute *lpfc_hba_attrs_no_npiv[] = { &class_device_attr_lpfc_poll_tmo, &class_device_attr_lpfc_use_msi, &class_device_attr_lpfc_enable_auth, - &class_device_attr_lpfc_restart_auth, + &class_device_attr_lpfc_authenticate, + &class_device_attr_lpfc_update_auth_config, &class_device_attr_lpfc_dev_loss_initiator, &class_device_attr_lpfc_soft_wwnn, &class_device_attr_lpfc_soft_wwpn, @@ -1997,9 +2188,118 @@ sysfs_mbox_idle(struct lpfc_hba *phba, mempool_free(sysfs_mbox->mbox, phba->mbox_mem_pool); } + + if (sysfs_mbox->mbext) + kfree(sysfs_mbox->mbext); + + /* If txmit buffer allocated free txmit buffer */ + if (sysfs_mbox->txmit_buff) { + if (sysfs_mbox->txmit_buff->virt) + __lpfc_mbuf_free(phba, + sysfs_mbox->txmit_buff->virt, + sysfs_mbox->txmit_buff->phys); + kfree(sysfs_mbox->txmit_buff); + } + + /* If rcv buffer allocated free txmit buffer */ + if (sysfs_mbox->rcv_buff) { + if (sysfs_mbox->rcv_buff->virt) + __lpfc_mbuf_free(phba, + sysfs_mbox->rcv_buff->virt, + sysfs_mbox->rcv_buff->phys); + kfree(sysfs_mbox->rcv_buff); + } + kfree(sysfs_mbox); } +static size_t +lpfc_syfs_mbox_copy_rcv_buff(struct lpfc_hba *phba, + struct lpfc_sysfs_mbox *sysfs_mbox, + char *buf, loff_t off, size_t count) +{ + uint32_t size; + spin_lock_irq(&phba->hbalock); + if (!sysfs_mbox->mbox) { + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EAGAIN; + } + + size = sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeSize; + + if ((count + off) > size) { + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -ERANGE; + } + + if (size > LPFC_BPL_SIZE) { + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -ERANGE; + } + + if (sysfs_mbox->extoff != off) { + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EAGAIN; + } + + memcpy(buf, (uint8_t *) sysfs_mbox->rcv_buff->virt + off, count); + sysfs_mbox->extoff = off + count; + + if (sysfs_mbox->extoff >= size) + sysfs_mbox_idle(phba, sysfs_mbox); + + spin_unlock_irq(&phba->hbalock); + + return count; +} + +static size_t +lpfc_syfs_mbox_copy_txmit_buff(struct lpfc_hba *phba, + struct lpfc_sysfs_mbox *sysfs_mbox, + char *buf, loff_t off, size_t count) +{ + uint32_t size; + spin_lock_irq(&phba->hbalock); + if (!sysfs_mbox->mbox || + (sysfs_mbox->offset != MAILBOX_CMD_SIZE)) { + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EAGAIN; + } + + size = sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2.xmit_bde64. + tus.f.bdeSize; + + if ((count + off) > size) { + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -ERANGE; + } + + if (size > LPFC_BPL_SIZE) { + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -ERANGE; + } + + if (sysfs_mbox->extoff != off) { + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EAGAIN; + } + + memcpy((uint8_t *) sysfs_mbox->txmit_buff->virt + off, buf, count); + sysfs_mbox->extoff = off + count; + + spin_unlock_irq(&phba->hbalock); + + return count; +} + static ssize_t sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count) { @@ -2010,9 +2310,8 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count) struct lpfc_hba *phba = vport->phba; struct lpfcMboxq *mbox = NULL; struct lpfc_sysfs_mbox *sysfs_mbox; - - if ((count + off) > MAILBOX_CMD_SIZE) - return -ERANGE; + uint8_t *ext; + uint32_t size; if (off % 4 || count % 4 || (unsigned long)buf % 4) return -EINVAL; @@ -2021,24 +2320,103 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count) return 0; if (off == 0) { - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - memset(mbox, 0, sizeof (LPFC_MBOXQ_t)); - } - - if (off == 0) { sysfs_mbox = lpfc_get_sysfs_mbox(phba, 1); - if (sysfs_mbox == NULL) { - mempool_free(mbox, phba->mbox_mem_pool); + if (sysfs_mbox == NULL) return -ENOMEM; + /* + * If sysfs expect the reading of buffer and + * app doesnot know how to do it, use a different + * context. + */ + if (sysfs_mbox->state == SMBOX_READING_BUFF) { + spin_lock_irq(&phba->hbalock); + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + sysfs_mbox = lpfc_get_sysfs_mbox(phba, 1); + if (sysfs_mbox == NULL) + return -ENOMEM; } } else { sysfs_mbox = lpfc_get_sysfs_mbox(phba, 0); - if (sysfs_mbox == NULL) { - mempool_free(mbox, phba->mbox_mem_pool); + if (sysfs_mbox == NULL) + return -EAGAIN; + } + + spin_lock_irq(&phba->hbalock); + + if (sysfs_mbox->state == SMBOX_WRITING_MBEXT) { + if (!sysfs_mbox->mbox || + (sysfs_mbox->offset != MAILBOX_CMD_SIZE)) { + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EAGAIN; + } + + size = sysfs_mbox->mbox->mb.un.varUpdateCfg.byte_cnt; + + if ((count + off) > size) { + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -ERANGE; + } + + if (size > MAILBOX_EXT_SIZE) { + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -ERANGE; + } + + if (!sysfs_mbox->mbext) { + spin_unlock_irq(&phba->hbalock); + + ext = kzalloc(size, GFP_KERNEL); + if (!ext) { + spin_lock_irq(&phba->hbalock); + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -ENOMEM; + } + + spin_lock_irq(&phba->hbalock); + sysfs_mbox->mbext = ext; + } + + if (sysfs_mbox->extoff != off) { + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); return -EAGAIN; } + + memcpy((uint8_t *) sysfs_mbox->mbext + off, buf, count); + sysfs_mbox->extoff = off + count; + + spin_unlock_irq(&phba->hbalock); + + return count; + } + + spin_unlock_irq(&phba->hbalock); + + if (sysfs_mbox->state == SMBOX_WRITING_BUFF) + return lpfc_syfs_mbox_copy_txmit_buff(phba, + sysfs_mbox, buf, off, count); + + if ((count + off) > MAILBOX_CMD_SIZE) { + spin_lock_irq(&phba->hbalock); + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -ERANGE; + } + + if (off == 0) { + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) { + spin_lock_irq(&phba->hbalock); + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -ENOMEM; + } + memset(mbox, 0, sizeof (LPFC_MBOXQ_t)); } spin_lock_irq(&phba->hbalock); @@ -2064,6 +2442,58 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count) sysfs_mbox->offset = off + count; + if ((sysfs_mbox->offset == MAILBOX_CMD_SIZE) && + (sysfs_mbox->mbox->mb.mbxCommand == MBX_UPDATE_CFG)) { + /* If no extension data just break */ + if (sysfs_mbox->mbox->mb.un.varUpdateCfg.co) + sysfs_mbox->state = SMBOX_WRITING_MBEXT; + } else if ((sysfs_mbox->offset == MAILBOX_CMD_SIZE) && + (sysfs_mbox->mbox->mb.mbxCommand == MBX_RUN_BIU_DIAG64)) { + sysfs_mbox->state = SMBOX_WRITING_BUFF; + spin_unlock_irq(&phba->hbalock); + + /* Allocate txmit buffer */ + sysfs_mbox->txmit_buff = + kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!sysfs_mbox->txmit_buff) { + spin_lock_irq(&phba->hbalock); + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -ENOMEM; + } + INIT_LIST_HEAD(&sysfs_mbox->txmit_buff->list); + sysfs_mbox->txmit_buff->virt = + lpfc_mbuf_alloc(phba, 0, + &(sysfs_mbox->txmit_buff->phys)); + if (!sysfs_mbox->txmit_buff->virt) { + spin_lock_irq(&phba->hbalock); + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -ENOMEM; + } + + /* Allocate rcv buffer */ + sysfs_mbox->rcv_buff = + kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!sysfs_mbox->rcv_buff) { + spin_lock_irq(&phba->hbalock); + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -ENOMEM; + } + INIT_LIST_HEAD(&sysfs_mbox->rcv_buff->list); + sysfs_mbox->rcv_buff->virt = + lpfc_mbuf_alloc(phba, 0, + &(sysfs_mbox->rcv_buff->phys)); + if (!sysfs_mbox->rcv_buff->virt) { + spin_lock_irq(&phba->hbalock); + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -ENOMEM; + } + return count; + } + spin_unlock_irq(&phba->hbalock); return count; @@ -2079,6 +2509,28 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) struct lpfc_hba *phba = vport->phba; int rc; struct lpfc_sysfs_mbox *sysfs_mbox; + ssize_t ret; + sysfs_mbox = lpfc_get_sysfs_mbox(phba, 0); + + if (!sysfs_mbox) + return -EPERM; + + /* + * If sysfs expect the writing of buffer and + * app doesnot know how to do it, fail the mailbox + * command. + */ + if (sysfs_mbox->state == SMBOX_WRITING_BUFF) { + spin_lock_irq(&phba->hbalock); + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EINVAL; + } + if (sysfs_mbox->state == SMBOX_READING_BUFF) { + ret = lpfc_syfs_mbox_copy_rcv_buff(phba, sysfs_mbox, + buf, off, count); + return ret; + } if (off > MAILBOX_CMD_SIZE) return -ERANGE; @@ -2092,21 +2544,18 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) if (off && count == 0) return 0; - sysfs_mbox = lpfc_get_sysfs_mbox(phba, 0); - - if (!sysfs_mbox) - return -EPERM; - spin_lock_irq(&phba->hbalock); if (phba->over_temp_state == HBA_OVER_TEMP) { sysfs_mbox_idle(phba, sysfs_mbox); spin_unlock_irq(&phba->hbalock); - return -EPERM; + return -EACCES; } if (off == 0 && - sysfs_mbox->state == SMBOX_WRITING && + ((sysfs_mbox->state == SMBOX_WRITING) || + (sysfs_mbox->state == SMBOX_WRITING_MBEXT) || + (sysfs_mbox->state == SMBOX_WRITING_BUFF) ) && sysfs_mbox->offset >= 2 * sizeof(uint32_t)) { switch (sysfs_mbox->mbox->mb.mbxCommand) { @@ -2121,9 +2570,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) case MBX_DUMP_CONTEXT: case MBX_RUN_DIAGS: case MBX_RESTART: - case MBX_FLASH_WR_ULA: case MBX_SET_MASK: - case MBX_SET_SLIM: if (!(vport->fc_flag & FC_OFFLINE_MODE)) { printk(KERN_WARNING "mbox_read:Command 0x%x " "is illegal in on-line state\n", @@ -2144,14 +2591,50 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) case MBX_READ_LNK_STAT: case MBX_DUMP_MEMORY: case MBX_DOWN_LOAD: - case MBX_UPDATE_CFG: case MBX_KILL_BOARD: case MBX_LOAD_AREA: case MBX_LOAD_EXP_ROM: case MBX_BEACON: case MBX_DEL_LD_ENTRY: case MBX_SET_DEBUG: + case MBX_SET_VARIABLE: + case MBX_WRITE_WWN: + break; + case MBX_UPDATE_CFG: + if (sysfs_mbox->state == SMBOX_WRITING_MBEXT) { + if (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE)) { + sysfs_mbox_idle(phba, sysfs_mbox); + spin_unlock_irq(&phba->hbalock); + return -EPERM; + } + sysfs_mbox->mbox->context2 = sysfs_mbox->mbext; + } + break; + case MBX_RUN_BIU_DIAG64: + if (sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2. + xmit_bde64.tus.f.bdeSize) { + sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2. + xmit_bde64.addrHigh = + putPaddrHigh(sysfs_mbox-> + txmit_buff->phys); + sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2. + xmit_bde64.addrLow = + putPaddrLow(sysfs_mbox-> + txmit_buff->phys); + } + + if (sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2. + rcv_bde64.tus.f.bdeSize) { + sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2. + rcv_bde64.addrHigh = + putPaddrHigh(sysfs_mbox-> + rcv_buff->phys); + sysfs_mbox->mbox->mb.un.varBIUdiag.un.s2. + rcv_bde64.addrLow = + putPaddrLow(sysfs_mbox->rcv_buff->phys); + } break; + case MBX_READ_SPARM64: case MBX_READ_LA: case MBX_READ_LA64: @@ -2219,6 +2702,14 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count) sysfs_mbox->offset = off + count; + if ((sysfs_mbox->offset == MAILBOX_CMD_SIZE) && + (sysfs_mbox->mbox->mb.mbxCommand == MBX_RUN_BIU_DIAG64)) { + sysfs_mbox->state = SMBOX_READING_BUFF; + sysfs_mbox->extoff = 0; + spin_unlock_irq(&phba->hbalock); + return count; + } + if (sysfs_mbox->offset == MAILBOX_CMD_SIZE) sysfs_mbox_idle(phba,sysfs_mbox); @@ -2233,7 +2724,7 @@ static struct bin_attribute sysfs_mbox_attr = { .mode = S_IRUSR | S_IWUSR, .owner = THIS_MODULE, }, - .size = MAILBOX_CMD_SIZE, + .size = MAILBOX_MAX_XMIT_SIZE, .read = sysfs_mbox_read, .write = sysfs_mbox_write, }; @@ -2372,7 +2863,8 @@ lpfc_get_host_speed(struct Scsi_Host *shost) fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; break; } - } + } else + fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; spin_unlock_irq(shost->host_lock); } @@ -2392,7 +2884,7 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost) node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn); else /* fabric is local port if there is no F/FL_Port */ - node_name = wwn_to_u64(vport->fc_nodename.u.wwn); + node_name = 0; spin_unlock_irq(shost->host_lock); @@ -2785,26 +3277,29 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_multi_ring_type_init(phba, lpfc_multi_ring_type); lpfc_ack0_init(phba, lpfc_ack0); lpfc_topology_init(phba, lpfc_topology); + lpfc_pci_max_read_init(phba, lpfc_pci_max_read); lpfc_link_speed_init(phba, lpfc_link_speed); lpfc_poll_tmo_init(phba, lpfc_poll_tmo); lpfc_enable_npiv_init(phba, lpfc_enable_npiv); lpfc_use_msi_init(phba, lpfc_use_msi); + lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset); + lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat); lpfc_dev_loss_initiator_init(phba, lpfc_dev_loss_initiator); phba->cfg_poll = lpfc_poll; phba->cfg_soft_wwnn = 0L; phba->cfg_soft_wwpn = 0L; - /* - * The total number of segments is the configuration value plus 2 - * since the IOCB need a command and response bde. - */ - phba->cfg_sg_seg_cnt = LPFC_SG_SEG_CNT + 2; + lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); + /* Also reinitialize the host templates with new values. */ + lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt; + lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt; /* * Since the sg_tablesize is module parameter, the sg_dma_buf_size - * used to create the sg_dma_buf_pool must be dynamically calculated + * used to create the sg_dma_buf_pool must be dynamically calculated. + * 2 segments are added since the IOCB needs a command and response bde. */ phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp) + - (phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64)); + ((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64)); lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); return; } diff --git a/drivers/scsi/lpfc/lpfc_auth.c b/drivers/scsi/lpfc/lpfc_auth.c index 6141c3c..de1f79a 100644 --- a/drivers/scsi/lpfc/lpfc_auth.c +++ b/drivers/scsi/lpfc/lpfc_auth.c @@ -17,7 +17,7 @@ * more details, a copy of which can be found in the file COPYING * * included with this package. * *******************************************************************/ - +/* See Fibre Channel protocol T11 FC-SP for details */ #include <linux/pci.h> #include <linux/interrupt.h> @@ -185,22 +185,22 @@ lpfc_unpack_auth_negotiate(struct lpfc_vport *vport, uint8_t *message, uint32_t param_len; int i, j = 0; - /* Following is the format of the message. + /* Following is the format of the message. Name Format. * uint16_t nameTag; * uint16_t nameLength; * uint8_t name[8]; + * AUTH_Negotiate Message * uint32_t NumberOfAuthProtocals * uint32_t AuthProtParameter#1Len * uint32_t AuthProtID#1 (DH-CHAP = 0x1) - + * AUTH_Negotiate DH-CHAP * uint16_t DH-CHAPParameterTag (HashList = 0x1) * uint16_t DH-CHAPParameterWordCount (number of uint32_t entries) - * uint8_t DH-CHAPParameter[]; - + * uint8_t DH-CHAPParameter[]; (uint32_t entries) * uint16_t DH-CHAPParameterTag (DHglDList = 0x2) * uint16_t DH-CHAPParameterWordCount (number of uint32_t entries) - * uint8_t DH-CHAPParameter[]; - + * uint8_t DH-CHAPParameter[]; (uint32_t entries) + * DHCHAP_Challenge Message * uint32_t hashIdentifier; * uint32_t dhgroupIdentifier; * uint32_t challengevalueLen; @@ -231,10 +231,10 @@ lpfc_unpack_auth_negotiate(struct lpfc_vport *vport, uint8_t *message, } message += sizeof(uint16_t); - /* Remote Port Name */ + /* Skip over Remote Port Name */ message += NAME_LEN; - /* Number of Auth Protocols */ + /* Number of Auth Protocols must be 1 DH-CHAP */ if (be32_to_cpu(*(uint32_t *)message) != 1) { *reason = AUTH_ERR; *explanation = BAD_PAYLOAD; @@ -249,7 +249,7 @@ lpfc_unpack_auth_negotiate(struct lpfc_vport *vport, uint8_t *message, prot_len = be32_to_cpu(*(uint32_t *)message); message += sizeof(uint32_t); - /* Protocol Paramter type */ + /* Protocol Parameter type */ if (be32_to_cpu(*(uint32_t *)message) != FC_DHCHAP) { *reason = AUTH_ERR; *explanation = BAD_PAYLOAD; @@ -266,7 +266,7 @@ lpfc_unpack_auth_negotiate(struct lpfc_vport *vport, uint8_t *message, *explanation = BAD_PAYLOAD; lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, "1010 Bad Tag 1 0x%x\n", - be32_to_cpu(*(uint16_t *)message)); + be16_to_cpu(*(uint16_t *)message)); return 1; } message += sizeof(uint16_t); @@ -295,13 +295,13 @@ lpfc_unpack_auth_negotiate(struct lpfc_vport *vport, uint8_t *message, vport->auth.hash_id = vport->auth.hash_priority[i]; message += sizeof(uint32_t) * param_len; - /* Parameter #2 Tag*/ + /* Parameter #2 Tag */ if (be16_to_cpu(*(uint16_t *)message) != DHGID_LIST_TAG) { *reason = AUTH_ERR; *explanation = BAD_PAYLOAD; lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, "1012 Auth_negotiate Bad Tag 2 0x%x\n", - be32_to_cpu(*(uint16_t *)message)); + be16_to_cpu(*(uint16_t *)message)); return 1; } message += sizeof(uint16_t); @@ -339,7 +339,7 @@ lpfc_unpack_dhchap_challenge(struct lpfc_vport *vport, uint8_t *message, { int i; - /* Following is the format of the message. + /* Following is the format of the message DHCHAP_Challenge. * uint16_t nameTag; * uint16_t nameLength; * uint8_t name[8]; @@ -461,7 +461,7 @@ lpfc_unpack_dhchap_reply(struct lpfc_vport *vport, uint8_t *message, uint32_t dh_len; uint32_t challenge_len; - /* Following is the format of the message. + /* Following is the format of the message DHCHAP_Reply. * uint32_t Response Value Length; * uint8_t Response Value[]; * uint32_t DH Value Length; @@ -501,9 +501,9 @@ lpfc_unpack_dhchap_success(struct lpfc_vport *vport, uint8_t *message, { uint32_t rsp_len = 0; - /* + /* DHCHAP_Success. * uint32_t responseValueLen; - * uint8_t response[]; + * uint8_t response[]; */ rsp_len = be32_to_cpu(*(uint32_t *)message); /* Response Len */ @@ -538,7 +538,7 @@ lpfc_build_auth_neg(struct lpfc_vport *vport, uint8_t *message) /* Because some of the fields are not static in length * and number we will pack on the fly.This will be expanded * in the future to optionally offer DHCHAP or FCAP or both. - * The packing is done in Big Endian byte order. + * The packing is done in Big Endian byte order DHCHAP_Reply. * * uint16_t nameTag; * uint16_t nameLength; @@ -644,7 +644,7 @@ lpfc_build_dhchap_challenge(struct lpfc_vport *vport, uint8_t *message, /* Because some of the fields are not static in length and number * we will pack on the fly. The packing is done in Big Endian byte - * order. + * order DHCHAP_Challenge. * * uint16_t nameTag; * uint16_t nameLength; @@ -654,7 +654,7 @@ lpfc_build_dhchap_challenge(struct lpfc_vport *vport, uint8_t *message, * uint32_t Challenge_Value_Length; * uint8_t Challenge_Value[]; * uint32_t DH_Value_Length; - * uint8_t DH_Value[]; + * uint8_t DH_Value[]; */ /* Name Tag */ @@ -724,7 +724,7 @@ lpfc_build_dhchap_reply(struct lpfc_vport *vport, uint8_t *message, /* * Because some of the fields are not static in length and * number we will pack on the fly. The packing is done in - * Big Endian byte order. + * Big Endian byte order DHCHAP_Reply. * * uint32_t ResonseLength; * uint8_t ResponseValue[]; @@ -741,22 +741,22 @@ lpfc_build_dhchap_reply(struct lpfc_vport *vport, uint8_t *message, * ( g^y mod p ) is our public key which we send. * ( g^x mod p ) is their public key which we received. */ - + /* Response Value Length */ *((uint32_t *)message) = cpu_to_be32(fc_rsp->u.dhchap_reply. our_challenge_rsp_len); message += sizeof(uint32_t); - + /* Response Value */ memcpy(message, fc_rsp->u.dhchap_reply.data, fc_rsp->u.dhchap_reply.our_challenge_rsp_len); message += fc_rsp->u.dhchap_reply.our_challenge_rsp_len; - + /* DH Value Length */ *((uint32_t *)message) = cpu_to_be32(fc_rsp->u.dhchap_reply. our_public_key_len); message += sizeof(uint32_t); - + /* DH Value */ memcpy(message, fc_rsp->u.dhchap_reply.data + fc_rsp->u.dhchap_reply.our_challenge_rsp_len, fc_rsp->u.dhchap_reply.our_public_key_len); @@ -779,11 +779,11 @@ lpfc_build_dhchap_reply(struct lpfc_vport *vport, uint8_t *message, fc_rsp->u.dhchap_reply.our_challenge_rsp_len + fc_rsp->u.dhchap_reply.our_public_key_len, fc_rsp->u.dhchap_reply.our_challenge_len); - + /* Challenge Value Length */ *((uint32_t *)message) = cpu_to_be32(fc_rsp->u. dhchap_reply.our_challenge_len); message += sizeof(uint32_t); - + /* Challenge Value */ memcpy(message, fc_rsp->u.dhchap_reply.data + fc_rsp->u.dhchap_reply.our_challenge_rsp_len + fc_rsp->u.dhchap_reply.our_public_key_len, @@ -810,7 +810,9 @@ lpfc_build_dhchap_success(struct lpfc_vport *vport, uint8_t *message, /* * Because some of the fields are not static in length and number * we will pack on the fly. The packing is done in Big Endian byte - * order. + * order DHCHAP_Success. + * uint32_t responseValueLen; + * uint8_t response[];. */ *((uint32_t *)message) = cpu_to_be32(fc_rsp->u. diff --git a/drivers/scsi/lpfc/lpfc_auth_access.h b/drivers/scsi/lpfc/lpfc_auth_access.h index 9cbe1d5..a57f3ba 100644 --- a/drivers/scsi/lpfc/lpfc_auth_access.h +++ b/drivers/scsi/lpfc/lpfc_auth_access.h @@ -20,27 +20,6 @@ #define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t) -#define NLMSG_ALIGNTO 4 -#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) -#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) -#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN)) -#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) -#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) -#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ - (struct nlmsghdr*)(((char*)(nlh)) + \ - NLMSG_ALIGN((nlh)->nlmsg_len))) -#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \ - (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ - (nlh)->nlmsg_len <= (len)) -#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) - -#define NLMSG_NOOP 0x1 /* Nothing. */ -#define NLMSG_ERROR 0x2 /* Error */ -#define NLMSG_DONE 0x3 /* End of a dump */ -#define NLMSG_OVERRUN 0x4 /* Data lost */ - -#define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */ - /* scsi_nl_hdr->version value */ #define SCSI_NL_VERSION 1 diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 663c263..52df6e2 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -42,6 +42,7 @@ void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *); int lpfc_reg_login(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *, LPFC_MBOXQ_t *, uint32_t); +void lpfc_set_var(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); @@ -102,6 +103,9 @@ void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *); int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, struct serv_parm *, uint32_t); int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); +void lpfc_more_plogi(struct lpfc_vport *); +void lpfc_more_adisc(struct lpfc_vport *); +void lpfc_end_rscn(struct lpfc_vport *); int lpfc_els_chk_latt(struct lpfc_vport *); struct lpfc_iocbq *lpfc_prep_els_iocb(struct lpfc_vport *, uint8_t, uint16_t, uint8_t, struct lpfc_nodelist *, uint32_t, @@ -168,6 +172,7 @@ void lpfc_offline(struct lpfc_hba *); int lpfc_sli_setup(struct lpfc_hba *); int lpfc_sli_queue_setup(struct lpfc_hba *); +int lpfc_sli_set_dma_length(struct lpfc_hba *, uint32_t); void lpfc_handle_eratt(struct lpfc_hba *); void lpfc_handle_latt(struct lpfc_hba *); @@ -223,6 +228,11 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, struct lpfc_sli_ring *, dma_addr_t); + +uint32_t lpfc_sli_get_buffer_tag(struct lpfc_hba *); +struct lpfc_dmabuf * lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *, + struct lpfc_sli_ring *, uint32_t ); + int lpfc_sli_hbq_count(void); int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t); int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t); @@ -288,12 +298,13 @@ void lpfc_terminate_rport_io(struct fc_rport *); void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport); struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct device *); -void lpfc_mbx_unreg_vpi(struct lpfc_vport *); +int lpfc_mbx_unreg_vpi(struct lpfc_vport *); void destroy_port(struct lpfc_vport *); int lpfc_get_instance(void); void lpfc_host_attrib_init(struct Scsi_Host *); -int lpfc_security_wait(void); +int lpfc_selective_reset(struct lpfc_hba *); +int lpfc_security_wait(struct lpfc_hba *); int lpfc_get_security_enabled(struct Scsi_Host *); void lpfc_security_service_online(struct Scsi_Host *); void lpfc_security_service_offline(struct Scsi_Host *); @@ -303,6 +314,7 @@ void lpfc_dhchap_make_challenge(struct Scsi_Host *, int , void *, uint32_t); void lpfc_dhchap_make_response(struct Scsi_Host *, int , void *, uint32_t); void lpfc_dhchap_authenticate(struct Scsi_Host *, int , void *, uint32_t); int lpfc_start_node_authentication(struct lpfc_nodelist *); +int lpfc_get_auth_config(struct lpfc_nodelist *); void lpfc_start_discovery(struct lpfc_vport *vport); void lpfc_start_authentication(struct lpfc_vport *, struct lpfc_nodelist *); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 3b0dd49..bbce374 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -19,7 +19,7 @@ *******************************************************************/ /* - * Fibre Channel SCSI LAN Device Driver CT support + * Fibre Channel SCSI LAN Device Driver CT support: FC Generic Services FC-GS */ #include <linux/blkdev.h> @@ -57,45 +57,27 @@ static char *lpfc_release_version = LPFC_DRIVER_VERSION; -/* - * lpfc_ct_unsol_event - */ static void -lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, - struct lpfc_dmabuf *mp, uint32_t size) +lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, + struct lpfc_dmabuf *mp, uint32_t size) { if (!mp) { - printk(KERN_ERR "%s (%d): Unsolited CT, no buffer, " - "piocbq = %p, status = x%x, mp = %p, size = %d\n", - __FUNCTION__, __LINE__, - piocbq, piocbq->iocb.ulpStatus, mp, size); + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "0146 Ignoring unsolicted CT No HBQ " + "status = x%x\n", + piocbq->iocb.ulpStatus); } - - printk(KERN_ERR "%s (%d): Ignoring unsolicted CT piocbq = %p, " - "buffer = %p, size = %d, status = x%x\n", - __FUNCTION__, __LINE__, - piocbq, mp, size, - piocbq->iocb.ulpStatus); - + lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + "0145 Ignoring unsolicted CT HBQ Size:%d " + "status = x%x\n", + piocbq->iocb.ulpStatus, size); } static void -lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, - struct lpfc_dmabuf *mp, uint32_t size) +lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, + struct lpfc_dmabuf *mp, uint32_t size) { - if (!mp) { - printk(KERN_ERR "%s (%d): Unsolited CT, no " - "HBQ buffer, piocbq = %p, status = x%x\n", - __FUNCTION__, __LINE__, - piocbq, piocbq->iocb.ulpStatus); - } else { - lpfc_ct_unsol_buffer(phba, piocbq, mp, size); - printk(KERN_ERR "%s (%d): Ignoring unsolicted CT " - "piocbq = %p, buffer = %p, size = %d, " - "status = x%x\n", - __FUNCTION__, __LINE__, - piocbq, mp, size, piocbq->iocb.ulpStatus); - } + lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size); } void @@ -109,11 +91,8 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *iocbq; dma_addr_t paddr; uint32_t size; - struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; - struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; - - piocbq->context2 = NULL; - piocbq->context3 = NULL; + struct list_head head; + struct lpfc_dmabuf *bdeBuf; if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) { lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); @@ -133,38 +112,34 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return; if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - list_for_each_entry(iocbq, &piocbq->list, list) { + INIT_LIST_HEAD(&head); + list_add_tail(&head, &piocbq->list); + list_for_each_entry(iocbq, &head, list) { icmd = &iocbq->iocb; - if (icmd->ulpBdeCount == 0) { - printk(KERN_ERR "%s (%d): Unsolited CT, no " - "BDE, iocbq = %p, status = x%x\n", - __FUNCTION__, __LINE__, - iocbq, iocbq->iocb.ulpStatus); + if (icmd->ulpBdeCount == 0) continue; - } - + bdeBuf = iocbq->context2; + iocbq->context2 = NULL; size = icmd->un.cont64[0].tus.f.bdeSize; - lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf1, size); - lpfc_in_buf_free(phba, bdeBuf1); + lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size); + lpfc_in_buf_free(phba, bdeBuf); if (icmd->ulpBdeCount == 2) { - lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf2, - size); - lpfc_in_buf_free(phba, bdeBuf2); + bdeBuf = iocbq->context3; + iocbq->context3 = NULL; + size = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize; + lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, + size); + lpfc_in_buf_free(phba, bdeBuf); } } + list_del(&head); } else { struct lpfc_iocbq *next; list_for_each_entry_safe(iocbq, next, &piocbq->list, list) { icmd = &iocbq->iocb; - if (icmd->ulpBdeCount == 0) { - printk(KERN_ERR "%s (%d): Unsolited CT, no " - "BDE, iocbq = %p, status = x%x\n", - __FUNCTION__, __LINE__, - iocbq, iocbq->iocb.ulpStatus); - continue; - } - + if (icmd->ulpBdeCount == 0) + lpfc_ct_unsol_buffer(phba, piocbq, NULL, 0); for (i = 0; i < icmd->ulpBdeCount; i++) { paddr = getPaddr(icmd->un.cont64[i].addrHigh, icmd->un.cont64[i].addrLow); @@ -203,7 +178,7 @@ lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl, struct lpfc_dmabuf *mp; int cnt, i = 0; - /* We get chucks of FCELSSIZE */ + /* We get chunks of FCELSSIZE */ cnt = size > FCELSSIZE ? FCELSSIZE: size; while (size) { @@ -426,6 +401,7 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) lpfc_set_disctmo(vport); vport->num_disc_nodes = 0; + vport->fc_ns_retry = 0; list_add_tail(&head, &mp->list); @@ -506,7 +482,17 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) Did, vport->fc_flag, vport->fc_rscn_id_cnt); - if (lpfc_ns_cmd(vport, + /* This NPortID was previously + * a FCP target, * Don't even + * bother to send GFF_ID. + */ + ndlp = lpfc_findnode_did(vport, + Did); + if (ndlp && (ndlp->nlp_type & + NLP_FCP_TARGET)) + lpfc_setup_disc_node + (vport, Did); + else if (lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID, 0, Did) == 0) vport->num_disc_nodes++; @@ -554,7 +540,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_dmabuf *outp; struct lpfc_sli_ct_request *CTrsp; struct lpfc_nodelist *ndlp; - int rc; + int rc, retry; /* First save ndlp, before we overwrite it */ ndlp = cmdiocb->context_un.ndlp; @@ -585,14 +571,35 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (irsp->ulpStatus) { /* Check for retry */ if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { - if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) || - (irsp->un.ulpWord[4] != IOERR_NO_RESOURCES)) + retry = 1; + if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { + switch (irsp->un.ulpWord[4]) { + case IOERR_NO_RESOURCES: + /* We don't increment the retry + * count for this case. + */ + break; + case IOERR_LINK_DOWN: + case IOERR_SLI_ABORTED: + case IOERR_SLI_DOWN: + retry = 0; + break; + default: + vport->fc_ns_retry++; + } + } + else vport->fc_ns_retry++; - /* CT command is being retried */ - rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, + + if (retry) { + /* CT command is being retried */ + rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, vport->fc_ns_retry, 0); - if (rc == 0) - goto out; + if (rc == 0) { + /* success */ + goto out; + } + } } lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, @@ -698,7 +705,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1; struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2; struct lpfc_sli_ct_request *CTrsp; - int did; + int did, rc, retry; uint8_t fbits; struct lpfc_nodelist *ndlp; @@ -729,6 +736,39 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } } else { + /* Check for retry */ + if (cmdiocb->retry < LPFC_MAX_NS_RETRY) { + retry = 1; + if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { + switch (irsp->un.ulpWord[4]) { + case IOERR_NO_RESOURCES: + /* We don't increment the retry + * count for this case. + */ + break; + case IOERR_LINK_DOWN: + case IOERR_SLI_ABORTED: + case IOERR_SLI_DOWN: + retry = 0; + break; + default: + cmdiocb->retry++; + } + } + else + cmdiocb->retry++; + + if (retry) { + /* CT command is being retried */ + rc = lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID, + cmdiocb->retry, did); + if (rc == 0) { + /* success */ + lpfc_ct_free_iocb(phba, cmdiocb); + return; + } + } + } lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, "0267 NameServer GFF Rsp " "x%x Error (%d %d) Data: x%x x%x\n", @@ -1110,7 +1150,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, case SLI_CTNS_GFF_ID: CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_GFF_ID); - CtReq->un.gff.PortId = be32_to_cpu(context); + CtReq->un.gff.PortId = cpu_to_be32(context); cmpl = lpfc_cmpl_ct_cmd_gff_id; break; @@ -1118,7 +1158,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, vport->ct_flags &= ~FC_CT_RFT_ID; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RFT_ID); - CtReq->un.rft.PortId = be32_to_cpu(vport->fc_myDID); + CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID); CtReq->un.rft.fcpReg = 1; cmpl = lpfc_cmpl_ct_cmd_rft_id; break; @@ -1127,7 +1167,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, vport->ct_flags &= ~FC_CT_RNN_ID; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RNN_ID); - CtReq->un.rnn.PortId = be32_to_cpu(vport->fc_myDID); + CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID); memcpy(CtReq->un.rnn.wwnn, &vport->fc_nodename, sizeof (struct lpfc_name)); cmpl = lpfc_cmpl_ct_cmd_rnn_id; @@ -1137,7 +1177,7 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, vport->ct_flags &= ~FC_CT_RSPN_ID; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RSPN_ID); - CtReq->un.rspn.PortId = be32_to_cpu(vport->fc_myDID); + CtReq->un.rspn.PortId = cpu_to_be32(vport->fc_myDID); size = sizeof(CtReq->un.rspn.symbname); CtReq->un.rspn.len = lpfc_vport_symbolic_port_name(vport, @@ -1160,14 +1200,14 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, /* Implement DA_ID Nameserver request */ CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_DA_ID); - CtReq->un.da_id.port_id = be32_to_cpu(vport->fc_myDID); + CtReq->un.da_id.port_id = cpu_to_be32(vport->fc_myDID); cmpl = lpfc_cmpl_ct_cmd_da_id; break; case SLI_CTNS_RFF_ID: vport->ct_flags &= ~FC_CT_RFF_ID; CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_CTNS_RFF_ID); - CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);; + 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; cmpl = lpfc_cmpl_ct_cmd_rff_id; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 0929c0e..783d1ee 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -43,7 +43,7 @@ #include "lpfc_crtn.h" #include "lpfc_vport.h" #include "lpfc_version.h" -#include "lpfc_vport.h" +#include "lpfc_compat.h" #include "lpfc_debugfs.h" #ifdef CONFIG_LPFC_DEBUG_FS @@ -76,18 +76,18 @@ module_param(lpfc_debugfs_enable, int, 0); MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services"); /* This MUST be a power of 2 */ -static int lpfc_debugfs_max_disc_trc = 0; +static int lpfc_debugfs_max_disc_trc; module_param(lpfc_debugfs_max_disc_trc, int, 0); MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc, "Set debugfs discovery trace depth"); /* This MUST be a power of 2 */ -static int lpfc_debugfs_max_slow_ring_trc = 0; +static int lpfc_debugfs_max_slow_ring_trc; module_param(lpfc_debugfs_max_slow_ring_trc, int, 0); MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc, "Set debugfs slow ring trace depth"); -static int lpfc_debugfs_mask_disc_trc = 0; +int lpfc_debugfs_mask_disc_trc; module_param(lpfc_debugfs_mask_disc_trc, int, 0); MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc, "Set debugfs discovery trace mask"); @@ -101,8 +101,11 @@ MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc, #define LPFC_NODELIST_SIZE 8192 #define LPFC_NODELIST_ENTRY_SIZE 120 -/* dumpslim output buffer size */ -#define LPFC_DUMPSLIM_SIZE 4096 +/* dumpHBASlim output buffer size */ +#define LPFC_DUMPHBASLIM_SIZE 4096 + +/* dumpHostSlim output buffer size */ +#define LPFC_DUMPHOSTSLIM_SIZE 4096 /* hbqinfo output buffer size */ #define LPFC_HBQINFO_SIZE 8192 @@ -299,18 +302,58 @@ skipit: return len; } +static int lpfc_debugfs_last_hba_slim_off; + +static int +lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size) +{ + int len = 0; + int i, off; + uint32_t *ptr; + char buffer[1024]; + + off = 0; + spin_lock_irq(&phba->hbalock); + + len += snprintf(buf+len, size-len, "HBA SLIM\n"); + lpfc_memcpy_from_slim(buffer, + ((uint8_t *)phba->MBslimaddr) + lpfc_debugfs_last_hba_slim_off, + 1024); + + ptr = (uint32_t *)&buffer[0]; + off = lpfc_debugfs_last_hba_slim_off; + + /* Set it up for the next time */ + lpfc_debugfs_last_hba_slim_off += 1024; + if (lpfc_debugfs_last_hba_slim_off >= 4096) + lpfc_debugfs_last_hba_slim_off = 0; + + i = 1024; + while (i > 0) { + len += snprintf(buf+len, size-len, + "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", + off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), + *(ptr+5), *(ptr+6), *(ptr+7)); + ptr += 8; + i -= (8 * sizeof(uint32_t)); + off += (8 * sizeof(uint32_t)); + } + + spin_unlock_irq(&phba->hbalock); + return len; +} + static int -lpfc_debugfs_dumpslim_data(struct lpfc_hba *phba, char *buf, int size) +lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) { int len = 0; - int cnt, i, off; + int i, off; uint32_t word0, word1, word2, word3; uint32_t *ptr; struct lpfc_pgp *pgpp; struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; - cnt = LPFC_DUMPSLIM_SIZE; off = 0; spin_lock_irq(&phba->hbalock); @@ -622,7 +665,34 @@ out: } static int -lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file) +lpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file) +{ + struct lpfc_hba *phba = inode->i_private; + struct lpfc_debug *debug; + int rc = -ENOMEM; + + debug = kmalloc(sizeof(*debug), GFP_KERNEL); + if (!debug) + goto out; + + /* Round to page boundry */ + debug->buffer = kmalloc(LPFC_DUMPHBASLIM_SIZE, GFP_KERNEL); + if (!debug->buffer) { + kfree(debug); + goto out; + } + + debug->len = lpfc_debugfs_dumpHBASlim_data(phba, debug->buffer, + LPFC_DUMPHBASLIM_SIZE); + file->private_data = debug; + + rc = 0; +out: + return rc; +} + +static int +lpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file) { struct lpfc_hba *phba = inode->i_private; struct lpfc_debug *debug; @@ -633,14 +703,14 @@ lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file) goto out; /* Round to page boundry */ - debug->buffer = kmalloc(LPFC_DUMPSLIM_SIZE, GFP_KERNEL); + debug->buffer = kmalloc(LPFC_DUMPHOSTSLIM_SIZE, GFP_KERNEL); if (!debug->buffer) { kfree(debug); goto out; } - debug->len = lpfc_debugfs_dumpslim_data(phba, debug->buffer, - LPFC_DUMPSLIM_SIZE); + debug->len = lpfc_debugfs_dumpHostSlim_data(phba, debug->buffer, + LPFC_DUMPHOSTSLIM_SIZE); file->private_data = debug; rc = 0; @@ -743,10 +813,19 @@ static struct file_operations lpfc_debugfs_op_hbqinfo = { .release = lpfc_debugfs_release, }; -#undef lpfc_debugfs_op_dumpslim -static struct file_operations lpfc_debugfs_op_dumpslim = { +#undef lpfc_debugfs_op_dumpHBASlim +static struct file_operations lpfc_debugfs_op_dumpHBASlim = { + .owner = THIS_MODULE, + .open = lpfc_debugfs_dumpHBASlim_open, + .llseek = lpfc_debugfs_lseek, + .read = lpfc_debugfs_read, + .release = lpfc_debugfs_release, +}; + +#undef lpfc_debugfs_op_dumpHostSlim +static struct file_operations lpfc_debugfs_op_dumpHostSlim = { .owner = THIS_MODULE, - .open = lpfc_debugfs_dumpslim_open, + .open = lpfc_debugfs_dumpHostSlim_open, .llseek = lpfc_debugfs_lseek, .read = lpfc_debugfs_read, .release = lpfc_debugfs_release, @@ -814,15 +893,27 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) goto debug_failed; } - /* Setup dumpslim */ - snprintf(name, sizeof(name), "dumpslim"); - phba->debug_dumpslim = + /* Setup dumpHBASlim */ + snprintf(name, sizeof(name), "dumpHBASlim"); + phba->debug_dumpHBASlim = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dumpHBASlim); + if (!phba->debug_dumpHBASlim) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0409 Cannot create debugfs dumpHBASlim\n"); + goto debug_failed; + } + + /* Setup dumpHostSlim */ + snprintf(name, sizeof(name), "dumpHostSlim"); + phba->debug_dumpHostSlim = debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dumpslim); - if (!phba->debug_dumpslim) { + phba, &lpfc_debugfs_op_dumpHostSlim); + if (!phba->debug_dumpHostSlim) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0409 Cannot create debugfs dumpslim\n"); + "0409 Cannot create debugfs dumpHostSlim\n"); goto debug_failed; } @@ -903,7 +994,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) } } - vport->disc_trc = kmalloc( + vport->disc_trc = kzalloc( (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc), GFP_KERNEL); @@ -914,8 +1005,6 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) goto debug_failed; } atomic_set(&vport->disc_trc_cnt, 0); - memset(vport->disc_trc, 0, - (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc)); snprintf(name, sizeof(name), "discovery_trace"); vport->debug_disc_trc = @@ -974,9 +1063,13 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */ phba->debug_hbqinfo = NULL; } - if (phba->debug_dumpslim) { - debugfs_remove(phba->debug_dumpslim); /* dumpslim */ - phba->debug_dumpslim = NULL; + if (phba->debug_dumpHBASlim) { + debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */ + phba->debug_dumpHBASlim = NULL; + } + if (phba->debug_dumpHostSlim) { + debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */ + phba->debug_dumpHostSlim = NULL; } if (phba->slow_ring_trc) { kfree(phba->slow_ring_trc); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 94138fb..7ed27c3 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -18,7 +18,7 @@ * more details, a copy of which can be found in the file COPYING * * included with this package. * *******************************************************************/ - +/* See Fibre Channel protocol T11 FC-LS for details */ #include <linux/blkdev.h> #include <linux/pci.h> #include <linux/interrupt.h> @@ -386,11 +386,12 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { lpfc_mbx_unreg_vpi(vport); + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); } } - ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID; lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED && @@ -478,6 +479,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_nlp_put(ndlp); } + /* If we are pt2pt with another NPort, force NPIV off! */ + phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_PT2PT; spin_unlock_irq(shost->host_lock); @@ -565,8 +569,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_printf_log(vport->phba, KERN_WARNING, LOG_SECURITY, - "%d:1030 Security config request: no buffers\n", - vport->phba->brd_no); + "1030 Security config request: no buffers\n"); phba->link_state = LPFC_HBA_ERROR; goto flogifail; } @@ -802,11 +805,11 @@ lpfc_initial_fdisc(struct lpfc_vport *vport) struct lpfc_nodelist *ndlp; if (vport->cfg_enable_auth) { - lpfc_security_wait(); - if (lpfc_security_service_state == SECURITY_OFFLINE) { + if (lpfc_security_wait(phba)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, - "1049 Security is enabled but no " - "security service!\n"); + "1049 Authentication is enabled but " + "authentication service is not " + "running\n"); vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN; return 0; } @@ -828,7 +831,8 @@ lpfc_initial_fdisc(struct lpfc_vport *vport) } return 1; } -static void + +void lpfc_more_plogi(struct lpfc_vport *vport) { int sentplogi; @@ -856,6 +860,8 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, { struct lpfc_vport *vport = ndlp->vport; struct lpfc_nodelist *new_ndlp; + struct lpfc_rport_data *rdata; + struct fc_rport *rport; struct serv_parm *sp; uint8_t name[sizeof(struct lpfc_name)]; uint32_t rc; @@ -892,6 +898,11 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, lpfc_unreg_rpi(vport, new_ndlp); new_ndlp->nlp_DID = ndlp->nlp_DID; new_ndlp->nlp_prev_state = ndlp->nlp_prev_state; + + if (ndlp->nlp_flag & NLP_NPR_2B_DISC) + new_ndlp->nlp_flag |= NLP_NPR_2B_DISC; + ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); /* Move this back to NPR state */ @@ -899,6 +910,20 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, /* The new_ndlp is replacing ndlp totally, so we need * to put ndlp on UNUSED list and try to free it. */ + + /* Fix up the rport accordingly */ + rport = ndlp->rport; + if (rport) { + rdata = rport->dd_data; + if (rdata->pnode == ndlp) { + lpfc_nlp_put(ndlp); + ndlp->rport = NULL; + rdata->pnode = lpfc_nlp_get(new_ndlp); + new_ndlp->rport = rport; + } + new_ndlp->nlp_type = ndlp->nlp_type; + } + lpfc_drop_node(vport, ndlp); } else { @@ -909,6 +934,27 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, return new_ndlp; } +void +lpfc_end_rscn(struct lpfc_vport *vport) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + if (vport->fc_flag & FC_RSCN_MODE) { + /* + * Check to see if more RSCNs came in while we were + * processing this one. + */ + if (vport->fc_rscn_id_cnt || + (vport->fc_flag & FC_RSCN_DISCOVERY) != 0) + lpfc_els_handle_rscn(vport); + else { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_RSCN_MODE; + spin_unlock_irq(shost->host_lock); + } + } +} + static void lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) @@ -1006,20 +1052,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, spin_unlock_irq(shost->host_lock); lpfc_can_disctmo(vport); - if (vport->fc_flag & FC_RSCN_MODE) { - /* - * Check to see if more RSCNs came in while - * we were processing this one. - */ - if ((vport->fc_rscn_id_cnt == 0) && - (!(vport->fc_flag & FC_RSCN_DISCOVERY))) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - } else { - lpfc_els_handle_rscn(vport); - } - } + lpfc_end_rscn(vport); } } @@ -1214,7 +1247,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return 0; } -static void +void lpfc_more_adisc(struct lpfc_vport *vport) { int sentadisc; @@ -1239,8 +1272,6 @@ lpfc_more_adisc(struct lpfc_vport *vport) static void lpfc_rscn_disc(struct lpfc_vport *vport) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - lpfc_can_disctmo(vport); /* RSCN discovery */ @@ -1249,19 +1280,7 @@ lpfc_rscn_disc(struct lpfc_vport *vport) if (lpfc_els_disc_plogi(vport)) return; - if (vport->fc_flag & FC_RSCN_MODE) { - /* Check to see if more RSCNs came in while we were - * processing this one. - */ - if ((vport->fc_rscn_id_cnt == 0) && - (!(vport->fc_flag & FC_RSCN_DISCOVERY))) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - } else { - lpfc_els_handle_rscn(vport); - } - } + lpfc_end_rscn(vport); } static void @@ -1711,27 +1730,6 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) return 0; } -static void -lpfc_end_rscn(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (vport->fc_flag & FC_RSCN_MODE) { - /* - * Check to see if more RSCNs came in while we were - * processing this one. - */ - if (vport->fc_rscn_id_cnt || - (vport->fc_flag & FC_RSCN_DISCOVERY) != 0) - lpfc_els_handle_rscn(vport); - else { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - } - } -} - void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) { @@ -2159,6 +2157,32 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } int +lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1) +{ + struct lpfc_dmabuf *buf_ptr; + + /* Free the response before processing the command. */ + if (!list_empty(&buf_ptr1->list)) { + list_remove_head(&buf_ptr1->list, buf_ptr, + struct lpfc_dmabuf, + list); + lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); + kfree(buf_ptr); + } + lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys); + kfree(buf_ptr1); + return 0; +} + +int +lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr) +{ + lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); + kfree(buf_ptr); + return 0; +} + +int lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) { struct lpfc_dmabuf *buf_ptr, *buf_ptr1; @@ -2185,23 +2209,41 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) } /* context2 = cmd, context2->next = rsp, context3 = bpl */ if (elsiocb->context2) { - buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; - /* Free the response before processing the command. */ - if (!list_empty(&buf_ptr1->list)) { - list_remove_head(&buf_ptr1->list, buf_ptr, - struct lpfc_dmabuf, - list); - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); + if (elsiocb->iocb_flag & LPFC_DELAY_MEM_FREE) { + /* Firmware could still be in progress of DMAing + * payload, so don't free data buffer till after + * a hbeat. + */ + elsiocb->iocb_flag &= ~LPFC_DELAY_MEM_FREE; + buf_ptr = elsiocb->context2; + elsiocb->context2 = NULL; + if (buf_ptr) { + buf_ptr1 = NULL; + spin_lock_irq(&phba->hbalock); + if (!list_empty(&buf_ptr->list)) { + list_remove_head(&buf_ptr->list, + buf_ptr1, struct lpfc_dmabuf, + list); + INIT_LIST_HEAD(&buf_ptr1->list); + list_add_tail(&buf_ptr1->list, + &phba->elsbuf); + phba->elsbuf_cnt++; + } + INIT_LIST_HEAD(&buf_ptr->list); + list_add_tail(&buf_ptr->list, &phba->elsbuf); + phba->elsbuf_cnt++; + spin_unlock_irq(&phba->hbalock); + } + } + else { + buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; + lpfc_els_free_data(phba, buf_ptr1); } - lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys); - kfree(buf_ptr1); } if (elsiocb->context3) { buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3; - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); + lpfc_els_free_bpl(phba, buf_ptr); } lpfc_sli_release_iocbq(phba, elsiocb); return 0; @@ -2831,7 +2873,10 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport) } } } - if (sentplogi == 0) { + if (sentplogi) { + lpfc_set_disctmo(vport); + } + else { spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_NLP_MORE; spin_unlock_irq(shost->host_lock); @@ -3019,10 +3064,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, "RCV RSCN defer: did:x%x/ste:x%x flg:x%x", ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag); + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_RSCN_DEFERRED; if ((rscn_cnt < FC_MAX_HOLD_RSCN) && !(vport->fc_flag & FC_RSCN_DISCOVERY)) { - spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_RSCN_MODE; spin_unlock_irq(shost->host_lock); if (rscn_cnt) { @@ -3051,7 +3096,6 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, vport->fc_rscn_id_cnt, vport->fc_flag, vport->port_state); } else { - spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_RSCN_DISCOVERY; spin_unlock_irq(shost->host_lock); /* ReDiscovery RSCN */ @@ -3066,7 +3110,9 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* send RECOVERY event for ALL nodes that match RSCN payload */ lpfc_rscn_recovery_check(vport); + spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_RSCN_DEFERRED; + spin_unlock_irq(shost->host_lock); return 0; } @@ -3118,6 +3164,8 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) /* To process RSCN, first compare RSCN data with NameServer */ vport->fc_ns_retry = 0; + vport->num_disc_nodes = 0; + ndlp = lpfc_findnode_did(vport, NameServer_DID); if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { /* Good ndlp, issue CT Request to NameServer */ @@ -3348,13 +3396,13 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) status |= 0x4; rps_rsp->rsvd1 = 0; - rps_rsp->portStatus = be16_to_cpu(status); - rps_rsp->linkFailureCnt = be32_to_cpu(mb->un.varRdLnk.linkFailureCnt); - rps_rsp->lossSyncCnt = be32_to_cpu(mb->un.varRdLnk.lossSyncCnt); - rps_rsp->lossSignalCnt = be32_to_cpu(mb->un.varRdLnk.lossSignalCnt); - rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt); - rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord); - rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt); + rps_rsp->portStatus = cpu_to_be16(status); + rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt); + rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt); + rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt); + rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt); + rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord); + rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt); /* Xmit ELS RPS ACC response tag <ulpIoTag> */ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, "0118 Xmit ELS RPS ACC response tag x%x xri x%x, " @@ -4038,6 +4086,7 @@ lpfc_els_rcv_auth_rjt(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, uint32_t message_len; uint32_t trans_id; struct lpfc_auth_reject *rjt; + struct lpfc_hba *phba = vport->phba; authcmd = pcmd->virt; rjt = (struct lpfc_auth_reject *)authcmd->data; @@ -4047,7 +4096,6 @@ lpfc_els_rcv_auth_rjt(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - if (vport->auth.auth_state == LPFC_AUTH_SUCCESS) { lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, "1036 Authentication transaction reject - " @@ -4069,11 +4117,15 @@ lpfc_els_rcv_auth_rjt(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, lpfc_start_authentication(vport, ndlp); } else { lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, - "%d:1038 Authentication transaction " + "1057 Authentication transaction " "reject. reason 0x%x exp 0x%x\n", - vport->phba->brd_no, rjt->reason, rjt->explanation); vport->auth.auth_msg_state = LPFC_AUTH_REJECT; + if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && + (phba->link_state != LPFC_CLEAR_LA)) { + /* If Auth failed enable link interrupt. */ + lpfc_issue_clear_la(phba, vport); + } } } } @@ -4240,6 +4292,7 @@ lpfc_els_rcv_chap_suc(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, "1042 Re-Authentication Successful\n"); } /* If config requires re-authentication start the timer */ + vport->auth.last_auth = jiffies; if (vport->auth.reauth_interval) mod_timer(&ndlp->nlp_reauth_tmr, jiffies + vport->auth.reauth_interval * 60 * HZ); @@ -4709,7 +4762,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; MAILBOX_t *mb = &pmb->mb; + spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); lpfc_nlp_put(ndlp); if (mb->mbxStatus) { @@ -4730,7 +4785,9 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) default: /* Try to recover from this error */ lpfc_mbx_unreg_vpi(vport); + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); lpfc_initial_fdisc(vport); break; } @@ -4752,6 +4809,7 @@ void lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); LPFC_MBOXQ_t *mbox; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -4763,7 +4821,9 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); + spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, @@ -4775,7 +4835,9 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, "0254 Register VPI: no memory\n"); + spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); lpfc_nlp_put(ndlp); } } @@ -4835,8 +4897,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, GFP_KERNEL)) == 0) { lpfc_printf_log(vport->phba, KERN_WARNING, LOG_SECURITY, - "%d:1050 Security config request: no buffers\n", - vport->phba->brd_no); + "1050 Security config request: no buffers\n"); goto fdisc_failed; } vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN; @@ -4845,7 +4906,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, auth_rsp, sizeof(struct fc_auth_rsp))) { kfree(auth_rsp); lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, - "1053 Unable to get security " + "1054 Unable to get security " "config.\n"); goto fdisc_failed; } @@ -4902,7 +4963,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_unreg_rpi(vport, np); } lpfc_mbx_unreg_vpi(vport); + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); } if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) @@ -5383,11 +5446,12 @@ lpfc_cmpl_els_auth(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } if (vport->auth.auth_mode == FC_AUTHMODE_ACTIVE) { lpfc_can_disctmo(vport); - lpfc_nlp_set_state(vport, ndlp, - NLP_STE_NPR_NODE); - lpfc_issue_els_logo(vport, ndlp, 0); + lpfc_port_auth_failed(ndlp); } } + if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && + (phba->link_state != LPFC_CLEAR_LA)) + lpfc_issue_clear_la(phba, vport); lpfc_els_free_iocb(phba, cmdiocb); return; } @@ -5419,6 +5483,7 @@ lpfc_cmpl_els_auth(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } } /* restart authentication timer */ + vport->auth.last_auth = jiffies; if (vport->auth.reauth_interval) mod_timer(&ndlp->nlp_reauth_tmr, jiffies + diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 1caf802..c442d52 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -77,7 +77,7 @@ lpfc_start_discovery(struct lpfc_vport *vport) } vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { if (vports[i]->port_type == LPFC_PHYSICAL_PORT) continue; if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) @@ -90,7 +90,7 @@ lpfc_start_discovery(struct lpfc_vport *vport) "support\n"); } } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); lpfc_do_scr_ns_plogi(phba, vport); } @@ -149,15 +149,8 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) rdata = rport->dd_data; ndlp = rdata->pnode; - - if (!ndlp) { - if (rport->scsi_target_id != -1) { - printk(KERN_ERR "Cannot find remote node" - " for rport in dev_loss_tmo_callbk x%x\n", - rport->port_id); - } + if (!ndlp) return; - } vport = ndlp->vport; phba = vport->phba; @@ -237,6 +230,12 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) * appropriately we just need to cleanup the ndlp rport info here. */ if (vport->load_flag & FC_UNLOADING) { + if (ndlp->nlp_sid != NLP_NO_SID) { + /* flush the target */ + lpfc_sli_abort_iocb(vport, + &phba->sli.ring[phba->sli.fcp_ring], + ndlp->nlp_sid, 0, LPFC_CTX_TGT); + } put_node = rdata->pnode != NULL; put_rport = ndlp->rport != NULL; rdata->pnode = NULL; @@ -463,7 +462,7 @@ lpfc_work_done(struct lpfc_hba *phba) lpfc_handle_latt(phba); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS; i++) { + for(i = 0; i <= phba->max_vpi; i++) { /* * We could have no vports in array if unloading, so if * this happens then just use the pport @@ -495,7 +494,7 @@ lpfc_work_done(struct lpfc_hba *phba) vport->work_port_events &= ~work_port_events; spin_unlock_irq(&vport->work_port_lock); } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); pring = &phba->sli.ring[LPFC_ELS_RING]; status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING))); @@ -539,23 +538,21 @@ check_work_wait_done(struct lpfc_hba *phba) { struct lpfc_vport *vport; struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - int rc = 0; spin_lock_irq(&phba->hbalock); list_for_each_entry(vport, &phba->port_list, listentry) { if (vport->work_port_events) { - rc = 1; - break; + spin_unlock_irq(&phba->hbalock); + return 1; } } - if (rc || phba->work_ha || (!list_empty(&phba->work_list)) || + if (phba->work_ha || (!list_empty(&phba->work_list)) || kthread_should_stop() || pring->flag & LPFC_DEFERRED_RING_EVENT) { - rc = 1; - phba->work_found++; - } else - phba->work_found = 0; + spin_unlock_irq(&phba->hbalock); + return 1; + } spin_unlock_irq(&phba->hbalock); - return rc; + return 0; } @@ -568,7 +565,6 @@ lpfc_do_work(void *p) set_user_nice(current, -20); phba->work_wait = &work_waitq; - phba->work_found = 0; while (1) { @@ -581,18 +577,6 @@ lpfc_do_work(void *p) break; lpfc_work_done(phba); - - /* If there is alot of slow ring work, like during link up - * check_work_wait_done() may cause this thread to not give - * up the CPU for very long periods of time. This may cause - * soft lockups or other problems. To avoid these situations - * give up the CPU here after LPFC_MAX_WORKER_ITERATION - * consecutive iterations. - */ - if (phba->work_found >= LPFC_MAX_WORKER_ITERATION) { - phba->work_found = 0; - schedule(); - } } phba->work_wait = NULL; return 0; @@ -634,6 +618,7 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp, *next_ndlp; int rc; @@ -659,8 +644,10 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) : NLP_EVT_DEVICE_RECOVERY); } if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) { - lpfc_mbx_unreg_vpi(vport); + rc = lpfc_mbx_unreg_vpi(vport); + spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); } } @@ -706,6 +693,7 @@ lpfc_port_auth_failed(struct lpfc_nodelist *ndlp) struct lpfc_vport *vport = ndlp->vport; vport->auth.auth_state = LPFC_AUTH_FAIL; + vport->auth.auth_msg_state = LPFC_AUTH_NONE; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); if (ndlp->nlp_type & NLP_FABRIC) { lpfc_port_link_failure (vport); @@ -734,11 +722,11 @@ lpfc_linkdown(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { /* Issue a LINK DOWN event to all nodes */ lpfc_linkdown_port(vports[i]); } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); /* Clean up any firmware default rpi's */ mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mb) { @@ -843,9 +831,9 @@ lpfc_linkup(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) lpfc_linkup_port(vports[i]); - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) lpfc_issue_clear_la(phba, phba->pport); @@ -1310,7 +1298,7 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) scsi_host_put(shost); } -void +int lpfc_mbx_unreg_vpi(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; @@ -1319,7 +1307,7 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vport) mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) - return; + return 1; lpfc_unreg_vpi(phba, vport->vpi, mbox); mbox->vport = vport; @@ -1330,7 +1318,9 @@ lpfc_mbx_unreg_vpi(struct lpfc_vport *vport) "1800 Could not issue unreg_vpi\n"); mempool_free(mbox, phba->mbox_mem_pool); vport->unreg_vpi_cmpl = VPORT_ERROR; + return rc; } + return 0; } static void @@ -1989,7 +1979,8 @@ lpfc_unreg_all_rpis(struct lpfc_vport *vport) lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox); mbox->vport = vport; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + mbox->context1 = NULL; + rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); if (rc == MBX_NOT_FINISHED) { mempool_free(mbox, phba->mbox_mem_pool); } @@ -2008,7 +1999,8 @@ lpfc_unreg_default_rpis(struct lpfc_vport *vport) lpfc_unreg_did(phba, vport->vpi, 0xffffffff, mbox); mbox->vport = vport; mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + mbox->context1 = NULL; + rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); if (rc == MBX_NOT_FINISHED) { lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, "1815 Could not issue " @@ -2655,6 +2647,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) } if (vport->port_state != LPFC_FLOGI) { lpfc_initial_flogi(vport); + return; } break; diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index fddca02..5fc08c6 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1303,7 +1303,7 @@ typedef struct { /* FireFly BIU registers */ #define MBX_DEL_LD_ENTRY 0x1D #define MBX_RUN_PROGRAM 0x1E #define MBX_SET_MASK 0x20 -#define MBX_SET_SLIM 0x21 +#define MBX_SET_VARIABLE 0x21 #define MBX_UNREG_D_ID 0x23 #define MBX_KILL_BOARD 0x24 #define MBX_CONFIG_FARP 0x25 @@ -1325,7 +1325,7 @@ typedef struct { /* FireFly BIU registers */ #define MBX_REG_VNPID 0x96 #define MBX_UNREG_VNPID 0x97 -#define MBX_FLASH_WR_ULA 0x98 +#define MBX_WRITE_WWN 0x98 #define MBX_SET_DEBUG 0x99 #define MBX_LOAD_EXP_ROM 0x9C @@ -1397,6 +1397,7 @@ typedef struct { /* FireFly BIU registers */ #define CMD_FCP_TRECEIVE64_CX 0xA1 #define CMD_FCP_TRSP64_CX 0xA3 +#define CMD_QUE_XRI64_CX 0xB3 #define CMD_IOCB_RCV_SEQ64_CX 0xB5 #define CMD_IOCB_RCV_ELS64_CX 0xB7 #define CMD_IOCB_RCV_CONT64_CX 0xBB @@ -1430,6 +1431,7 @@ typedef struct { /* FireFly BIU registers */ #define MBXERR_BAD_RCV_LENGTH 14 #define MBXERR_DMA_ERROR 15 #define MBXERR_ERROR 16 +#define MBXERR_UNKNOWN_CMD 18 #define MBX_NOT_FINISHED 255 #define MBX_BUSY 0xffffff /* Attempted cmd to busy Mailbox */ @@ -2297,6 +2299,14 @@ typedef struct { uint32_t rsvd1; } CLEAR_LA_VAR; +/* Structure for MB Command SET_SLIM (33) */ +/* Values needed to set MAX_DMA_LENGTH parameter */ +#define SLIM_VAR_MAX_DMA_LENGTH 0x100506 +#define SLIM_VAL_MAX_DMA_512 0x0 +#define SLIM_VAL_MAX_DMA_1024 0x1 +#define SLIM_VAL_MAX_DMA_2048 0x2 +#define SLIM_VAL_MAX_DMA_4096 0x3 + /* Structure for MB Command DUMP */ typedef struct { @@ -2331,6 +2341,37 @@ typedef struct { #define DMP_RSP_OFFSET 0x14 /* word 5 contains first word of rsp */ #define DMP_RSP_SIZE 0x6C /* maximum of 27 words of rsp data */ +/* Structure for MB Command UPDATE_CFG (0x1B) */ + +struct update_cfg_var { +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t rsvd2:16; + uint32_t type:8; + uint32_t rsvd:1; + uint32_t ra:1; + uint32_t co:1; + uint32_t cv:1; + uint32_t req:4; + uint32_t entry_length:16; + uint32_t region_id:16; +#else /* __LITTLE_ENDIAN_BITFIELD */ + uint32_t req:4; + uint32_t cv:1; + uint32_t co:1; + uint32_t ra:1; + uint32_t rsvd:1; + uint32_t type:8; + uint32_t rsvd2:16; + uint32_t region_id:16; + uint32_t entry_length:16; +#endif + + uint32_t resp_info; + uint32_t byte_cnt; + uint32_t data_offset; +}; + + struct hbq_mask { #ifdef __BIG_ENDIAN_BITFIELD uint8_t tmatch; @@ -2652,6 +2693,9 @@ typedef struct { /* Union of all Mailbox Command types */ #define MAILBOX_CMD_WSIZE 32 #define MAILBOX_CMD_SIZE (MAILBOX_CMD_WSIZE * sizeof(uint32_t)) +#define MAILBOX_EXT_WSIZE 64 +#define MAILBOX_EXT_SIZE (MAILBOX_EXT_WSIZE * sizeof(uint32_t)) +#define MAILBOX_MAX_XMIT_SIZE 1024 typedef union { uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/ @@ -2685,6 +2729,7 @@ typedef union { * NEW_FEATURE */ struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ) */ + struct update_cfg_var varUpdateCfg; /* cmd = 0x1B (UPDATE_CFG)*/ CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */ REG_VPI_VAR varRegVpi; /* cmd = 0x96 (REG_VPI) */ UNREG_VPI_VAR varUnregVpi; /* cmd = 0x97 (UNREG_VPI) */ @@ -3017,6 +3062,34 @@ typedef struct { #endif } RCV_ELS_REQ64; +/* IOCB Command template for RCV_SEQ64 */ +struct rcv_seq64 { + struct ulp_bde64 elsReq; + uint32_t hbq_1; + uint32_t parmRo; +#ifdef __BIG_ENDIAN_BITFIELD + uint32_t rctl:8; + uint32_t type:8; + uint32_t dfctl:8; + uint32_t ls:1; + uint32_t fs:1; + uint32_t rsvd2:3; + uint32_t si:1; + uint32_t bc:1; + uint32_t rsvd3:1; +#else /* __LITTLE_ENDIAN_BITFIELD */ + uint32_t rsvd3:1; + uint32_t bc:1; + uint32_t si:1; + uint32_t rsvd2:3; + uint32_t fs:1; + uint32_t ls:1; + uint32_t dfctl:8; + uint32_t type:8; + uint32_t rctl:8; +#endif +}; + /* IOCB Command template for all 64 bit FCP Initiator commands */ typedef struct { ULP_BDL bdl; @@ -3063,7 +3136,26 @@ struct rcv_sli3 { struct ulp_bde64 bde2; }; +/* Structure used for a single HBQ entry */ +struct lpfc_hbq_entry { + struct ulp_bde64 bde; + uint32_t buffer_tag; +}; +/* IOCB Command template for QUE_XRI64_CX (0xB3) command */ +typedef struct { + struct lpfc_hbq_entry buff; + uint32_t rsvd; + uint32_t rsvd1; +} QUE_XRI64_CX_FIELDS; + +struct que_xri64cx_ext_fields { + uint32_t iotag64_low; + uint32_t iotag64_high; + uint32_t ebde_count; + uint32_t rsvd; + struct lpfc_hbq_entry buff[5]; +}; typedef struct _IOCB { /* IOCB structure */ union { @@ -3088,6 +3180,8 @@ typedef struct _IOCB { /* IOCB structure */ FCPI_FIELDS64 fcpi64; /* FCP 64 bit Initiator template */ FCPT_FIELDS64 fcpt64; /* FCP 64 bit target template */ ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */ + QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */ + struct rcv_seq64 rcvseq64; /* RCV_SEQ64 and RCV_CONT64 */ uint32_t ulpWord[IOCB_WORD_SZ - 2]; /* generic 6 'words' */ } un; @@ -3145,6 +3239,10 @@ typedef struct _IOCB { /* IOCB structure */ union { struct rcv_sli3 rcvsli3; /* words 8 - 15 */ + + /* words 8-31 used for que_xri_cx iocb */ + struct que_xri64cx_ext_fields que_xri64cx_ext_words; + uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */ } unsli3; @@ -3184,12 +3282,6 @@ typedef struct _IOCB { /* IOCB structure */ } IOCB_t; -/* Structure used for a single HBQ entry */ -struct lpfc_hbq_entry { - struct ulp_bde64 bde; - uint32_t buffer_tag; -}; - #define SLI1_SLIM_SIZE (4 * 1024) @@ -3232,6 +3324,8 @@ lpfc_is_LC_HBA(unsigned short device) (device == PCI_DEVICE_ID_BSMB) || (device == PCI_DEVICE_ID_ZMID) || (device == PCI_DEVICE_ID_ZSMB) || + (device == PCI_DEVICE_ID_SAT_MID) || + (device == PCI_DEVICE_ID_SAT_SMB) || (device == PCI_DEVICE_ID_RFLY)) return 1; else diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 71c72d6..f375894 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -43,7 +43,6 @@ #include "lpfc_crtn.h" #include "lpfc_vport.h" #include "lpfc_version.h" -#include "lpfc_vport.h" #include "lpfc_auth_access.h" #include "lpfc_ioctl.h" #include "lpfc_security.h" @@ -73,6 +72,43 @@ static DEFINE_IDR(lpfc_hba_index); +int pci_select_bars(struct pci_dev *dev, unsigned long flags) +{ + int i, bars = 0; + for (i = 0; i < PCI_NUM_RESOURCES; i++) + if (pci_resource_flags(dev, i) & flags) + bars |= (1 << i); + return bars; +} + +int pci_request_selected_regions(struct pci_dev *pdev, int bars, + char *res_name) +{ + int i; + + for (i = 0; i < 6; i++) + if (bars & (1 << i)) + if(pci_request_region(pdev, i, res_name)) + goto err_out; + return 0; + +err_out: + while(--i >= 0) + if (bars & (1 << i)) + pci_release_region(pdev, i); + + return -EBUSY; +} + +void pci_release_selected_regions(struct pci_dev *pdev, int bars) +{ + int i; + + for (i = 0; i < 6; i++) + if (bars & (1 << i)) + pci_release_region(pdev, i); +} + /************************************************************************/ /* */ /* lpfc_config_port_prep */ @@ -428,11 +464,10 @@ lpfc_config_port_post(struct lpfc_hba *phba) phba->last_completion_time = jiffies; if (vport->cfg_enable_auth) { - lpfc_security_wait(); if (lpfc_security_service_state == SECURITY_OFFLINE) { lpfc_printf_log(vport->phba, KERN_ERR, LOG_SECURITY, - "1029 Authentication is enabled but security " - "service is not running!\n"); + "1029 Authentication is enabled but " + "authentication service is not running\n"); vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN; phba->link_state = LPFC_HBA_ERROR; mempool_free( pmb, phba->mbox_mem_pool); @@ -520,6 +555,9 @@ lpfc_hba_down_post(struct lpfc_hba *phba) struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; struct lpfc_dmabuf *mp, *next_mp; + struct lpfc_iocbq *iocb; + IOCB_t *cmd = NULL; + LIST_HEAD(completions); int i; if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) @@ -535,10 +573,36 @@ lpfc_hba_down_post(struct lpfc_hba *phba) } } + spin_lock_irq(&phba->hbalock); for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; + + /* At this point in time the HBA is either reset or DOA. Either + * way, nothing should be on txcmplq as it will NEVER complete. + */ + list_splice_init(&pring->txcmplq, &completions); + pring->txcmplq_cnt = 0; + spin_unlock_irq(&phba->hbalock); + + while (!list_empty(&completions)) { + iocb = list_get_first(&completions, struct lpfc_iocbq, + list); + cmd = &iocb->iocb; + list_del_init(&iocb->list); + + if (!iocb->iocb_cmpl) + lpfc_sli_release_iocbq(phba, iocb); + else { + cmd->ulpStatus = IOSTAT_LOCAL_REJECT; + cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; + (iocb->iocb_cmpl) (phba, iocb, iocb); + } + } + lpfc_sli_abort_iocb_ring(phba, pring); + spin_lock_irq(&phba->hbalock); } + spin_unlock_irq(&phba->hbalock); return 0; } @@ -583,8 +647,10 @@ void lpfc_hb_timeout_handler(struct lpfc_hba *phba) { LPFC_MBOXQ_t *pmboxq; + struct lpfc_dmabuf *buf_ptr; int retval; struct lpfc_sli *psli = &phba->sli; + LIST_HEAD(completions); if ((phba->link_state == LPFC_HBA_ERROR) || (phba->pport->load_flag & FC_UNLOADING) || @@ -611,49 +677,88 @@ lpfc_hb_timeout_handler(struct lpfc_hba *phba) } spin_unlock_irq(&phba->pport->work_port_lock); - /* If there is no heart beat outstanding, issue a heartbeat command */ - if (!phba->hb_outstanding) { - pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL); - if (!pmboxq) { - mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_INTERVAL); - return; + if (phba->elsbuf_cnt && + (phba->elsbuf_cnt == phba->elsbuf_prev_cnt)) { + spin_lock_irq(&phba->hbalock); + list_splice_init(&phba->elsbuf, &completions); + phba->elsbuf_cnt = 0; + phba->elsbuf_prev_cnt = 0; + spin_unlock_irq(&phba->hbalock); + + while (!list_empty(&completions)) { + list_remove_head(&completions, buf_ptr, + struct lpfc_dmabuf, list); + lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); + kfree(buf_ptr); } + } + phba->elsbuf_prev_cnt = phba->elsbuf_cnt; - lpfc_heart_beat(phba, pmboxq); - pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl; - pmboxq->vport = phba->pport; - retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); + /* If there is no heart beat outstanding, issue a heartbeat command */ + if (phba->cfg_enable_hba_heartbeat) { + if (!phba->hb_outstanding) { + pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL); + if (!pmboxq) { + mod_timer(&phba->hb_tmofunc, + jiffies + HZ * LPFC_HB_MBOX_INTERVAL); + return; + } - if (retval != MBX_BUSY && retval != MBX_SUCCESS) { - mempool_free(pmboxq, phba->mbox_mem_pool); + lpfc_heart_beat(phba, pmboxq); + pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl; + pmboxq->vport = phba->pport; + retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); + + if (retval != MBX_BUSY && retval != MBX_SUCCESS) { + mempool_free(pmboxq, phba->mbox_mem_pool); + mod_timer(&phba->hb_tmofunc, + jiffies + HZ * LPFC_HB_MBOX_INTERVAL); + return; + } mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_INTERVAL); + jiffies + HZ * LPFC_HB_MBOX_TIMEOUT); + phba->hb_outstanding = 1; return; + } else { + /* + * If heart beat timeout called with hb_outstanding set + * we need to take the HBA offline. + */ + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0459 Adapter heartbeat failure, " + "taking this port offline.\n"); + + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + spin_unlock_irq(&phba->hbalock); + + lpfc_offline_prep(phba); + lpfc_offline(phba); + lpfc_unblock_mgmt_io(phba); + phba->link_state = LPFC_HBA_ERROR; + lpfc_hba_down_post(phba); } - mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_TIMEOUT); - phba->hb_outstanding = 1; - return; - } else { - /* - * If heart beat timeout called with hb_outstanding set we - * need to take the HBA offline. - */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0459 Adapter heartbeat failure, taking " - "this port offline.\n"); + } +} - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; - spin_unlock_irq(&phba->hbalock); +static void +lpfc_offline_eratt(struct lpfc_hba *phba) +{ + struct lpfc_sli *psli = &phba->sli; - lpfc_offline_prep(phba); - lpfc_offline(phba); - lpfc_unblock_mgmt_io(phba); - phba->link_state = LPFC_HBA_ERROR; - lpfc_hba_down_post(phba); - } + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + spin_unlock_irq(&phba->hbalock); + lpfc_offline_prep(phba); + + lpfc_offline(phba); + lpfc_reset_barrier(phba); + lpfc_sli_brdreset(phba); + lpfc_hba_down_post(phba); + lpfc_sli_brdready(phba, HS_MBRDY); + lpfc_unblock_mgmt_io(phba); + phba->link_state = LPFC_HBA_ERROR; + return; } /************************************************************************/ @@ -677,6 +782,9 @@ lpfc_handle_eratt(struct lpfc_hba *phba) struct Scsi_Host *shost; int i; + /* If resets are disabled then leave the HBA alone and return */ + if (!phba->cfg_enable_hba_reset) + return; if (phba->work_hs & HS_FFER6 || phba->work_hs & HS_FFER5) { @@ -689,14 +797,14 @@ lpfc_handle_eratt(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for(i = 0; - i < LPFC_MAX_VPORTS && vports[i] != NULL; + i <= phba->max_vpi && vports[i] != NULL; i++){ shost = lpfc_shost_from_vport(vports[i]); spin_lock_irq(shost->host_lock); vports[i]->fc_flag |= FC_ESTABLISH_LINK; spin_unlock_irq(shost->host_lock); } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~LPFC_SLI2_ACTIVE; spin_unlock_irq(&phba->hbalock); @@ -745,14 +853,9 @@ lpfc_handle_eratt(struct lpfc_hba *phba) | PCI_VENDOR_ID_EMULEX); spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; phba->over_temp_state = HBA_OVER_TEMP; spin_unlock_irq(&phba->hbalock); - lpfc_offline_prep(phba); - lpfc_offline(phba); - lpfc_unblock_mgmt_io(phba); - phba->link_state = LPFC_HBA_ERROR; - lpfc_hba_down_post(phba); + lpfc_offline_eratt(phba); } else { /* The if clause above forces this code path when the status @@ -771,14 +874,7 @@ lpfc_handle_eratt(struct lpfc_hba *phba) sizeof(event_data), (char *) &event_data, SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI2_ACTIVE; - spin_unlock_irq(&phba->hbalock); - lpfc_offline_prep(phba); - lpfc_offline(phba); - lpfc_unblock_mgmt_io(phba); - phba->link_state = LPFC_HBA_ERROR; - lpfc_hba_down_post(phba); + lpfc_offline_eratt(phba); } } @@ -798,21 +894,25 @@ lpfc_handle_latt(struct lpfc_hba *phba) LPFC_MBOXQ_t *pmb; volatile uint32_t control; struct lpfc_dmabuf *mp; - int rc = -ENOMEM; + int rc = 0; pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) + if (!pmb) { + rc = 1; goto lpfc_handle_latt_err_exit; + } mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!mp) + if (!mp) { + rc = 2; goto lpfc_handle_latt_free_pmb; + } mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - if (!mp->virt) + if (!mp->virt) { + rc = 3; goto lpfc_handle_latt_free_mp; - - rc = -EIO; + } /* Cleanup any outstanding ELS commands */ lpfc_els_flush_all_cmd(phba); @@ -822,8 +922,10 @@ lpfc_handle_latt(struct lpfc_hba *phba) pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la; pmb->vport = vport; rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) + if (rc == MBX_NOT_FINISHED) { + rc = 4; goto lpfc_handle_latt_free_mbuf; + } /* Clear Link Attention in HA REG */ spin_lock_irq(&phba->hbalock); @@ -855,10 +957,8 @@ lpfc_handle_latt_err_exit: lpfc_linkdown(phba); phba->link_state = LPFC_HBA_ERROR; - /* The other case is an error from issue_mbox */ - if (rc == -ENOMEM) - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, - "0300 READ_LA: no buffers\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "0300 LATT: Cannot issue READ_LA: Data:%d\n", rc); return; } @@ -1364,11 +1464,10 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit) uint32_t *HashWorking; uint32_t *pwwnn = (uint32_t *) phba->wwnn; - HashWorking = kmalloc(80 * sizeof(uint32_t), GFP_KERNEL); + HashWorking = kcalloc(80, sizeof(uint32_t), GFP_KERNEL); if (!HashWorking) return; - memset(HashWorking, 0, (80 * sizeof(uint32_t))); HashWorking[0] = HashWorking[78] = *pwwnn++; HashWorking[1] = HashWorking[79] = *pwwnn; @@ -1431,14 +1530,14 @@ lpfc_establish_link_tmo(unsigned long ptr) phba->pport->fc_flag, phba->pport->port_state); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { struct Scsi_Host *shost; shost = lpfc_shost_from_vport(vports[i]); spin_lock_irqsave(shost->host_lock, iflag); vports[i]->fc_flag &= ~FC_ESTABLISH_LINK; spin_unlock_irqrestore(shost->host_lock, iflag); } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); } void @@ -1493,7 +1592,7 @@ lpfc_online(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { struct Scsi_Host *shost; shost = lpfc_shost_from_vport(vports[i]); spin_lock_irq(shost->host_lock); @@ -1502,7 +1601,7 @@ lpfc_online(struct lpfc_hba *phba) vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); lpfc_unblock_mgmt_io(phba); return 0; @@ -1546,7 +1645,7 @@ lpfc_offline_prep(struct lpfc_hba * phba) /* Issue an unreg_login to all nodes on all vports */ vports = lpfc_create_vport_work_array(phba); if (vports != NULL) { - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { struct Scsi_Host *shost; if (vports[i]->load_flag & FC_UNLOADING) @@ -1570,7 +1669,7 @@ lpfc_offline_prep(struct lpfc_hba * phba) } } } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); lpfc_sli_flush_mbox_queue(phba); } @@ -1589,9 +1688,9 @@ lpfc_offline(struct lpfc_hba *phba) lpfc_stop_phba_timers(phba); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) lpfc_stop_vport_timers(vports[i]); - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0460 Bring Adapter offline\n"); /* Bring down the SLI Layer and cleanup. The HBA is offline @@ -1602,14 +1701,14 @@ lpfc_offline(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); spin_lock_irq(shost->host_lock); vports[i]->work_port_events = 0; vports[i]->fc_flag |= FC_OFFLINE_MODE; spin_unlock_irq(shost->host_lock); } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); } /****************************************************************************** @@ -1866,6 +1965,37 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) spin_unlock_irq(shost->host_lock); } +void +lpfc_setup_max_dma_length(struct lpfc_hba * phba) +{ + struct pci_dev *pdev = phba->pcidev; + struct pci_bus *bus = pdev->bus; + uint8_t rev; + + while (bus) { + /* + * 0x7450 == PCI_DEVICE_ID_AMD_8131_BRIDGE for 2.6 kernels + * 0x7450 == PCI_DEVICE_ID_AMD_8131_APIC for 2.4 kernels + */ + if ( bus->self && + (bus->self->vendor == PCI_VENDOR_ID_AMD) && + (bus->self->device == 0x7450)) { + pci_read_config_byte(bus->self, 0x08, &rev); + if (rev == 0x13) { + /* + * If set a value in module paramter, + * use that value. + */ + if (phba->cfg_pci_max_read == 2048) + phba->cfg_pci_max_read = 1024; + return; + } + } + bus = bus->parent; + } + return; +} + static int __devinit lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) { @@ -1879,11 +2009,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) int error = -ENODEV, retval; int i, hbq_count; uint16_t iotag; + int bars = pci_select_bars(pdev, IORESOURCE_MEM); unsigned long start; - if (pci_enable_device(pdev)) + if (pci_enable_device_bars(pdev, bars)) goto out; - if (pci_request_regions(pdev, LPFC_DRIVER_NAME)) + if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME)) goto out_disable_device; phba = kzalloc(sizeof (struct lpfc_hba), GFP_KERNEL); @@ -1904,6 +2035,10 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) * establish the host. */ lpfc_get_cfgparam(phba); + + /* Check if we need to change the DMA length */ + lpfc_setup_max_dma_length(phba); + phba->max_vpi = LPFC_MAX_VPI; /* Initialize timers used by driver */ @@ -1992,6 +2127,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size()); + INIT_LIST_HEAD(&phba->hbqbuf_in_list); + /* Initialize the SLI Layer to run with lpfc HBAs. */ lpfc_sli_setup(phba); lpfc_sli_queue_setup(phba); @@ -2055,6 +2192,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) /* Initialize list of fabric iocbs */ INIT_LIST_HEAD(&phba->fabric_iocb_list); + /* Initialize list to save ELS buffers */ + INIT_LIST_HEAD(&phba->elsbuf); + /* Initialize list of sysfs mailbox commands */ INIT_LIST_HEAD(&phba->sysfs_mbox_list); @@ -2188,7 +2328,7 @@ out_idr_remove: out_free_phba: kfree(phba); out_release_regions: - pci_release_regions(pdev); + pci_release_selected_regions(pdev, bars); out_disable_device: pci_disable_device(pdev); out: @@ -2204,6 +2344,7 @@ lpfc_pci_remove_one(struct pci_dev *pdev) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; struct lpfc_hba *phba = vport->phba; + int bars = pci_select_bars(pdev, IORESOURCE_MEM); struct lpfc_vport **vports; int i; @@ -2219,12 +2360,12 @@ lpfc_pci_remove_one(struct pci_dev *pdev) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { if (vports[i]->port_type == LPFC_PHYSICAL_PORT) continue; lpfc_vport_delete(lpfc_shost_from_vport(vports[i])); } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); fc_remove_host(shost); scsi_remove_host(shost); lpfc_cleanup(vport); @@ -2276,10 +2417,102 @@ lpfc_pci_remove_one(struct pci_dev *pdev) kfree(phba); - pci_release_regions(pdev); + pci_release_selected_regions(pdev, bars); pci_disable_device(pdev); } +/** + * lpfc_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci conneection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t lpfc_io_error_detected(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) + return PCI_ERS_RESULT_DISCONNECT; + + 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); + + /* Release the irq reservation */ + free_irq(phba->pcidev->irq, phba); + if (phba->using_msi) + pci_disable_msi(phba->pcidev); + + /* Request a slot reset. */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * lpfc_io_slot_reset - called after the pci bus has been reset. + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + */ +static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + struct lpfc_sli *psli = &phba->sli; + int bars = pci_select_bars(pdev, IORESOURCE_MEM); + + dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); + if (pci_enable_device_bars(pdev, bars)) { + printk(KERN_ERR "lpfc: Cannot re-enable " + "PCI device after reset.\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_set_master(pdev); + + /* Re-establishing Link */ + spin_lock_irq(shost->host_lock); + phba->pport->fc_flag |= FC_ESTABLISH_LINK; + spin_unlock_irq(shost->host_lock); + + spin_lock_irq(&phba->hbalock); + psli->sli_flag &= ~LPFC_SLI2_ACTIVE; + spin_unlock_irq(&phba->hbalock); + + + /* Take device offline; this will perform cleanup */ + lpfc_offline(phba); + lpfc_sli_brdrestart(phba); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * lpfc_io_resume - called when traffic can start flowing again. + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. + */ +static void lpfc_io_resume(struct pci_dev *pdev) +{ + struct Scsi_Host *shost = pci_get_drvdata(pdev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + + if (lpfc_online(phba) == 0) { + mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60); + } +} static struct pci_device_id lpfc_id_table[] = { {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER, @@ -2353,12 +2586,18 @@ static struct pci_device_id lpfc_id_table[] = { MODULE_DEVICE_TABLE(pci, lpfc_id_table); +static struct pci_error_handlers lpfc_err_handler = { + .error_detected = lpfc_io_error_detected, + .slot_reset = lpfc_io_slot_reset, + .resume = lpfc_io_resume, +}; static struct pci_driver lpfc_driver = { .name = LPFC_DRIVER_NAME, .id_table = lpfc_id_table, .probe = lpfc_pci_probe_one, .remove = __devexit_p(lpfc_pci_remove_one), + .err_handler = &lpfc_err_handler, }; static int __init @@ -2382,26 +2621,21 @@ lpfc_init(void) } } - if (netlink_register_notifier(&lpfc_fc_netlink_notifier)) - return 1; + error = netlink_register_notifier(&lpfc_fc_netlink_notifier); + if (error) + goto out_release_transport; fc_nl_sock = netlink_kernel_create(NETLINK_FCTRANSPORT, FC_NL_GROUP_CNT, lpfc_fc_nl_rcv, THIS_MODULE); - if (!fc_nl_sock) { - netlink_unregister_notifier(&lpfc_fc_netlink_notifier); - return 1; - } + if (!fc_nl_sock) + goto out_unregister_notifier; snprintf(security_work_q_name, KOBJ_NAME_LEN, "fc_sc_wq"); security_work_q = create_singlethread_workqueue(security_work_q_name); - if (!security_work_q) { - netlink_unregister_notifier(&lpfc_fc_netlink_notifier); - sock_release(fc_nl_sock->sk_socket); - return 1; - } + if (!security_work_q) + goto out_sock_release; INIT_LIST_HEAD(&fc_security_user_list); error = pci_register_driver(&lpfc_driver); if (error) - goto out_release_transport; - + goto out_destroy_workqueue; error = lpfc_cdev_init(); if (error) goto out_pci_unregister; @@ -2410,9 +2644,18 @@ lpfc_init(void) out_pci_unregister: pci_unregister_driver(&lpfc_driver); +out_destroy_workqueue: + destroy_workqueue(security_work_q); + security_work_q = NULL; +out_sock_release: + sock_release(fc_nl_sock->sk_socket); + fc_nl_sock = NULL; +out_unregister_notifier: + netlink_unregister_notifier(&lpfc_fc_netlink_notifier); out_release_transport: fc_release_transport(lpfc_transport_template); - fc_release_transport(lpfc_vport_transport_template); + if (lpfc_enable_npiv) + fc_release_transport(lpfc_vport_transport_template); return error; } @@ -2421,12 +2664,14 @@ static void __exit lpfc_exit(void) { pci_unregister_driver(&lpfc_driver); - - if (fc_nl_sock) + if (security_work_q) + destroy_workqueue(security_work_q); + security_work_q = NULL; + if (fc_nl_sock) { sock_release(fc_nl_sock->sk_socket); - netlink_unregister_notifier(&lpfc_fc_netlink_notifier); - fc_nl_sock = NULL; - + netlink_unregister_notifier(&lpfc_fc_netlink_notifier); + fc_nl_sock = NULL; + } fc_release_transport(lpfc_transport_template); if (lpfc_enable_npiv) fc_release_transport(lpfc_vport_transport_template); diff --git a/drivers/scsi/lpfc/lpfc_ioctl.c b/drivers/scsi/lpfc/lpfc_ioctl.c index 20f0c2e..0e890fa 100644 --- a/drivers/scsi/lpfc/lpfc_ioctl.c +++ b/drivers/scsi/lpfc/lpfc_ioctl.c @@ -34,6 +34,7 @@ #include "lpfc_crtn.h" #include "lpfc_ioctl.h" #include "lpfc_logmsg.h" +#include "lpfc_vport.h" struct lpfcdfc_event { @@ -1065,11 +1066,12 @@ static int lpfc_ioctl_loopback_mode(struct lpfc_hba *phba, struct lpfcCmdInput *cip, void *dataout) { - struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport); + struct Scsi_Host *shost; struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING]; uint32_t link_flags = cip->lpfc_arg4; uint32_t timeout = cip->lpfc_arg5 * 100; + struct lpfc_vport **vports; LPFC_MBOXQ_t *pmboxq; int mbxstatus; int i = 0; @@ -1083,7 +1085,18 @@ lpfc_ioctl_loopback_mode(struct lpfc_hba *phba, if ((pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL)) == 0) return ENOMEM; - scsi_block_requests(shost); + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++){ + shost = lpfc_shost_from_vport(vports[i]); + scsi_block_requests(shost); + } + lpfc_destroy_vport_work_array(phba, vports); + } + else { + shost = lpfc_shost_from_vport(phba->pport); + scsi_block_requests(shost); + } while (pring->txcmplq_cnt) { if (i++ > 500) /* wait up to 5 seconds */ @@ -1143,7 +1156,18 @@ lpfc_ioctl_loopback_mode(struct lpfc_hba *phba, rc = ENODEV; loopback_mode_exit: - scsi_unblock_requests(shost); + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++){ + shost = lpfc_shost_from_vport(vports[i]); + scsi_unblock_requests(shost); + } + lpfc_destroy_vport_work_array(phba, vports); + } + else { + shost = lpfc_shost_from_vport(phba->pport); + scsi_unblock_requests(shost); + } /* * Let SLI layer release mboxq if mbox command completed after timeout. @@ -1406,17 +1430,35 @@ static int lpfcdfc_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, mp[i] = list_entry(curr, struct lpfc_dmabuf, list); list_del(curr); - cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys); - cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys); - cmd->un.cont64[i].tus.f.bdeSize = - ((struct lpfc_dmabufext *)mp[i])->size; - cmd->ulpBdeCount = ++i; + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba); + cmd->un.quexri64cx.buff.bde.addrHigh = + putPaddrHigh(mp[i]->phys); + cmd->un.quexri64cx.buff.bde.addrLow = + putPaddrLow(mp[i]->phys); + cmd->un.quexri64cx.buff.bde.tus.f.bdeSize = + ((struct lpfc_dmabufext *)mp[i])->size; + cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag; + cmd->ulpCommand = CMD_QUE_XRI64_CX; + cmd->ulpPU = 0; + cmd->ulpLe = 1; + cmd->ulpBdeCount = 1; + cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0; - if ((--num_bde > 0) && (i < 2)) - continue; + } else { + cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys); + cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys); + cmd->un.cont64[i].tus.f.bdeSize = + ((struct lpfc_dmabufext *)mp[i])->size; + cmd->ulpBdeCount = ++i; + + if ((--num_bde > 0) && (i < 2)) + continue; + + cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX; + cmd->ulpLe = 1; + } - cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX; - cmd->ulpLe = 1; cmd->ulpClass = CLASS3; cmd->ulpContext = rxxri; @@ -1630,19 +1672,20 @@ lpfc_ioctl_loopback_test(struct lpfc_hba *phba, } evt->waiting = 0; - mutex_lock(&lpfcdfc_lock); - lpfcdfc_event_unref(evt); /* release ref */ - lpfcdfc_event_unref(evt); /* delete */ - mutex_unlock(&lpfcdfc_lock); - if (rx_databuf == NULL) { rc = EIO; - goto err_loopback_test_exit; + goto err_loopback_free_evt_exit; } rx_databuf += ELX_LOOPBACK_HEADER_SZ; memcpy(ptr, rx_databuf, size); +err_loopback_free_evt_exit: + mutex_lock(&lpfcdfc_lock); + lpfcdfc_event_unref(evt); /* release ref */ + lpfcdfc_event_unref(evt); /* delete */ + mutex_unlock(&lpfcdfc_lock); + err_loopback_test_exit: lpfcdfc_loop_self_unreg(phba, rpi); @@ -1786,7 +1829,6 @@ lpfcdfc_ct_unsol_event(struct lpfc_hba * phba, struct lpfc_iocbq * piocbq) { struct lpfcdfc_host * dfchba = lpfcdfc_host_from_hba(phba); - uint32_t evt_type; uint32_t evt_req_id = 0; uint32_t cmd; uint32_t len; @@ -1801,10 +1843,10 @@ lpfcdfc_ct_unsol_event(struct lpfc_hba * phba, int i; struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; + struct lpfc_hbq_entry *hbqe; BUG_ON(&dfchba->node == &lpfcdfc_hosts); INIT_LIST_HEAD(&head); - evt_type = FC_REG_CT_EVENT; if (piocbq->iocb.ulpBdeCount == 0 || piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) goto error_unsol_ct_exit; @@ -1842,10 +1884,27 @@ lpfcdfc_ct_unsol_event(struct lpfc_hba * phba, INIT_LIST_HEAD(&head); list_add_tail(&head, &piocbq->list); - list_for_each_entry(iocbq, &head, list) - for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) - evt_dat->len += + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + list_for_each_entry(iocbq, &head, list) { + if (iocbq->iocb.ulpBdeCount != 0) { + hbqe = (struct lpfc_hbq_entry *) + &iocbq->iocb.un.ulpWord[0]; + evt_dat->len += hbqe->bde.tus.f.bdeSize; + } + if (iocbq->iocb.ulpBdeCount == 2) { + hbqe = (struct lpfc_hbq_entry *) + &iocbq->iocb.unsli3.sli3Words[4]; + evt_dat->len += hbqe->bde.tus.f.bdeSize; + } + } + } else { + list_for_each_entry(iocbq, &head, list) { + for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) + evt_dat->len += iocbq->iocb.un.cont64[i].tus.f.bdeSize; + } + } + evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); if (evt_dat->data == NULL) { @@ -1856,17 +1915,33 @@ lpfcdfc_ct_unsol_event(struct lpfc_hba * phba, goto error_unsol_ct_exit; } - list_for_each_entry(iocbq, &head, list) + list_for_each_entry(iocbq, &head, list) { + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + bdeBuf1 = iocbq->context2; + bdeBuf2 = iocbq->context3; + } for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { - int size; - size = iocbq->iocb.un.cont64[i].tus.f.bdeSize; + int size = 0; + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - if (i == 0) + BUG_ON(i>1); + + if (i == 0) { + hbqe = (struct lpfc_hbq_entry *) + &iocbq->iocb.un.ulpWord[0]; + size = hbqe->bde.tus.f.bdeSize; dmabuf = bdeBuf1; - else if (i == 1) + } else if (i == 1) { + hbqe = (struct lpfc_hbq_entry *) + &iocbq->iocb.unsli3. + sli3Words[4]; + size = hbqe->bde.tus.f.bdeSize; dmabuf = bdeBuf2; + } } else { + size = iocbq->iocb.un.cont64[i]. + tus.f.bdeSize; bde = &iocbq->iocb.un.cont64[i]; dma_addr = getPaddr(bde->addrHigh, bde->addrLow); @@ -1903,15 +1978,15 @@ lpfcdfc_ct_unsol_event(struct lpfc_hba * phba, lpfc_post_buffer(phba, pring, 1, 1); - lpfc_in_buf_free(phba, dmabuf); break; }; } } + } mutex_lock(&lpfcdfc_lock); evt_dat->immed_dat = piocbq->iocb.ulpContext; - evt_dat->type = evt_type; + evt_dat->type = FC_REG_CT_EVENT; list_add(&evt_dat->node, &evt->events_to_see); wake_up_interruptible(&evt->wq); lpfcdfc_event_unref(evt); diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 872190d..60db1d5 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -542,6 +542,32 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba) } } +/***********************************************/ +/* command to write slim */ +/***********************************************/ +void +lpfc_set_var(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, uint32_t addr, + uint32_t value) +{ + MAILBOX_t *mb; + + mb = &pmb->mb; + memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); + + /* + * Always turn on DELAYED ABTS for ELS timeouts + */ + if ((addr == 0x052198) && (value == 0)) + value = 1; + + mb->un.varWords[0] = addr; + mb->un.varWords[1] = value; + + mb->mbxCommand = MBX_SET_VARIABLE; + mb->mbxOwner = OWN_HOST; + return; +} + void lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) { @@ -902,7 +928,7 @@ lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd) case MBX_DOWN_LOAD: /* 0x1C */ case MBX_DEL_LD_ENTRY: /* 0x1D */ case MBX_LOAD_AREA: /* 0x81 */ - case MBX_FLASH_WR_ULA: /* 0x98 */ + case MBX_WRITE_WWN: /* 0x98 */ case MBX_LOAD_EXP_ROM: /* 0x9C */ return LPFC_MBOX_TMO_FLASH_CMD; } diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 43c3b8a..8daa385 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -98,6 +98,7 @@ lpfc_mem_alloc(struct lpfc_hba * phba) fail_free_hbq_pool: lpfc_sli_hbqbuf_free_all(phba); + pci_pool_destroy(phba->lpfc_hbq_pool); fail_free_nlp_mem_pool: mempool_destroy(phba->nlp_mem_pool); phba->nlp_mem_pool = NULL; @@ -236,11 +237,11 @@ lpfc_els_hbq_alloc(struct lpfc_hba *phba) { struct hbq_dmabuf *hbqbp; - hbqbp = kmalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); + hbqbp = kmalloc(sizeof(struct hbq_dmabuf), GFP_ATOMIC); if (!hbqbp) return NULL; - hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_KERNEL, + hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_ATOMIC, &hbqbp->dbuf.phys); if (!hbqbp->dbuf.virt) { kfree(hbqbp); @@ -263,15 +264,24 @@ void lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp) { struct hbq_dmabuf *hbq_entry; + unsigned long flags; if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + /* Check whether HBQ is still in use */ + spin_lock_irqsave(&phba->hbalock, flags); + if (!phba->hbq_in_use) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return; + } hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf); + list_del(&hbq_entry->dbuf.list); if (hbq_entry->tag == -1) { (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) (phba, hbq_entry); } else { lpfc_sli_free_hbq(phba, hbq_entry); } + spin_unlock_irqrestore(&phba->hbalock, flags); } else { lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 346999a..fbe62d8 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -442,6 +442,40 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); + + if ((ndlp->nlp_flag & NLP_ADISC_SND) && + (vport->num_disc_nodes)) { + /* Check to see if there are more + * ADISCs to be sent + */ + lpfc_more_adisc(vport); + + if ((vport->num_disc_nodes == 0) && + (vport->fc_npr_cnt)) + lpfc_els_disc_plogi(vport); + + if (vport->num_disc_nodes == 0) { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_NDISC_ACTIVE; + spin_unlock_irq(shost->host_lock); + lpfc_can_disctmo(vport); + lpfc_end_rscn(vport); + } + } + else if (vport->num_disc_nodes) { + /* Check to see if there are more + * PLOGIs to be sent + */ + lpfc_more_plogi(vport); + + if (vport->num_disc_nodes == 0) { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_NDISC_ACTIVE; + spin_unlock_irq(shost->host_lock); + lpfc_can_disctmo(vport); + lpfc_end_rscn(vport); + } + } } } @@ -629,6 +663,25 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return ndlp->nlp_state; } +static uint32_t +lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + /* This transition is only legal if we previously + * rcv'ed a PLOGI. Since we don't want 2 discovery threads + * working on the same NPortID, do nothing for this thread + * to stop it. + */ + if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, + "0253 Illegal State Transition: node x%x " + "event x%x, state x%x Data: x%x x%x\n", + ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, + ndlp->nlp_flag); + } + return ndlp->nlp_state; +} + /* Start of Discovery State Machine routines */ static uint32_t @@ -780,6 +833,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, uint32_t evt) { struct lpfc_hba *phba = vport->phba; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_iocbq *cmdiocb, *rspiocb; struct lpfc_dmabuf *pcmd, *prsp, *mp; uint32_t *lp; @@ -897,11 +951,27 @@ out: "0261 Cannot Register NameServer login\n"); } + spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_DEFER_RM; + spin_unlock_irq(shost->host_lock); return NLP_STE_FREED_NODE; } static uint32_t +lpfc_cmpl_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + void *arg, uint32_t evt) +{ + return ndlp->nlp_state; +} + +static uint32_t +lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) +{ + return ndlp->nlp_state; +} + +static uint32_t lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { @@ -1978,9 +2048,9 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) lpfc_rcv_els_plogi_issue, /* RCV_PRLO */ lpfc_cmpl_plogi_plogi_issue, /* CMPL_PLOGI */ lpfc_disc_illegal, /* CMPL_PRLI */ - lpfc_disc_illegal, /* CMPL_LOGO */ + lpfc_cmpl_logo_plogi_issue, /* CMPL_LOGO */ lpfc_disc_illegal, /* CMPL_ADISC */ - lpfc_disc_illegal, /* CMPL_REG_LOGIN */ + lpfc_cmpl_reglogin_plogi_issue,/* CMPL_REG_LOGIN */ lpfc_device_rm_plogi_issue, /* DEVICE_RM */ lpfc_device_recov_plogi_issue, /* DEVICE_RECOVERY */ @@ -2004,7 +2074,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) lpfc_rcv_padisc_reglogin_issue, /* RCV_ADISC */ lpfc_rcv_padisc_reglogin_issue, /* RCV_PDISC */ lpfc_rcv_prlo_reglogin_issue, /* RCV_PRLO */ - lpfc_disc_illegal, /* CMPL_PLOGI */ + lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */ lpfc_disc_illegal, /* CMPL_PRLI */ lpfc_disc_illegal, /* CMPL_LOGO */ lpfc_disc_illegal, /* CMPL_ADISC */ @@ -2018,7 +2088,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) lpfc_rcv_padisc_prli_issue, /* RCV_ADISC */ lpfc_rcv_padisc_prli_issue, /* RCV_PDISC */ lpfc_rcv_prlo_prli_issue, /* RCV_PRLO */ - lpfc_disc_illegal, /* CMPL_PLOGI */ + lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */ lpfc_cmpl_prli_prli_issue, /* CMPL_PRLI */ lpfc_disc_illegal, /* CMPL_LOGO */ lpfc_disc_illegal, /* CMPL_ADISC */ diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index bb8d833..82c6bd4 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -130,7 +130,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); shost_for_each_device(sdev, shost) { new_queue_depth = @@ -151,7 +151,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) new_queue_depth); } } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); atomic_set(&phba->num_rsrc_err, 0); atomic_set(&phba->num_cmd_success, 0); } @@ -166,7 +166,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) { + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { shost = lpfc_shost_from_vport(vports[i]); shost_for_each_device(sdev, shost) { if (sdev->ordered_tags) @@ -179,7 +179,7 @@ lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) sdev->queue_depth+1); } } - lpfc_destroy_vport_work_array(vports); + lpfc_destroy_vport_work_array(phba, vports); atomic_set(&phba->num_rsrc_err, 0); atomic_set(&phba->num_cmd_success, 0); } @@ -202,10 +202,9 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport) dma_addr_t pdma_phys; uint16_t iotag; - psb = kmalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); + psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); if (!psb) return NULL; - memset(psb, 0, sizeof (struct lpfc_scsi_buf)); /* * Get memory from the pci pool to map the virt space to pci bus space @@ -411,7 +410,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) (num_bde * sizeof (struct ulp_bde64)); iocb_cmd->ulpBdeCount = 1; iocb_cmd->ulpLe = 1; - fcp_cmnd->fcpDl = be32_to_cpu(scsi_cmnd->request_bufflen); + fcp_cmnd->fcpDl = cpu_to_be32(scsi_cmnd->request_bufflen); return 0; } @@ -437,8 +436,8 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb) } static void -lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, - struct lpfc_iocbq *rsp_iocb) +lpfc_handle_fcp_err(struct lpfc_hba *phba, struct lpfc_vport *vport, + struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb) { struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd; @@ -475,15 +474,16 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, if (!scsi_status && (resp_info & RESID_UNDER)) logit = LOG_FCP; - lpfc_printf_vlog(vport, KERN_WARNING, logit, - "0730 FCP command x%x failed: x%x SNS x%x x%x " - "Data: x%x x%x x%x x%x x%x\n", - cmnd->cmnd[0], scsi_status, - be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info, - be32_to_cpu(fcprsp->rspResId), - be32_to_cpu(fcprsp->rspSnsLen), - be32_to_cpu(fcprsp->rspRspLen), - fcprsp->rspInfo3); + lpfc_printf_log(phba, KERN_WARNING, logit, + "(%d)0730 FCP command x%x failed: x%x SNS x%x x%x " + "Data: x%x x%x x%x x%x x%x\n", + (vport ? vport->vpi : 0), + cmnd->cmnd[0], scsi_status, + be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info, + be32_to_cpu(fcprsp->rspResId), + be32_to_cpu(fcprsp->rspSnsLen), + be32_to_cpu(fcprsp->rspRspLen), + fcprsp->rspInfo3); if (resp_info & RSP_LEN_VALID) { rsplen = be32_to_cpu(fcprsp->rspRspLen); @@ -498,12 +498,13 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, if (resp_info & RESID_UNDER) { cmnd->resid = be32_to_cpu(fcprsp->rspResId); - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "0716 FCP Read Underrun, expected %d, " - "residual %d Data: x%x x%x x%x\n", - be32_to_cpu(fcpcmd->fcpDl), - cmnd->resid, fcpi_parm, cmnd->cmnd[0], - cmnd->underflow); + lpfc_printf_log(phba, KERN_INFO, LOG_FCP, + "(%d)0716 FCP Read Underrun, expected %d, " + "residual %d Data: x%x x%x x%x\n", + (vport ? vport->vpi : 0), + be32_to_cpu(fcpcmd->fcpDl), + cmnd->resid, fcpi_parm, cmnd->cmnd[0], + cmnd->underflow); /* * If there is an under run check if under run reported by * storage array is same as the under run reported by HBA. @@ -512,12 +513,14 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) && fcpi_parm && (cmnd->resid != fcpi_parm)) { - lpfc_printf_vlog(vport, KERN_WARNING, - LOG_FCP | LOG_FCP_ERROR, - "0735 FCP Read Check Error " - "and Underrun Data: x%x x%x x%x x%x\n", - be32_to_cpu(fcpcmd->fcpDl), - cmnd->resid, fcpi_parm, cmnd->cmnd[0]); + lpfc_printf_log(phba, KERN_WARNING, + LOG_FCP | LOG_FCP_ERROR, + "(%d)0735 FCP Read Check Error " + "and Underrun Data: x%x x%x x%x x%x\n", + (vport ? vport->vpi : 0), + be32_to_cpu(fcpcmd->fcpDl), + cmnd->resid, fcpi_parm, + cmnd->cmnd[0]); cmnd->resid = cmnd->request_bufflen; host_status = DID_ERROR; } @@ -530,19 +533,22 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, if (!(resp_info & SNS_LEN_VALID) && (scsi_status == SAM_STAT_GOOD) && (cmnd->request_bufflen - cmnd->resid) < cmnd->underflow) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "0717 FCP command x%x residual " - "underrun converted to error " - "Data: x%x x%x x%x\n", - cmnd->cmnd[0], cmnd->request_bufflen, - cmnd->resid, cmnd->underflow); + lpfc_printf_log(phba, KERN_INFO, LOG_FCP, + "(%d)0717 FCP command x%x residual " + "underrun converted to error " + "Data: x%x x%x x%x\n", + (vport ? vport->vpi : 0), + cmnd->cmnd[0], cmnd->request_bufflen, + cmnd->resid, cmnd->underflow); host_status = DID_ERROR; } } else if (resp_info & RESID_OVER) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, - "0720 FCP command x%x residual overrun error. " - "Data: x%x x%x \n", cmnd->cmnd[0], - cmnd->request_bufflen, cmnd->resid); + lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, + "(%d)0720 FCP command x%x residual " + "overrun error. Data: x%x x%x \n", + (vport ? vport->vpi : 0), + cmnd->cmnd[0], + cmnd->request_bufflen, cmnd->resid); host_status = DID_ERROR; /* @@ -551,12 +557,14 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, */ } else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm && (cmnd->sc_data_direction == DMA_FROM_DEVICE)) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR, - "0734 FCP Read Check Error Data: " - "x%x x%x x%x x%x\n", - be32_to_cpu(fcpcmd->fcpDl), - be32_to_cpu(fcprsp->rspResId), - fcpi_parm, cmnd->cmnd[0]); + lpfc_printf_log(phba, KERN_WARNING, + LOG_FCP | LOG_FCP_ERROR, + "(%d)0734 FCP Read Check Error Data: " + "x%x x%x x%x x%x\n", + (vport ? vport->vpi : 0), + be32_to_cpu(fcpcmd->fcpDl), + be32_to_cpu(fcprsp->rspResId), + fcpi_parm, cmnd->cmnd[0]); host_status = DID_ERROR; cmnd->resid = cmnd->request_bufflen; } @@ -578,6 +586,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, int result; struct scsi_device *sdev, *tmp_sdev; int depth = 0; + unsigned long flags; lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; lpfc_cmd->status = pIocbOut->iocb.ulpStatus; @@ -589,11 +598,11 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, else if (lpfc_cmd->status >= IOSTAT_CNT) lpfc_cmd->status = IOSTAT_DEFAULT; - lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, + lpfc_printf_log(phba, KERN_WARNING, LOG_FCP, "0729 FCP cmd x%x failed <%d/%d> " "status: x%x result: x%x Data: x%x x%x\n", cmd->cmnd[0], - cmd->device ? cmd->device->id : 0xffff, + vport ? vport->vpi : 0, cmd->device ? cmd->device->lun : 0xffff, lpfc_cmd->status, lpfc_cmd->result, pIocbOut->iocb.ulpContext, @@ -602,7 +611,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, switch (lpfc_cmd->status) { case IOSTAT_FCP_RSP_ERROR: /* Call FCP RSP handler to determine result */ - lpfc_handle_fcp_err(vport, lpfc_cmd, pIocbOut); + lpfc_handle_fcp_err(phba, vport, lpfc_cmd, pIocbOut); break; case IOSTAT_NPORT_BSY: case IOSTAT_FABRIC_BSY: @@ -630,10 +639,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, if (cmd->result || lpfc_cmd->fcp_rsp->rspSnsLen) { uint32_t *lp = (uint32_t *)cmd->sense_buffer; - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, + lpfc_printf_log(phba, KERN_INFO, LOG_FCP, "0710 Iodone <%d/%d> cmd %p, error " "x%x SNS x%x x%x Data: x%x x%x\n", - cmd->device->id, cmd->device->lun, cmd, + vport ? vport->vpi : 0, cmd->device->lun, cmd, cmd->result, *lp, *(lp + 3), cmd->retries, cmd->resid); } @@ -644,10 +653,21 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, cmd->scsi_done(cmd); if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { + /* + * If there is a thread waiting for command completion + * wake up the thread. + */ + spin_lock_irqsave(sdev->host->host_lock, flags); + lpfc_cmd->pCmd = NULL; + if (lpfc_cmd->waitq) + wake_up(lpfc_cmd->waitq); + spin_unlock_irqrestore(sdev->host->host_lock, flags); lpfc_release_scsi_buf(phba, lpfc_cmd); return; } + if (!vport) + goto out_vport_deleted; if (!result) lpfc_rampup_queue_depth(vport, sdev); @@ -705,6 +725,17 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } } + out_vport_deleted: + /* + * If there is a thread waiting for command completion + * wake up the thread. + */ + spin_lock_irqsave(sdev->host->host_lock, flags); + lpfc_cmd->pCmd = NULL; + if (lpfc_cmd->waitq) + wake_up(lpfc_cmd->waitq); + spin_unlock_irqrestore(sdev->host->host_lock, flags); + lpfc_release_scsi_buf(phba, lpfc_cmd); } @@ -718,6 +749,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq); int datadir = scsi_cmnd->sc_data_direction; + char tag[2]; lpfc_cmd->fcp_rsp->rspSnsLen = 0; /* clear task management bits */ @@ -728,8 +760,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, 16); - if (scsi_cmnd->device->tagged_supported) { - switch (scsi_cmnd->tag) { + if (scsi_populate_tag_msg(scsi_cmnd, tag)) { + switch (tag[0]) { case HEAD_OF_QUEUE_TAG: fcp_cmnd->fcpCntl1 = HEAD_OF_Q; break; @@ -794,6 +826,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, piocbq->iocb.ulpContext = pnode->nlp_rpi; if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE) piocbq->iocb.ulpFCP2Rcvy = 1; + else + piocbq->iocb.ulpFCP2Rcvy = 0; piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f); piocbq->context1 = lpfc_cmd; @@ -975,12 +1009,33 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) struct lpfc_rport_data *rdata = cmnd->device->hostdata; struct lpfc_nodelist *ndlp = rdata->pnode; struct lpfc_scsi_buf *lpfc_cmd; + struct scsi_device *sdev; struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); int err; err = fc_remote_port_chkready(rport); if (err) { cmnd->result = err; + sdev = cmnd->device; + if ((phba->link_state == LPFC_HBA_ERROR) && + (cmnd->result == ScsiResult(DID_NO_CONNECT, 0)) && + (sdev->queue_depth != 1)) { + + /* If we reach this point, the HBA is not responding + * and has been taken offline. If alot of SCSI IO + * was active, this could cause a massive amount of + * SCSI layer initiated logging. On some systems, + * this massive amount of logging has been known to + * cause CPU soft lockups. In an attempt to throttle + * the amount of logging, set the sdev queue depth to 1. + */ + if (sdev->ordered_tags) + scsi_adjust_queue_depth(sdev, + MSG_ORDERED_TAG, 1); + else + scsi_adjust_queue_depth(sdev, + MSG_SIMPLE_TAG, 1); + } goto out_fail_command; } @@ -1072,8 +1127,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) struct lpfc_iocbq *abtsiocb; struct lpfc_scsi_buf *lpfc_cmd; IOCB_t *cmd, *icmd; - unsigned int loop_count = 0; int ret = SUCCESS; + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); + lpfc_block_error_handler(cmnd); lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; @@ -1128,17 +1184,15 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_sli_poll_fcp_ring (phba); + lpfc_cmd->waitq = &waitq; /* Wait for abort to complete */ - while (lpfc_cmd->pCmd == cmnd) - { - if (phba->cfg_poll & DISABLE_FCP_RING_INT) - lpfc_sli_poll_fcp_ring (phba); + wait_event_timeout(waitq, + (lpfc_cmd->pCmd != cmnd), + (2*vport->cfg_devloss_tmo*HZ)); - schedule_timeout_uninterruptible(LPFC_ABORT_WAIT * HZ); - if (++loop_count - > (2 * vport->cfg_devloss_tmo)/LPFC_ABORT_WAIT) - break; - } + spin_lock_irq(shost->host_lock); + lpfc_cmd->waitq = NULL; + spin_unlock_irq(shost->host_lock); if (lpfc_cmd->pCmd == cmnd) { ret = FAILED; @@ -1491,7 +1545,7 @@ struct scsi_host_template lpfc_template = { .slave_configure = lpfc_slave_configure, .slave_destroy = lpfc_slave_destroy, .this_id = -1, - .sg_tablesize = LPFC_SG_SEG_CNT, + .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, .cmd_per_lun = LPFC_CMD_PER_LUN, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = lpfc_hba_attrs, @@ -1510,7 +1564,7 @@ struct scsi_host_template lpfc_template_no_npiv = { .slave_configure = lpfc_slave_configure, .slave_destroy = lpfc_slave_destroy, .this_id = -1, - .sg_tablesize = LPFC_SG_SEG_CNT, + .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, .cmd_per_lun = LPFC_CMD_PER_LUN, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = lpfc_hba_attrs_no_npiv, @@ -1529,7 +1583,7 @@ struct scsi_host_template lpfc_vport_template = { .slave_configure = lpfc_slave_configure, .slave_destroy = lpfc_slave_destroy, .this_id = -1, - .sg_tablesize = LPFC_SG_SEG_CNT, + .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, .cmd_per_lun = LPFC_CMD_PER_LUN, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = lpfc_vport_attrs, diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 31787bb..daba923 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -138,6 +138,7 @@ struct lpfc_scsi_buf { * Iotag is in here */ struct lpfc_iocbq cur_iocbq; + wait_queue_head_t *waitq; }; #define LPFC_SCSI_DMA_EXT_SIZE 264 diff --git a/drivers/scsi/lpfc/lpfc_security.c b/drivers/scsi/lpfc/lpfc_security.c index 413b022..6cf4d96 100644 --- a/drivers/scsi/lpfc/lpfc_security.c +++ b/drivers/scsi/lpfc/lpfc_security.c @@ -39,7 +39,13 @@ uint8_t lpfc_security_service_state = SECURITY_OFFLINE; void lpfc_security_service_online(struct Scsi_Host *shost) { + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + lpfc_security_service_state = SECURITY_ONLINE; + if (vport->cfg_enable_auth && + vport->auth.auth_mode == FC_AUTHMODE_UNKNOWN && + vport->phba->link_state == LPFC_HBA_ERROR) + lpfc_selective_reset(vport->phba); } void @@ -54,66 +60,79 @@ lpfc_security_config(struct Scsi_Host *shost, int status, void *rsp) struct fc_auth_rsp *auth_rsp = (struct fc_auth_rsp *)rsp; struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; struct lpfc_nodelist *ndlp; + uint32_t old_interval, new_interval; + unsigned long new_jiffies, temp_jiffies; - if (status == 0) { - vport->auth.bidirectional = - auth_rsp->u.dhchap_security_config.bidirectional; - memcpy(&vport->auth.hash_priority[0], - &auth_rsp->u.dhchap_security_config.hash_priority[0], - sizeof(vport->auth.hash_priority)); - vport->auth.hash_len = - auth_rsp->u.dhchap_security_config.hash_len; - memcpy(&vport->auth.dh_group_priority[0], - &auth_rsp->u.dhchap_security_config. - dh_group_priority[0], - sizeof(vport->auth.dh_group_priority)); - vport->auth.dh_group_len = - auth_rsp->u.dhchap_security_config.dh_group_len; - vport->auth.reauth_interval = - auth_rsp->u.dhchap_security_config.reauth_interval; - vport->auth.auth_mode = - auth_rsp->u.dhchap_security_config.auth_mode; - - lpfc_printf_vlog(vport, KERN_INFO, LOG_SECURITY, - "1025 Received security config local_wwpn:" - "%llX remote_wwpn:%llX \nmode:0x%x " - "hash(%d):%x:%x:%x:%x bidir:0x%x " - "dh_group(%d):%x:%x:%x:%x:%x:%x:%x:%x " - "reauth_interval:0x%x\n", - (unsigned long long)auth_rsp->local_wwpn, - (unsigned long long)auth_rsp->remote_wwpn, - auth_rsp->u.dhchap_security_config.auth_mode, - auth_rsp->u.dhchap_security_config.hash_len, - auth_rsp->u.dhchap_security_config.hash_priority[0], - auth_rsp->u.dhchap_security_config.hash_priority[1], - auth_rsp->u.dhchap_security_config.hash_priority[2], - auth_rsp->u.dhchap_security_config.hash_priority[3], - auth_rsp->u.dhchap_security_config.bidirectional, - auth_rsp->u.dhchap_security_config.dh_group_len, - auth_rsp->u.dhchap_security_config.dh_group_priority[0], - auth_rsp->u.dhchap_security_config.dh_group_priority[1], - auth_rsp->u.dhchap_security_config.dh_group_priority[2], - auth_rsp->u.dhchap_security_config.dh_group_priority[3], - auth_rsp->u.dhchap_security_config.dh_group_priority[4], - auth_rsp->u.dhchap_security_config.dh_group_priority[5], - auth_rsp->u.dhchap_security_config.dh_group_priority[6], - auth_rsp->u.dhchap_security_config.dh_group_priority[7], - auth_rsp->u.dhchap_security_config.reauth_interval); - kfree(auth_rsp); - } - - /* re-authenticate whenever we get new configs */ - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_SECURITY, - "1026 Unable to find ndlp. \n"); + if (status) return; + ndlp = lpfc_findnode_did(vport, Fabric_DID); + vport->auth.bidirectional = + auth_rsp->u.dhchap_security_config.bidirectional; + memcpy(&vport->auth.hash_priority[0], + &auth_rsp->u.dhchap_security_config.hash_priority[0], + sizeof(vport->auth.hash_priority)); + vport->auth.hash_len = auth_rsp->u.dhchap_security_config.hash_len; + memcpy(&vport->auth.dh_group_priority[0], + &auth_rsp->u.dhchap_security_config. + dh_group_priority[0], + sizeof(vport->auth.dh_group_priority)); + vport->auth.dh_group_len = + auth_rsp->u.dhchap_security_config.dh_group_len; + old_interval = vport->auth.reauth_interval; + vport->auth.reauth_interval = + auth_rsp->u.dhchap_security_config.reauth_interval; + new_interval = vport->auth.reauth_interval; + /* + * If interval changed we need to adjust the running timer + * If enabled then start timer now. + * If disabled then stop the timer. + * If changed to chorter then elapsed time, then set to fire now + * If changed to longer than elapsed time, extend the timer. + */ + if (old_interval != new_interval && + vport->auth.auth_state == LPFC_AUTH_SUCCESS) { + new_jiffies = msecs_to_jiffies(new_interval * 60000); + del_timer_sync(&ndlp->nlp_reauth_tmr); + if (old_interval == 0) + temp_jiffies = jiffies + new_jiffies; + if (new_interval == 0) + temp_jiffies = 0; + else if (new_jiffies < (jiffies - vport->auth.last_auth)) + temp_jiffies = jiffies + msecs_to_jiffies(1); + else + temp_jiffies = jiffies + (new_jiffies - + (jiffies - vport->auth.last_auth)); + if (temp_jiffies) + mod_timer(&ndlp->nlp_reauth_tmr, temp_jiffies); } - if (vport->port_state == LPFC_VPORT_READY) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_SECURITY, - "1027 Re-Authentication triggered. \n"); - lpfc_start_authentication(vport, ndlp); - } + vport->auth.auth_mode = + auth_rsp->u.dhchap_security_config.auth_mode; + lpfc_printf_vlog(vport, KERN_INFO, LOG_SECURITY, + "1025 Received security config local_wwpn:" + "%llX remote_wwpn:%llX \nmode:0x%x " + "hash(%d):%x:%x:%x:%x bidir:0x%x " + "dh_group(%d):%x:%x:%x:%x:%x:%x:%x:%x " + "reauth_interval:0x%x\n", + (unsigned long long)auth_rsp->local_wwpn, + (unsigned long long)auth_rsp->remote_wwpn, + auth_rsp->u.dhchap_security_config.auth_mode, + auth_rsp->u.dhchap_security_config.hash_len, + auth_rsp->u.dhchap_security_config.hash_priority[0], + auth_rsp->u.dhchap_security_config.hash_priority[1], + auth_rsp->u.dhchap_security_config.hash_priority[2], + auth_rsp->u.dhchap_security_config.hash_priority[3], + auth_rsp->u.dhchap_security_config.bidirectional, + auth_rsp->u.dhchap_security_config.dh_group_len, + auth_rsp->u.dhchap_security_config.dh_group_priority[0], + auth_rsp->u.dhchap_security_config.dh_group_priority[1], + auth_rsp->u.dhchap_security_config.dh_group_priority[2], + auth_rsp->u.dhchap_security_config.dh_group_priority[3], + auth_rsp->u.dhchap_security_config.dh_group_priority[4], + auth_rsp->u.dhchap_security_config.dh_group_priority[5], + auth_rsp->u.dhchap_security_config.dh_group_priority[6], + auth_rsp->u.dhchap_security_config.dh_group_priority[7], + auth_rsp->u.dhchap_security_config.reauth_interval); + kfree(auth_rsp); } int @@ -125,17 +144,22 @@ lpfc_get_security_enabled(struct Scsi_Host *shost) } int -lpfc_security_wait(void) +lpfc_security_wait(struct lpfc_hba *phba) { int i = 0; + if (lpfc_security_service_state == SECURITY_ONLINE) + return 0; + lpfc_printf_log(phba, KERN_WARNING, LOG_SECURITY, + "1058 Waiting for authentication service...\n"); while (lpfc_security_service_state == SECURITY_OFFLINE) { i++; - if (i > 240) { + if (i > SECURITY_WAIT_TMO * 2) return -ETIMEDOUT; - } /* Delay for half of a second */ msleep(500); } + lpfc_printf_log(phba, KERN_WARNING, LOG_SECURITY, + "1059 Authentication service online.\n"); return 0; } @@ -206,6 +230,35 @@ int lpfc_start_node_authentication(struct lpfc_nodelist *ndlp) { struct lpfc_vport *vport; + int ret; + + vport = ndlp->vport; + /* If there is authentication timer cancel the timer */ + del_timer_sync(&ndlp->nlp_reauth_tmr); + if ((ret = lpfc_get_auth_config(ndlp))) + return ret; + if ((ret = lpfc_security_config_wait(vport))) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, + "1032 Start Authentication: get config " + "timed out.\n"); + return ret; + } + /* no need to authenticate if mode is disabled (not an error) */ + if (vport->auth.auth_mode == FC_AUTHMODE_NONE) + return 0; + /* re-authenticate after getting new configs */ + if (vport->port_state == LPFC_VPORT_READY) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_SECURITY, + "1027 Re-Authentication triggered. \n"); + lpfc_start_authentication(vport, ndlp); + } + return 0; +} + +int +lpfc_get_auth_config(struct lpfc_nodelist *ndlp) +{ + struct lpfc_vport *vport; struct fc_auth_req auth_req; struct fc_auth_rsp *auth_rsp; struct Scsi_Host *shost; @@ -214,9 +267,6 @@ lpfc_start_node_authentication(struct lpfc_nodelist *ndlp) vport = ndlp->vport; shost = lpfc_shost_from_vport(vport); - /* If there is authentication timer cancel the timer */ - del_timer_sync(&ndlp->nlp_reauth_tmr); - auth_req.local_wwpn = wwn_to_u64(vport->fc_portname.u.wwn); if (ndlp->nlp_type & NLP_FABRIC) auth_req.remote_wwpn = AUTH_FABRIC_WWN; @@ -235,6 +285,7 @@ lpfc_start_node_authentication(struct lpfc_nodelist *ndlp) return -ENOMEM; } + vport->auth.auth_mode = FC_AUTHMODE_UNKNOWN; if ((ret = lpfc_fc_security_get_config(shost, &auth_req, sizeof(struct fc_auth_req), auth_rsp, @@ -245,11 +296,5 @@ lpfc_start_node_authentication(struct lpfc_nodelist *ndlp) kfree(auth_rsp); return ret; } - if ((ret = lpfc_security_config_wait(vport))) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_SECURITY, - "1032 Start Authentication: get config " - "timed out.\n"); - return ret; - } return 0; } diff --git a/drivers/scsi/lpfc/lpfc_security.h b/drivers/scsi/lpfc/lpfc_security.h index c86d36d..2d5fe20 100644 --- a/drivers/scsi/lpfc/lpfc_security.h +++ b/drivers/scsi/lpfc/lpfc_security.h @@ -20,3 +20,5 @@ #define SECURITY_OFFLINE 0x0 #define SECURITY_ONLINE 0x1 + +#define SECURITY_WAIT_TMO 30 /* seconds to wait for the auth service */ diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 1d807ff..806723b 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -529,10 +529,13 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba) { struct lpfc_dmabuf *dmabuf, *next_dmabuf; struct hbq_dmabuf *hbq_buf; + unsigned long flags; int i, hbq_count; + uint32_t hbqno; hbq_count = lpfc_sli_hbq_count(); /* Return all memory used by all HBQs */ + spin_lock_irqsave(&phba->hbalock, flags); for (i = 0; i < hbq_count; ++i) { list_for_each_entry_safe(dmabuf, next_dmabuf, &phba->hbqs[i].hbq_buffer_list, list) { @@ -542,6 +545,28 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba) } phba->hbqs[i].buffer_count = 0; } + /* Return all HBQ buffer that are in-fly */ + list_for_each_entry_safe(dmabuf, next_dmabuf, + &phba->hbqbuf_in_list, list) { + hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf); + list_del(&hbq_buf->dbuf.list); + if (hbq_buf->tag == -1) { + (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) + (phba, hbq_buf); + } else { + hbqno = hbq_buf->tag >> 16; + if (hbqno >= LPFC_MAX_HBQS) + (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) + (phba, hbq_buf); + else + (phba->hbqs[hbqno].hbq_free_buffer)(phba, + hbq_buf); + } + } + + /* Mark the HBQs not in use */ + phba->hbq_in_use = 0; + spin_unlock_irqrestore(&phba->hbalock, flags); } static struct lpfc_hbq_entry * @@ -603,6 +628,7 @@ static int lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) { uint32_t i, start, end; + unsigned long flags; struct hbq_dmabuf *hbq_buffer; if (!phba->hbqs[hbqno].hbq_alloc_buffer) { @@ -615,6 +641,13 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) end = lpfc_hbq_defs[hbqno]->entry_count; } + /* Check whether HBQ is still in use */ + spin_lock_irqsave(&phba->hbalock, flags); + if (!phba->hbq_in_use) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return 0; + } + /* Populate HBQ entries */ for (i = start; i < end; i++) { hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); @@ -626,6 +659,8 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) else (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); } + + spin_unlock_irqrestore(&phba->hbalock, flags); return 0; } @@ -651,7 +686,7 @@ lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) uint32_t hbqno; hbqno = tag >> 16; - if (hbqno > LPFC_MAX_HBQS) + if (hbqno >= LPFC_MAX_HBQS) return NULL; list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) { @@ -716,7 +751,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) case MBX_DEL_LD_ENTRY: case MBX_RUN_PROGRAM: case MBX_SET_MASK: - case MBX_SET_SLIM: + case MBX_SET_VARIABLE: case MBX_UNREG_D_ID: case MBX_KILL_BOARD: case MBX_CONFIG_FARP: @@ -728,7 +763,7 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand) case MBX_READ_RPI64: case MBX_REG_LOGIN64: case MBX_READ_LA64: - case MBX_FLASH_WR_ULA: + case MBX_WRITE_WWN: case MBX_SET_DEBUG: case MBX_LOAD_EXP_ROM: case MBX_ASYNCEVT_ENABLE: @@ -910,16 +945,29 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag) uint32_t hbqno; void *virt; /* virtual address ptr */ dma_addr_t phys; /* mapped address */ + unsigned long flags; + + /* Check whether HBQ is still in use */ + spin_lock_irqsave(&phba->hbalock, flags); + if (!phba->hbq_in_use) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return NULL; + } hbq_entry = lpfc_sli_hbqbuf_find(phba, tag); - if (hbq_entry == NULL) + if (hbq_entry == NULL) { + spin_unlock_irqrestore(&phba->hbalock, flags); return NULL; + } list_del(&hbq_entry->dbuf.list); hbqno = tag >> 16; new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); - if (new_hbq_entry == NULL) + if (new_hbq_entry == NULL) { + list_add_tail(&hbq_entry->dbuf.list, &phba->hbqbuf_in_list); + spin_unlock_irqrestore(&phba->hbalock, flags); return &hbq_entry->dbuf; + } new_hbq_entry->tag = -1; phys = new_hbq_entry->dbuf.phys; virt = new_hbq_entry->dbuf.virt; @@ -928,9 +976,22 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag) hbq_entry->dbuf.phys = phys; hbq_entry->dbuf.virt = virt; lpfc_sli_free_hbq(phba, hbq_entry); + list_add_tail(&new_hbq_entry->dbuf.list, &phba->hbqbuf_in_list); + spin_unlock_irqrestore(&phba->hbalock, flags); + return &new_hbq_entry->dbuf; } +static struct lpfc_dmabuf * +lpfc_sli_get_buff(struct lpfc_hba *phba, + struct lpfc_sli_ring *pring, + uint32_t tag) +{ + if (tag & QUE_BUFTAG_BIT) + return lpfc_sli_ring_taggedbuf_get(phba, pring, tag); + else + return lpfc_sli_replace_hbqbuff(phba, tag); +} static int lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, @@ -940,10 +1001,13 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, WORD5 * w5p; uint32_t Rctl, Type; uint32_t match, i; + struct lpfc_iocbq *iocbq; match = 0; irsp = &(saveq->iocb); + if (irsp->ulpStatus == IOSTAT_NEED_BUFFER) + return 1; if (irsp->ulpCommand == CMD_ASYNC_STATUS) { if (pring->lpfc_sli_rcv_async_status) pring->lpfc_sli_rcv_async_status(phba, pring, saveq); @@ -959,16 +1023,90 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return 1; } - if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) - || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) - || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX) - || (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX)) { + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + if (irsp->ulpBdeCount != 0) { + saveq->context2 = lpfc_sli_get_buff(phba, pring, + irsp->un.ulpWord[3]); + if (!saveq->context2) + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0341 Ring %d Cannot find buffer for " + "an unsolicited iocb. tag 0x%x\n", + pring->ringno, + irsp->un.ulpWord[3]); + } + if (irsp->ulpBdeCount == 2) { + saveq->context3 = lpfc_sli_get_buff(phba, pring, + irsp->unsli3.sli3Words[7]); + if (!saveq->context3) + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0342 Ring %d Cannot find buffer for an" + " unsolicited iocb. tag 0x%x\n", + pring->ringno, + irsp->unsli3.sli3Words[7]); + } + list_for_each_entry(iocbq, &saveq->list, list) { + irsp = &(iocbq->iocb); + if (irsp->ulpBdeCount != 0) { + iocbq->context2 = lpfc_sli_get_buff(phba, pring, + irsp->un.ulpWord[3]); + if (!iocbq->context2) + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0343 Ring %d Cannot find " + "buffer for an unsolicited iocb" + ". tag 0x%x\n", pring->ringno, + irsp->un.ulpWord[3]); + } + if (irsp->ulpBdeCount == 2) { + iocbq->context3 = lpfc_sli_get_buff(phba, pring, + irsp->unsli3.sli3Words[7]); + if (!iocbq->context3) + lpfc_printf_log(phba, + KERN_ERR, + LOG_SLI, + "0344 Ring %d Cannot find " + "buffer for an unsolicited " + "iocb. tag 0x%x\n", + pring->ringno, + irsp->unsli3.sli3Words[7]); + } + } + } + if (irsp->ulpBdeCount != 0 && + (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX || + irsp->ulpStatus == IOSTAT_INTERMED_RSP)) { + int found = 0; + + /* search continue save q for same XRI */ + list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) { + if (iocbq->iocb.ulpContext == saveq->iocb.ulpContext) { + list_add_tail(&saveq->list, &iocbq->list); + found = 1; + break; + } + } + if (!found) + list_add_tail(&saveq->clist, + &pring->iocb_continue_saveq); + if (saveq->iocb.ulpStatus != IOSTAT_INTERMED_RSP) { + list_del_init(&iocbq->clist); + saveq = iocbq; + irsp = &(saveq->iocb); + } else + return 0; + } + 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; } else { - w5p = - (WORD5 *) & (saveq->iocb.un. - ulpWord[5]); + w5p = (WORD5 *)&(saveq->iocb.un.ulpWord[5]); Rctl = w5p->hcsw.Rctl; Type = w5p->hcsw.Type; @@ -983,15 +1121,6 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } } - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - if (irsp->ulpBdeCount != 0) - saveq->context2 = lpfc_sli_replace_hbqbuff(phba, - irsp->un.ulpWord[3]); - if (irsp->ulpBdeCount == 2) - saveq->context3 = lpfc_sli_replace_hbqbuff(phba, - irsp->unsli3.sli3Words[7]); - } - /* unSolicited Responses */ if (pring->prt[0].profile) { if (pring->prt[0].lpfc_sli_rcv_unsol_event) @@ -1001,12 +1130,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } else { /* We must search, based on rctl / type for the right routine */ - for (i = 0; i < pring->num_mask; - i++) { - if ((pring->prt[i].rctl == - Rctl) - && (pring->prt[i]. - type == Type)) { + for (i = 0; i < pring->num_mask; i++) { + if ((pring->prt[i].rctl == Rctl) + && (pring->prt[i].type == Type)) { if (pring->prt[i].lpfc_sli_rcv_unsol_event) (pring->prt[i].lpfc_sli_rcv_unsol_event) (phba, pring, saveq); @@ -1079,6 +1205,12 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, IOSTAT_LOCAL_REJECT; saveq->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED; + + /* Firmware could still be in progress + * of DMAing payload, so don't free data + * buffer till after a hbeat. + */ + saveq->iocb_flag |= LPFC_DELAY_MEM_FREE; } } (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); @@ -1565,12 +1697,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); - if (list_empty(&(pring->iocb_continueq))) { - list_add(&rspiocbp->list, &(pring->iocb_continueq)); - } else { - list_add_tail(&rspiocbp->list, - &(pring->iocb_continueq)); - } + list_add_tail(&rspiocbp->list, &(pring->iocb_continueq)); pring->iocb_continueq_cnt++; if (irsp->ulpLe) { @@ -1635,17 +1762,17 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK; type = lpfc_sli_iocb_cmd_type(iocb_cmd_type); if (type == LPFC_SOL_IOCB) { - spin_unlock_irqrestore(&phba->hbalock, - iflag); + spin_unlock_irqrestore(&phba->hbalock, iflag); rc = lpfc_sli_process_sol_iocb(phba, pring, saveq); spin_lock_irqsave(&phba->hbalock, iflag); } else if (type == LPFC_UNSOL_IOCB) { - spin_unlock_irqrestore(&phba->hbalock, - iflag); + spin_unlock_irqrestore(&phba->hbalock, iflag); rc = lpfc_sli_process_unsol_iocb(phba, pring, saveq); spin_lock_irqsave(&phba->hbalock, iflag); + if (!rc) + free_saveq = 0; } else if (type == LPFC_ABORT_IOCB) { if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) && ((cmdiocbp = @@ -2026,6 +2153,72 @@ lpfc_sli_brdreset(struct lpfc_hba *phba) } int +lpfc_sli_set_dma_length(struct lpfc_hba * phba, uint32_t polling) +{ + uint32_t dma_length; + LPFC_MBOXQ_t *mbox; + int ret = 0; + + switch (phba->cfg_pci_max_read) { + case 512: + dma_length = SLIM_VAL_MAX_DMA_512; + break; + case 1024: + dma_length = SLIM_VAL_MAX_DMA_1024; + break; + case 2048: + dma_length = SLIM_VAL_MAX_DMA_2048; + break; + case 4096: + dma_length = SLIM_VAL_MAX_DMA_4096; + break; + default: + return -EINVAL; + } + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + goto failed; + + lpfc_set_var(phba, mbox, SLIM_VAR_MAX_DMA_LENGTH, dma_length); + + if (polling) + ret = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); + else + ret = lpfc_sli_issue_mbox_wait(phba, mbox, + LPFC_MBOX_TMO * 2); + + if (ret != MBX_SUCCESS) { + if (mbox->mb.mbxStatus != MBXERR_UNKNOWN_CMD) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "%d:0443 Adapter failed to set maximum" + " DMA length mbxStatus x%x \n", + phba->brd_no, mbox->mb.mbxStatus) + else + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "%d:0447 Adapter failed to set maximum" + " DMA length mbxStatus x%x \n", + phba->brd_no, mbox->mb.mbxStatus); + goto failed; + } + + mempool_free( mbox, phba->mbox_mem_pool); + return 0; + +failed: + /* If mailbox command failed, reset the value to default value */ + phba->cfg_pci_max_read = 2048; + if (ret == MBX_TIMEOUT) { + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + return -EPERM; + } else if (mbox) { + mempool_free( mbox, phba->mbox_mem_pool); + return -EPERM; + } else + return -ENOMEM; +} + +int lpfc_sli_brdrestart(struct lpfc_hba *phba) { MAILBOX_t *mb; @@ -2194,18 +2387,13 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba) uint32_t hbqno; uint32_t hbq_entry_index; - /* Get a Mailbox buffer to setup mailbox - * commands for HBA initialization - */ pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) return -ENOMEM; - pmbox = &pmb->mb; - /* Initialize the struct lpfc_sli_hbq structure for each hbq */ phba->link_state = LPFC_INIT_MBX_CMDS; + phba->hbq_in_use = 1; hbq_entry_index = 0; for (hbqno = 0; hbqno < hbq_count; ++hbqno) { @@ -2215,20 +2403,16 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba) phba->hbqs[hbqno].entry_count = lpfc_hbq_defs[hbqno]->entry_count; lpfc_config_hbq(phba, hbqno, lpfc_hbq_defs[hbqno], - hbq_entry_index, pmb); + hbq_entry_index, pmb); hbq_entry_index += phba->hbqs[hbqno].entry_count; if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { - /* Adapter failed to init, mbxCmd <cmd> CFG_RING, - mbxStatus <status>, ring <num> */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT, "1805 Adapter failed to init. " "Data: x%x x%x x%x\n", pmbox->mbxCommand, pmbox->mbxStatus, hbqno); - phba->link_state = LPFC_HBA_ERROR; mempool_free(pmb, phba->mbox_mem_pool); return ENXIO; @@ -2379,6 +2563,9 @@ lpfc_sli_hba_setup(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0444 Firmware in SLI %x mode. Max_vpi %d\n", phba->sli_rev, phba->max_vpi); + + lpfc_sli_set_dma_length(phba,1); + rc = lpfc_sli_ring_map(phba); if (rc) @@ -2478,11 +2665,16 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba) lpfc_sli_abort_iocb_ring(phba, pring); lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0316 Resetting board due to mailbox timeout\n"); + "0345 Resetting board due to mailbox timeout\n"); /* * lpfc_offline calls lpfc_sli_hba_down which will clean up * on oustanding mailbox commands. */ + /* If resets are disabled then set error state and return. */ + if (!phba->cfg_enable_hba_reset) { + phba->link_state = LPFC_HBA_ERROR; + return; + } lpfc_offline_prep(phba); lpfc_offline(phba); lpfc_sli_brdrestart(phba); @@ -2646,6 +2838,12 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) if (psli->sli_flag & LPFC_SLI2_ACTIVE) { /* First copy command data to host SLIM area */ lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx, MAILBOX_CMD_SIZE); + if ((mb->mbxCommand == MBX_UPDATE_CFG) && pmbox->context2) + lpfc_sli_pcimem_bcopy(pmbox->context2, + (uint8_t*)&phba->slim2p->mbx + + mb->un.varUpdateCfg.data_offset, + mb->un.varUpdateCfg.byte_cnt); + } else { if (mb->mbxCommand == MBX_CONFIG_PORT) { /* copy command data into host mbox for cmpl */ @@ -2672,18 +2870,24 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) } wmb(); - /* interrupt board to doit right away */ - writel(CA_MBATT, phba->CAregaddr); - readl(phba->CAregaddr); /* flush */ switch (flag) { case MBX_NOWAIT: - /* Don't wait for it to finish, just return */ + /* Set up reference to mailbox command */ psli->mbox_active = pmbox; + /* Interrupt board to do it */ + writel(CA_MBATT, phba->CAregaddr); + readl(phba->CAregaddr); /* flush */ + /* Don't wait for it to finish, just return */ break; case MBX_POLL: + /* Set up null reference to mailbox command */ psli->mbox_active = NULL; + /* Interrupt board to do it */ + writel(CA_MBATT, phba->CAregaddr); + readl(phba->CAregaddr); /* flush */ + if (psli->sli_flag & LPFC_SLI2_ACTIVE) { /* First read mbox status word */ word0 = *((volatile uint32_t *)&phba->slim2p->mbx); @@ -2967,7 +3171,7 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba, lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0327 Ring %d handler: unexpected ASYNC_STATUS" + "0346 Ring %d handler: unexpected ASYNC_STATUS" " evt_code 0x%x\n", pring->ringno, icmd->un.asyncstat.evt_code); @@ -2978,16 +3182,16 @@ lpfc_sli_async_event_handler(struct lpfc_hba * phba, if (evt_code == ASYNC_TEMP_WARN) { temp_event_data.event_code = LPFC_THRESHOLD_TEMP; lpfc_printf_log(phba, - KERN_WARNING, + KERN_ERR, LOG_TEMP, - "0339 Adapter is very hot, please take " + "0347 Adapter is very hot, please take " "corrective action. temperature : %d Celsius\n", temp); } if (evt_code == ASYNC_TEMP_SAFE) { temp_event_data.event_code = LPFC_NORMAL_TEMP; lpfc_printf_log(phba, - KERN_INFO, + KERN_ERR, LOG_TEMP, "0340 Adapter temperature is OK now. " "temperature : %d Celsius\n", @@ -3135,6 +3339,7 @@ lpfc_sli_queue_setup(struct lpfc_hba *phba) INIT_LIST_HEAD(&pring->txq); INIT_LIST_HEAD(&pring->txcmplq); INIT_LIST_HEAD(&pring->iocb_continueq); + INIT_LIST_HEAD(&pring->iocb_continue_saveq); INIT_LIST_HEAD(&pring->postbufq); } spin_unlock_irq(&phba->hbalock); @@ -3205,6 +3410,7 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) LIST_HEAD(completions); struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; + struct lpfc_dmabuf *buf_ptr; LPFC_MBOXQ_t *pmb; struct lpfc_iocbq *iocb; IOCB_t *cmd = NULL; @@ -3244,6 +3450,19 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) } } + spin_lock_irqsave(&phba->hbalock, flags); + list_splice_init(&phba->elsbuf, &completions); + phba->elsbuf_cnt = 0; + phba->elsbuf_prev_cnt = 0; + spin_unlock_irqrestore(&phba->hbalock, flags); + + while (!list_empty(&completions)) { + list_remove_head(&completions, buf_ptr, + struct lpfc_dmabuf, list); + lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); + kfree(buf_ptr); + } + /* Return any active mbox cmds */ del_timer_sync(&psli->mbox_tmo); spin_lock_irqsave(&phba->hbalock, flags); @@ -3306,6 +3525,47 @@ lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return 0; } +uint32_t +lpfc_sli_get_buffer_tag(struct lpfc_hba *phba) +{ + spin_lock_irq(&phba->hbalock); + phba->buffer_tag_count++; + /* + * Always set the QUE_BUFTAG_BIT to distiguish between + * a tag assigned by HBQ. + */ + phba->buffer_tag_count |= QUE_BUFTAG_BIT; + spin_unlock_irq(&phba->hbalock); + return phba->buffer_tag_count; +} + +struct lpfc_dmabuf * +lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + uint32_t tag) +{ + struct lpfc_dmabuf *mp, *next_mp; + struct list_head *slp = &pring->postbufq; + + /* Search postbufq, from the begining, looking for a match on tag */ + spin_lock_irq(&phba->hbalock); + list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { + if (mp->buffer_tag == tag) { + list_del_init(&mp->list); + pring->postbufq_cnt--; + spin_unlock_irq(&phba->hbalock); + return mp; + } + } + + spin_unlock_irq(&phba->hbalock); + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0410 Cannot find virtual addr for buffer tag on " + "ring %d Data x%lx x%p x%p x%x\n", + pring->ringno, (unsigned long) tag, + slp->next, slp->prev, pring->postbufq_cnt); + + return NULL; +} struct lpfc_dmabuf * lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, @@ -3373,6 +3633,12 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, pring->txcmplq_cnt--; spin_unlock_irq(&phba->hbalock); + /* Firmware could still be in progress of DMAing + * payload, so don't free data buffer till after + * a hbeat. + */ + abort_iocb->iocb_flag |= LPFC_DELAY_MEM_FREE; + abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED; @@ -3411,7 +3677,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *abtsiocbp; IOCB_t *icmd = NULL; IOCB_t *iabt = NULL; - int retval = IOCB_ERROR; + int retval; /* * There are certain command types we don't want to abort. And we @@ -3433,19 +3699,22 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl; else cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl; - goto abort_iotag_exit; + return 0; } /* issue ABTS for this IOCB based on iotag */ abtsiocbp = __lpfc_sli_get_iocbq(phba); if (abtsiocbp == NULL) - return 0; + return IOCB_ERROR; /* This signals the response to set the correct status * before calling the completion handler. */ cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED; + if (vport->load_flag & FC_UNLOADING) + cmdiocb->vport = NULL; + iabt = &abtsiocbp->iocb; iabt->un.acxri.abortType = ABORT_TYPE_ABTS; iabt->un.acxri.abortContextTag = icmd->ulpContext; @@ -3467,7 +3736,9 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, iabt->un.acxri.abortIoTag, abtsiocbp->iotag); retval = __lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0); -abort_iotag_exit: + if (retval) + __lpfc_sli_release_iocbq(phba, abtsiocbp); + /* * Caller to this routine should check for IOCB_ERROR * and handle it properly. This routine no longer removes @@ -3713,7 +3984,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, unsigned long flag; /* The caller must leave context1 empty. */ - if (pmboxq->context1 != 0) + if (pmboxq->context1) return MBX_NOT_FINISHED; /* setup wake call as IOCB callback */ @@ -3898,7 +4169,6 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs) } if (work_ha_copy & HA_ERATT) { - phba->link_state = LPFC_HBA_ERROR; /* * There was a link/board error. Read the * status register to retrieve the error event @@ -3930,7 +4200,7 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs) * Stray Mailbox Interrupt, mbxCommand <cmd> * mbxStatus <status> */ - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "(%d):0304 Stray Mailbox " "Interrupt mbxCommand x%x " @@ -3938,51 +4208,60 @@ lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs) (vport ? vport->vpi : 0), pmbox->mbxCommand, pmbox->mbxStatus); - } - phba->last_completion_time = jiffies; - del_timer_sync(&phba->sli.mbox_tmo); - - phba->sli.mbox_active = NULL; - if (pmb->mbox_cmpl) { - lpfc_sli_pcimem_bcopy(mbox, pmbox, - MAILBOX_CMD_SIZE); - } - if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) { - pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG; + /* clear mailbox attention bit */ + work_ha_copy &= ~HA_MBATT; + } else { + phba->last_completion_time = jiffies; + del_timer(&phba->sli.mbox_tmo); - lpfc_debugfs_disc_trc(vport, - LPFC_DISC_TRC_MBOX_VPORT, - "MBOX dflt rpi: : status:x%x rpi:x%x", - (uint32_t)pmbox->mbxStatus, - pmbox->un.varWords[0], 0); - - if ( !pmbox->mbxStatus) { - mp = (struct lpfc_dmabuf *) - (pmb->context1); - ndlp = (struct lpfc_nodelist *) - pmb->context2; - - /* Reg_LOGIN of dflt RPI was successful. - * new lets get rid of the RPI using the - * same mbox buffer. - */ - lpfc_unreg_login(phba, vport->vpi, - pmbox->un.varWords[0], pmb); - pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; - pmb->context1 = mp; - pmb->context2 = ndlp; - pmb->vport = vport; - spin_lock(&phba->hbalock); - phba->sli.sli_flag &= - ~LPFC_SLI_MBOX_ACTIVE; - spin_unlock(&phba->hbalock); - goto send_current_mbox; + phba->sli.mbox_active = NULL; + if (pmb->mbox_cmpl) { + lpfc_sli_pcimem_bcopy(mbox, pmbox, + MAILBOX_CMD_SIZE); + } + if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) { + pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG; + + lpfc_debugfs_disc_trc(vport, + LPFC_DISC_TRC_MBOX_VPORT, + "MBOX dflt rpi: : " + "status:x%x rpi:x%x", + (uint32_t)pmbox->mbxStatus, + pmbox->un.varWords[0], 0); + + if (!pmbox->mbxStatus) { + mp = (struct lpfc_dmabuf *) + (pmb->context1); + ndlp = (struct lpfc_nodelist *) + pmb->context2; + + /* Reg_LOGIN of dflt RPI was + * successful. new lets get + * rid of the RPI using the + * same mbox buffer. + */ + lpfc_unreg_login(phba, + vport->vpi, + pmbox->un.varWords[0], + pmb); + pmb->mbox_cmpl = + lpfc_mbx_cmpl_dflt_rpi; + pmb->context1 = mp; + pmb->context2 = ndlp; + pmb->vport = vport; + spin_lock(&phba->hbalock); + phba->sli.sli_flag &= + ~LPFC_SLI_MBOX_ACTIVE; + spin_unlock(&phba->hbalock); + goto send_current_mbox; + } } + spin_lock(&phba->pport->work_port_lock); + phba->pport->work_port_events &= + ~WORKER_MBOX_TMO; + spin_unlock(&phba->pport->work_port_lock); + lpfc_mbox_cmpl_put(phba, pmb); } - spin_lock(&phba->pport->work_port_lock); - phba->pport->work_port_events &= ~WORKER_MBOX_TMO; - spin_unlock(&phba->pport->work_port_lock); - lpfc_mbox_cmpl_put(phba, pmb); } if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active == NULL)) { diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 5fcfe88..7249fd2 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -33,6 +33,7 @@ typedef enum _lpfc_ctx_cmd { struct lpfc_iocbq { /* lpfc_iocbqs are used in double linked lists */ struct list_head list; + struct list_head clist; uint16_t iotag; /* pre-assigned IO tag */ uint16_t rsvd1; @@ -44,6 +45,7 @@ struct lpfc_iocbq { #define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ #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 */ uint8_t abort_count; uint8_t rsvd2; @@ -159,6 +161,7 @@ struct lpfc_sli_ring { struct list_head iocb_continueq; uint16_t iocb_continueq_cnt; /* current length of queue */ uint16_t iocb_continueq_max; /* max length */ + struct list_head iocb_continue_saveq; struct lpfc_sli_ring_mask prt[LPFC_MAX_RING_MASK]; uint32_t num_mask; /* number of mask entries in prt array */ diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 2dac2dd..0f21b32 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.2.0.8" +#define LPFC_DRIVER_VERSION "8.2.0.13" #define LPFC_DRIVER_NAME "lpfc" diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index b32c5a6..7f97b86 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -207,8 +207,7 @@ lpfc_vport_create(struct Scsi_Host *shost, const uint8_t *wwnn, int rc = VPORT_ERROR; int status; - if ((phba->sli_rev < 3) || - !(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { + if ((phba->sli_rev < 3) || !phba->cfg_enable_npiv) { lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, "1808 Create VPORT failed: " "NPIV is not enabled: SLImode:%d\n", @@ -395,8 +394,13 @@ lpfc_vport_delete(struct Scsi_Host *shost) * initiated after we've disposed of all other resources associated * with the port. */ - if (!scsi_host_get(shost) || !scsi_host_get(shost)) + if (!scsi_host_get(shost)) return VPORT_INVAL; + if (!scsi_host_get(shost)) { + scsi_host_put(shost); + return VPORT_INVAL; + } + spin_lock_irq(&phba->hbalock); vport->load_flag |= FC_UNLOADING; spin_unlock_irq(&phba->hbalock); @@ -450,7 +454,18 @@ skip_logo: * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) * does the scsi_host_put() to release the vport. */ - lpfc_mbx_unreg_vpi(vport); + if (lpfc_mbx_unreg_vpi(vport)) { + /* + * Need to release the reference count to shost + */ + scsi_host_put(shost); + } + } + else { + /* + * Need to release the reference count to shost + */ + scsi_host_put(shost); } lpfc_free_vpi(phba, vport->vpi); @@ -473,7 +488,7 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) struct lpfc_vport *port_iterator; struct lpfc_vport **vports; int index = 0; - vports = kzalloc(LPFC_MAX_VPORTS * sizeof(struct lpfc_vport *), + vports = kzalloc((phba->max_vpi + 1) * sizeof(struct lpfc_vport *), GFP_KERNEL); if (vports == NULL) return NULL; @@ -492,12 +507,12 @@ lpfc_create_vport_work_array(struct lpfc_hba *phba) } void -lpfc_destroy_vport_work_array(struct lpfc_vport **vports) +lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports) { int i; if (vports == NULL) return; - for (i=0; vports[i] != NULL && i < LPFC_MAX_VPORTS; i++) + for (i=0; vports[i] != NULL && i <= phba->max_vpi; i++) scsi_host_put(lpfc_shost_from_vport(vports[i])); kfree(vports); } diff --git a/drivers/scsi/lpfc/lpfc_vport.h b/drivers/scsi/lpfc/lpfc_vport.h index c689ed8..345ce7a 100644 --- a/drivers/scsi/lpfc/lpfc_vport.h +++ b/drivers/scsi/lpfc/lpfc_vport.h @@ -89,7 +89,7 @@ int lpfc_vport_delete(struct Scsi_Host *); int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *); int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint); struct lpfc_vport **lpfc_create_vport_work_array(struct lpfc_hba *); -void lpfc_destroy_vport_work_array(struct lpfc_vport **); +void lpfc_destroy_vport_work_array(struct lpfc_hba *, struct lpfc_vport **); /* * queuecommand VPORT-specific return codes. Specified in the host byte code.