diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 07:19:18 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-21 07:19:18 -0700 |
commit | 33cf23b0a535475aead57707cb9f4fe135a93544 (patch) | |
tree | 67e14f77f0eeab847a26a6cbfcb44eecb5fa2fda /drivers/scsi/lpfc | |
parent | 7a9b149212f3716c598afe973b6261fd58453b7a (diff) | |
parent | 95bb335c0ebe96afe926387a1ef3a096bd884a82 (diff) | |
download | linux-33cf23b0a535475aead57707cb9f4fe135a93544.tar.gz linux-33cf23b0a535475aead57707cb9f4fe135a93544.tar.bz2 linux-33cf23b0a535475aead57707cb9f4fe135a93544.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (182 commits)
[SCSI] aacraid: add an ifdef'd device delete case instead of taking the device offline
[SCSI] aacraid: prohibit access to array container space
[SCSI] aacraid: add support for handling ATA pass-through commands.
[SCSI] aacraid: expose physical devices for models with newer firmware
[SCSI] aacraid: respond automatically to volumes added by config tool
[SCSI] fcoe: fix fcoe module ref counting
[SCSI] libfcoe: FIP Keep-Alive messages for VPorts are sent with incorrect port_id and wwn
[SCSI] libfcoe: Fix incorrect MAC address clearing
[SCSI] fcoe: fix a circular locking issue with rtnl and sysfs mutex
[SCSI] libfc: Move the port_id into lport
[SCSI] fcoe: move link speed checking into its own routine
[SCSI] libfc: Remove extra pointer check
[SCSI] libfc: Remove unused fc_get_host_port_type
[SCSI] fcoe: fixes wrong error exit in fcoe_create
[SCSI] libfc: set seq_id for incoming sequence
[SCSI] qla2xxx: Updates to ISP82xx support.
[SCSI] qla2xxx: Optionally disable target reset.
[SCSI] qla2xxx: ensure flash operation and host reset via sg_reset are mutually exclusive
[SCSI] qla2xxx: Silence bogus warning by gcc for wrap and did.
[SCSI] qla2xxx: T10 DIF support added.
...
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 20 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.c | 498 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_bsg.h | 3 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_crtn.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_disc.h | 1 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 24 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 79 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 190 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 60 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 213 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_mbox.c | 69 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_nportdisc.c | 99 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 149 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.c | 269 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli.h | 4 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 5 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 2 | ||||
-rw-r--r-- | drivers/scsi/lpfc/lpfc_vport.c | 4 |
19 files changed, 1291 insertions, 403 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 565e16dd74fc..e35a4c71eb9a 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -310,7 +310,9 @@ struct lpfc_vport { #define FC_NLP_MORE 0x40 /* More node to process in node tbl */ #define FC_OFFLINE_MODE 0x80 /* Interface is offline for diag */ #define FC_FABRIC 0x100 /* We are fabric attached */ +#define FC_VPORT_LOGO_RCVD 0x200 /* LOGO received on vport */ #define FC_RSCN_DISCOVERY 0x400 /* Auth all devices after RSCN */ +#define FC_LOGO_RCVD_DID_CHNG 0x800 /* FDISC on phys port detect DID chng*/ #define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */ #define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */ #define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */ @@ -554,6 +556,7 @@ struct lpfc_hba { struct lpfc_dmabuf slim2p; MAILBOX_t *mbox; + uint32_t *mbox_ext; uint32_t *inb_ha_copy; uint32_t *inb_counter; uint32_t inb_last_counter; @@ -622,6 +625,7 @@ struct lpfc_hba { uint32_t cfg_enable_hba_reset; uint32_t cfg_enable_hba_heartbeat; uint32_t cfg_enable_bg; + uint32_t cfg_hostmem_hgp; uint32_t cfg_log_verbose; uint32_t cfg_aer_support; uint32_t cfg_suppress_link_up; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 1849e33e68f9..2e5f376d9ccc 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -869,6 +869,7 @@ lpfc_get_hba_info(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq; MAILBOX_t *pmb; int rc = 0; + uint32_t max_vpi; /* * prevent udev from issuing mailbox commands until the port is @@ -916,11 +917,17 @@ lpfc_get_hba_info(struct lpfc_hba *phba, if (axri) *axri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config) - phba->sli4_hba.max_cfg_param.xri_used; + + /* Account for differences with SLI-3. Get vpi count from + * mailbox data and subtract one for max vpi value. + */ + max_vpi = (bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) > 0) ? + (bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) - 1) : 0; + if (mvpi) - *mvpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config); + *mvpi = max_vpi; if (avpi) - *avpi = bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) - - phba->sli4_hba.max_cfg_param.vpi_used; + *avpi = max_vpi - phba->sli4_hba.max_cfg_param.vpi_used; } else { if (mrpi) *mrpi = pmb->un.varRdConfig.max_rpi; @@ -1925,13 +1932,12 @@ MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:" " 2 - select SLI-2 even on SLI-3 capable HBAs," " 3 - select SLI-3"); -int lpfc_enable_npiv = 0; +int lpfc_enable_npiv = 1; module_param(lpfc_enable_npiv, int, 0); MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality"); lpfc_param_show(enable_npiv); -lpfc_param_init(enable_npiv, 0, 0, 1); -static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, - lpfc_enable_npiv_show, NULL); +lpfc_param_init(enable_npiv, 1, 0, 1); +static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL); /* # lpfc_suppress_link_up: Bring link up at initialization diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index d62b3e467926..dcf088262b20 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -79,6 +79,12 @@ struct lpfc_bsg_iocb { struct lpfc_bsg_mbox { LPFC_MBOXQ_t *pmboxq; MAILBOX_t *mb; + struct lpfc_dmabuf *rxbmp; /* for BIU diags */ + struct lpfc_dmabufext *dmp; /* for BIU diags */ + uint8_t *ext; /* extended mailbox data */ + uint32_t mbOffset; /* from app */ + uint32_t inExtWLen; /* from app */ + uint32_t outExtWLen; /* from app */ /* job waiting for this mbox command to finish */ struct fc_bsg_job *set_job; @@ -1708,21 +1714,26 @@ static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); if (dmabuf) { dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys); - INIT_LIST_HEAD(&dmabuf->list); - bpl = (struct ulp_bde64 *) dmabuf->virt; - memset(bpl, 0, sizeof(*bpl)); - ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); - bpl->addrHigh = - le32_to_cpu(putPaddrHigh(dmabuf->phys + sizeof(*bpl))); - bpl->addrLow = - le32_to_cpu(putPaddrLow(dmabuf->phys + sizeof(*bpl))); - bpl->tus.f.bdeFlags = 0; - bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; - bpl->tus.w = le32_to_cpu(bpl->tus.w); + if (dmabuf->virt) { + INIT_LIST_HEAD(&dmabuf->list); + bpl = (struct ulp_bde64 *) dmabuf->virt; + memset(bpl, 0, sizeof(*bpl)); + ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); + bpl->addrHigh = + le32_to_cpu(putPaddrHigh(dmabuf->phys + + sizeof(*bpl))); + bpl->addrLow = + le32_to_cpu(putPaddrLow(dmabuf->phys + + sizeof(*bpl))); + bpl->tus.f.bdeFlags = 0; + bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; + bpl->tus.w = le32_to_cpu(bpl->tus.w); + } } if (cmdiocbq == NULL || rspiocbq == NULL || - dmabuf == NULL || bpl == NULL || ctreq == NULL) { + dmabuf == NULL || bpl == NULL || ctreq == NULL || + dmabuf->virt == NULL) { ret_val = ENOMEM; goto err_get_xri_exit; } @@ -1918,9 +1929,11 @@ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); if (rxbmp != NULL) { rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); - INIT_LIST_HEAD(&rxbmp->list); - rxbpl = (struct ulp_bde64 *) rxbmp->virt; - rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0); + if (rxbmp->virt) { + INIT_LIST_HEAD(&rxbmp->list); + rxbpl = (struct ulp_bde64 *) rxbmp->virt; + rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0); + } } if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) { @@ -2174,14 +2187,16 @@ lpfc_bsg_diag_test(struct fc_bsg_job *job) if (txbmp) { txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys); - INIT_LIST_HEAD(&txbmp->list); - txbpl = (struct ulp_bde64 *) txbmp->virt; - if (txbpl) + if (txbmp->virt) { + INIT_LIST_HEAD(&txbmp->list); + txbpl = (struct ulp_bde64 *) txbmp->virt; txbuffer = diag_cmd_data_alloc(phba, txbpl, full_size, 0); + } } - if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer) { + if (!cmdiocbq || !rspiocbq || !txbmp || !txbpl || !txbuffer || + !txbmp->virt) { rc = -ENOMEM; goto err_loopback_test_exit; } @@ -2377,35 +2392,90 @@ void lpfc_bsg_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) { struct bsg_job_data *dd_data; - MAILBOX_t *pmb; - MAILBOX_t *mb; struct fc_bsg_job *job; uint32_t size; unsigned long flags; + uint8_t *to; + uint8_t *from; spin_lock_irqsave(&phba->ct_ev_lock, flags); dd_data = pmboxq->context1; + /* job already timed out? */ if (!dd_data) { spin_unlock_irqrestore(&phba->ct_ev_lock, flags); return; } - pmb = &dd_data->context_un.mbox.pmboxq->u.mb; - mb = dd_data->context_un.mbox.mb; + /* build the outgoing buffer to do an sg copy + * the format is the response mailbox followed by any extended + * mailbox data + */ + from = (uint8_t *)&pmboxq->u.mb; + to = (uint8_t *)dd_data->context_un.mbox.mb; + memcpy(to, from, sizeof(MAILBOX_t)); + if (pmboxq->u.mb.mbxStatus == MBX_SUCCESS) { + /* copy the extended data if any, count is in words */ + if (dd_data->context_un.mbox.outExtWLen) { + from = (uint8_t *)dd_data->context_un.mbox.ext; + to += sizeof(MAILBOX_t); + size = dd_data->context_un.mbox.outExtWLen * + sizeof(uint32_t); + memcpy(to, from, size); + } else if (pmboxq->u.mb.mbxCommand == MBX_RUN_BIU_DIAG64) { + from = (uint8_t *)dd_data->context_un.mbox. + dmp->dma.virt; + to += sizeof(MAILBOX_t); + size = dd_data->context_un.mbox.dmp->size; + memcpy(to, from, size); + } else if ((phba->sli_rev == LPFC_SLI_REV4) && + (pmboxq->u.mb.mbxCommand == MBX_DUMP_MEMORY)) { + from = (uint8_t *)dd_data->context_un.mbox.dmp->dma. + virt; + to += sizeof(MAILBOX_t); + size = pmboxq->u.mb.un.varWords[5]; + memcpy(to, from, size); + } else if (pmboxq->u.mb.mbxCommand == MBX_READ_EVENT_LOG) { + from = (uint8_t *)dd_data->context_un. + mbox.dmp->dma.virt; + to += sizeof(MAILBOX_t); + size = dd_data->context_un.mbox.dmp->size; + memcpy(to, from, size); + } + } + + from = (uint8_t *)dd_data->context_un.mbox.mb; job = dd_data->context_un.mbox.set_job; - memcpy(mb, pmb, sizeof(*pmb)); - size = job->request_payload.payload_len; + size = job->reply_payload.payload_len; job->reply->reply_payload_rcv_len = sg_copy_from_buffer(job->reply_payload.sg_list, job->reply_payload.sg_cnt, - mb, size); + from, size); job->reply->result = 0; + dd_data->context_un.mbox.set_job = NULL; job->dd_data = NULL; job->job_done(job); + /* need to hold the lock until we call job done to hold off + * the timeout handler returning to the midlayer while + * we are stillprocessing the job + */ spin_unlock_irqrestore(&phba->ct_ev_lock, flags); + + kfree(dd_data->context_un.mbox.mb); mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); - kfree(mb); + kfree(dd_data->context_un.mbox.ext); + if (dd_data->context_un.mbox.dmp) { + dma_free_coherent(&phba->pcidev->dev, + dd_data->context_un.mbox.dmp->size, + dd_data->context_un.mbox.dmp->dma.virt, + dd_data->context_un.mbox.dmp->dma.phys); + kfree(dd_data->context_un.mbox.dmp); + } + if (dd_data->context_un.mbox.rxbmp) { + lpfc_mbuf_free(phba, dd_data->context_un.mbox.rxbmp->virt, + dd_data->context_un.mbox.rxbmp->phys); + kfree(dd_data->context_un.mbox.rxbmp); + } kfree(dd_data); return; } @@ -2464,10 +2534,12 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, case MBX_SET_DEBUG: case MBX_WRITE_WWN: case MBX_SLI4_CONFIG: + case MBX_READ_EVENT_LOG: case MBX_READ_EVENT_LOG_STATUS: case MBX_WRITE_EVENT_LOG: case MBX_PORT_CAPABILITIES: case MBX_PORT_IOV_CONTROL: + case MBX_RUN_BIU_DIAG64: break; case MBX_SET_VARIABLE: lpfc_printf_log(phba, KERN_INFO, LOG_INIT, @@ -2482,8 +2554,6 @@ static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, phba->fc_topology = TOPOLOGY_PT_PT; } break; - case MBX_RUN_BIU_DIAG64: - case MBX_READ_EVENT_LOG: case MBX_READ_SPARM64: case MBX_READ_LA: case MBX_READ_LA64: @@ -2518,97 +2588,365 @@ static uint32_t lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, struct lpfc_vport *vport) { - LPFC_MBOXQ_t *pmboxq; - MAILBOX_t *pmb; - MAILBOX_t *mb; - struct bsg_job_data *dd_data; + LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */ + MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */ + /* a 4k buffer to hold the mb and extended data from/to the bsg */ + MAILBOX_t *mb = NULL; + struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */ uint32_t size; + struct lpfc_dmabuf *rxbmp = NULL; /* for biu diag */ + struct lpfc_dmabufext *dmp = NULL; /* for biu diag */ + struct ulp_bde64 *rxbpl = NULL; + struct dfc_mbox_req *mbox_req = (struct dfc_mbox_req *) + job->request->rqst_data.h_vendor.vendor_cmd; + uint8_t *ext = NULL; int rc = 0; + uint8_t *from; + + /* in case no data is transferred */ + job->reply->reply_payload_rcv_len = 0; + + /* check if requested extended data lengths are valid */ + if ((mbox_req->inExtWLen > MAILBOX_EXT_SIZE) || + (mbox_req->outExtWLen > MAILBOX_EXT_SIZE)) { + rc = -ERANGE; + goto job_done; + } /* allocate our bsg tracking structure */ dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); if (!dd_data) { lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, "2727 Failed allocation of dd_data\n"); - return -ENOMEM; + rc = -ENOMEM; + goto job_done; } - mb = kzalloc(PAGE_SIZE, GFP_KERNEL); + mb = kzalloc(BSG_MBOX_SIZE, GFP_KERNEL); if (!mb) { - kfree(dd_data); - return -ENOMEM; + rc = -ENOMEM; + goto job_done; } pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmboxq) { - kfree(dd_data); - kfree(mb); - return -ENOMEM; + rc = -ENOMEM; + goto job_done; } + memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); size = job->request_payload.payload_len; - job->reply->reply_payload_rcv_len = - sg_copy_to_buffer(job->request_payload.sg_list, - job->request_payload.sg_cnt, - mb, size); + sg_copy_to_buffer(job->request_payload.sg_list, + job->request_payload.sg_cnt, + mb, size); rc = lpfc_bsg_check_cmd_access(phba, mb, vport); - if (rc != 0) { - kfree(dd_data); - kfree(mb); - mempool_free(pmboxq, phba->mbox_mem_pool); - return rc; /* must be negative */ - } + if (rc != 0) + goto job_done; /* must be negative */ - memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); pmb = &pmboxq->u.mb; memcpy(pmb, mb, sizeof(*pmb)); pmb->mbxOwner = OWN_HOST; - pmboxq->context1 = NULL; pmboxq->vport = vport; - if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { - rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) { - kfree(dd_data); - kfree(mb); - mempool_free(pmboxq, phba->mbox_mem_pool); + /* If HBA encountered an error attention, allow only DUMP + * or RESTART mailbox commands until the HBA is restarted. + */ + if (phba->pport->stopped && + pmb->mbxCommand != MBX_DUMP_MEMORY && + pmb->mbxCommand != MBX_RESTART && + pmb->mbxCommand != MBX_WRITE_VPARMS && + pmb->mbxCommand != MBX_WRITE_WWN) + lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, + "2797 mbox: Issued mailbox cmd " + "0x%x while in stopped state.\n", + pmb->mbxCommand); + + /* Don't allow mailbox commands to be sent when blocked + * or when in the middle of discovery + */ + if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { + rc = -EAGAIN; + goto job_done; + } + + /* extended mailbox commands will need an extended buffer */ + if (mbox_req->inExtWLen || mbox_req->outExtWLen) { + ext = kzalloc(MAILBOX_EXT_SIZE, GFP_KERNEL); + if (!ext) { + rc = -ENOMEM; + goto job_done; + } + + /* any data for the device? */ + if (mbox_req->inExtWLen) { + from = (uint8_t *)mb; + from += sizeof(MAILBOX_t); + memcpy((uint8_t *)ext, from, + mbox_req->inExtWLen * sizeof(uint32_t)); + } + + pmboxq->context2 = ext; + pmboxq->in_ext_byte_len = + mbox_req->inExtWLen * + sizeof(uint32_t); + pmboxq->out_ext_byte_len = + mbox_req->outExtWLen * + sizeof(uint32_t); + pmboxq->mbox_offset_word = + mbox_req->mbOffset; + pmboxq->context2 = ext; + pmboxq->in_ext_byte_len = + mbox_req->inExtWLen * sizeof(uint32_t); + pmboxq->out_ext_byte_len = + mbox_req->outExtWLen * sizeof(uint32_t); + pmboxq->mbox_offset_word = mbox_req->mbOffset; + } + + /* biu diag will need a kernel buffer to transfer the data + * allocate our own buffer and setup the mailbox command to + * use ours + */ + if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) { + uint32_t transmit_length = pmb->un.varWords[1]; + uint32_t receive_length = pmb->un.varWords[4]; + /* transmit length cannot be greater than receive length or + * mailbox extension size + */ + if ((transmit_length > receive_length) || + (transmit_length > MAILBOX_EXT_SIZE)) { + rc = -ERANGE; + goto job_done; + } + + rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!rxbmp) { + rc = -ENOMEM; + goto job_done; + } + + rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); + if (!rxbmp->virt) { + rc = -ENOMEM; + goto job_done; + } + + INIT_LIST_HEAD(&rxbmp->list); + rxbpl = (struct ulp_bde64 *) rxbmp->virt; + dmp = diag_cmd_data_alloc(phba, rxbpl, transmit_length, 0); + if (!dmp) { + rc = -ENOMEM; + goto job_done; + } + + INIT_LIST_HEAD(&dmp->dma.list); + pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = + putPaddrHigh(dmp->dma.phys); + pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = + putPaddrLow(dmp->dma.phys); + + pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = + putPaddrHigh(dmp->dma.phys + + pmb->un.varBIUdiag.un.s2. + xmit_bde64.tus.f.bdeSize); + pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = + putPaddrLow(dmp->dma.phys + + pmb->un.varBIUdiag.un.s2. + xmit_bde64.tus.f.bdeSize); + + /* copy the transmit data found in the mailbox extension area */ + from = (uint8_t *)mb; + from += sizeof(MAILBOX_t); + memcpy((uint8_t *)dmp->dma.virt, from, transmit_length); + } else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) { + struct READ_EVENT_LOG_VAR *rdEventLog = + &pmb->un.varRdEventLog ; + uint32_t receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; + uint32_t mode = bf_get(lpfc_event_log, rdEventLog); + + /* receive length cannot be greater than mailbox + * extension size + */ + if (receive_length > MAILBOX_EXT_SIZE) { + rc = -ERANGE; + goto job_done; + } + + /* mode zero uses a bde like biu diags command */ + if (mode == 0) { + + /* rebuild the command for sli4 using our own buffers + * like we do for biu diags + */ + + rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!rxbmp) { + rc = -ENOMEM; + goto job_done; } - return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; + + rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); + rxbpl = (struct ulp_bde64 *) rxbmp->virt; + if (rxbpl) { + INIT_LIST_HEAD(&rxbmp->list); + dmp = diag_cmd_data_alloc(phba, rxbpl, + receive_length, 0); + } + + if (!dmp) { + rc = -ENOMEM; + goto job_done; + } + + INIT_LIST_HEAD(&dmp->dma.list); + pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys); + pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys); } + } else if (phba->sli_rev == LPFC_SLI_REV4) { + if (pmb->mbxCommand == MBX_DUMP_MEMORY) { + /* rebuild the command for sli4 using our own buffers + * like we do for biu diags + */ + uint32_t receive_length = pmb->un.varWords[2]; + /* receive length cannot be greater than mailbox + * extension size + */ + if ((receive_length == 0) || + (receive_length > MAILBOX_EXT_SIZE)) { + rc = -ERANGE; + goto job_done; + } - memcpy(mb, pmb, sizeof(*pmb)); - job->reply->reply_payload_rcv_len = - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, - mb, size); - kfree(dd_data); - kfree(mb); - mempool_free(pmboxq, phba->mbox_mem_pool); - /* not waiting mbox already done */ - return 0; + rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!rxbmp) { + rc = -ENOMEM; + goto job_done; + } + + rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); + if (!rxbmp->virt) { + rc = -ENOMEM; + goto job_done; + } + + INIT_LIST_HEAD(&rxbmp->list); + rxbpl = (struct ulp_bde64 *) rxbmp->virt; + dmp = diag_cmd_data_alloc(phba, rxbpl, receive_length, + 0); + if (!dmp) { + rc = -ENOMEM; + goto job_done; + } + + INIT_LIST_HEAD(&dmp->dma.list); + pmb->un.varWords[3] = putPaddrLow(dmp->dma.phys); + pmb->un.varWords[4] = putPaddrHigh(dmp->dma.phys); + } else if ((pmb->mbxCommand == MBX_UPDATE_CFG) && + pmb->un.varUpdateCfg.co) { + struct ulp_bde64 *bde = + (struct ulp_bde64 *)&pmb->un.varWords[4]; + + /* bde size cannot be greater than mailbox ext size */ + if (bde->tus.f.bdeSize > MAILBOX_EXT_SIZE) { + rc = -ERANGE; + goto job_done; + } + + rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!rxbmp) { + rc = -ENOMEM; + goto job_done; + } + + rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); + if (!rxbmp->virt) { + rc = -ENOMEM; + goto job_done; + } + + INIT_LIST_HEAD(&rxbmp->list); + rxbpl = (struct ulp_bde64 *) rxbmp->virt; + dmp = diag_cmd_data_alloc(phba, rxbpl, + bde->tus.f.bdeSize, 0); + if (!dmp) { + rc = -ENOMEM; + goto job_done; + } + + INIT_LIST_HEAD(&dmp->dma.list); + bde->addrHigh = putPaddrHigh(dmp->dma.phys); + bde->addrLow = putPaddrLow(dmp->dma.phys); + + /* copy the transmit data found in the mailbox + * extension area + */ + from = (uint8_t *)mb; + from += sizeof(MAILBOX_t); + memcpy((uint8_t *)dmp->dma.virt, from, + bde->tus.f.bdeSize); + } } + dd_data->context_un.mbox.rxbmp = rxbmp; + dd_data->context_un.mbox.dmp = dmp; + /* setup wake call as IOCB callback */ pmboxq->mbox_cmpl = lpfc_bsg_wake_mbox_wait; + /* setup context field to pass wait_queue pointer to wake function */ pmboxq->context1 = dd_data; dd_data->type = TYPE_MBOX; dd_data->context_un.mbox.pmboxq = pmboxq; dd_data->context_un.mbox.mb = mb; dd_data->context_un.mbox.set_job = job; + dd_data->context_un.mbox.ext = ext; + dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset; + dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen; + dd_data->context_un.mbox.outExtWLen = mbox_req->outExtWLen; job->dd_data = dd_data; + + if ((vport->fc_flag & FC_OFFLINE_MODE) || + (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { + rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); + if (rc != MBX_SUCCESS) { + rc = (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; + goto job_done; + } + + /* job finished, copy the data */ + memcpy(mb, pmb, sizeof(*pmb)); + job->reply->reply_payload_rcv_len = + sg_copy_from_buffer(job->reply_payload.sg_list, + job->reply_payload.sg_cnt, + mb, size); + /* not waiting mbox already done */ + rc = 0; + goto job_done; + } + rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); - if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { - kfree(dd_data); - kfree(mb); + if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) + return 1; /* job started */ + +job_done: + /* common exit for error or job completed inline */ + kfree(mb); + if (pmboxq) mempool_free(pmboxq, phba->mbox_mem_pool); - return -EIO; + kfree(ext); + if (dmp) { + dma_free_coherent(&phba->pcidev->dev, + dmp->size, dmp->dma.virt, + dmp->dma.phys); + kfree(dmp); } + if (rxbmp) { + lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); + kfree(rxbmp); + } + kfree(dd_data); - return 1; + return rc; } /** @@ -2633,7 +2971,12 @@ lpfc_bsg_mbox_cmd(struct fc_bsg_job *job) goto job_error; } - if (job->request_payload.payload_len != PAGE_SIZE) { + if (job->request_payload.payload_len != BSG_MBOX_SIZE) { + rc = -EINVAL; + goto job_error; + } + + if (job->reply_payload.payload_len != BSG_MBOX_SIZE) { rc = -EINVAL; goto job_error; } @@ -3094,6 +3437,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job) job->dd_data = NULL; job->reply->reply_payload_rcv_len = 0; job->reply->result = -EAGAIN; + /* the mbox completion handler can now be run */ spin_unlock_irqrestore(&phba->ct_ev_lock, flags); job->job_done(job); break; diff --git a/drivers/scsi/lpfc/lpfc_bsg.h b/drivers/scsi/lpfc/lpfc_bsg.h index 5bc630819b9e..a2c33e7c9152 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.h +++ b/drivers/scsi/lpfc/lpfc_bsg.h @@ -91,11 +91,12 @@ struct get_mgmt_rev_reply { struct MgmtRevInfo info; }; +#define BSG_MBOX_SIZE 4096 /* mailbox command plus extended data */ struct dfc_mbox_req { uint32_t command; + uint32_t mbOffset; uint32_t inExtWLen; uint32_t outExtWLen; - uint8_t mbOffset; }; /* Used for menlo command or menlo data. The xri is only used for menlo data */ diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 5087c4211b43..fbc9baeb6048 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -65,6 +65,7 @@ void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *); void lpfc_retry_pport_discovery(struct lpfc_hba *); +void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t); void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *); diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 2851d75ffc6f..36257a685509 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -38,6 +38,7 @@ enum lpfc_work_type { LPFC_EVT_ELS_RETRY, LPFC_EVT_DEV_LOSS, LPFC_EVT_FASTPATH_MGMT_EVT, + LPFC_EVT_RESET_HBA, }; /* structure used to queue event to the discovery tasklet */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 5fbdb22c1899..c4c7f0ad7468 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -584,6 +584,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_unlock_irq(shost->host_lock); lpfc_unreg_rpi(vport, np); } + lpfc_cleanup_pending_mbox(vport); if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { lpfc_mbx_unreg_vpi(vport); spin_lock_irq(shost->host_lock); @@ -864,6 +865,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_VPORT_CVL_RCVD; + vport->fc_flag &= ~FC_VPORT_LOGO_RCVD; spin_unlock_irq(shost->host_lock); /* @@ -893,11 +895,14 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (!rc) { /* Mark the FCF discovery process done */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP | LOG_ELS, - "2769 FLOGI successful on FCF record: " - "current_fcf_index:x%x, terminate FCF " - "round robin failover process\n", - phba->fcf.current_rec.fcf_indx); + if (phba->hba_flag & HBA_FIP_SUPPORT) + lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP | + LOG_ELS, + "2769 FLOGI successful on FCF " + "record: current_fcf_index:" + "x%x, terminate FCF round " + "robin failover process\n", + phba->fcf.current_rec.fcf_indx); spin_lock_irq(&phba->hbalock); phba->fcf.fcf_flag &= ~FCF_DISCOVERY; spin_unlock_irq(&phba->hbalock); @@ -5366,7 +5371,7 @@ lpfc_send_els_failure_event(struct lpfc_hba *phba, sizeof(struct lpfc_name)); pcmd = (uint32_t *) (((struct lpfc_dmabuf *) cmdiocbp->context2)->virt); - lsrjt_event.command = *pcmd; + lsrjt_event.command = (pcmd != NULL) ? *pcmd : 0; stat.un.lsRjtError = be32_to_cpu(rspiocbp->iocb.un.ulpWord[4]); lsrjt_event.reason_code = stat.un.b.lsRjtRsnCode; lsrjt_event.explanation = stat.un.b.lsRjtRsnCodeExp; @@ -6050,7 +6055,8 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); - if (vport->port_type == LPFC_PHYSICAL_PORT) + if (vport->port_type == LPFC_PHYSICAL_PORT + && !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG)) lpfc_initial_flogi(vport); else lpfc_initial_fdisc(vport); @@ -6286,6 +6292,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_VPORT_CVL_RCVD; + vport->fc_flag &= ~FC_VPORT_LOGO_RCVD; vport->fc_flag |= FC_FABRIC; if (vport->phba->fc_topology == TOPOLOGY_LOOP) vport->f |