diff options
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.h | 3 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 8 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.c | 46 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.h | 418 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 141 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 18 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 3 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 18 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 377 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 9 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 414 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 785 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 17 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 2 |
17 files changed, 1463 insertions, 806 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 3a1ffdd6d831..e5da6da20f8a 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -93,6 +93,9 @@ struct lpfc_sli2_slim; /* lpfc wait event data ready flag */ #define LPFC_DATA_READY (1<<0) +/* queue dump line buffer size */ +#define LPFC_LBUF_SZ 128 + enum lpfc_polling_flags { ENABLE_FCP_RING_POLLING = 0x1, DISABLE_FCP_RING_INT = 0x2 @@ -620,6 +623,7 @@ struct lpfc_hba { #define HBA_AER_ENABLED 0x1000 /* AER enabled with HBA */ #define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */ #define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */ +#define HBA_FCP_IOQ_FLUSH 0x8000 /* FCP I/O queues being flushed */ uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ struct lpfc_dmabuf slim2p; diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 141e4b40bb55..253d9a857346 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009-2011 Emulex. All rights reserved. * + * Copyright (C) 2009-2012 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -599,6 +599,7 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job) cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp; cmdiocbq->context1 = dd_data; + cmdiocbq->context_un.ndlp = ndlp; cmdiocbq->context2 = rspiocbq; dd_data->type = TYPE_IOCB; dd_data->context_un.iocb.cmdiocbq = cmdiocbq; @@ -3978,6 +3979,7 @@ lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, } else if (subsys == SLI_CONFIG_SUBSYS_COMN) { switch (opcode) { case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES: + case COMN_OPCODE_GET_CNTL_ATTRIBUTES: lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, "3106 Handled SLI_CONFIG " "subsys_comn, opcode:x%x\n", diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index edfe61fc52b1..67f7d0a160d1 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2010 Emulex. All rights reserved. * + * Copyright (C) 2010-2012 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -249,6 +249,7 @@ struct lpfc_sli_config_emb1_subsys { #define COMN_OPCODE_READ_OBJECT_LIST 0xAD #define COMN_OPCODE_DELETE_OBJECT 0xAE #define COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES 0x79 +#define COMN_OPCODE_GET_CNTL_ATTRIBUTES 0x20 uint32_t timeout; uint32_t request_length; uint32_t word9; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 330dd7192a7f..9b2a16f3bc79 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -254,6 +254,7 @@ int lpfc_sli_handle_fast_ring_event(struct lpfc_hba *, struct lpfc_sli_ring *, uint32_t); +struct lpfc_iocbq *__lpfc_sli_get_iocbq(struct lpfc_hba *); struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *); uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *); @@ -460,6 +461,7 @@ int lpfc_hba_init_link_fc_topology(struct lpfc_hba *, uint32_t, uint32_t); int lpfc_issue_reg_vfi(struct lpfc_vport *); int lpfc_issue_unreg_vfi(struct lpfc_vport *); int lpfc_selective_reset(struct lpfc_hba *); -int lpfc_sli4_read_config(struct lpfc_hba *phba); -int lpfc_scsi_buf_update(struct lpfc_hba *phba); -void lpfc_sli4_node_prep(struct lpfc_hba *phba); +int lpfc_sli4_read_config(struct lpfc_hba *); +void lpfc_sli4_node_prep(struct lpfc_hba *); +int lpfc_sli4_xri_sgl_update(struct lpfc_hba *); +void lpfc_free_sgl_list(struct lpfc_hba *, struct list_head *); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index af04b0d6688d..3217d63ed282 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -4466,3 +4466,49 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) #endif return; } + +/* + * Driver debug utility routines outside of debugfs. The debug utility + * routines implemented here is intended to be used in the instrumented + * debug driver for debugging host or port issues. + */ + +/** + * lpfc_debug_dump_all_queues - dump all the queues with a hba + * @phba: Pointer to HBA context object. + * + * This function dumps entries of all the queues asociated with the @phba. + **/ +void +lpfc_debug_dump_all_queues(struct lpfc_hba *phba) +{ + int fcp_wqidx; + + /* + * Dump Work Queues (WQs) + */ + lpfc_debug_dump_mbx_wq(phba); + lpfc_debug_dump_els_wq(phba); + + for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) + lpfc_debug_dump_fcp_wq(phba, fcp_wqidx); + + lpfc_debug_dump_hdr_rq(phba); + lpfc_debug_dump_dat_rq(phba); + /* + * Dump Complete Queues (CQs) + */ + lpfc_debug_dump_mbx_cq(phba); + lpfc_debug_dump_els_cq(phba); + + for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) + lpfc_debug_dump_fcp_cq(phba, fcp_wqidx); + + /* + * Dump Event Queues (EQs) + */ + lpfc_debug_dump_sp_eq(phba); + + for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) + lpfc_debug_dump_fcp_eq(phba, fcp_wqidx); +} diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index f83bd944edd8..616c400dae14 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -267,3 +267,421 @@ struct lpfc_idiag { #define LPFC_DISC_TRC_DISCOVERY 0xef /* common mask for general * discovery */ #endif /* H_LPFC_DEBUG_FS */ + + +/* + * Driver debug utility routines outside of debugfs. The debug utility + * routines implemented here is intended to be used in the instrumented + * debug driver for debugging host or port issues. + */ + +/** + * lpfc_debug_dump_qe - dump an specific entry from a queue + * @q: Pointer to the queue descriptor. + * @idx: Index to the entry on the queue. + * + * This function dumps an entry indexed by @idx from a queue specified by the + * queue descriptor @q. + **/ +static inline void +lpfc_debug_dump_qe(struct lpfc_queue *q, uint32_t idx) +{ + char line_buf[LPFC_LBUF_SZ]; + int i, esize, qe_word_cnt, len; + uint32_t *pword; + + /* sanity checks */ + if (!q) + return; + if (idx >= q->entry_count) + return; + + esize = q->entry_size; + qe_word_cnt = esize / sizeof(uint32_t); + pword = q->qe[idx].address; + + len = 0; + len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, "QE[%04d]: ", idx); + if (qe_word_cnt > 8) + printk(KERN_ERR "%s\n", line_buf); + + for (i = 0; i < qe_word_cnt; i++) { + if (!(i % 8)) { + if (i != 0) + printk(KERN_ERR "%s\n", line_buf); + if (qe_word_cnt > 8) { + len = 0; + memset(line_buf, 0, LPFC_LBUF_SZ); + len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, + "%03d: ", i); + } + } + len += snprintf(line_buf+len, LPFC_LBUF_SZ-len, "%08x ", + ((uint32_t)*pword) & 0xffffffff); + pword++; + } + if (qe_word_cnt <= 8 || (i - 1) % 8) + printk(KERN_ERR "%s\n", line_buf); +} + +/** + * lpfc_debug_dump_q - dump all entries from an specific queue + * @q: Pointer to the queue descriptor. + * + * This function dumps all entries from a queue specified by the queue + * descriptor @q. + **/ +static inline void +lpfc_debug_dump_q(struct lpfc_queue *q) +{ + int idx, entry_count; + + /* sanity check */ + if (!q) + return; + + dev_printk(KERN_ERR, &(((q->phba))->pcidev)->dev, + "%d: [qid:%d, type:%d, subtype:%d, " + "qe_size:%d, qe_count:%d, " + "host_index:%d, port_index:%d]\n", + (q->phba)->brd_no, + q->queue_id, q->type, q->subtype, + q->entry_size, q->entry_count, + q->host_index, q->hba_index); + entry_count = q->entry_count; + for (idx = 0; idx < entry_count; idx++) + lpfc_debug_dump_qe(q, idx); + printk(KERN_ERR "\n"); +} + +/** + * lpfc_debug_dump_fcp_wq - dump all entries from a fcp work queue + * @phba: Pointer to HBA context object. + * @fcp_wqidx: Index to a FCP work queue. + * + * This function dumps all entries from a FCP work queue specified by the + * @fcp_wqidx. + **/ +static inline void +lpfc_debug_dump_fcp_wq(struct lpfc_hba *phba, int fcp_wqidx) +{ + /* sanity check */ + if (fcp_wqidx >= phba->cfg_fcp_wq_count) + return; + + printk(KERN_ERR "FCP WQ: WQ[Idx:%d|Qid:%d]\n", + fcp_wqidx, phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.fcp_wq[fcp_wqidx]); +} + +/** + * lpfc_debug_dump_fcp_cq - dump all entries from a fcp work queue's cmpl queue + * @phba: Pointer to HBA context object. + * @fcp_wqidx: Index to a FCP work queue. + * + * This function dumps all entries from a FCP complete queue which is + * associated to the FCP work queue specified by the @fcp_wqidx. + **/ +static inline void +lpfc_debug_dump_fcp_cq(struct lpfc_hba *phba, int fcp_wqidx) +{ + int fcp_cqidx, fcp_cqid; + + /* sanity check */ + if (fcp_wqidx >= phba->cfg_fcp_wq_count) + return; + + fcp_cqid = phba->sli4_hba.fcp_wq[fcp_wqidx]->assoc_qid; + for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) + if (phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id == fcp_cqid) + break; + if (fcp_cqidx >= phba->cfg_fcp_eq_count) + return; + + printk(KERN_ERR "FCP CQ: WQ[Idx:%d|Qid%d]->CQ[Idx%d|Qid%d]:\n", + fcp_wqidx, phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id, + fcp_cqidx, fcp_cqid); + lpfc_debug_dump_q(phba->sli4_hba.fcp_cq[fcp_cqidx]); +} + +/** + * lpfc_debug_dump_fcp_eq - dump all entries from a fcp work queue's evt queue + * @phba: Pointer to HBA context object. + * @fcp_wqidx: Index to a FCP work queue. + * + * This function dumps all entries from a FCP event queue which is + * associated to the FCP work queue specified by the @fcp_wqidx. + **/ +static inline void +lpfc_debug_dump_fcp_eq(struct lpfc_hba *phba, int fcp_wqidx) +{ + struct lpfc_queue *qdesc; + int fcp_eqidx, fcp_eqid; + int fcp_cqidx, fcp_cqid; + + /* sanity check */ + if (fcp_wqidx >= phba->cfg_fcp_wq_count) + return; + fcp_cqid = phba->sli4_hba.fcp_wq[fcp_wqidx]->assoc_qid; + for (fcp_cqidx = 0; fcp_cqidx < phba->cfg_fcp_eq_count; fcp_cqidx++) + if (phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id == fcp_cqid) + break; + if (fcp_cqidx >= phba->cfg_fcp_eq_count) + return; + + if (phba->cfg_fcp_eq_count == 0) { + fcp_eqidx = -1; + fcp_eqid = phba->sli4_hba.sp_eq->queue_id; + qdesc = phba->sli4_hba.sp_eq; + } else { + fcp_eqidx = fcp_cqidx; + fcp_eqid = phba->sli4_hba.fp_eq[fcp_eqidx]->queue_id; + qdesc = phba->sli4_hba.fp_eq[fcp_eqidx]; + } + + printk(KERN_ERR "FCP EQ: WQ[Idx:%d|Qid:%d]->CQ[Idx:%d|Qid:%d]->" + "EQ[Idx:%d|Qid:%d]\n", + fcp_wqidx, phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id, + fcp_cqidx, fcp_cqid, fcp_eqidx, fcp_eqid); + lpfc_debug_dump_q(qdesc); +} + +/** + * lpfc_debug_dump_els_wq - dump all entries from the els work queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the ELS work queue. + **/ +static inline void +lpfc_debug_dump_els_wq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "ELS WQ: WQ[Qid:%d]:\n", + phba->sli4_hba.els_wq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.els_wq); +} + +/** + * lpfc_debug_dump_mbx_wq - dump all entries from the mbox work queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the MBOX work queue. + **/ +static inline void +lpfc_debug_dump_mbx_wq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "MBX WQ: WQ[Qid:%d]\n", + phba->sli4_hba.mbx_wq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.mbx_wq); +} + +/** + * lpfc_debug_dump_dat_rq - dump all entries from the receive data queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the receive data queue. + **/ +static inline void +lpfc_debug_dump_dat_rq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "DAT RQ: RQ[Qid:%d]\n", + phba->sli4_hba.dat_rq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.dat_rq); +} + +/** + * lpfc_debug_dump_hdr_rq - dump all entries from the receive header queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the receive header queue. + **/ +static inline void +lpfc_debug_dump_hdr_rq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "HDR RQ: RQ[Qid:%d]\n", + phba->sli4_hba.hdr_rq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.hdr_rq); +} + +/** + * lpfc_debug_dump_els_cq - dump all entries from the els complete queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the els complete queue. + **/ +static inline void +lpfc_debug_dump_els_cq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "ELS CQ: WQ[Qid:%d]->CQ[Qid:%d]\n", + phba->sli4_hba.els_wq->queue_id, + phba->sli4_hba.els_cq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.els_cq); +} + +/** + * lpfc_debug_dump_mbx_cq - dump all entries from the mbox complete queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the mbox complete queue. + **/ +static inline void +lpfc_debug_dump_mbx_cq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "MBX CQ: WQ[Qid:%d]->CQ[Qid:%d]\n", + phba->sli4_hba.mbx_wq->queue_id, + phba->sli4_hba.mbx_cq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.mbx_cq); +} + +/** + * lpfc_debug_dump_sp_eq - dump all entries from slow-path event queue + * @phba: Pointer to HBA context object. + * + * This function dumps all entries from the slow-path event queue. + **/ +static inline void +lpfc_debug_dump_sp_eq(struct lpfc_hba *phba) +{ + printk(KERN_ERR "SP EQ: WQ[Qid:%d/Qid:%d]->CQ[Qid:%d/Qid:%d]->" + "EQ[Qid:%d]:\n", + phba->sli4_hba.mbx_wq->queue_id, + phba->sli4_hba.els_wq->queue_id, + phba->sli4_hba.mbx_cq->queue_id, + phba->sli4_hba.els_cq->queue_id, + phba->sli4_hba.sp_eq->queue_id); + lpfc_debug_dump_q(phba->sli4_hba.sp_eq); +} + +/** + * lpfc_debug_dump_wq_by_id - dump all entries from a work queue by queue id + * @phba: Pointer to HBA context object. + * @qid: Work queue identifier. + * + * This function dumps all entries from a work queue identified by the queue + * identifier. + **/ +static inline void +lpfc_debug_dump_wq_by_id(struct lpfc_hba *phba, int qid) +{ + int wq_idx; + + for (wq_idx = 0; wq_idx < phba->cfg_fcp_wq_count; wq_idx++) + if (phba->sli4_hba.fcp_wq[wq_idx]->queue_id == qid) + break; + if (wq_idx < phba->cfg_fcp_wq_count) { + printk(KERN_ERR "FCP WQ[Idx:%d|Qid:%d]\n", wq_idx, qid); + lpfc_debug_dump_q(phba->sli4_hba.fcp_wq[wq_idx]); + return; + } + + if (phba->sli4_hba.els_wq->queue_id == qid) { + printk(KERN_ERR "ELS WQ[Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.els_wq); + } +} + +/** + * lpfc_debug_dump_mq_by_id - dump all entries from a mbox queue by queue id + * @phba: Pointer to HBA context object. + * @qid: Mbox work queue identifier. + * + * This function dumps all entries from a mbox work queue identified by the + * queue identifier. + **/ +static inline void +lpfc_debug_dump_mq_by_id(struct lpfc_hba *phba, int qid) +{ + if (phba->sli4_hba.mbx_wq->queue_id == qid) { + printk(KERN_ERR "MBX WQ[Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.mbx_wq); + } +} + +/** + * lpfc_debug_dump_rq_by_id - dump all entries from a receive queue by queue id + * @phba: Pointer to HBA context object. + * @qid: Receive queue identifier. + * + * This function dumps all entries from a receive queue identified by the + * queue identifier. + **/ +static inline void +lpfc_debug_dump_rq_by_id(struct lpfc_hba *phba, int qid) +{ + if (phba->sli4_hba.hdr_rq->queue_id == qid) { + printk(KERN_ERR "HDR RQ[Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.hdr_rq); + return; + } + if (phba->sli4_hba.dat_rq->queue_id == qid) { + printk(KERN_ERR "DAT RQ[Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.dat_rq); + } +} + +/** + * lpfc_debug_dump_cq_by_id - dump all entries from a cmpl queue by queue id + * @phba: Pointer to HBA context object. + * @qid: Complete queue identifier. + * + * This function dumps all entries from a complete queue identified by the + * queue identifier. + **/ +static inline void +lpfc_debug_dump_cq_by_id(struct lpfc_hba *phba, int qid) +{ + int cq_idx = 0; + + do { + if (phba->sli4_hba.fcp_cq[cq_idx]->queue_id == qid) + break; + } while (++cq_idx < phba->cfg_fcp_eq_count); + + if (cq_idx < phba->cfg_fcp_eq_count) { + printk(KERN_ERR "FCP CQ[Idx:%d|Qid:%d]\n", cq_idx, qid); + lpfc_debug_dump_q(phba->sli4_hba.fcp_cq[cq_idx]); + return; + } + + if (phba->sli4_hba.els_cq->queue_id == qid) { + printk(KERN_ERR "ELS CQ[Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.els_cq); + return; + } + + if (phba->sli4_hba.mbx_cq->queue_id == qid) { + printk(KERN_ERR "MBX CQ[Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.mbx_cq); + } +} + +/** + * lpfc_debug_dump_eq_by_id - dump all entries from an event queue by queue id + * @phba: Pointer to HBA context object. + * @qid: Complete queue identifier. + * + * This function dumps all entries from an event queue identified by the + * queue identifier. + **/ +static inline void +lpfc_debug_dump_eq_by_id(struct lpfc_hba *phba, int qid) +{ + int eq_idx; + + for (eq_idx = 0; eq_idx < phba->cfg_fcp_eq_count; eq_idx++) { + if (phba->sli4_hba.fp_eq[eq_idx]->queue_id == qid) + break; + } + + if (eq_idx < phba->cfg_fcp_eq_count) { + printk(KERN_ERR "FCP EQ[Idx:%d|Qid:%d]\n", eq_idx, qid); + lpfc_debug_dump_q(phba->sli4_hba.fp_eq[eq_idx]); + return; + } + + if (phba->sli4_hba.sp_eq->queue_id == qid) { + printk(KERN_ERR "SP EQ[|Qid:%d]\n", qid); + lpfc_debug_dump_q(phba->sli4_hba.sp_eq); + } +} + +void lpfc_debug_dump_all_queues(struct lpfc_hba *); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 3407b39e0a3f..d54ae1999797 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -230,27 +230,43 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, INIT_LIST_HEAD(&pbuflist->list); - icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys); - icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys); - icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - icmd->un.elsreq64.remoteID = did; /* DID */ if (expectRsp) { + icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys); + icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys); + icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64)); + + icmd->un.elsreq64.remoteID = did; /* DID */ icmd->ulpCommand = CMD_ELS_REQUEST64_CR; icmd->ulpTimeout = phba->fc_ratov * 2; } else { - icmd->un.elsreq64.bdl.bdeSize = sizeof(struct ulp_bde64); + icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys); + icmd->un.xseq64.bdl.addrLow = putPaddrLow(pbuflist->phys); + icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; + icmd->un.xseq64.bdl.bdeSize = sizeof(struct ulp_bde64); + icmd->un.xseq64.xmit_els_remoteID = did; /* DID */ icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX; } icmd->ulpBdeCount = 1; icmd->ulpLe = 1; icmd->ulpClass = CLASS3; - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { - icmd->un.elsreq64.myID = vport->fc_myDID; + /* + * If we have NPIV enabled, we want to send ELS traffic by VPI. + * For SLI4, since the driver controls VPIs we also want to include + * all ELS pt2pt protocol traffic as well. + */ + if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) || + ((phba->sli_rev == LPFC_SLI_REV4) && + (vport->fc_flag & FC_PT2PT))) { + + if (expectRsp) { + icmd->un.elsreq64.myID = vport->fc_myDID; + + /* For ELS_REQUEST64_CR, use the VPI by default */ + icmd->ulpContext = phba->vpi_ids[vport->vpi]; + } - /* For ELS_REQUEST64_CR, use the VPI by default */ - icmd->ulpContext = phba->vpi_ids[vport->vpi]; icmd->ulpCt_h = 0; /* The CT field must be 0=INVALID_RPI for the ECHO cmd */ if (elscmd == ELS_CMD_ECHO) @@ -438,9 +454,10 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) int rc = 0; sp = &phba->fc_fabparam; - /* move forward in case of SLI4 FC port loopback test */ + /* move forward in case of SLI4 FC port loopback test and pt2pt mode */ if ((phba->sli_rev == LPFC_SLI_REV4) && - !(phba->link_flag & LS_LOOPBACK_MODE)) { + !(phba->link_flag & LS_LOOPBACK_MODE) && + !(vport->fc_flag & FC_PT2PT)) { ndlp = lpfc_findnode_did(vport, Fabric_DID); if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { rc = -ENODEV; @@ -707,14 +724,17 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_sli4_unreg_all_rpis(vport); lpfc_mbx_unreg_vpi(vport); spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - /* - * If VPI is unreged, driver need to do INIT_VPI - * before re-registering - */ vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; spin_unlock_irq(shost->host_lock); } + + /* + * For SLI3 and SLI4, the VPI needs to be reregistered in + * response to this fabric parameter change event. + */ + spin_lock_irq(shost->host_lock); + vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); } else if ((phba->sli_rev == LPFC_SLI_REV4) && !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { /* @@ -817,6 +837,17 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, mempool_free(mbox, phba->mbox_mem_pool); goto fail; } + + /* + * For SLI4, the VFI/VPI are registered AFTER the + * Nport with the higher WWPN sends the PLOGI with + * an assigned NPortId. + */ + + /* not equal */ + if ((phba->sli_rev == LPFC_SLI_REV4) && rc) + lpfc_issue_reg_vfi(vport); + /* Decrement ndlp reference count indicating that ndlp can be * safely released when other references to it are done. */ @@ -2972,7 +3003,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * ABTS we cannot generate and RRQ. */ lpfc_set_rrq_active(phba, ndlp, - cmdiocb->sli4_xritag, 0, 0); + cmdiocb->sli4_lxritag, 0, 0); } break; case IOSTAT_LOCAL_REJECT: @@ -3803,10 +3834,11 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, /* Xmit ELS ACC response tag <ulpIoTag> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0128 Xmit ELS ACC response tag x%x, XRI: x%x, " - "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n", + "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x " + "fc_flag x%x\n", elsiocb->iotag, elsiocb->iocb.ulpContext, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); + ndlp->nlp_rpi, vport->fc_flag); if (ndlp->nlp_flag & NLP_LOGO_ACC) { spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_LOGO_ACC; @@ -4936,8 +4968,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, return 1; } - did = Fabric_DID; - if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) { /* For a FLOGI we accept, then if our portname is greater * then the remote portname we initiate Nport login. @@ -4976,26 +5006,82 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_PT2PT_PLOGI; spin_unlock_irq(shost->host_lock); + + /* If we have the high WWPN we can assign our own + * myDID; otherwise, we have to WAIT for a PLOGI + * from the remote NPort to find out what it + * will be. + */ + vport->fc_myDID = PT2PT_LocalID; } + + /* + * The vport state should go to LPFC_FLOGI only + * AFTER we issue a FLOGI, not receive one. + */ spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_PT2PT; vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); spin_unlock_irq(shost->host_lock); + + /* + * We temporarily set fc_myDID to make it look like we are + * a Fabric. This is done just so we end up with the right + * did / sid on the FLOGI ACC rsp. + */ + did = vport->fc_myDID; + vport->fc_myDID = Fabric_DID; + } else { /* Reject this request because invalid parameters */ stat.un.b.lsRjtRsvd0 = 0; stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; stat.un.b.vendorUnique = 0; + + /* + * We temporarily set fc_myDID to make it look like we are + * a Fabric. This is done just so we end up with the right + * did / sid on the FLOGI LS_RJT rsp. + */ + did = vport->fc_myDID; + vport->fc_myDID = Fabric_DID; + lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); + + /* Now lets put fc_myDID back to what its supposed to be */ + vport->fc_myDID = did; + return 1; } /* Send back ACC */ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL); + /* Now lets put fc_myDID back to what its supposed to be */ + vport->fc_myDID = did; + + if (!(vport->fc_flag & FC_PT2PT_PLOGI)) { + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + goto fail; + + lpfc_config_link(phba, mbox); + + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->vport = vport; + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + mempool_free(mbox, phba->mbox_mem_pool); + goto fail; + } + } + return 0; +fail: + return 1; } /** @@ -5176,7 +5262,6 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } cmdsize = sizeof(struct RLS_RSP) + sizeof(uint32_t); - mempool_free(pmb, phba->mbox_mem_pool); elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, lpfc_max_els_tries, ndlp, ndlp->nlp_DID, ELS_CMD_ACC); @@ -5184,8 +5269,10 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Decrement the ndlp reference count from previous mbox command */ lpfc_nlp_put(ndlp); - if (!elsiocb) + if (!elsiocb) { + mempool_free(pmb, phba->mbox_mem_pool); return; + } icmd = &elsiocb->iocb; icmd->ulpContext = rxid; @@ -5202,7 +5289,7 @@ lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) rls_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt); rls_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord); rls_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt); - + mempool_free(pmb, phba->mbox_mem_pool); /* Xmit ELS RLS ACC response tag <ulpIoTag> */ lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, "2874 Xmit ELS RLS ACC response tag x%x xri x%x, " @@ -5586,7 +5673,7 @@ lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, pcmd += sizeof(uint32_t); els_rrq = (struct RRQ *) pcmd; - bf_set(rrq_oxid, els_rrq, rrq->xritag); + bf_set(rrq_oxid, els_rrq, phba->sli4_hba.xri_ids[rrq->xritag]); bf_set(rrq_rxid, els_rrq, rrq->rxid); bf_set(rrq_did, els_rrq, vport->fc_myDID); els_rrq->rrq = cpu_to_be32(els_rrq->rrq); @@ -7873,7 +7960,9 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, sglq_entry->state = SGL_FREED; spin_unlock(&phba->sli4_hba.abts_sgl_list_lock); spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1); + lpfc_set_rrq_active(phba, ndlp, + sglq_entry->sli4_lxritag, + rxid, 1); /* Check if TXQ queue needs to be serviced */ if (pring->txq_cnt) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index b507536dc5b5..5bb269e224f6 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -713,6 +713,7 @@ lpfc_do_work(void *p) int rc; set_user_nice(current, -20); + current->flags |= PF_NOFREEZE; phba->data_flags = 0; while (!kthread_should_stop()) { @@ -1094,7 +1095,7 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Start discovery by sending a FLOGI. port_state is identically * LPFC_FLOGI while waiting for FLOGI cmpl */ - if (vport->port_state != LPFC_FLOGI) + if (vport->port_state != LPFC_FLOGI || vport->fc_flag & FC_PT2PT_PLOGI) lpfc_initial_flogi(vport); return; @@ -2881,9 +2882,14 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) } if (vport->port_state == LPFC_FABRIC_CFG_LINK) { - /* For private loop just start discovery and we are done. */ - if ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) && - !(vport->fc_flag & FC_PUBLIC_LOOP)) { + /* + * For private loop or for NPort pt2pt, + * just start discovery and we are done. + */ + if ((vport->fc_flag & FC_PT2PT) || + ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) && + !(vport->fc_flag & FC_PUBLIC_LOOP))) { + /* Use loop map to make discovery list */ lpfc_disc_list_loopmap(vport); /* Start discovery */ @@ -5490,9 +5496,9 @@ lpfc_nlp_release(struct kref *kref) ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "0279 lpfc_nlp_release: ndlp:x%p " + "0279 lpfc_nlp_release: ndlp:x%p did %x " "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, + (void *)ndlp, ndlp->nlp_DID, ndlp->nlp_usg_map, atomic_read(&ndlp->kref.refcount)); /* remove ndlp from action. */ diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 5f280b5ae3db..41bb1d2fb625 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -3374,6 +3374,9 @@ typedef struct { WORD5 w5; /* Header control/status word */ } XMT_SEQ_FIELDS64; +/* This word is remote ports D_ID for XMIT_ELS_RSP64 */ +#define xmit_els_remoteID xrsqRo + /* IOCB Command template for 64 bit RCV_SEQUENCE64 */ typedef struct { struct ulp_bde64 rcvBde; diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 91f09761bd32..f1946dfda5b4 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -228,19 +228,15 @@ struct lpfc_sli4_flags { #define lpfc_idx_rsrc_rdy_MASK 0x00000001 #define lpfc_idx_rsrc_rdy_WORD word0 #define LPFC_IDX_RSRC_RDY 1 -#define lpfc_xri_rsrc_rdy_SHIFT 1 -#define lpfc_xri_rsrc_rdy_MASK 0x00000001 -#define lpfc_xri_rsrc_rdy_WORD word0 -#define LPFC_XRI_RSRC_RDY 1 -#define lpfc_rpi_rsrc_rdy_SHIFT 2 +#define lpfc_rpi_rsrc_rdy_SHIFT 1 #define lpfc_rpi_rsrc_rdy_MASK 0x00000001 #define lpfc_rpi_rsrc_rdy_WORD word0 #define LPFC_RPI_RSRC_RDY 1 -#define lpfc_vpi_rsrc_rdy_SHIFT 3 +#define lpfc_vpi_rsrc_rdy_SHIFT 2 #define lpfc_vpi_rsrc_rdy_MASK 0x00000001 #define lpfc_vpi_rsrc_rdy_WORD word0 #define LPFC_VPI_RSRC_RDY 1 -#define lpfc_vfi_rsrc_rdy_SHIFT 4 +#define lpfc_vfi_rsrc_rdy_SHIFT 3 #define lpfc_vfi_rsrc_rdy_MASK 0x00000001 #define lpfc_vfi_rsrc_rdy_WORD word0 #define LPFC_VFI_RSRC_RDY 1 @@ -3299,7 +3295,13 @@ struct els_request64_wqe { struct xmit_els_rsp64_wqe { struct ulp_bde64 bde; uint32_t response_payload_len; - uint32_t rsvd4; + uint32_t word4; +#define els_rsp64_sid_SHIFT 0 +#define els_rsp64_sid_MASK 0x00FFFFFF +#define els_rsp64_sid_WORD word4 +#define els_rsp64_sp_SHIFT 24 +#define els_rsp64_sp_MASK 0x00000001 +#define els_rsp64_sp_WORD word4 struct wqe_did wqe_dest; struct wqe_common wqe_com; /* words 6-11 */ uint32_t word12; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 9598fdcb08ab..411ed48d79da 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -64,8 +64,8 @@ static int lpfc_sli4_queue_verify(struct lpfc_hba *); static int lpfc_create_bootstrap_mbox(struct lpfc_hba *); static int lpfc_setup_endian_order(struct lpfc_hba *); static void lpfc_destroy_bootstrap_mbox(struct lpfc_hba *); -static void lpfc_free_sgl_list(struct lpfc_hba *); -static int lpfc_init_sgl_list(struct lpfc_hba *); +static void lpfc_free_els_sgl_list(struct lpfc_hba *); +static void lpfc_init_sgl_list(struct lpfc_hba *); static int lpfc_init_active_sgl_array(struct lpfc_hba *); static void lpfc_free_active_sgl(struct lpfc_hba *); static int lpfc_hba_down_post_s3(struct lpfc_hba *phba); @@ -2767,47 +2767,14 @@ lpfc_offline(struct lpfc_hba *phba) } /** - * lpfc_scsi_buf_update - Update the scsi_buffers that are already allocated. - * @phba: pointer to lpfc hba data structure. - * - * This routine goes through all the scsi buffers in the system and updates the - * Physical XRIs assigned to the SCSI buffer because these may change after any - * firmware reset - * - * Return codes - * 0 - successful (for now, it always returns 0) - **/ -int -lpfc_scsi_buf_update(struct lpfc_hba *phba) -{ - struct lpfc_scsi_buf *sb, *sb_next; - - spin_lock_irq(&phba->hbalock); - spin_lock(&phba->scsi_buf_list_lock); - list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) { - sb->cur_iocbq.sli4_xritag = - phba->sli4_hba.xri_ids[sb->cur_iocbq.sli4_lxritag]; - set_bit(sb->cur_iocbq.sli4_lxritag, phba->sli4_hba.xri_bmask); - phba->sli4_hba.max_cfg_param.xri_used++; - phba->sli4_hba.xri_count++; - } - spin_unlock(&phba->scsi_buf_list_lock); - spin_unlock_irq(&phba->hbalock); - return 0; -} - -/** * lpfc_scsi_free - Free all the SCSI buffers and IOCBs from driver lists * @phba: pointer to lpfc hba data structure. * * This routine is to free all the SCSI buffers and IOCBs from the driver * list back to kernel. It is called from lpfc_pci_remove_one to free * the internal resources before the device is removed from the system. - * - * Return codes - * 0 - successful (for now, it always returns 0) **/ -static int +static void lpfc_scsi_free(struct lpfc_hba *phba) { struct lpfc_scsi_buf *sb, *sb_next; @@ -2833,7 +2800,178 @@ lpfc_scsi_free(struct lpfc_hba *phba) } spin_unlock_irq(&phba->hbalock); +} + +/** + * lpfc_sli4_xri_sgl_update - update xri-sgl sizing and mapping + * @phba: pointer to lpfc hba data structure. + * + * This routine first calculates the sizes of the current els and allocated + * scsi sgl lists, and then goes through all sgls to updates the physical + * XRIs assigned due to port function reset. During port initialization, the + * current els and allocated scsi sgl lists are 0s. + * + * Return codes + * 0 - successful (for now, it always returns 0) + **/ +int +lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba) +{ + struct lpfc_sglq *sglq_entry = NULL, *sglq_entry_next = NULL; + struct lpfc_scsi_buf *psb = NULL, *psb_next = NULL; + uint16_t i, lxri, xri_cnt, els_xri_cnt, scsi_xri_cnt; + LIST_HEAD(els_sgl_list); + LIST_HEAD(scsi_sgl_list); + int rc; + + /* + * update on pci function's els xri-sgl list + */ + els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); + if (els_xri_cnt > phba->sli4_hba.els_xri_cnt) { + /* els xri-sgl expanded */ + xri_cnt = els_xri_cnt - phba->sli4_hba.els_xri_cnt; + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3157 ELS xri-sgl count increased from " + "%d to %d\n", phba->sli4_hba.els_xri_cnt, + els_xri_cnt); + /* allocate the additional els sgls */ + for (i = 0; i < xri_cnt; i++) { + sglq_entry = kzalloc(sizeof(struct lpfc_sglq), + GFP_KERNEL); + if (sglq_entry == NULL) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2562 Failure to allocate an " + "ELS sgl entry:%d\n", i); + rc = -ENOMEM; + goto out_free_mem; + } + sglq_entry->buff_type = GEN_BUFF_TYPE; + sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, + &sglq_entry->phys); + if (sglq_entry->virt == NULL) { + kfree(sglq_entry); + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2563 Failure to allocate an " + "ELS mbuf:%d\n", i); + rc = -ENOMEM; + goto out_free_mem; + } + sglq_entry->sgl = sglq_entry->virt; + memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE); + sglq_entry->state = SGL_FREED; + list_add_tail(&sglq_entry->list, &els_sgl_list); + } + spin_lock(&phba->hbalock); + list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list); + spin_unlock(&phba->hbalock); + } else if (els_xri_cnt < phba->sli4_hba.els_xri_cnt) { + /* els xri-sgl shrinked */ + xri_cnt = phba->sli4_hba.els_xri_cnt - els_xri_cnt; + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3158 ELS xri-sgl count decreased from " + "%d to %d\n", phba->sli4_hba.els_xri_cnt, + els_xri_cnt); + spin_lock_irq(&phba->hbalock); + list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &els_sgl_list); + spin_unlock_irq(&phba->hbalock); + /* release extra els sgls from list */ + for (i = 0; i < xri_cnt; i++) { + list_remove_head(&els_sgl_list, + sglq_entry, struct lpfc_sglq, list); + if (sglq_entry) { + lpfc_mbuf_free(phba, sglq_entry->virt, + sglq_entry->phys); + kfree(sglq_entry); + } + } + spin_lock_irq(&phba->hbalock); + list_splice_init(&els_sgl_list, &phba->sli4_hba.lpfc_sgl_list); + spin_unlock_irq(&phba->hbalock); + } else + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3163 ELS xri-sgl count unchanged: %d\n", + els_xri_cnt); + phba->sli4_hba.els_xri_cnt = els_xri_cnt; + + /* update xris to els sgls on the list */ + sglq_entry = NULL; + sglq_entry_next = NULL; + list_for_each_entry_safe(sglq_entry, sglq_entry_next, + &phba->sli4_hba.lpfc_sgl_list, list) { + lxri = lpfc_sli4_next_xritag(phba); + if (lxri == NO_XRI) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2400 Failed to allocate xri for " + "ELS sgl\n"); + rc = -ENOMEM; + goto out_free_mem; + } + sglq_entry->sli4_lxritag = lxri; + sglq_entry->sli4_xritag = phba->sli4_hba.xri_ids[lxri]; + } + + /* + * update on pci function's allocated scsi xri-sgl list + */ + phba->total_scsi_bufs = 0; + + /* maximum number of xris available for scsi buffers */ + phba->sli4_hba.scsi_xri_max = phba->sli4_hba.max_cfg_param.max_xri - + els_xri_cnt; + + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2401 Current allocated SCSI xri-sgl count:%d, " + "maximum SCSI xri count:%d\n", + phba->sli4_hba.scsi_xri_cnt, + phba->sli4_hba.scsi_xri_max); + + spin_lock_irq(&phba->scsi_buf_list_lock); + list_splice_init(&phba->lpfc_scsi_buf_list, &scsi_sgl_list); + spin_unlock_irq(&phba->scsi_buf_list_lock); + + if (phba->sli4_hba.scsi_xri_cnt > phba->sli4_hba.scsi_xri_max) { + /* max scsi xri shrinked below the allocated scsi buffers */ + scsi_xri_cnt = phba->sli4_hba.scsi_xri_cnt - + phba->sli4_hba.scsi_xri_max; + /* release the extra allocated scsi buffers */ + for (i = 0; i < scsi_xri_cnt; i++) { + list_remove_head(&scsi_sgl_list, psb, + struct lpfc_scsi_buf, list); + pci_pool_free(phba->lpfc_scsi_dma_buf_pool, psb->data, + psb->dma_handle); + kfree(psb); + } + spin_lock_irq(&phba->scsi_buf_list_lock); + phba->sli4_hba.scsi_xri_cnt -= scsi_xri_cnt; + spin_unlock_irq(&phba->scsi_buf_list_lock); + } + + /* update xris associated to remaining allocated scsi buffers */ + psb = NULL; + psb_next = NULL; + list_for_each_entry_safe(psb, psb_next, &scsi_sgl_list, list) { + lxri = lpfc_sli4_next_xritag(phba); + if (lxri == NO_XRI) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "2560 Failed to allocate xri for " + "scsi buffer\n"); + rc = -ENOMEM; + goto out_free_mem; + } + psb->cur_iocbq.sli4_lxritag = lxri; + psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri]; + } + spin_lock(&phba->scsi_buf_list_lock); + list_splice_init(&scsi_sgl_list, &phba->lpfc_scsi_buf_list); + spin_unlock(&phba->scsi_buf_list_lock); + return 0; + +out_free_mem: + lpfc_free_els_sgl_list(phba); + lpfc_scsi_free(phba); + return rc; } /** @@ -4636,18 +4774,15 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) if (rc) goto out_free_bsmbx; - /* Initialize and populate the iocb list per host */ - rc = lpfc_init_sgl_list(phba); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1400 Failed to initialize sgl list.\n"); - goto out_destroy_cq_event_pool; - } + /* Initialize sgl lists per host */ + lpfc_init_sgl_list(phba); + + /* Allocate and initialize active sgl array */ rc = lpfc_init_active_sgl_array(phba); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "1430 Failed to initialize sgl list.\n"); - goto out_free_sgl_list; + goto out_destroy_cq_event_pool; } rc = lpfc_sli4_init_rpi_hdrs(phba); if (rc) { @@ -4722,8 +4857,6 @@ out_remove_rpi_hdrs: lpfc_sli4_remove_rpi_hdrs(phba); out_free_active_sgl: lpfc_free_active_sgl(phba); -out_free_sgl_list: - lpfc_free_sgl_list(phba); out_destroy_cq_event_pool: lpfc_sli4_cq_event_pool_destroy(phba); out_free_bsmbx: @@ -4760,10 +4893,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) /* Free the ELS sgl list */ lpfc_free_active_sgl(phba); - lpfc_free_sgl_list(phba); - - /* Free the SCSI sgl management array */ - kfree(phba->sli4_hba.lpfc_scsi_psb_array); + lpfc_free_els_sgl_list(phba); /* Free the completion queue EQ event pool */ lpfc_sli4_cq_event_release_all(phba); @@ -4990,29 +5120,42 @@ out_free_iocbq: } /** - * lpfc_free_sgl_list - Free sgl list. + * lpfc_free_sgl_list - Free a given sgl list. * @phba: pointer to lpfc hba data structure. + * @sglq_list: pointer to the head of sgl list. * - * This routine is invoked to free the driver's sgl list and memory. + * This routine is invoked to free a give sgl list and memory. **/ -static void -lpfc_free_sgl_list(struct lpfc_hba *phba) +void +lpfc_free_sgl_list(struct lpfc_hba *phba, struct list_head *sglq_list) { struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; + + list_for_each_entry_safe(sglq_entry, sglq_next, sglq_list, list) { + list_del(&sglq_entry->list); + lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys); + kfree(sglq_entry); + } +} + +/** + * lpfc_free_els_sgl_list - Free els sgl list. + * @phba: pointer to lpfc hba data structure. + * + * This routine is invoked to free the driver's els sgl list and memory. + **/ +static void +lpfc_free_els_sgl_list(struct lpfc_hba *phba) +{ LIST_HEAD(sglq_list); + /* Retrieve all els sgls from driver list */ spin_lock_irq(&phba->hbalock); list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &sglq_list); spin_unlock_irq(&phba->hbalock); - list_for_each_entry_safe(sglq_entry, sglq_next, - &sglq_list, list) { - list_del(&sglq_entry->list); - lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys); - kfree(sglq_entry); - phba->sli4_hba.total_sglq_bufs--; - } - kfree(phba->sli4_hba.lpfc_els_sgl_array); + /* Now free the sgl list */ + lpfc_free_sgl_list(phba, &sglq_list); } /** @@ -5057,99 +5200,19 @@ lpfc_free_active_sgl(struct lpfc_hba *phba) * This routine is invoked to allocate and initizlize the driver's sgl * list and set up the sgl xritag tag array accordingly. * - * Return codes - * 0 - successful - * other values - error **/ -static int +static void lpfc_init_sgl_list(struct lpfc_hba *phba) { - struct lpfc_sglq *sglq_entry = NULL; - int i; - int els_xri_cnt; - - els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2400 ELS XRI count %d.\n", - els_xri_cnt); /* Initialize and populate the sglq list per host/VF. */ INIT_LIST_HEAD(&phba->sli4_hba.lpfc_sgl_list); INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_els_sgl_list); - /* Sanity check on XRI management */ - if (phba->sli4_hba.max_cfg_param.max_xri <= els_xri_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2562 No room left for SCSI XRI allocation: " - "max_xri=%d, els_xri=%d\n", - phba->sli4_hba.max_cfg_param.max_xri, - els_xri_cnt); - return -ENOMEM; - } - - /* Allocate memory for the ELS XRI management array */ - phba->sli4_hba.lpfc_els_sgl_array = - kzalloc((sizeof(struct lpfc_sglq *) * els_xri_cnt), - GFP_KERNEL); - - if (!phba->sli4_hba.lpfc_els_sgl_array) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2401 Failed to allocate memory for ELS " - "XRI management array of size %d.\n", - els_xri_cnt); - return -ENOMEM; - } + /* els xri-sgl book keeping */ + phba->sli4_hba.els_xri_cnt = 0; - /* Keep the SCSI XRI into the XRI management array */ - phba->sli4_hba.scsi_xri_max = - phba->sli4_hba.max_cfg_param.max_xri - els_xri_cnt; + /* scsi xri-buffer book keeping */ phba->sli4_hba.scsi_xri_cnt = 0; - phba->sli4_hba.lpfc_scsi_psb_array = - kzalloc((sizeof(struct lpfc_scsi_buf *) * - phba->sli4_hba.scsi_xri_max), GFP_KERNEL); - - if (!phba->sli4_hba.lpfc_scsi_psb_array) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2563 Failed to allocate memory for SCSI " - "XRI management array of size %d.\n", - phba->sli4_hba.scsi_xri_max); - kfree(phba->sli4_hba.lpfc_els_sgl_array); - return -ENOMEM; - } - - for (i = 0; i < els_xri_cnt; i++) { - sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL); - if (sglq_entry == NULL) { - printk(KERN_ERR "%s: only allocated %d sgls of " - "expected %d count. Unloading driver.\n", - __func__, i, els_xri_cnt); - goto out_free_mem; - } - - sglq_entry->buff_type = GEN_BUFF_TYPE; - sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, &sglq_entry->phys); - if (sglq_entry->virt == NULL) { - kfree(sglq_entry); - printk(KERN_ERR "%s: failed to allocate mbuf.\n" - "Unloading driver.\n", __func__); - goto out_free_mem; - } - sglq_entry->sgl = sglq_entry->virt; - memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE); - - /* The list order is used by later block SGL registraton */ - spin_lock_irq(&phba->hbalock); - sglq_entry->state = SGL_FREED; - list_add_tail(&sglq_entry->list, &phba->sli4_hba.lpfc_sgl_list); - phba->sli4_hba.lpfc_els_sgl_array[i] = sglq_entry; - phba->sli4_hba.total_sglq_bufs++; - spin_unlock_irq(&phba->hbalock); - } - return 0; - -out_free_mem: - kfree(phba->sli4_hba.lpfc_scsi_psb_array); - lpfc_free_sgl_list(phba); - return -ENOMEM; } /** @@ -7320,9 +7383,11 @@ lpfc_pci_function_reset(struct lpfc_hba *phba) phba->sli4_hba.u.if_type2.ERR2regaddr); lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "2890 Port error detected during port " - "reset(%d): port status reg 0x%x, " + "reset(%d): wait_tmo:%d ms, " + "port status reg 0x%x, " "error 1=0x%x, error 2=0x%x\n", - num_resets, reg_data.word0, + num_resets, rdy_chk*10, + reg_data.word0, phba->work_status[0], phba->work_status[1]); rc = -ENODEV; @@ -8694,8 +8759,11 @@ lpfc_pci_remove_one_s3(struct pci_dev *pdev) /* Release all the vports against this physical port */ vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++) + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + if (vports[i]->port_type == LPFC_PHYSICAL_PORT) + continue; fc_vport_terminate(vports[i]->fc_vport); + } lpfc_destroy_vport_work_array(phba, vports); /* Remove FC host and then SCSI host with the physical port */ @@ -9115,8 +9183,12 @@ lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba) return 50; else if (max_xri <= 1024) return 100; - else + else if (max_xri <= 1536) return 150; + else if (max_xri <= 2048) + return 200; + else + return 250; } else return 0; } @@ -9455,8 +9527,11 @@ lpfc_pci_remove_one_s4(struct pci_dev *pdev) /* Release all the vports against this physical port */ vports = lpfc_create_vport_work_array(phba); if (vports != NULL) - for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++) + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + if (vports[i]->port_type == LPFC_PHYSICAL_PORT) + continue; fc_vport_terminate(vports[i]->fc_vport); + } lpfc_destroy_vport_work_array(phba, vports); /* Remove FC host and then SCSI host with the physical port */ diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 15ca2a9a0cdd..9133a97f045f 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -367,8 +367,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return 1; } + /* Check for Nport to NPort pt2pt protocol */ if ((vport->fc_flag & FC_PT2PT) && !(vport->fc_flag & FC_PT2PT_PLOGI)) { + /* rcv'ed PLOGI decides what our NPortId will be */ vport->fc_myDID = icmd->un.rcvels.parmRo; mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); @@ -382,6 +384,13 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, mempool_free(mbox, phba->mbox_mem_pool); goto out; } + /* + * For SLI4, the VFI/VPI are registered AFTER the + * Nport with the higher WWPN sends us a PLOGI with + * our assigned NPortId. + */ + if (phba->sli_rev == LPFC_SLI_REV4) + lpfc_issue_reg_vfi(vport); lpfc_can_disctmo(vport); } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 88f3a83dbd2e..66e09069f281 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -399,6 +399,14 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) num_rsrc_err = atomic_read(&phba->num_rsrc_err); num_cmd_success = atomic_read(&phba->num_cmd_success); + /* + * The error and success command counters are global per + * driver instance. If another handler has already + * operated on this error event, just exit. + */ + if (num_rsrc_err == 0) + return; + vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { @@ -688,7 +696,8 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, rrq_empty = list_empty(&phba->active_rrq_list); spin_unlock_irqrestore(&phba->hbalock, iflag); if (ndlp) { - lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1); + lpfc_set_rrq_active(phba, ndlp, + psb->cur_iocbq.sli4_lxritag, rxid, 1); lpfc_sli4_abts_err_handler(phba, ndlp, axri); } lpfc_release_scsi_buf_s4(phba, psb); @@ -718,72 +727,162 @@ lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, } /** - * lpfc_sli4_repost_scsi_sgl_list - Repsot the Scsi buffers sgl pages as block + * lpfc_sli4_post_scsi_sgl_list - Psot blocks of scsi buffer sgls from a list * @phba: pointer to lpfc hba data structure. + * @post_sblist: pointer to the scsi buffer list. * - * This routine walks the list of scsi buffers that have been allocated and - * repost them to the HBA by using SGL block post. This is needed after a - * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine - * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list - * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers. + * This routine walks a list of scsi buffers that was passed in. It attempts + * to construct blocks of scsi buffer sgls which contains contiguous xris and + * uses the non-embedded SGL block post mailbox commands to post to the port. + * For single SCSI buffer sgl with non-contiguous xri, if any, it shall use + * embedded SGL post mailbox command for posting. The @post_sblist passed in + * must be local list, thus no lock is needed when manipulate the list. * - * Returns: 0 = success, non-zero failure. + * Returns: 0 = failure, non-zero number of successfully posted buffers. **/ int -lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) +lpfc_sli4_post_scsi_sgl_list(struct lpfc_hba *phba, + struct list_head *post_sblist, int sb_count) { - struct lpfc_scsi_buf *psb; - int index, status, bcnt = 0, rcnt = 0, rc = 0; - LIST_HEAD(sblist); - - for (index = 0; index < phba->sli4_hba.scsi_xri_cnt; index++) { - psb = phba->sli4_hba.lpfc_scsi_psb_array[index]; - if (psb) { - /* Remove from SCSI buffer list */ - list_del(&psb->list); - /* Add it to a local SCSI buffer list */ - list_add_tail(&psb->list, &sblist); - if (++rcnt == LPFC_NEMBED_MBOX_SGL_CNT) { - bcnt = rcnt; - rcnt = 0; + struct lpfc_scsi_buf *psb, *psb_next; + int status; + int post_cnt = 0, block_cnt = 0, num_posting = 0, num_posted = 0; + dma_addr_t pdma_phys_bpl1; + int last_xritag = NO_XRI; + LIST_HEAD(prep_sblist); + LIST_HEAD(blck_sblist); + LIST_HEAD(scsi_sblist); + + /* sanity check */ + if (sb_count <= 0) + return -EINVAL; + + list_for_each_entry_safe(psb, psb_next, post_sblist, list) { + list_del_init(&psb->list); + block_cnt++; + if ((last_xritag != NO_XRI) && + (psb->cur_iocbq.sli4_xritag != last_xritag + 1)) { + /* a hole in xri block, form a sgl posting block */ + list_splice_init(&prep_sblist, &blck_sblist); + post_cnt = block_cnt - 1; + /* prepare list for next posting block */ + list_add_tail(&psb->list, &prep_sblist); + block_cnt = 1; + } else { + /* prepare list for next posting block */ + list_add_tail(&psb->list, &prep_sblist); + /* enough sgls for non-embed sgl mbox command */ + if (block_cnt == LPFC_NEMBED_MBOX_SGL_CNT) { + list_splice_init(&prep_sblist, &blck_sblist); + post_cnt = block_cnt; + block_cnt = 0; } - } else - /* A hole present in the XRI array, need to skip */ - bcnt = rcnt; + } + num_posting++; + last_xritag = psb->cur_iocbq.sli4_xritag; - if (index == phba->sli4_hba.scsi_xri_cnt - 1) - /* End of XRI array for SCSI buffer, complete */ - bcnt = rcnt; + /* end of repost sgl list condition for SCSI buffers */ + if (num_posting == sb_count) { + if (post_cnt == 0) { + /* last sgl posting block */ + list_splice_init(&prep_sblist, &blck_sblist); + post_cnt = block_cnt; + } else if (block_cnt == 1) { + /* last single sgl with non-contiguous xri */ + if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) + pdma_phys_bpl1 = psb->dma_phys_bpl + + SGL_PAGE_SIZE; + else + pdma_phys_bpl1 = 0; + status = lpfc_sli4_post_sgl(phba, + psb->dma_phys_bpl, + pdma_phys_bpl1, + psb->cur_iocbq.sli4_xritag); + if (status) { + /* failure, put on abort scsi list */ + psb->exch_busy = 1; + } else { + /* success, put on SCSI buffer list */ + psb->exch_busy = 0; + psb->status = IOSTAT_SUCCESS; + num_posted++; + } + /* success, put on SCSI buffer sgl list */ + list_add_tail(&psb->list, &scsi_sblist); + } + } - /* Continue until collect up to a nembed page worth of sgls */ - if (bcnt == 0) + /* continue until a nembed page worth of sgls */ + if (post_cnt == 0) continue; - /* Now, post the SCSI buffer list sgls as a block */ - if (!phba->sli4_hba.extents_in_use) - status = lpfc_sli4_post_scsi_sgl_block(phba, - &sblist, - bcnt); - else - status = lpfc_sli4_post_scsi_sgl_blk_ext(phba, - &sblist, - bcnt); - /* Reset SCSI buffer count for next round of posting */ - bcnt = 0; - while (!list_empty(&sblist)) { - list_remove_head(&sblist, psb, struct lpfc_scsi_buf, - list); + + /* post block of SCSI buffer list sgls */ + status = lpfc_sli4_post_scsi_sgl_block(phba, &blck_sblist, + post_cnt); + + /* don't reset xirtag due to hole in xri block */ + if (block_cnt == 0) + last_xritag = NO_XRI; + + /* reset SCSI buffer post count for next round of posting */ + post_cnt = 0; + + /* put posted SCSI buffer-sgl posted on SCSI buffer sgl list */ + while (!list_empty(&blck_sblist)) { + list_remove_head(&blck_sblist, psb, + struct lpfc_scsi_buf, list); if (status) { - /* Put this back on the abort scsi list */ + /* failure, put on abort scsi list */ psb->exch_busy = 1; - rc++; } else { + /* success, put on SCSI buffer list */ psb->exch_busy = 0; psb->status = IOSTAT_SUCCESS; + num_posted++; } - /* Put it back into the SCSI buffer list */ - lpfc_release_scsi_buf_s4(phba, psb); + list_add_tail(&psb->list, &scsi_sblist); } } + /* Push SCSI buffers with sgl posted to the availble list */ + while (!list_empty(&scsi_sblist)) { + list_remove_head(&scsi_sblist, psb, + struct lpfc_scsi_buf, list); + lpfc_release_scsi_buf_s4(phba, psb); + } + return num_posted; +} + +/** + * lpfc_sli4_repost_scsi_sgl_list - Repsot all the allocated scsi buffer sgls + * @phba: pointer to lpfc hba data structure. + * + * This routine walks the list of scsi buffers that have been allocated and + * repost them to the port by using SGL block post. This is needed after a + * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine + * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list + * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers. + * + * Returns: 0 = success, non-zero failure. + **/ +int +lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) +{ + LIST_HEAD(post_sblist); + int num_posted, rc = 0; + + /* get all SCSI buffers need to repost to a local list */ + spin_lock(&phba->scsi_buf_list_lock); + list_splice_init(&phba->lpfc_scsi_buf_list, &post_sblist); + spin_unlock(&phba->scsi_buf_list_lock); + + /* post the list of scsi buffer sgls to port if available */ + if (!list_empty(&post_sblist)) { + num_posted = lpfc_sli4_post_scsi_sgl_list(phba, &post_sblist, + phba->sli4_hba.scsi_xri_cnt); + /* failed to post any scsi buffer, return error */ + if (num_posted == 0) + rc = -EIO; + } return rc; } @@ -792,12 +891,13 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) * @vport: The virtual port for which this call being executed. * @num_to_allocate: The requested number of buffers to allocate. * - * This routine allocates a scsi buffer for device with SLI-4 interface spec, + * This routine allocates scsi buffers for device with SLI-4 interface spec, * the scsi buffer contains all the necessary information needed to initiate - * a SCSI I/O. + * a SCSI I/O. After allocating up to @num_to_allocate SCSI buffers and put + * them on a list, it post them to the port by using SGL block post. * * Return codes: - * int - number of scsi buffers that were allocated. + * int - number of scsi buffers that were allocated and posted. * 0 = failure, less than num_to_alloc is a partial failure. **/ static int @@ -810,22 +910,21 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) dma_addr_t pdma_phys_fcp_cmd; dma_addr_t pdma_phys_fcp_rsp; dma_addr_t pdma_phys_bpl, pdma_phys_bpl1; - uint16_t iotag, last_xritag = NO_XRI, lxri = 0; - int status = 0, index; - int bcnt; - int non_sequential_xri = 0; - LIST_HEAD(sblist); + uint16_t iotag, lxri = 0; + int bcnt, num_posted; + LIST_HEAD(prep_sblist); + LIST_HEAD(post_sblist); + LIST_HEAD(scsi_sblist); for (bcnt = 0; bcnt < num_to_alloc; bcnt++) { psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); if (!psb) break; - /* - * Get memory from the pci pool to map the virt space to pci bus - * space for an I/O. The DMA buffer includes space for the - * struct fcp_cmnd, struct fcp_rsp and the number of bde's - * necessary to support the sg_tablesize. + * Get memory from the pci pool to map the virt space to + * pci bus space for an I/O. The DMA buffer includes space + * for the struct fcp_cmnd, struct fcp_rsp and the number + * of bde's necessary to support the sg_tablesize. */ psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool, GFP_KERNEL, &psb->dma_handle); @@ -833,8 +932,6 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) kfree(psb); break; } - - /* Initialize virtual ptrs to dma_buf region. */ memset(psb->data, 0, phba->cfg_sg_dma_buf_size); /* Allocate iotag for psb->cur_iocbq. */ @@ -855,16 +952,7 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) } psb->cur_iocbq.sli4_lxritag = lxri; psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri]; - if (last_xritag != NO_XRI - && psb->cur_iocbq.sli4_xritag != (last_xritag+1)) { - non_sequential_xri = 1; - } else - list_add_tail(&psb->list, &sblist); - last_xritag = psb->cur_iocbq.sli4_xritag; - - index = phba->sli4_hba.scsi_xri_cnt++; psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP; - psb->fcp_bpl = psb->data; psb->fcp_cmnd = (psb->data + phba->cfg_sg_dma_buf_size) - (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp)); @@ -880,9 +968,9 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd); /* - * The first two bdes are the FCP_CMD and FCP_RSP. The balance - * are sg list bdes. Initialize the first two and leave the - * rest for queuecommand. + * The first two bdes are the FCP_CMD and FCP_RSP. + * The balance are sg list bdes. Initialize the + * first two and leave the rest for queuecommand. */ sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd)); sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd)); @@ -917,62 +1005,31 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) iocb->ulpBdeCount = 1; iocb->ulpLe = 1; iocb->ulpClass = CLASS3; - psb->cur_iocbq.context1 = psb; + psb->cur_iocbq.context1 = psb; if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) pdma_phys_bpl1 = pdma_phys_bpl + SGL_PAGE_SIZE; else pdma_phys_bpl1 = 0; psb->dma_phys_bpl = pdma_phys_bpl; - phba->sli4_hba.lpfc_scsi_psb_array[index] = psb; - if (non_sequential_xri) { - status = lpfc_sli4_post_sgl(phba, pdma_phys_bpl, - pdma_phys_bpl1, - psb->cur_iocbq.sli4_xritag); - if (status) { - /* Put this back on the abort scsi list */ - psb->exch_busy = 1; - } else { - psb->exch_busy = 0; - psb->status = IOSTAT_SUCCESS; - } - /* Put it back into the SCSI buffer list */ - lpfc_release_scsi_buf_s4(phba, psb); - break; - } - } - if (bcnt) { - if (!phba->sli4_hba.extents_in_use) - status = lpfc_sli4_post_scsi_sgl_block(phba, - &sblist, - bcnt); - else - status = lpfc_sli4_post_scsi_sgl_blk_ext(phba, - &sblist, - bcnt); - - if (status) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "3021 SCSI SGL post error %d\n", - status); - bcnt = 0; - } - /* Reset SCSI buffer count for next round of posting */ - while (!list_empty(&sblist)) { - list_remove_head(&sblist, psb, struct lpfc_scsi_buf, - list); - if (status) { - /* Put this back on the abort scsi list */ - psb->exch_busy = 1; - } else { - psb->exch_busy = 0; - psb->status = IOSTAT_SUCCESS; - } - /* Put it back into the SCSI buffer list */ - lpfc_release_scsi_buf_s4(phba, psb); - } + + /* add the scsi buffer to a post list */ + list_add_tail(&psb->list, &post_sblist); + spin_lock_irq(&phba->scsi_buf_list_lock); + phba->sli4_hba.scsi_xri_cnt++; + spin_unlock_irq(&phba->scsi_buf_list_lock); } + lpfc_printf_log(phba, KERN_INFO, LOG_BG, + "3021 Allocate %d out of %d requested new SCSI " + "buffers\n", bcnt, num_to_alloc); + + /* post the list of scsi buffer sgls to port if available */ + if (!list_empty(&post_sblist)) + num_posted = lpfc_sli4_post_scsi_sgl_list(phba, + &post_sblist, bcnt); + else + num_posted = 0; - return bcnt + non_sequential_xri; + return num_posted; } /** @@ -1043,7 +1100,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) list_for_each_entry(lpfc_cmd, &phba->lpfc_scsi_buf_list, list) { if (lpfc_test_rrq_active(phba, ndlp, - lpfc_cmd->cur_iocbq.sli4_xritag)) + lpfc_cmd->cur_iocbq.sli4_lxritag)) continue; list_del(&lpfc_cmd->list); found = 1; @@ -1897,7 +1954,9 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, dma_addr_t physaddr; int i = 0, num_bde = 0, status; int datadir = sc->sc_data_direction; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS uint32_t rc; +#endif uint32_t checking = 1; uint32_t reftag; unsigned blksize; @@ -2034,7 +2093,9 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, int datadir = sc->sc_data_direction; unsigned char pgdone = 0, alldone = 0; unsigned blksize; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS uint32_t rc; +#endif uint32_t checking = 1; uint32_t reftag; uint8_t txop, rxop; @@ -2253,7 +2314,9 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint32_t reftag; unsigned blksize; uint8_t txop, rxop; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS uint32_t rc; +#endif uint32_t checking = 1; uint32_t dma_len; uint32_t dma_offset = 0; @@ -2383,7 +2446,9 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, uint32_t reftag; uint8_t txop, rxop; uint32_t dma_len; +#ifdef CONFIG_SCSI_LPFC_DEBUG_FS uint32_t rc; +#endif uint32_t checking = 1; uint32_t dma_offset = 0; int num_sge = 0; @@ -3604,11 +3669,16 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, logit = LOG_FCP | LOG_FCP_UNDER; lpfc_printf_vlog(vport, KERN_WARNING, logit, "9030 FCP cmd x%x failed <%d/%d> " - "status: x%x result: x%x Data: x%x x%x\n", + "status: x%x result: x%x " + "sid: x%x did: x%x oxid: x%x " + "Data: x%x x%x\n", cmd->cmnd[0], cmd->device ? cmd->device->id : 0xffff, cmd->device ? cmd->device->lun : 0xffff, lpfc_cmd->status, lpfc_cmd->result, + vport->fc_myDID, pnode->nlp_DID, + phba->sli_rev == LPFC_SLI_REV4 ? + lpfc_cmd->cur_iocbq.sli4_xritag : 0xffff, pIocbOut->iocb.ulpContext, lpfc_cmd->cur_iocbq.iocb.ulpIoTag); @@ -3689,8 +3759,8 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, * ABTS we cannot generate and RRQ. */ lpfc_set_rrq_active(phba, pnode, - lpfc_cmd->cur_iocbq.sli4_xritag, - 0, 0); + lpfc_cmd->cur_iocbq.sli4_lxritag, + 0, 0); } /* else: fall through */ default: @@ -4348,8 +4418,20 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) ret = fc_block_scsi_eh(cmnd); if (ret) return ret; + + spin_lock_irq(&phba->hbalock); + /* driver queued commands are in process of being flushed */ + if (phba->hba_flag & HBA_FCP_IOQ_FLUSH) { + spin_unlock_irq(&phba->hbalock); + lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, + "3168 SCSI Layer abort requested I/O has been " + "flushed by LLD.\n"); + return FAILED; + } + lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; if (!lpfc_cmd) { + spin_unlock_irq(&phba->hbalock); lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "2873 SCSI Layer I/O Abort Request IO CMPL Status " "x%x ID %d LUN %d\n", @@ -4357,23 +4439,34 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) return SUCCESS; } + iocb = &lpfc_cmd->cur_iocbq; + /* the command is in process of being cancelled */ + if (!(iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ)) { + spin_unlock_irq(&phba->hbalock); + lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, + "3169 SCSI Layer abort requested I/O has been " + "cancelled by LLD.\n"); + return FAILED; + } /* * If pCmd field of the corresponding lpfc_scsi_buf structure * points to a different SCSI command, then the driver has * already completed this command, but the midlayer did not - * see the completion before the eh fired. Just return - * SUCCESS. + * see the completion before the eh fired. Just return SUCCESS. */ - iocb = &lpfc_cmd->cur_iocbq; - if (lpfc_cmd->pCmd != cmnd) - goto out; + if (lpfc_cmd->pCmd != cmnd) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, + "3170 SCSI Layer abort requested I/O has been " + "completed by LLD.\n"); + goto out_unlock; + } BUG_ON(iocb->context1 != lpfc_cmd); - abtsiocb = lpfc_sli_get_iocbq(phba); + abtsiocb = __lpfc_sli_get_iocbq(phba); if (abtsiocb == NULL) { ret = FAILED; - goto out; + goto out_unlock; } /* @@ -4405,6 +4498,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; abtsiocb->vport = vport; + /* no longer need the lock after this point */ + spin_unlock_irq(&phba->hbalock); + if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) == IOCB_ERROR) { lpfc_sli_release_iocbq(phba, abtsiocb); @@ -4421,10 +4517,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) wait_event_timeout(waitq, (lpfc_cmd->pCmd != cmnd), (2*vport->cfg_devloss_tmo*HZ)); - - spin_lock_irq(shost->host_lock); lpfc_cmd->waitq = NULL; - spin_unlock_irq(shost->host_lock); if (lpfc_cmd->pCmd == cmnd) { ret = FAILED; @@ -4434,8 +4527,11 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) "LUN %d\n", ret, cmnd->device->id, cmnd->device->lun); } + goto out; - out: +out_unlock: + spin_unlock_irq(&phba->hbalock); +out: lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, "0749 SCSI Layer I/O Abort Request Status x%x ID %d " "LUN %d\n", ret, cmnd->device->id, @@ -4863,6 +4959,43 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) } /** + * lpfc_host_reset_handler - scsi_host_template eh_host_reset_handler entry pt + * @cmnd: Pointer to scsi_cmnd data structure. + * + * This routine does host reset to the adaptor port. It brings the HBA + * offline, performs a board restart, and then brings the board back online. + * The lpfc_offline calls lpfc_sli_hba_down which will abort and local + * reject all outstanding SCSI commands to the host and error returned + * back to SCSI mid-level. As this will be SCSI mid-level's last resort + * of error handling, it will only return error if resetting of the adapter + * is not successful; in all other cases, will return success. + * + * Return code : + * 0x2003 - Error + * 0x2002 - Success + **/ +static int +lpfc_host_reset_handler(struct scsi_cmnd *cmnd) +{ + struct Scsi_Host *shost = cmnd->device->host; + struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct lpfc_hba *phba = vport->phba; + int rc, ret = SUCCESS; + + lpfc_offline_prep(phba); + lpfc_offline(phba); + rc = lpfc_sli_brdrestart(phba); + if (rc) + ret = FAILED; + lpfc_online(phba); + lpfc_unblock_mgmt_io(phba); + + lpfc_printf_log(phba, KERN_ERR, LOG_FCP, + "3172 SCSI layer issued Host Reset Data: x%x\n", ret); + return ret; +} + +/** * lpfc_slave_alloc - scsi_host_template slave_alloc entry point * @sdev: Pointer to scsi_device. * @@ -4994,6 +5127,7 @@ struct scsi_host_template lpfc_template = { .eh_device_reset_handler = lpfc_device_reset_handler, .eh_target_reset_handler = lpfc_target_reset_handler, .eh_bus_reset_handler = lpfc_bus_reset_handler, + .eh_host_reset_handler = lpfc_host_reset_handler, .slave_alloc = lpfc_slave_alloc, .slave_configure = lpfc_slave_configure, .slave_destroy = lpfc_slave_destroy, diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index dbaf5b963bff..b4720a109817 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -67,6 +67,8 @@ static void lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *, struct hbq_dmabuf *); static int lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *, struct lpfc_queue *, struct lpfc_cqe *); +static int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *, struct list_head *, + int); static IOCB_t * lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) @@ -500,7 +502,7 @@ lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) * allocation is successful, it returns pointer to the newly * allocated iocb object else it returns NULL. **/ -static struct lpfc_iocbq * +struct lpfc_iocbq * __lpfc_sli_get_iocbq(struct lpfc_hba *phba) { struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; @@ -875,6 +877,9 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) } else if ((piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) && !(piocbq->iocb_flag & LPFC_IO_LIBDFC)) ndlp = piocbq->context_un.ndlp; + else if ((piocbq->iocb.ulpCommand == CMD_ELS_REQUEST64_CR) && + (piocbq->iocb_flag & LPFC_IO_LIBDFC)) + ndlp = piocbq->context_un.ndlp; else ndlp = piocbq->context1; @@ -883,7 +888,7 @@ __lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) while (!found) { if (!sglq) return NULL; - if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_xritag)) { + if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_lxritag)) { /* This xri has an rrq outstanding for this DID. * put it back in the list and get another xri. */ @@ -1257,7 +1262,7 @@ lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb) { list_add_tail(&piocb->list, &pring->txcmplq); - piocb->iocb_flag |= LPFC_IO_ON_Q; + piocb->iocb_flag |= LPFC_IO_ON_TXCMPLQ; pring->txcmplq_cnt++; if (pring->txcmplq_cnt > pring->txcmplq_max) pring->txcmplq_max = pring->txcmplq_cnt; @@ -2556,9 +2561,9 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, if (iotag != 0 && iotag <= phba->sli.last_iotag) { cmd_iocb = phba->sli.iocbq_lookup[iotag]; list_del_init(&cmd_iocb->list); - if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) { + if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) { pring->txcmplq_cnt--; - cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q; + cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; } return cmd_iocb; } @@ -2591,14 +2596,14 @@ lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba, if (iotag != 0 && iotag <= phba->sli.last_iotag) { cmd_iocb = phba->sli.iocbq_lookup[iotag]; - list_del_init(&cmd_iocb->list); - if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) { - cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q; + if (cmd_iocb->iocb_flag & LPFC_IO_ON_TXCMPLQ) { + /* remove from txcmpl queue list */ + list_del_init(&cmd_iocb->list); + cmd_iocb->iocb_flag &= ~LPFC_IO_ON_TXCMPLQ; pring->txcmplq_cnt--; + return cmd_iocb; } - return cmd_iocb; } - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0372 iotag x%x is out off range: max iotag (x%x)\n", iotag, phba->sli.last_iotag); @@ -3466,6 +3471,9 @@ lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) /* Retrieve everything on the txcmplq */ list_splice_init(&pring->txcmplq, &txcmplq); pring->txcmplq_cnt = 0; + + /* Indicate the I/O queues are flushed */ + phba->hba_flag |= HBA_FCP_IOQ_FLUSH; spin_unlock_irq(&phba->hbalock); /* Flush the txq */ @@ -3877,6 +3885,7 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; uint16_t cfg_value; + int rc; /* Reset HBA */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, @@ -3905,12 +3914,12 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) /* Perform FCoE PCI function reset */ lpfc_sli4_queue_destroy(phba); - lpfc_pci_function_reset(phba); + rc = lpfc_pci_function_reset(phba); /* Restore PCI cmd register */ pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value); - return 0; + return rc; } /** @@ -4002,6 +4011,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; uint32_t hba_aer_enabled; + int rc; /* Restart HBA */ lpfc_printf_log(phba, KERN_INFO, LOG_SLI, @@ -4011,7 +4021,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) /* Take PCIe device Advanced Error Reporting (AER) state */ hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED; - lpfc_sli4_brdreset(phba); + rc = lpfc_sli4_brdreset(phba); spin_lock_irq(&phba->hbalock); phba->pport->stopped = 0; @@ -4028,7 +4038,7 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) lpfc_hba_down_post(phba); - return 0; + return rc; } /** @@ -4967,7 +4977,12 @@ lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type, &rsrc_info->u.rsp); *extnt_size = bf_get(lpfc_mbx_get_rsrc_extent_info_size, &rsrc_info->u.rsp); - err_exit: + + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "3162 Retrieved extents type-%d from port: count:%d, " + "size:%d\n", type, *extnt_count, *extnt_size); + +err_exit: mempool_free(mbox, phba->mbox_mem_pool); return rc; } @@ -5051,7 +5066,7 @@ lpfc_sli4_chk_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type) * 0: if successful **/ static int -lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt, +lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t extnt_cnt, uint16_t type, bool *emb, LPFC_MBOXQ_t *mbox) { int rc = 0; @@ -5060,7 +5075,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt, uint32_t alloc_len, mbox_tmo; /* Calculate the total requested length of the dma memory */ - req_len = *extnt_cnt * sizeof(uint16_t); + req_len = extnt_cnt * sizeof(uint16_t); /* * Calculate the size of an embedded mailbox. The uint32_t @@ -5075,7 +5090,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt, */ *emb = LPFC_SLI4_MBX_EMBED; if (req_len > emb_len) { - req_len = *extnt_cnt * sizeof(uint16_t) + + req_len = extnt_cnt * sizeof(uint16_t) + sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); *emb = LPFC_SLI4_MBX_NEMBED; @@ -5091,7 +5106,7 @@ lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt, "size (x%x)\n", alloc_len, req_len); return -ENOMEM; } - rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, *extnt_cnt, type, *emb); + rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, extnt_cnt, type, *emb); if (unlikely(rc)) return -EIO; @@ -5149,17 +5164,15 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) return -ENOMEM; } - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT, - "2903 Available Resource Extents " - "for resource type 0x%x: Count: 0x%x, " - "Size 0x%x\n", type, rsrc_cnt, - rsrc_size); + lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT | LOG_SLI, + "2903 Post resource extents type-0x%x: " + "count:%d, size %d\n", type, rsrc_cnt, rsrc_size); mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mbox) return -ENOMEM; - rc = lpfc_sli4_cfg_post_extnts(phba, &rsrc_cnt, type, &emb, mbox); + rc = lpfc_sli4_cfg_post_extnts(phba, rsrc_cnt, type, &emb, mbox); if (unlikely(rc)) { rc = -EIO; goto err_exit; @@ -5250,6 +5263,7 @@ lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) rc = -ENOMEM; goto err_exit; } + phba->sli4_hba.max_cfg_param.xri_used = 0; phba->sli4_hba.xri_ids = kzalloc(rsrc_id_cnt * sizeof(uint16_t), GFP_KERNEL); @@ -5420,7 +5434,6 @@ lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type) case LPFC_RSC_TYPE_FCOE_XRI: kfree(phba->sli4_hba.xri_bmask); kfree(phba->sli4_hba.xri_ids); - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); list_for_each_entry_safe(rsrc_blk, rsrc_blk_next, &phba->sli4_hba.lpfc_xri_blk_list, list) { list_del_init(&rsrc_blk->list); @@ -5612,7 +5625,6 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) goto free_vpi_ids; } phba->sli4_hba.max_cfg_param.xri_used = 0; - phba->sli4_hba.xri_count = 0; phba->sli4_hba.xri_ids = kzalloc(count * sizeof(uint16_t), GFP_KERNEL); @@ -5694,7 +5706,6 @@ lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba) bf_set(lpfc_vpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); kfree(phba->sli4_hba.xri_bmask); kfree(phba->sli4_hba.xri_ids); - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); kfree(phba->sli4_hba.vfi_bmask); kfree(phba->sli4_hba.vfi_ids); bf_set(lpfc_vfi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); @@ -5853,6 +5864,149 @@ lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type, } /** + * lpfc_sli4_repost_els_sgl_list - Repsot the els buffers sgl pages as block + * @phba: pointer to lpfc hba data structure. + * + * This routine walks the list of els buffers that have been allocated and + * repost them to the port by using SGL block post. This is needed after a + * pci_function_reset/warm_start or start. It attempts to construct blocks + * of els buffer sgls which contains contiguous xris and uses the non-embedded + * SGL block post mailbox commands to post them to the port. For single els + * buffer sgl with non-contiguous xri, if any, it shall use embedded SGL post + * mailbox command for posting. + * + * Returns: 0 = success, non-zero failure. + **/ +static int +lpfc_sli4_repost_els_sgl_list(struct lpfc_hba *phba) +{ + struct lpfc_sglq *sglq_entry = NULL; + struct lpfc_sglq *sglq_entry_next = NULL; + struct lpfc_sglq *sglq_entry_first = NULL; + int status, post_cnt = 0, num_posted = 0, block_cnt = 0; + int last_xritag = NO_XRI; + LIST_HEAD(prep_sgl_list); + LIST_HEAD(blck_sgl_list); + LIST_HEAD(allc_sgl_list); + LIST_HEAD(post_sgl_list); + LIST_HEAD(free_sgl_list); + + spin_lock(&phba->hbalock); + list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &allc_sgl_list); + spin_unlock(&phba->hbalock); + + list_for_each_entry_safe(sglq_entry, sglq_entry_next, + &allc_sgl_list, list) { + list_del_init(&sglq_entry->list); + block_cnt++; + if ((last_xritag != NO_XRI) && + (sglq_entry->sli4_xritag != last_xritag + 1)) { + /* a hole in xri block, form a sgl posting block */ + list_splice_init(&prep_sgl_list, &blck_sgl_list); + post_cnt = block_cnt - 1; + /* prepare list for next posting block */ + list_add_tail(&sglq_entry->list, &prep_sgl_list); + block_cnt = 1; + } else { + /* prepare list for next posting block */ + list_add_tail(&sglq_entry->list, &prep_sgl_list); + /* enough sgls for non-embed sgl mbox command */ + if (block_cnt == LPFC_NEMBED_MBOX_SGL_CNT) { + list_splice_init(&prep_sgl_list, + &blck_sgl_list); + post_cnt = block_cnt; + block_cnt = 0; + } + } + num_posted++; + + /* keep track of last sgl's xritag */ + last_xritag = sglq_entry->sli4_xritag; + + /* end of repost sgl list condition for els buffers */ + if (num_posted == phba->sli4_hba.els_xri_cnt) { + if (post_cnt == 0) { + list_splice_init(&prep_sgl_list, + &blck_sgl_list); + post_cnt = block_cnt; + } else if (block_cnt == 1) { + status = lpfc_sli4_post_sgl(phba, + sglq_entry->phys, 0, + sglq_entry->sli4_xritag); + if (!status) { + /* successful, put sgl to posted list */ + list_add_tail(&sglq_entry->list, + &post_sgl_list); + } else { + /* Failure, put sgl to free list */ + lpfc_printf_log(phba, KERN_WARNING, + LOG_SLI, + "3159 Failed to post els " + "sgl, xritag:x%x\n", + sglq_entry->sli4_xritag); + list_add_tail(&sglq_entry->list, + &free_sgl_list); + spin_lock_irq(&phba->hbalock); + phba->sli4_hba.els_xri_cnt--; + spin_unlock_irq(&phba->hbalock); + } + } + } + + /* continue until a nembed page worth of sgls */ + if (post_cnt == 0) + continue; + + /* post the els buffer list sgls as a block */ + status = lpfc_sli4_post_els_sgl_list(phba, &blck_sgl_list, + post_cnt); + + if (!status) { + /* success, put sgl list to posted sgl list */ + list_splice_init(&blck_sgl_list, &post_sgl_list); + } else { + /* Failure, put sgl list to free sgl list */ + sglq_entry_first = list_first_entry(&blck_sgl_list, + struct lpfc_sglq, + list); + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "3160 Failed to post els sgl-list, " + "xritag:x%x-x%x\n", + sglq_entry_first->sli4_xritag, + (sglq_entry_first->sli4_xritag + + post_cnt - 1)); + list_splice_init(&blck_sgl_list, &free_sgl_list); + spin_lock_irq(&phba->hbalock); + phba->sli4_hba.els_xri_cnt -= post_cnt; + spin_unlock_irq(&phba->hbalock); + } + + /* don't reset xirtag due to hole in xri block */ + if (block_cnt == 0) + last_xritag = NO_XRI; + + /* reset els sgl post count for next round of posting */ + post_cnt = 0; + } + + /* free the els sgls failed to post */ + lpfc_free_sgl_list(phba, &free_sgl_list); + + /* push els sgls posted to the availble list */ + if (!list_empty(&post_sgl_list)) { + spin_lock(&phba->hbalock); + list_splice_init(&post_sgl_list, + &phba->sli4_hba.lpfc_sgl_list); + spin_unlock(&phba->hbalock); + } else { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, + "3161 Failure to post els sgl to port.\n"); + return -EIO; + } + return 0; +} + +/** * lpfc_sli4_hba_setup - SLI4 device intialization PCI function * @phba: Pointer to HBA context object. * @@ -5923,6 +6077,8 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) else phba->hba_flag &= ~HBA_FIP_SUPPORT; + phba->hba_flag &= ~HBA_FCP_IOQ_FLUSH; + if (phba->sli_rev != LPFC_SLI_REV4) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "0376 READ_REV Error. SLI Level %d " @@ -6063,8 +6219,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) "rc = x%x\n", rc); goto out_free_mbox; } - /* update physical xri mappings in the scsi buffers */ - lpfc_scsi_buf_update(phba); /* Read the port's service parameters. */ rc = lpfc_read_sparam(phba, mboxq, vport->vpi); @@ -6105,28 +6259,26 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn); fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn); - /* Register SGL pool to the device using non-embedded mailbox command */ - if (!phba->sli4_hba.extents_in_use) { - rc = lpfc_sli4_post_els_sgl_list(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0582 Error %d during els sgl post " - "operation\n", rc); - rc = -ENODEV; - goto out_free_mbox; - } - } else { - rc = lpfc_sli4_post_els_sgl_list_ext(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "2560 Error %d during els sgl post " - "operation\n", rc); - rc = -ENODEV; - goto out_free_mbox; - } + /* update host els and scsi xri-sgl sizes and mappings */ + rc = lpfc_sli4_xri_sgl_update(phba); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "1400 Failed to update xri-sgl size and " + "mapping: %d\n", rc); + goto out_free_mbox; } - /* Register SCSI SGL pool to the device */ + /* register the els sgl pool to the port */ + rc = lpfc_sli4_repost_els_sgl_list(phba); + if (unlikely(rc)) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, + "0582 Error %d during els sgl post " + "operation\n", rc); + rc = -ENODEV; + goto out_free_mbox; + } + + /* register the allocated scsi sgl pool to the port */ rc = lpfc_sli4_repost_scsi_sgl_list(phba); if (unlikely(rc)) { lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, @@ -7060,14 +7212,19 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, if (rc != MBX_SUCCESS) lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, "(%d):2541 Mailbox command x%x " - "(x%x/x%x) cannot issue Data: " - "x%x x%x\n", + "(x%x/x%x) failure: " + "mqe_sta: x%x mcqe_sta: x%x/x%x " + "Data: x%x x%x\n,", mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, mboxq), lpfc_sli_config_mbox_opcode_get(phba, mboxq), + bf_get(lpfc_mqe_status, &mboxq->u.mqe), + bf_get(lpfc_mcqe_status, &mboxq->mcqe), + bf_get(lpfc_mcqe_ext_status, + &mboxq->mcqe), psli->sli_flag, flag); return rc; } else if (flag == MBX_POLL) { @@ -7086,18 +7243,22 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, /* Successfully blocked, now issue sync mbox cmd */ rc = lpfc_sli4_post_sync_mbox(phba, mboxq); if (rc != MBX_SUCCESS) - lpfc_printf_log(phba, KERN_ERR, + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, - "(%d):2597 Mailbox command " - "x%x (x%x/x%x) cannot issue " - "Data: x%x x%x\n", - mboxq->vport ? - mboxq->vport->vpi : 0, + "(%d):2597 Sync Mailbox command " + "x%x (x%x/x%x) failure: " + "mqe_sta: x%x mcqe_sta: x%x/x%x " + "Data: x%x x%x\n,", + mboxq->vport ? mboxq->vport->vpi : 0, mboxq->u.mb.mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, mboxq), lpfc_sli_config_mbox_opcode_get(phba, mboxq), + bf_get(lpfc_mqe_status, &mboxq->u.mqe), + bf_get(lpfc_mcqe_status, &mboxq->mcqe), + bf_get(lpfc_mcqe_ext_status, + &mboxq->mcqe), psli->sli_flag, flag); /* Unblock the async mailbox posting afterward */ lpfc_sli4_async_mbox_unblock(phba); @@ -7712,7 +7873,10 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, switch (iocbq->iocb.ulpCommand) { case CMD_ELS_REQUEST64_CR: - ndlp = (struct lpfc_nodelist *)iocbq->context1; + if (iocbq->iocb_flag & LPFC_IO_LIBDFC) + ndlp = iocbq->context_un.ndlp; + else + ndlp = (struct lpfc_nodelist *)iocbq->context1; if (!iocbq->iocb.ulpLe) { lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2007 Only Limited Edition cmd Format" @@ -7751,9 +7915,13 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, bf_set(els_req64_sp, &wqe->els_req, 1); bf_set(els_req64_sid, &wqe->els_req, iocbq->vport->fc_myDID); + if ((*pcmd == ELS_CMD_FLOGI) && + !(phba->fc_topology == + LPFC_TOPOLOGY_LOOP)) + bf_set(els_req64_sid, &wqe->els_req, 0); bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, - phba->vpi_ids[phba->pport->vpi]); + phba->vpi_ids[iocbq->vport->vpi]); } else if (pcmd && iocbq->context1) { bf_set(wqe_ct, &wqe->els_req.wqe_com, 0); bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, @@ -7908,11 +8076,25 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, /* words0-2 BDE memcpy */ /* word3 iocb=iotag32 wqe=response_payload_len */ wqe->xmit_els_rsp.response_payload_len = xmit_len; - /* word4 iocb=did wge=rsvd. */ - wqe->xmit_els_rsp.rsvd4 = 0; + /* word4 */ + wqe->xmit_els_rsp.word4 = 0; /* word5 iocb=rsvd wge=did */ bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest, - iocbq->iocb.un.elsreq64.remoteID); + iocbq->iocb.un.xseq64.xmit_els_remoteID); + + if_type = bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf); + if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { + if (iocbq->vport->fc_flag & FC_PT2PT) { + bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1); + bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, + iocbq->vport->fc_myDID); + if (iocbq->vport->fc_myDID == Fabric_DID) { + bf_set(wqe_els_did, + &wqe->xmit_els_rsp.wqe_dest, 0); + } + } + } bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com, ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); bf_set(wqe_pu, &wqe->xmit_els_rsp.wqe_com, iocbq->iocb.ulpPU); @@ -7932,11 +8114,11 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, pcmd = (uint32_t *) (((struct lpfc_dmabuf *) iocbq->context2)->virt); if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - bf_set(els_req64_sp, &wqe->els_req, 1); - bf_set(els_req64_sid, &wqe->els_req, + bf_set(els_rsp64_sp, &wqe->xmit_els_rsp, 1); + bf_set(els_rsp64_sid, &wqe->xmit_els_rsp, iocbq->vport->fc_myDID); - bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); - bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, + bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com, 1); + bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, phba->vpi_ids[phba->pport->vpi]); } command_type = OTHER_COMMAND; @@ -13080,9 +13262,7 @@ lpfc_sli4_alloc_xri(struct lpfc_hba *phba) } else { set_bit(xri, phba->sli4_hba.xri_bmask); phba->sli4_hba.max_cfg_param.xri_used++; - phba->sli4_hba.xri_count++; } - spin_unlock_irq(&phba->hbalock); return xri; } @@ -13098,7 +13278,6 @@ void __lpfc_sli4_free_xri(struct lpfc_hba *phba, int xri) { if (test_and_clear_bit(xri, phba->sli4_hba.xri_bmask)) { - phba->sli4_hba.xri_count--; phba->sli4_hba.max_cfg_param.xri_used--; } } @@ -13134,46 +13313,45 @@ lpfc_sli4_next_xritag(struct lpfc_hba *phba) uint16_t xri_index; xri_index = lpfc_sli4_alloc_xri(phba); - if (xri_index != NO_XRI) - return xri_index; - - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2004 Failed to allocate XRI.last XRITAG is %d" - " Max XRI is %d, Used XRI is %d\n", - xri_index, - phba->sli4_hba.max_cfg_param.max_xri, - phba->sli4_hba.max_cfg_param.xri_used); - return NO_XRI; + if (xri_index == NO_XRI) + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "2004 Failed to allocate XRI.last XRITAG is %d" + " Max XRI is %d, Used XRI is %d\n", + xri_index, + phba->sli4_hba.max_cfg_param.max_xri, + phba->sli4_hba.max_cfg_param.xri_used); + return xri_index; } /** * lpfc_sli4_post_els_sgl_list - post a block of ELS sgls to the port. * @phba: pointer to lpfc hba data structure. + * @post_sgl_list: pointer to els sgl entry list. + * @count: number of els sgl entries on the list. * * This routine is invoked to post a block of driver's sgl pages to the * HBA using non-embedded mailbox command. No Lock is held. This routine * is only called when the driver is loading and after all IO has been * stopped. **/ -int -lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) +static int +lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba, + struct list_head *post_sgl_list, + int post_cnt) { - struct lpfc_sglq *sglq_entry; + struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; struct lpfc_mbx_post_uembed_sgl_page1 *sgl; struct sgl_page_pairs *sgl_pg_pairs; void *viraddr; LPFC_MBOXQ_t *mbox; uint32_t reqlen, alloclen, pg_pairs; uint32_t mbox_tmo; - uint16_t xritag_start = 0, lxri = 0; - int els_xri_cnt, rc = 0; + uint16_t xritag_start = 0; + int rc = 0; uint32_t shdr_status, shdr_add_status; union lpfc_sli4_cfg_shdr *shdr; - /* The number of sgls to be posted */ - els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); - - reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) + + reqlen = phba->sli4_hba.els_xri_cnt * sizeof(struct sgl_page_pairs) + sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); if (reqlen > SLI4_PAGE_SIZE) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -13203,25 +13381,8 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; sgl_pg_pairs = &sgl->sgl_pg_pairs; - for (pg_pairs = 0; pg_pairs < els_xri_cnt; pg_pairs++) { - sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[pg_pairs]; - - /* - * Assign the sglq a physical xri only if the driver has not - * initialized those resources. A port reset only needs - * the sglq's posted. - */ - if (bf_get(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags) != - LPFC_XRI_RSRC_RDY) { - lxri = lpfc_sli4_next_xritag(phba); - if (lxri == NO_XRI) { - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - sglq_entry->sli4_lxritag = lxri; - sglq_entry->sli4_xritag = phba->sli4_hba.xri_ids[lxri]; - } - + pg_pairs = 0; + list_for_each_entry_safe(sglq_entry, sglq_next, post_sgl_list, list) { /* Set up the sge entry */ sgl_pg_pairs->sgl_pg0_addr_lo = cpu_to_le32(putPaddrLow(sglq_entry->phys)); @@ -13236,11 +13397,12 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) if (pg_pairs == 0) xritag_start = sglq_entry->sli4_xritag; sgl_pg_pairs++; + pg_pairs++; } /* Complete initialization and perform endian conversion. */ bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start); - bf_set(lpfc_post_sgl_pages_xricnt, sgl, els_xri_cnt); + bf_set(lpfc_post_sgl_pages_xricnt, sgl, phba->sli4_hba.els_xri_cnt); sgl->word0 = cpu_to_le32(sgl->word0); if (!phba->sli4_hba.intr_enable) rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); @@ -13260,183 +13422,6 @@ lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) shdr_status, shdr_add_status, rc); rc = -ENXIO; } - - if (rc == 0) - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, - LPFC_XRI_RSRC_RDY); - return rc; -} - -/** - * lpfc_sli4_post_els_sgl_list_ext - post a block of ELS sgls to the port. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to post a block of driver's sgl pages to the - * HBA using non-embedded mailbox command. No Lock is held. This routine - * is only called when the driver is loading and after all IO has been - * stopped. - **/ -int -lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba) -{ - struct lpfc_sglq *sglq_entry; - struct lpfc_mbx_post_uembed_sgl_page1 *sgl; - struct sgl_page_pairs *sgl_pg_pairs; - void *viraddr; - LPFC_MBOXQ_t *mbox; - uint32_t reqlen, alloclen, index; - uint32_t mbox_tmo; - uint16_t rsrc_start, rsrc_size, els_xri_cnt, post_els_xri_cnt; - uint16_t xritag_start = 0, lxri = 0; - struct lpfc_rsrc_blks *rsrc_blk; - int cnt, ttl_cnt, rc = 0; - int loop_cnt; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - - /* The number of sgls to be posted */ - els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); - - reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - if (reqlen > SLI4_PAGE_SIZE) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2989 Block sgl registration required DMA " - "size (%d) great than a page\n", reqlen); - return -ENOMEM; - } - - cnt = 0; - ttl_cnt = 0; - post_els_xri_cnt = els_xri_cnt; - list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list, - list) { - rsrc_start = rsrc_blk->rsrc_start; - rsrc_size = rsrc_blk->rsrc_size; - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3014 Working ELS Extent start %d, cnt %d\n", - rsrc_start, rsrc_size); - - loop_cnt = min(post_els_xri_cnt, rsrc_size); - if (loop_cnt < post_els_xri_cnt) { - post_els_xri_cnt -= loop_cnt; - ttl_cnt += loop_cnt; - } else - ttl_cnt += post_els_xri_cnt; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - /* - * Allocate DMA memory and set up the non-embedded mailbox - * command. - */ - alloclen = lpfc_sli4_config(phba, mbox, - LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, - reqlen, LPFC_SLI4_MBX_NEMBED); - if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2987 Allocated DMA memory size (%d) " - "is less than the requested DMA memory " - "size (%d)\n", alloclen, reqlen); - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - - /* Set up the SGL pages in the non-embedded DMA pages */ - viraddr = mbox->sge_array->addr[0]; - sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; - sgl_pg_pairs = &sgl->sgl_pg_pairs; - - /* - * The starting resource may not begin at zero. Control - * the loop variants via the block resource parameters, - * but handle the sge pointers with a zero-based index - * that doesn't get reset per loop pass. - */ - for (index = rsrc_start; - index < rsrc_start + loop_cnt; - index++) { - sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[cnt]; - - /* - * Assign the sglq a physical xri only if the driver - * has not initialized those resources. A port reset - * only needs the sglq's posted. - */ - if (bf_get(lpfc_xri_rsrc_rdy, - &phba->sli4_hba.sli4_flags) != - LPFC_XRI_RSRC_RDY) { - lxri = lpfc_sli4_next_xritag(phba); - if (lxri == NO_XRI) { - lpfc_sli4_mbox_cmd_free(phba, mbox); - rc = -ENOMEM; - goto err_exit; - } - sglq_entry->sli4_lxritag = lxri; - sglq_entry->sli4_xritag = - phba->sli4_hba.xri_ids[lxri]; - } - - /* Set up the sge entry */ - sgl_pg_pairs->sgl_pg0_addr_lo = - cpu_to_le32(putPaddrLow(sglq_entry->phys)); - sgl_pg_pairs->sgl_pg0_addr_hi = - cpu_to_le32(putPaddrHigh(sglq_entry->phys)); - sgl_pg_pairs->sgl_pg1_addr_lo = - cpu_to_le32(putPaddrLow(0)); - sgl_pg_pairs->sgl_pg1_addr_hi = - cpu_to_le32(putPaddrHigh(0)); - - /* Track the starting physical XRI for the mailbox. */ - if (index == rsrc_start) - xritag_start = sglq_entry->sli4_xritag; - sgl_pg_pairs++; - cnt++; - } - - /* Complete initialization and perform endian conversion. */ - rsrc_blk->rsrc_used += loop_cnt; - bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start); - bf_set(lpfc_post_sgl_pages_xricnt, sgl, loop_cnt); - sgl->word0 = cpu_to_le32(sgl->word0); - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3015 Post ELS Extent SGL, start %d, " - "cnt %d, used %d\n", - xritag_start, loop_cnt, rsrc_blk->rsrc_used); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, - &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &shdr->response); - if (rc != MBX_TIMEOUT) - lpfc_sli4_mbox_cmd_free(phba, mbox); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2988 POST_SGL_BLOCK mailbox " - "command failed status x%x " - "add_status x%x mbx status x%x\n", - shdr_status, shdr_add_status, rc); - rc = -ENXIO; - goto err_exit; - } - if (ttl_cnt >= els_xri_cnt) - break; - } - - err_exit: - if (rc == 0) - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, - LPFC_XRI_RSRC_RDY); return rc; } @@ -13452,8 +13437,9 @@ lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba) * **/ int -lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist, - int cnt) +lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, + struct list_head *sblist, + int count) { struct lpfc_scsi_buf *psb; struct lpfc_mbx_post_uembed_sgl_page1 *sgl; @@ -13469,7 +13455,7 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist, union lpfc_sli4_cfg_shdr *shdr; /* Calculate the requested length of the dma memory */ - reqlen = cnt * sizeof(struct sgl_page_pairs) + + reqlen = count * sizeof(struct sgl_page_pairs) + sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); if (reqlen > SLI4_PAGE_SIZE) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, @@ -13553,169 +13539,6 @@ lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist, } /** - * lpfc_sli4_post_scsi_sgl_blk_ext - post a block of scsi sgls to the port. - * @phba: pointer to lpfc hba data structure. - * @sblist: pointer to scsi buffer list. - * @count: number of scsi buffers on the list. - * - * This routine is invoked to post a block of @count scsi sgl pages from a - * SCSI buffer list @sblist to the HBA using non-embedded mailbox command. - * No Lock is held. - * - **/ -int -lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *phba, struct list_head *sblist, - int cnt) -{ - struct lpfc_scsi_buf *psb = NULL; - struct lpfc_mbx_post_uembed_sgl_page1 *sgl; - struct sgl_page_pairs *sgl_pg_pairs; - void *viraddr; - LPFC_MBOXQ_t *mbox; - uint32_t reqlen, alloclen, pg_pairs; - uint32_t mbox_tmo; - uint16_t xri_start = 0, scsi_xri_start; - uint16_t rsrc_range; - int rc = 0, avail_cnt; - uint32_t shdr_status, shdr_add_status; - dma_addr_t pdma_phys_bpl1; - union lpfc_sli4_cfg_shdr *shdr; - struct lpfc_rsrc_blks *rsrc_blk; - uint32_t xri_cnt = 0; - - /* Calculate the total requested length of the dma memory */ - reqlen = cnt * sizeof(struct sgl_page_pairs) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - if (reqlen > SLI4_PAGE_SIZE) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2932 Block sgl registration required DMA " - "size (%d) great than a page\n", reqlen); - return -ENOMEM; - } - - /* - * The use of extents requires the driver to post the sgl headers - * in multiple postings to meet the contiguous resource assignment. - */ - psb = list_prepare_entry(psb, sblist, list); - scsi_xri_start = phba->sli4_hba.scsi_xri_start; - list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list, - list) { - rsrc_range = rsrc_blk->rsrc_start + rsrc_blk->rsrc_size; - if (rsrc_range < scsi_xri_start) - continue; - else if (rsrc_blk->rsrc_used >= rsrc_blk->rsrc_size) - continue; - else - avail_cnt = rsrc_blk->rsrc_size - rsrc_blk->rsrc_used; - - reqlen = (avail_cnt * sizeof(struct sgl_page_pairs)) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - /* - * Allocate DMA memory and set up the non-embedded mailbox - * command. The mbox is used to post an SGL page per loop - * but the DMA memory has a use-once semantic so the mailbox - * is used and freed per loop pass. - */ - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2933 Failed to allocate mbox cmd " - "memory\n"); - return -ENOMEM; - } - alloclen = lpfc_sli4_config(phba, mbox, - LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, - reqlen, - LPFC_SLI4_MBX_NEMBED); - if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2934 Allocated DMA memory size (%d) " - "is less than the requested DMA memory " - "size (%d)\n", alloclen, reqlen); - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - - /* Get the first SGE entry from the non-embedded DMA memory */ - viraddr = mbox->sge_array->addr[0]; - - /* Set up the SGL pages in the non-embedded DMA pages */ - sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; - sgl_pg_pairs = &sgl->sgl_pg_pairs; - - /* pg_pairs tracks posted SGEs per loop iteration. */ - pg_pairs = 0; - list_for_each_entry_continue(psb, sblist, list) { - /* Set up the sge entry */ - sgl_pg_pairs->sgl_pg0_addr_lo = - cpu_to_le32(putPaddrLow(psb->dma_phys_bpl)); - sgl_pg_pairs->sgl_pg0_addr_hi = - cpu_to_le32(putPaddrHigh(psb->dma_phys_bpl)); - if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) - pdma_phys_bpl1 = psb->dma_phys_bpl + - SGL_PAGE_SIZE; - else - pdma_phys_bpl1 = 0; - sgl_pg_pairs->sgl_pg1_addr_lo = - cpu_to_le32(putPaddrLow(pdma_phys_bpl1)); - sgl_pg_pairs->sgl_pg1_addr_hi = - cpu_to_le32(putPaddrHigh(pdma_phys_bpl1)); - /* Keep the first xri for this extent. */ - if (pg_pairs == 0) - xri_start = psb->cur_iocbq.sli4_xritag; - sgl_pg_pairs++; - pg_pairs++; - xri_cnt++; - - /* - * Track two exit conditions - the loop has constructed - * all of the caller's SGE pairs or all available - * resource IDs in this extent are consumed. - */ - if ((xri_cnt == cnt) || (pg_pairs >= avail_cnt)) - break; - } - rsrc_blk->rsrc_used += pg_pairs; - bf_set(lpfc_post_sgl_pages_xri, sgl, xri_start); - bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs); - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3016 Post SCSI Extent SGL, start %d, cnt %d " - "blk use %d\n", - xri_start, pg_pairs, rsrc_blk->rsrc_used); - /* Perform endian conversion if necessary */ - sgl->word0 = cpu_to_le32(sgl->word0); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &shdr->response); - if (rc != MBX_TIMEOUT) - lpfc_sli4_mbox_cmd_free(phba, mbox); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2935 POST_SGL_BLOCK mailbox command " - "failed status x%x add_status x%x " - "mbx status x%x\n", - shdr_status, shdr_add_status, rc); - return -ENXIO; - } - - /* Post only what is requested. */ - if (xri_cnt >= cnt) - break; - } - return rc; -} - -/** * lpfc_fc_frame_check - Check that this frame is a valid frame to handle * @phba: pointer to lpfc_hba struct that the frame was received on * @fc_hdr: A pointer to the FC Header data (In Big Endian Format) @@ -13839,8 +13662,13 @@ lpfc_fc_frame_to_vport(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr, uint32_t did = (fc_hdr->fh_d_id[0] << 16 | fc_hdr->fh_d_id[1] << 8 | fc_hdr->fh_d_id[2]); + if (did == Fabric_DID) return phba->pport; + if ((phba->pport->fc_flag & FC_PT2PT) && + !(phba->link_state == LPFC_HBA_READY)) + return phba->pport; + vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { @@ -14133,7 +13961,6 @@ lpfc_sli4_xri_inrange(struct lpfc_hba *phba, return NO_XRI; } - /** * lpfc_sli4_seq_abort_rsp - bls rsp to sequence abort * @phba: Pointer to HBA context object. @@ -14148,7 +13975,7 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, { struct lpfc_iocbq *ctiocb = NULL; struct lpfc_nodelist *ndlp; - uint16_t oxid, rxid; + uint16_t oxid, rxid, xri, lxri; uint32_t sid, fctl; IOCB_t *icmd; int rc; @@ -14167,8 +13994,6 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, "SID:x%x\n", oxid, sid); return; } - if (lpfc_sli4_xri_inrange(phba, rxid)) - lpfc_set_rrq_active(phba, ndlp, rxid, oxid, 0); /* Allocate buffer for rsp iocb */ ctiocb = lpfc_sli_get_iocbq(phba); @@ -14199,13 +14024,24 @@ lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, ctiocb->sli4_lxritag = NO_XRI; ctiocb->sli4_xritag = NO_XRI; + if (fctl & FC_FC_EX_CTX) + /* Exchange responder sent the abort so we + * own the oxid. + */ + xri = oxid; + else + xri = rxid; + lxri = lpfc_sli4_xri_inrange(phba, xri); + if (lxri != NO_XRI) + lpfc_set_rrq_active(phba, ndlp, lxri, + (xri == oxid) ? rxid : oxid, 0); /* If the oxid maps to the FCP XRI range or if it is out of range, * send a BLS_RJT. The driver no longer has that exchange. * Override the IOCB for a BA_RJT. */ - if (oxid > (phba->sli4_hba.max_cfg_param.max_xri + + if (xri > (phba->sli4_hba.max_cfg_param.max_xri + phba->sli4_hba.max_cfg_param.xri_base) || - oxid > (lpfc_sli4_get_els_iocb_cnt(phba) + + xri > (lpfc_sli4_get_els_iocb_cnt(phba) + phba->sli4_hba.max_cfg_param.xri_base)) { icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT; bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0); @@ -14377,7 +14213,15 @@ lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) /* Initialize the first IOCB. */ first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0; first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS; - first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX; + + /* Check FC Header to see what TYPE of frame we are rcv'ing */ + if (sli4_type_from_fc_hdr(fc_hdr) == FC_TYPE_ELS) { + first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_ELS64_CX; + first_iocbq->iocb.un.rcvels.parmRo = + sli4_did_from_fc_hdr(fc_hdr); + first_iocbq->iocb.ulpPU = PARM_NPIV_DID; + } else + first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX; first_iocbq->iocb.ulpContext = NO_XRI; first_iocbq->iocb.unsli3.rcvsli3.ox_id = be16_to_cpu(fc_hdr->fh_ox_id); @@ -14507,6 +14351,7 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr; struct lpfc_vport *vport; uint32_t fcfi; + uint32_t did; /* Process each received buffer */ fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; @@ -14522,12 +14367,32 @@ lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, else fcfi = bf_get(lpfc_rcqe_fcf_id, &dmabuf->cq_event.cqe.rcqe_cmpl); + vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi); - if (!vport || !(vport->vpi_state & LPFC_VPI_REGISTERED)) { + if (!vport) { /* throw out the frame */ lpfc_in_buf_free(phba, &dmabuf->dbuf); return; } + + /* d_id this frame is directed to */ + did = sli4_did_from_fc_hdr(fc_hdr); + + /* vport is registered unless we rcv a FLOGI directed to Fabric_DID */ + if (!(vport->vpi_state & LPFC_VPI_REGISTERED) && + (did != Fabric_DID)) { + /* + * Throw out the frame if we are not pt2pt. + * The pt2pt protocol allows for discovery frames + * to be received without a registered VPI. + */ + if (!(vport->fc_flag & FC_PT2PT) || + (phba->link_state == LPFC_HBA_READY)) { + lpfc_in_buf_free(phba, &dmabuf->dbuf); + return; + } + } + /* Handle the basic abort sequence (BA_ABTS) event */ if (fc_hdr->fh_r_ctl == FC_RCTL_BA_ABTS) { lpfc_sli4_handle_unsol_abort(vport, dmabuf); diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 3290b8e7ab65..2626f58c0747 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -68,7 +68,7 @@ struct lpfc_iocbq { #define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */ #define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */ #define DSS_SECURITY_OP 0x100 /* security IO */ -#define LPFC_IO_ON_Q 0x200 /* The IO is still on the TXCMPLQ */ +#define LPFC_IO_ON_TXCMPLQ 0x200 /* The IO is still on the TXCMPLQ */ #define LPFC_IO_DIF 0x400 /* T10 DIF IO */ #define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */ diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index c19d139618b7..a4a77080091b 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -75,11 +75,19 @@ (fc_hdr)->fh_s_id[1] << 8 | \ (fc_hdr)->fh_s_id[2]) +#define sli4_did_from_fc_hdr(fc_hdr) \ + ((fc_hdr)->fh_d_id[0] << 16 | \ + (fc_hdr)->fh_d_id[1] << 8 | \ + (fc_hdr)->fh_d_id[2]) + #define sli4_fctl_from_fc_hdr(fc_hdr) \ ((fc_hdr)->fh_f_ctl[0] << 16 | \ (fc_hdr)->fh_f_ctl[1] << 8 | \ (fc_hdr)->fh_f_ctl[2]) +#define sli4_type_from_fc_hdr(fc_hdr) \ + ((fc_hdr)->fh_type) + #define LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT 12000 enum lpfc_sli4_queue_type { @@ -493,14 +501,12 @@ struct lpfc_sli4_hba { uint16_t next_rpi; uint16_t scsi_xri_max; uint16_t scsi_xri_cnt; + uint16_t els_xri_cnt; uint16_t scsi_xri_start; struct list_head lpfc_free_sgl_list; struct list_head lpfc_sgl_list; - struct lpfc_sglq **lpfc_els_sgl_array; struct list_head lpfc_abts_els_sgl_list; - struct lpfc_scsi_buf **lpfc_scsi_psb_array; struct list_head lpfc_abts_scsi_buf_list; - uint32_t total_sglq_bufs; struct lpfc_sglq **lpfc_sglq_active_list; struct list_head lpfc_rpi_hdr_list; unsigned long *rpi_bmask; @@ -509,7 +515,6 @@ struct lpfc_sli4_hba { struct list_head lpfc_rpi_blk_list; unsigned long *xri_bmask; uint16_t *xri_ids; - uint16_t xri_count; struct list_head lpfc_xri_blk_list; unsigned long *vfi_bmask; uint16_t *vfi_ids; @@ -614,11 +619,7 @@ int lpfc_sli4_post_sgl(struct lpfc_hba *, dma_addr_t, dma_addr_t, uint16_t); int lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *); uint16_t lpfc_sli4_next_xritag(struct lpfc_hba *); int lpfc_sli4_post_async_mbox(struct lpfc_hba *); -int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba); -int lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba); int lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *, struct list_head *, int); -int lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *, struct list_head *, - int); struct lpfc_cq_event *__lpfc_sli4_cq_event_alloc(struct lpfc_hba *); struct lpfc_cq_event *lpfc_sli4_cq_event_alloc(struct lpfc_hba *); void __lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *); diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 25cefc254b76..59c57a409981 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.3.30" +#define LPFC_DRIVER_VERSION "8.3.31" #define LPFC_DRIVER_NAME "lpfc" #define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" #define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" |